Skip to main content

Developing a Kiosk Application

· 5 min read

In this article, I'll show how to turn your Android application into Kiosk App.

info

Kiosk App is a special type of application that is designed to always run fullscreen and does not allow the user to exit the app.

In order to achieve that, we need to set our app a device owner.

Why Do I Need This?

The main point of a Kiosk App is that the user has no way to exit your app – a device is locked to use only your app. This feature exists natively starting with Android 5.0 and is called Lock task mode: with lock task mode, a user can’t escape the app and the Home and Recents buttons are hidden. But only apps whitelisted by DPC (device policy controller) can be locked.

While you can use a third-party enterprise mobility management (EMM) solution to enable lock task mode (and do another fancy stuff), that can be an overkill in case you just need a single-purpose device – you either have to pay to EMM provider or become an EMM provider yourself (which is not an easy way).

What Will I Need?

For developing purposes, any device with Android >= 5.0 will be ok, device owner mode can be set up with adb command. However, in order to provision device in real life, you will need a clean (or factory reset) device with Android >= 7.0 (actually 5.0-6.0 can be put into device owner mode, but only using NFC – so you will need 2 devices with NFC support, one of them should use NFC programmer app which needs to be written separately. In this article, we will talk about the simpler method with QR-code, but it's supported starting with Android 7.0 only – well, the good news about enterprise development is that you can control what devices will be used).

You will also need to register admin receiver: it will get a notification when the app is put into device owner mode. It can be as simple as that:

package com.example.ookami.myapplication

import android.app.admin.DeviceAdminReceiver
import android.app.admin.DevicePolicyManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent

class AdminReceiver : DeviceAdminReceiver() {
override fun onEnabled(context: Context, intent: Intent?) {
super.onEnabled(context, intent)
val manager = context.getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val component = ComponentName(context.applicationContext, AdminReceiver::class.java)
manager.setLockTaskPackages(component, arrayOf(context.packageName))
}
}

In this code, we're granting permission to our app to enter lock task mode.

Register this receiver in AndroidManifest:

<receiver
android:name=".AdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin"/>
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED"/>
</intent-filter>
</receiver>

And add file device_admin.xml to res/xml with the following content:

res/xml/device_admin.xml
<device-admin>
</device-admin>

Now if we just add android:lockTaskMode="if_whitelisted" to every activity in AndroidManifest, they will be automatically launched in lock task mode.

How Can I Test It?

So let's start with provisioning app in develop mode. Actually, it's as simple as that:

adb shell dpm set-device-owner com.example.ookami.myapplication/.AdminReceiver

where com.example.ookami.myapplication/.AdminReceiver is the path to our admin receiver.

In order to unset the app as a device owner, run this (but for this to work, your application tag in AndroidManifest should have android:testOnly="true" attribute):

adb shell dpm remove-active-admin com.example.ookami.myapplication/.AdminReceiver

How Can I Distribute It?

The app is ready and tested, time to give it customer. adb method is, of course, unacceptable here, and we need some simpler way to install our app.

As official docs say:

The QR code provisioning method sets up and configures device owner mode by scanning a QR code from the setup wizard. The QR code contains a payload of key-value pairs with all the information that’s needed for the DPC to provision a device.

So you will need to provide a client with a QR-code. If you need to pass some dynamic parameters (depending on the customer, or app configuration for example) then you have to generate this QR-code dynamically, otherwise you can just create this QR-code once and give it to ll your clients (though it still needs to be updated whenever a new version is released if you use package checksum – more on this later).

In the simplest case, this QR-code can be generated with some online tool, like this. You just need to paste JSON there with all the required parameters.

You can see all the possible parameters here, I'll just provide minimal configuration:

{
"android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME": "com.example.ookami.myapplication/.AdminReceiver",
"android.app.extra.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION": "http://example.com/app.apk",
"android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM": "gJD2YwtOiWJHkSMkkIfLRlj-quNqG1fb6v100QmzM9w="
}
  • android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME is the same path to the admin receiver that we've used in develop mode

  • android.app.extra.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION is the direct path to our app apk

  • android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM is a string holding the URL-safe base64 encoded SHA-256 hash ot this apk. On Linux/MacOS, it can be get with the following command:

    cat /path/to/app.apk | openssl dgst -binary -sha256 | openssl base64 | tr '+/' '-_' | tr -d '='

Pay attention that if you use this package signature, you'll have to update your QR-code every time a new version of an app is released. You can use android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM that should contain the URL-safe base64 encoded SHA-256 checksum of any signature of the Android package (but I failed to make it work properly).

Now when your customer has QR-code and clean (or factory reset) device, he needs to do the following:

  • Power on the device and wait for a Welcome screen to appear.
  • Tap 6 times wherever on this screen – this will launch provisioning mode.
  • Connect to WiFi network by entering credentials and wait for the tablet to download and launch QR-code scanner.
  • Scan this QR-code, the app will be downloaded and installed automatically.

If everything goes well, your app will receive device owner mode and can grant itself the necessary permissions.