Kiosk
Example of Kiosk Mode for Android
Install / Use
/learn @mrugacz95/KioskREADME
Kiosk
Application demonstrates basic usage of Android Lock Task mode for creating Kiosk app
Usage
- Make factory reset
- Skip adding google account
- Install apk
$ adb install path/to/kiosk.apk - Set device owner
$ adb shell dpm set-device-owner pl.mrugacz95.kiosk/.MyDeviceAdminReceiver
Screenshots
<img src="https://user-images.githubusercontent.com/12548284/37874490-775d37d6-3030-11e8-897c-e5d930a3d44f.png" width="292" height="519" alt="Screen unpinned"/> <img src="https://user-images.githubusercontent.com/12548284/37874485-6c9b6a70-3030-11e8-8ea4-75ec19f10a59.png" width="292" height="519" alt="Screen pinned"/>
Article
How to turn your Android application into a kiosk
Nowadays, we find kiosk devices in more places than ever before. We use these at the train station, tourist information centers, shops, museums, hotels, post offices, and more. They usually provide an app giving useful information, the ability for communication, commerce, entertainment marketing or education. These are often equipped with a colorful touchscreen to facilitate user interaction.
Android devices can be turned into kiosks by configuring them as a COSU app (Corporate Owned Single Use application) or a Single-Use device. In this article, I will explain how to enable kiosk mode and build a simple application for this purpose.
COSU / Kiosk mode
To create a secure kiosk mode we have to disable some Android features. It is important to capture the user within one application, without a way to close it or run a different app. To achieve this we need to satisfy these requirements:
- A single application – the user shouldn't be able to exit our application and access any settings or private data
- Hidden Home and Recent Apps buttons – these buttons are the most common way to navigate in Android
- Disabled status bar – it is possible to navigate to settings or use a notification to change context
- Running with device's boot – device should be ready to use immediately after powering on
- Turning off incoming calls – interaction with the application shouldn't be interrupted
- Blocking all paths to settings – there are many ways to access settings and we should consider them all (for example it is possible to go to language settings through the keyboard)
- The device should be always awake – the user will not have to search for the power button,
- The app is in fullscreen mode
Starting from Android 5.0 we have the opportunity to easily create a kiosk application in Android. Let's see how we can achieve it.
Screen Pinning
Screen Pinning is a feature which allows you to show only one application until unpinning. It can be used when giving your phone to children or other people without risk of leaking personal information. On every smartphone with system version starting from Android 5.0 Lollipop, you can enable this feature manually in Settings → Security → Screen pinning → On. You can also specify if the device should show your lock screen after unpinning.
After that, when clicking the Recent Apps button you will see a blue pin icon which allows you to pin the application to your screen. To exit the pinned screen you have to hold recent and home buttons down for a while. With screen pinned enabled, the system behaviour has changed:
- the status bar is blank and status icons are hidden,
- Home and Recent apps buttons are disabled, and
- other apps cannot launch new activities.
The pinned application has a visible but disabled home and recent button and it's still possible to change context. We will need more privileges to lock the user in our kiosk and pin the screen without confirmation.
Device Admin
It is possible to make our application the administrator of the device, which will enable more possibilities to adjust system settings and manage applications. You can find your current privileged apps in Settings → Security → Device admin apps. After opening the admin details you can see the permissions each app are using. Most permissions are related with wiping device data and blocking the screen if you lose your phone.
If our application is a device admin, it can pin screen without confirmation. Home and Recent apps buttons are also hidden, so exiting from the application is not possible manually and only available from the code.
LockTask mode
Our Kiosk application will mostly be based on a class inheriting from DeviceAdminReceiver and ComponentName. First, we have to tell the system that our app is pretending to become device administrator. We can do it by adding a receiver in AndroidManifest.xml containing metadata with name android.app.device_admin:
<application
...
android:testOnly="true">
<receiver
android:name=".MyDeviceAdminReceiver"
android:description="@string/admin_description"
android:label="@string/app_name"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin_receiver" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
</intent-filter>
</receiver>
</application>
Here we can provide the same basic information about our admin like name and description, which will be displayed in device's settings. Also take note of testOnly="true", which will allow us to remove the admin without complications, which will be discussed in next section.
As you can see there is also a path to an xml file containing some information about policies which the admin app will use. To do this we have to create a new directory in res with name xml.
<?xml version="1.0" encoding="utf-8"?>
<device-admin>
<uses-policies>
<limit-password />
<watch-login />
<reset-password />
<force-lock />
<wipe-data />
<expire-password />
<encrypted-storage />
<disable-camera />
<disable-keyguard-features />
</uses-policies>
</device-admin>
And finally, we can add a class inheriting from DeviceAdminReceiver. This class can also catch intents related to administrator settings and react to them:
// ...
class MyDeviceAdminReceiver : DeviceAdminReceiver() {
companion object {
fun getComponentName(context: Context): ComponentName {
return ComponentName(context.applicationContext, MyDeviceAdminReceiver::class.java)
}
}
}
From this point, we should install our application, but enabling admin is only possible on devices which don't have any users added. So before we install app we have to wipe device/factory reset if any Google accounts have been added:
- Wipe/Factory reset device
- Do not add Google account on the first start, just skip it
- Install our application with Android Studio or command line: adb install path/to/kiosk.apk
- Set device admin:
adb shell dpm set-device-owner pl.mrugacz95.kiosk/.MyDeviceAdminReceiver
If everything has gone well we should be able to see our application in the list of device's administrators in Settings → Security → Device admin apps.
We can also check if our application is device admin programmatically:
//...
class MainActivity : AppCompatActivity() {
private lateinit var mAdminComponentName: ComponentName
private lateinit var mDevicePolicyManager: DevicePolicyManager
override fun onCreate(savedInstanceState: Bundle?) {
...
mAdminComponentName = MyDeviceAdminReceiver.getComponentName(this)
mDevicePolicyManager = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
if (mDevicePolicyManager.isDeviceOwnerApp(packageName)) {
// You are the owner!
setKioskPolicies()
} else {
// Please contact your system administrator
}
}
}
When our application is device admin we can enable our package to enter lock task. If app wouldn't be added to this list startLockTask() would only pin screen.
mDevicePolicyManager.setLockTaskPackages(mAdminComponentName, arrayOf(packageName))
startLockTask()
Next, we have to set our application as a Home app. To do this we should add the intent filter in AndroidManifest.xml:
<application
... >
<activity android:name=".MainActivity">
<intent-filter>
...
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
And set our app as the default application:
val intentFilter = IntentFilter(Intent.ACTION_MAIN)
intentFilter.addCategory(Intent.CATEGORY_HOME)
intentFilter.addCategory(Intent.CATEGORY_DEFAULT)
mDevicePolicyManager.addPersistentPreferredActivity(mAdminComponentName,
intentFilter, ComponentName(packageName, MainActivity::class.java.name))
We should also disable Keyguard so that when the device boots, our application will start immediately without the lock screen appearing.
mDevicePolicyManager.setKeyguardDisabled(mAdminComponentName, true)
Additionally we have two possibilities to keep our application awake. First is adding a flag to WindowManager which will keep the screen on with full power:
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
But if we have admin privileges, we can also set an option Stay awake – Screen will never sleep while charging, which can be found in Developer options in Settings. With this option, the screen will dim after some time but it will never turn off completely:
mDevicePolicyM
