Android 12 Device Owner Provisioning
Asked Answered
S

2

9

I have an application, that can be successfully setup as Device Owner on devices up to Android 12 via QR code from JSON below:

{
"android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME":
"package.CustomDeviceAdminReceiver",
"android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM":
"actual_checksum",
"android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION":
"https://Site/APK_Link",
"android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED": true
 }

App contains declared receiver:

<receiver
        android:name=".deviceadmin.CustomDeviceAdminReceiver"
        android:description="@string/app_name"
        android:label="@string/app_name"
        android:permission="android.permission.BIND_DEVICE_ADMIN">
        <meta-data
            android:name="android.app.device_admin"
            android:resource="@xml/enterprise_device_admin" />

        <intent-filter>
            <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
            <action android:name="android.app.action.PROFILE_PROVISIONING_COMPLETE" />
        </intent-filter>
</receiver> 

For Android 12 (as described here https://source.android.com/devices/tech/admin/provision) I added 2 activities:

<activity
        android:name=".deviceadmin.AdminPolicyComplianceActivity"
        android:screenOrientation="portrait"
        android:permission="android.permission.BIND_DEVICE_ADMIN">
        <intent-filter>
            <action android:name="android.app.action.ADMIN_POLICY_COMPLIANCE"/>
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
</activity>
<activity
        android:name=".deviceadmin.ProvisioningModeActivity"
        android:screenOrientation="portrait"
        android:permission="android.permission.BIND_DEVICE_ADMIN">
        <intent-filter>
            <action android:name="android.app.action.GET_PROVISIONING_MODE" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
</activity>

1st one:

public class ProvisioningModeActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_provisioning_mode);

    Intent intent = getIntent();
    int provisioningMode = 1;
    List<Integer> allowedProvisioningModes = intent.getIntegerArrayListExtra(DevicePolicyManager.EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES);

    if (allowedProvisioningModes.contains(DevicePolicyManager.PROVISIONING_MODE_FULLY_MANAGED_DEVICE))
        provisioningMode = DevicePolicyManager.PROVISIONING_MODE_FULLY_MANAGED_DEVICE;
    else if (allowedProvisioningModes.contains(DevicePolicyManager.PROVISIONING_MODE_MANAGED_PROFILE))
        provisioningMode = DevicePolicyManager.PROVISIONING_MODE_MANAGED_PROFILE;

    Intent resultIntent = new Intent();
    resultIntent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_MODE, provisioningMode);

    setResult(RESULT_OK, resultIntent);
    finish();
}
}

and 2nd one (almost empty):

public class AdminPolicyComplianceActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_admin_policy_compliance);

    setResult(RESULT_OK);
    finish();
}
}

but I got error while enrollment: "Can't setup device. Can't use the admin app. It's missing components or corrupted".

Can somebody find that I missed please?

Sclar answered 25/11, 2021 at 12:44 Comment(5)
I found the problem in my code: looks like I need to set android:testOnly="false", but I didn't find any information about it. On pre-12 everything worked fine with default value. Maybe it will help someoneSclar
And now Android 11 and below does not work @SclarBridgework
"This kind of APK can be installed only through adb" developer.android.com/guide/topics/manifest/… Test Only APKs can't be installed via normal means.Metchnikoff
@Metchnikoff - right, but what was unexpected is that they needed to EXPLICITLY specify false. Previously, they omitted that attribute: "everything worked fine with default value". It would be surprising for OS upgrade to change the default from false to true.Crassulaceous
@Sclar thank you for this question. I've been struggling with getting my DeviceOwner app working on Android12. Your question filled in the missing pieces. Now it installs, but doesn't quit behave the same way. But at least I'm past the "Please contact your IT Admin" dead end. It's just insane to me that there is no facility to collect logs from a QR code provisioning failure.... I was about to try this against a lineage image in an emulator hoping I could see why it failed. You save me from that!Ann
W
9

From Android 12 we are supposed to have components exported safely. Since your activities ProvisioningModeActivity and AdminPolicyComplianceActivity uses intent filter, we have to set the exported flag.

<activity
    android:name=".deviceadmin.AdminPolicyComplianceActivity"
    android:screenOrientation="portrait"
    android:permission="android.permission.BIND_DEVICE_ADMIN"
    android:exported="true">
    <intent-filter>
        <action 
          android:name="android.app.action.ADMIN_POLICY_COMPLIANCE"/>
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
<activity
    android:name=".deviceadmin.ProvisioningModeActivity"
    android:screenOrientation="portrait"
    android:permission="android.permission.BIND_DEVICE_ADMIN"
    android:exported="true">
    <intent-filter>
        <action android:name="android.app.action.GET_PROVISIONING_MODE" 
        />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

This way firmware will be able to recognize the activity and launch it.

Also, regarding android:testOnly="false", this flag must be false if you are going to do QR code provisioning. If its true then, you will be able to remove admin via android settings.

Westleigh answered 24/1, 2022 at 5:16 Comment(2)
And now Android 11 and below does not work @GokulBridgework
@Bridgework can you elaborate on what is not working? To provision Below android 11 device, you still have to listen to "android.app.action.PROFILE_PROVISIONING_COMPLETE".Westleigh
T
2

@faz the reason this code doesn't work on Android 11 and below is because the ProvisioningModeActivity intent is not fired with an extra integer array of DevicePolicyManager.EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES. To overcome this add a null check to the allowedProvisioningModes

Tashinatashkent answered 4/1, 2023 at 23:22 Comment(4)
This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From ReviewHillary
@Vonjin yes this answer doesn't fully solve the original question. But it will help users that come here with issues after they are required to upgrade their app to Android 12. Most will come across this question like faz and myself did and implement the solution in the question and then be stuck because it won't install on Android 10 or lower. And due to Android DPC the developer is really unable to troubleshoot the QR code setup and be unable to come to a solution.Tashinatashkent
@ChrisHallgren This actually helped me. Thanks a lot! If anybody is looking for how to implement what you mentioned, it's been explained here by Daniel in the answerAerophobia
@ChrisHallgren This is exactly what I was looking for. Without it, the original is not even working.Insignia

© 2022 - 2024 — McMap. All rights reserved.