The world of mobile app development is vast and ever-evolving, with new frameworks and technologies popping up almost on a daily basis. When you think about a mobile device, you probably think of your phone or maybe your tablet, even though they are nowhere nearly as popular as smartphones.

Apple’s iOS and Google’s Android dominate the mobile market, each having had its ups and downs over the past decade. Today, I am going to talk more about Android and its use on devices that aren’t necessarily mobile.

Being open-source had a really interesting side effect on Google’s mobile operating system. Sure, we may think of all of the different Android forks from various smartphone companies, but what about all the devices running Android that aren’t mobile? Everything ranging from fridges, smart ovens, door locks, or even Point of Sale (POS) devices can run Android nowadays. The latter are the reason I ended up writing this article.

Point of Sale (POS) devices can run Android nowadays

Android POS Systems

About a year ago, I got to play with an Android device that was anything but ordinary, and it’s not something most people are likely to use. The device in question is an Android-based POS system from a Chinese vendor that also has an integrated thermal printer (like the ones used to print out receipts at stores or on ATMs).

The biggest surprise, though, was its software: It was running a bone stock version of Android. If I recall correctly, at the time, it was running Android 8, or Android Oreo if you prefer Google codenames. The device itself looks like an old school portable POS device, but instead of the physical keyboard where you would enter your PIN, it sports a capacitive touchscreen like the ones used in the Android phones of yesteryear.

My requirement was easy: I had to see if there was a way we could use this device’s features such as the thermal printer while also running the app we were developing. As soon as I realized that the requirement itself was possible, another problem came to my attention: security.

The thing is, if you have a device that handles card payments and other kinds of transactions, you might not want that same device to be able to run TikTok, Gmail, or Snapchat. This device was behaving exactly like a tablet, and it even came with Google’s Play Store pre-installed. Imagine going to a small convenience store and seeing your cashier taking selfies, opening emails from a Nigerian prince, and browsing weird, malware-ridden websites.

And afterward, the cashier hands you the same device to enter your PIN. Personally, I would not feel safe about providing my credit card information over such a device.

Locking Users Out of Android Menus

Security aside, I had to take on an even more important challenge: I had to lock the person using the Android POS device inside my app. Messing with the operating system was not an option since these devices were delivered to non-technical people.

Sure, cashiers are more than able to install an application, but most of them could not flash custom ROMs or handle other lower-level operations. The app itself was written in React Native, although that is irrelevant in this context. All the modifications I made are in native Java code, so no matter what you are using to develop your main application, these tweaks should work.

As a little disclaimer, this procedure only works for Android apps. Apple does not give us the control we need to easily accomplish something like this on an iPhone or iPad, which is understandable given the closed nature of iOS.

There are four ways a user could possibly exit an application:

  • Use the Home button.
  • Use the Back button.
  • Use the Recents button.
  • Leave your app through the notification bar.

Either clicking on a recent notification or going to settings from that bar would cause a user to exit our application. You also have gestures, but at the end of the day, these gestures trigger the exact same actions as regular button presses would.

Also, having a PIN system to unlock the application can be really useful for someone to manage the device. This way, only someone holding a PIN would be able to install a different version of the application, without offering deeper access to the end user.

The Home Button

In order to prevent a user from pressing the Home button, we don’t have to actually disable it.

One useful feature of Android is the availability of different launchers. Usually, these apps provide you with different home screens, app drawers, and access to various UI customizations. Every Android device has one pre-installed by the manufacturer. Ultimately, these are just normal, regular apps with one small but crucial exception.

What that means is that if the operating system could recognize our application as being a launcher, we could set it as a default launcher. The side effect of this is that every time you press the Home button, the device will take you to the Home launcher. And if our application is the Home launcher, then basically, this Home button becomes useless. To do that, we have to edit the AndroidManifest XML file in our Android project and add these two lines of code:

<activity
   android:name=".MainActivity"
   android:label="@string/app_name"
   android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
   android:launchMode="singleTask"
   android:windowSoftInputMode="adjustResize">
   <intent-filter>
       <action android:name="android.intent.action.MAIN" />
       <category android:name="android.intent.category.LAUNCHER" />
       <category android:name="android.intent.category.HOME" />
       <category android:name="android.intent.category.DEFAULT" />
   </intent-filter>
</activity>

The first line will make our app eligible to be selected in case the user presses the Home button, and the second line allows our app to be set as the default whenever this action happens.

