I need to build a custom Setup Wizard to provision another app as a device owner. The setup wizard will then run on our hardware as a privileged app (residing in the priv-app folder)
I have spent a lot of time trying to get this to work in an emulator. unfortunately, without result.
I am trying to verify that the setup wizard runs correctly and got permission ACTION_PROVISION_MANAGED_DEVICE to be able to set device owner by the following check:
devicePolicyManager.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE)
It always returns false. I think this is indicating that the device is not either in setup wizard mode or the setup wizard app is not allowed to do provisioning?
When I try this on an emulator I do the following:
$ emulator -avd View711 -writable-system
$ adb root
$ adb remount
$ adb shell rm -rf /system/priv-app/SetupWizard
$ adb push app-debug.apk /system/priv-app/SetupWizard/SetupWizard.apk
This makes the emulator writable and pushes the apk to the priv-app folder.
At this stage, I shut off the emulator and make a “wipe data” from the AVD Manager in Android Studio (to try to get it into setup wizard state again). Im not sure if that is the exact same thing as a normal factory reset. The factory reset option in Android's settings menu do not do anything in the emulator. (I do not know why)
When I boot up the device again my app starts but devicePolicyManager.isProvisioningAllowed returns false indicating that I cannot set my app as device owner.
I test this with a really small SetupWizard app to try to isolate the issues I’m having:
It got one activity that checks if provisioning is allowed:
class SetupWizardActivity : AppCompatActivity() {
private lateinit var devicePolicyManager: DevicePolicyManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
devicePolicyManager = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
Log.d(
"test",
"Is provisioning allowed: " + devicePolicyManager.isProvisioningAllowed(
DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE
)
)
}
}
And my manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.setupwizard">
<uses-permission android:name="android.permission.DISPATCH_PROVISIONING_MESSAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".SetupWizardActivity"
android:excludeFromRecents="true"
android:immersive="true"
android:label="Test"
android:launchMode="singleTask"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter android:priority="10">
<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" />
<category android:name="android.intent.category.SETUP_WIZARD" />
</intent-filter>
</activity>
</application>
</manifest>
I tried to manually reset the emulator to setup wizard state by:
$ adb root
$ adb remount
$ adb shell settings put global setup_wizard_has_run 0
$ adb shell settings put global device_provisioned 0
$ adb shell settings put secure user_setup_complete 0
$ adb shell pm enable com.example.setupwizard/.SetupWizardActivity
$ adb shell am start -n com.example.setupwizard/.SetupWizardActivity
But devicePolicyManager.isProvisioningAllowed does still returns false after the app opens.
My emulator runs Android 7.1.1 without google APIs.
I found a person having very similar issues to me without any answer: Android: Emulator factory data reset menu option not working
I found the reset wizard adb commands from here: https://android.stackexchange.com/questions/137324/trigger-setup-wizard-at-next-boot-using-command-line
If I could get this to work I could eventually set device owner on my application by something like this:
public Intent createProvisionManagedDeviceIntent() {
ComponentName adminComponent = new ComponentName(getPackageName(), DeviceOwnerReceiver.class.getName());
if (!devicePolicyManager.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE)) {
return null;
}
String action = DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
try {
if (checkSelfPermission("android.permission.DISPATCH_PROVISIONING_MESSAGE") == PackageManager.PERMISSION_GRANTED) {
action = (String) DevicePolicyManager.class.getField("ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE").get(null);
}
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
return new Intent(action)
.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, adminComponent)
.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION, true)
.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED, true);
}
I am out of ideas. Its a pretty cumbersome way of developing and hard to debug. Im having problems finding good documentation on this as well. Our application needs device owner perimissions to function well as a kiosk mode app.