I was working my way through the device admin api, and while invoking the setPermissionGrantState
function on the DevicePolicyManager
I got
Unable to start receiver com.xx.admin.receivers.AdminReceiver: java.lang.SecurityException: Admin ComponentInfo{com.xx/com.xx.admin.receivers.AdminReceiver} does not own the profile.
I understand that there are certain functions that can be only run by device/profile owners. Further more that NFC provisioning and dpm command
is the way through it. But this is hardly the way I want to proceed when I distribute my app. Is there any way I can automate this authorization by requesting the user to permit my app with a profile ownership with/without root.
Here is my receiver
class AdminReceiver : DeviceAdminReceiver() {
var manager: DevicePolicyManager? = null
override fun onEnabled(context: Context?, intent: Intent?) {
super.onEnabled(context, intent)
manager = getManager(context)
manager!!.setPermissionGrantState(getComponentName(context!!)
, "com.abc.app"
, Manifest.permission.WRITE_EXTERNAL_STORAGE
, DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED)
}
fun getComponentName(context: Context): ComponentName {
return ComponentName(context.applicationContext, AdminReceiver::class.java)
}
}
NFC provisioning is only required for setting a device owner.
I would say the dpm command is generally used also for testing/setting the device owner (that's what I've used it for), but you can also set a profile owner.
You can set up a managed profile programmatically using the code below. The apps that you want to manage must be installed in this profile. This code was based off of android-AppRestrictionEnforcer.
/**
* Initiates the managed profile provisioning. If we already have a managed profile set up on
* this device, we will get an error dialog in the following provisioning phase.
*/
private void provisionManagedProfile() {
Activity activity = getActivity();
if (null == activity) {
return;
}
Intent intent = new Intent(ACTION_PROVISION_MANAGED_PROFILE);
if (Build.VERSION.SDK_INT >= 24) {
intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
CustomDeviceAdminReceiver.getComponentName(activity));
} else {
//noinspection deprecation
intent.putExtra(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
activity.getApplicationContext().getPackageName());
intent.putExtra(EXTRA_DEVICE_ADMIN, CustomDeviceAdminReceiver.getComponentName(activity));
}
if (intent.resolveActivity(activity.getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_PROVISION_MANAGED_PROFILE);
activity.finish();
} else {
Toast.makeText(activity, "Device provisioning is not enabled. Stopping.",
Toast.LENGTH_SHORT).show();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_PROVISION_MANAGED_PROFILE) {
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(getActivity(), "Provisioning done.", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), "Provisioning failed.", Toast.LENGTH_SHORT).show();
}
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
The device owner or profile owner app needs to be set during the setup of the device or work profile. Unlike for device admin, it cannot be changed after setup without factory reset (or removing the work profile). To configure your app to be a device owner or profile owner, see the Android EMM Developers documentation.
It's quite complicated to implement this in your own app, and instead you should consider using the Android Management API which offers the same features as a simpler cloud API. For example the equivalent of setPermissionGrantState
is PermissionGrant
.
来源:https://stackoverflow.com/questions/45548476/work-around-for-device-admin-api-does-not-own-profile