Now, the only thing left to do was for the field agent to install the application on the device when delivering it to the client. Whenever you install an app that has the potential to be a launcher, Android will ask you if you want to use another launcher and if you want to set that one as the default.

So now, if you pressed the Home button or if you cleared all your recent applications, the device would automatically direct you to my application.

Building an Android POS App That Can’t Be Closed

The Back Button

Next, we have to handle the Back button. Mobile apps usually provide an on-screen way of going back through screens, especially since many devices don’t have a dedicated “back” key.

A few years ago, this was the case with Apple’s iOS devices, which featured their already iconic design with a single physical button below the screen. However, in recent years, most Android devices have dropped physical Home buttons, too. First, they moved to on-screen buttons, and now we’re seeing them being phased out phones in favor of gestures, as phone makers move to all-screen devices with small bezels and chin.

What this means is that the Back button that Android provides by default isn’t really needed, and to render this button completely useless, we just need to add a simple block of code in our activity:

@Override
public void onBackPressed() {
}

Building an Android POS App That Can’t Be Closed

This is a pretty straightforward block of code: Our main activity allows us to intercept whenever a user presses the Back button. In our case, since we don’t want the user to be pressing that button too many times in order to exit the app, we can simply overwrite the default method with one that does nothing, telling our app to do nothing in case the Back button is pressed.

This is how some applications ask for confirmation before you accidentally exit them by going back too many times.

The Recents Button

We still need to handle the Recents button, and this is the trickiest one. Also, this is definitely not a best practice or something that you should push to the Play Store, but it does work for our niche case here.

The same way that the main activity allows us to know when the Back button is pressed, it also allows us to know when the app is paused. What does this mean? This code is triggered every time our app switches from being the foreground application to being in the background.

When intercepting this event, we will get the task ID of our current application and tell the activity manager to move this task to the front. To do this, we need one special permission in the same Android manifest file that we edited earlier.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.johnwick">
   <uses-permission android:name="android.permission.INTERNET" />
   <uses-permission android:name="android.permission.REORDER_TASKS" />
   <application
     android:name=".MainApplication"
     android:label="@string/app_name"
     android:icon="@mipmap/ic_launcher"
     android:roundIcon="@mipmap/ic_launcher_round"
     android:allowBackup="false"
     android:theme="@style/AppTheme">
     <activity
       android:name=".MainActivity"
       android:label="@string/app_name"
  android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
       android:launchMode="singleTask"
       android:windowSoftInputMode="adjustResize">
       <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />

           <category android:name="android.intent.category.HOME" />
           <category android:name="android.intent.category.DEFAULT" />

       </intent-filter>
     </activity>
     <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
   </application>

</manifest>

This will allow us to read the ongoing tasks and make changes to these tasks. Also, we still need to intercept the moment when our application is being sent to the background. We can again override the onPause method in our activity.

Here, we get the task manager and force it to move a specific task to the foreground. In our case, that specific task is the one that has just been sent to the background (our application).

@Override
public void onPause() {
   super.onPause();
   ActivityManager activityManager = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
   activityManager.moveTaskToFront(getTaskId(), 0);
}

Now, every time you want to go to the recents menu, the application will refocus automatically. Sure, you might get a little screen flickering at times, but you will not be able to exit this application. And here’s one more cool thing - remember how I said that you could also exit by clicking a notification or by going directly to the settings through the notification tray? Well, performing those actions will put the app in the background, which will trigger our code, and then the user is shoved right back in.

All of this happens so quickly that the user will not notice what happens in the background. Also, another nice part about this approach is that your quick toggles are still available. You can still select a wifi network, for example, or disable sounds, but anything that requires you to go into the actual Settings app is not allowed.

Building an Android POS App That Can’t Be Closed

The Solution

I am not sure this is the best way to do it, but it was nevertheless a really interesting process while researching a topic that I didn’t even know was possible. And it works! A word of warning: At this point, there are only two ways you can exit the application as a developer—you either reinstall the operating system or you kill/uninstall the app through ADB.

If you somehow lose the ADB connection to the device, I am not aware of an easy way that could get you out. To avoid that, I ended up building a PIN system.

Edge Cases

There are a few situations that we need to make sure we account for. First of all, what if a device reboots? It doesn’t have to be a manual reboot, it can also be a crash of the operating system.

