Device owner QR stopped working on Android12 devices, getting Can't set up device message
Asked Answered
A

1

5

For some reason, the QR code for installing our app as a device owner stopped working on Android12 devices (the same QR codeworks perfectly on previous Android versions).

The error message we are getting is:

Can't set up device
Contact your IT admin for help

This is the JSON of the QR code

{
  "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION": "https://someurlthatworkforsure",
  "android.app.extra.PROVISIONING_SKIP_ENCRYPTION": true,
  "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM": "validCheckSumThatWasTestedAndDoesWorkOnAndroidPriodTo12",
  "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME": "com.brand.name/com.brand.some.SomeClass"
}

I have done some googling but haven't found whats wrong with our QR code,

I have also tried setting PROVISIONING_SKIP_ENCRYPTION to false and removing it, the result is the same.

The CHECKSUM is valid, if I mess with it throws a different error...

Thanks in advance.

Armorial answered 24/4, 2022 at 15:15 Comment(7)
Maybe https://mcmap.net/q/1189918/-android-12-device-owner-provisioning/199364Amargo
Thanks @Amargo I have looked at the solution, but couldn't make it work yet, thanks for the link anywayArmorial
Hi @Armorial have you found a solution for this problem? I have the same problem on a samsung device. Thanks!Triquetrous
@AlessandroCaliaro yes, I will post it hereArmorial
Hi @Daniel, Could you please post your solution?Lease
@AlessandroCaliaro I just posted the full solutionArmorial
@MiguelSesma I just posted full solutionArmorial
A
7

Well, I eventually solved it in the following way

You must add two more activities that will handle the new flow In both activities, you will have to set results and finish the activity

setResult(RESULT_OK, intent);
finish();

Note that I noticed that the new approach worked 100% on Android 12 (v31) but sometimes failed on Android 11 v30, so I made this solution conditional, its being enabled on Android 12+, by checking the following boolean provision_mode_compliance_enabled, which is stored in XML resource files

ProvisioningModeActivity.java

package com.my.pkg;

import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;

import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.PersistableBundle;

import androidx.appcompat.app.AppCompatActivity;
import com.my.pkg.R;

import java.util.List;

public class ProvisioningModeActivity extends AppCompatActivity {

    private String EXTRA_PROVISIONING_ALLOWED_PROVISIONING_MODES = "android.app.extra.PROVISIONING_ALLOWED_PROVISIONING_MODES";
    private int PROVISIONING_MODE_FULLY_MANAGED_DEVICE = 1;
    private int PROVISIONING_MODE_MANAGED_PROFILE = 2;
    private String EXTRA_PROVISIONING_MODE = "android.app.extra.PROVISIONING_MODE";

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

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

        if (allowedProvisioningModes != null) {
            if (allowedProvisioningModes.contains(PROVISIONING_MODE_FULLY_MANAGED_DEVICE)) {
                provisioningMode = PROVISIONING_MODE_FULLY_MANAGED_DEVICE;
            } else if (allowedProvisioningModes.contains(PROVISIONING_MODE_MANAGED_PROFILE)) {
                provisioningMode = PROVISIONING_MODE_MANAGED_PROFILE;
            }
        }
        //grab the extras (might contain some needed values from QR code) and pass to AdminPolicyComplianceActivity
        PersistableBundle extras = intent.getParcelableExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE);
        Intent resultIntent = getIntent();

        if (extras != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                resultIntent.putExtra(EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE, extras);
            }
        }
        resultIntent.putExtra(EXTRA_PROVISIONING_MODE, provisioningMode);

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

and

AdminPolicyComplianceActivity.java

package com.my.pkg;


import android.content.Intent;
import android.os.Bundle;
import com.my.pkg.R;
import androidx.appcompat.app.AppCompatActivity;



public class AdminPolicyComplianceActivity extends AppCompatActivity {

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

        Intent intent = getIntent();

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

Manifest entries: notice that these activities are enabled conditionaly (continue reading till the end of the answer)

<activity
    android:name="com.communitake.android.lib.deviceadmin.AdminPolicyComplianceActivity"
    android:exported="true"
    android:enabled="@bool/provision_mode_compliance_enabled"
    android:screenOrientation="portrait"
    android:theme="@style/Theme.AppCompat"
    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="com.communitake.android.lib.deviceadmin.ProvisioningModeActivity"
    android:screenOrientation="portrait"
    android:exported="true"
    android:enabled="@bool/provision_mode_compliance_enabled"
    android:theme="@style/Theme.AppCompat"
    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>

activity_get_provisioning_mode.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".GetProvisioningModeActivity">

    <Button
        android:id="@+id/get_provisioning_data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Get Provisioning Data"/>

</LinearLayout>

activity_policy_compliance.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".PolicyComplianceActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Policy Compliance Screen"/>

</LinearLayout>

Last thing is adding bools.xml to the values and values-v31 folders, with the following content, note that the new flow better be enabled on Android 12 and higher

values folder

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="provision_mode_compliance_enabled">false</bool>
</resources>

values-v31 folder

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="provision_mode_compliance_enabled">true</bool>
</resources>
Armorial answered 8/11, 2022 at 21:55 Comment(2)
Thanks @Daniel. Working like a charm. Just commenting that there is no need for setContent line in the activities as we are not showing anything. We can avoid the layout file too.Lease
you are right, but in case someone wants to provide the user with a choice of device owner/profile owner, then it will be usefulArmorial

© 2022 - 2024 — McMap. All rights reserved.