Creating an Android Device Owner app in 2023
Device Owner is an Android Enterprise feature supported by Android OS since version 5.0. It allows you to create an application that can fully manage a device. For example MDMs use device owner permissions to keep track of devices and install applications.
Ok, great. Can you just point me at documentation provided directly by Google?
Um, well, they don’t provide much. The example code they do provide is written in Java, and is archived and marked read-only:
https://github.com/googlearchive/android-BasicManagedProfile
There is another application that is maintained, but provides code for a much more complex app, and is also written in Java:
So, yeah, I thought I should write an article that shows you how to create a device owner app that:
- is written in Kotlin
- is a minimal implementation of a device owner app
- uses up-to-date versions of gradle and the Android SDK
Ok! I’m convinced. Where’s the code?
The full code sample is available on Github here:
https://github.com/codybrookshear/android-deviceowner-kotlin
Read on for an explanation of what parts are actually required in order to support Device Owner mode.
AndroidManifest.xml
We need to export a receiver in our manifest that can handle the BIND_DEVICE_ADMIN
permission:
<receiver
android:name=".DeviceOwnerReceiver"
android:description="@string/app_name"
android:label="@string/app_name"
android:permission="android.permission.BIND_DEVICE_ADMIN"
android:exported="true">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_owner_receiver"/>
<intent-filter>
<action android:name="android.app.action.PROFILE_PROVISIONING_COMPLETE"/>
</intent-filter>
</receiver>
@xml/device_owner_receiver/
is referenced in the manifest file and defines the policies that the app supports. If you want all the options device owner provides, you would put the following in your device_owner_receiver.xml file:
<?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/>
</uses-policies>
</device-admin>
DeviceOwnerReceiver.kt
is where we define a class that implements DeviceAdminReceiver
and overrides the onProfileProvisioningCompete
function, registering itself as the Device Owner and starting the app’s MainActivity
.
class DeviceOwnerReceiver : DeviceAdminReceiver() {
@Override
override fun onProfileProvisioningComplete(context: Context, intent: Intent) {
val manager = context.getSystemService(ComponentActivity.DEVICE_POLICY_SERVICE) as DevicePolicyManager
val componentName = ComponentName(context.applicationContext, DeviceOwnerReceiver::class.java)
manager.setProfileName(componentName, context.getString(R.string.profile_name))
val intent = Intent(context, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
}
}
So, how do I make my app Device Owner exactly?
On a test device, you can make your app device owner using adb:
adb shell dpm set-device-owner co.coburglabs.mdm/.DeviceOwnerReceiver
When the app is device owner, the sample code provided on Github displays the message “App is device owner”. If it’s not, it displays the message “App is not device owner”.
When you are done, you can remove device owner permissions from the app with this command:
adb shell dpm remove-active-admin co.coburglabs.mdm/.DeviceOwnerReceiver
Note: on “recent versions” of Android it’s not required, but if you run into errors running these commands, you may need to add the android:testOnly=”true"
setting to your <application
tag in your AndroidManifest.xml file.
On a production device, you must make your app device owner as soon as the device is initialized, at the Hi There! screen. You can do this with a QR code, a NFC bump, or one of several other options. The steps to do that are interesting and I’ll probably write another article that goes into that, but for now you can find details here and here.
Ok, my app is device owner. Now what?
Congrats 🎉, your app has lots of powers that it never could have before. You should probably start by looking at Google’s DevicePolicyController documentation.