Since we set our application as the default launcher earlier, as soon as the operating system boots back up, it should automatically start our application. But how does Android know to load your home screen on boot? It’s because it basically just loads your default launcher. Since we are the default launcher at this point, reboots should not be an issue. And could Android kill our application at some point? Theoretically, it could kill the app if the RAM memory fills up, but in real life, this is almost impossible. Since our app is unclosable, nobody can open up other apps, and so the RAM memory shouldn’t fill.

The only way I can think of it filling up is if our application has a huge memory leak, but in that case, you would have bigger issues than keeping your user inside the application. Still, even if Android somehow triggers a kill signal to our application, whenever you try to go back home, the OS will attempt to start our app again since it is the default launcher, thus keeping the user locked in.

Building a Back Door

As a quick explanation, there was a place in the application settings where you could enter a PIN to unlock the app. If the PIN is correct, it will disable the limitations set by our onPause and onBackPressed methods by doing a simple conditional statement. From there, a user would be allowed to enter the settings through the quick toggle menu. Afterward, you can always set the default launcher back to the stock one, and that would get you completely out of the app. There are a lot of ways one could handle this part, but it’s good to have a mechanism to disable the same limitations you put in place. Maybe you could do a fingerprint authentication to unlock. The possibilities are almost endless.

Building an Android POS App That Can’t Be Closed

Wrapping Up

Eventually, I was left with an application that nobody could close or kill. Even rebooting the device wouldn’t help since it would power back on directly to the default launcher, which currently is our application. It proved useful for our project, and the satisfaction of trying out something so wacky and out of line was indeed great and highly motivating.

There are a lot of devices and use cases where Android has made developers’ life easy. These days, writing an Android application is much easier than using many different platform-specific languages and tools. Think of IoT devices, kiosk applications, point of sale systems, navigation and payment gateways for taxis, and many more.

These are use cases where Android made app development easier, but also niche use cases where you would want to restrict access in a similar manner to what we demonstrated in this article.

两个鬼故事余姓咋起名姓氏惠起名鼠年起名用晨好吗谈心谈话内容烤鸭肠加盟四大名捕游戏宠物品牌起名鼠宝宝起啥名好文具店起名大全参考米线店名字起什么好莹莹的起名含义妄想学生会剧场版征兆都市之空教育起名字开放式基金每日净值查询机电公司起名怎么起名日本极度色诱生活万岁电视剧演员表物业公司起名大全好听叫兽王易小星起名免费网 企业大全起名字狗年宝宝起名女孩名字cctv在线观看网站起个名字美国十次啦超级大导航女字中间加一点是什么字姓曹男孩起名字好听宏起名少年生前被连续抽血16次?多部门介入两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”淀粉肠小王子日销售额涨超10倍高中生被打伤下体休学 邯郸通报单亲妈妈陷入热恋 14岁儿子报警何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言张家界的山上“长”满了韩国人?男孩8年未见母亲被告知被遗忘中国拥有亿元资产的家庭达13.3万户19岁小伙救下5人后溺亡 多方发声315晚会后胖东来又人满为患了张立群任西安交通大学校长“重生之我在北大当嫡校长”男子被猫抓伤后确诊“猫抓病”测试车高速逃费 小米:已补缴周杰伦一审败诉网易网友洛杉矶偶遇贾玲今日春分倪萍分享减重40斤方法七年后宇文玥被薅头发捞上岸许家印被限制高消费萧美琴窜访捷克 外交部回应联合利华开始重组专访95后高颜值猪保姆胖东来员工每周单休无小长假男子被流浪猫绊倒 投喂者赔24万小米汽车超级工厂正式揭幕黑马情侣提车了西双版纳热带植物园回应蜉蝣大爆发当地回应沈阳致3死车祸车主疑毒驾恒大被罚41.75亿到底怎么缴妈妈回应孩子在校撞护栏坠楼外国人感慨凌晨的中国很安全杨倩无缘巴黎奥运校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变王树国卸任西安交大校长 师生送别手机成瘾是影响睡眠质量重要因素国产伟哥去年销售近13亿阿根廷将发行1万与2万面值的纸币兔狲“狲大娘”因病死亡遭遇山火的松茸之乡“开封王婆”爆火:促成四五十对奥巴马现身唐宁街 黑色着装引猜测考生莫言也上北大硕士复试名单了德国打算提及普京时仅用姓名天水麻辣烫把捣辣椒大爷累坏了

两个鬼故事 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化