Android中有很多的应用想要取得设备管理器权限,成为系统设备管理器之后可以实现锁屏、擦除用户数据等功能,项目中客户希望自己的app能够默认成为系统的设备管理器,如何操作呢?,下面来介绍一下:

        DevicePolicyManager mDPM = (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);        if(!mDPM.isAdminActive(new ComponentName(PkgName,ClassName))){            mDPM.setActiveAdmin(new ComponentName(PkgName,ClassName), false);        }

首先获取DevicePolicyManager,然后通过DevicePolicyManager的isAdminActive方法判断当前要设置的应用是否已经是默认的设备管理器.如果不是的话,通过DevicePolicyManager的setActiveAdmin方法将它设置为默认设备管理器.

下面来看看DevicePolicyManager的isAdminActive方法具体做了什么,DevicePolicyManager的isAdminActive方法最终调用的是DevicePolicyManagerService的isAdminActive;

    @Override    public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {        if (!mHasFeature) {            return false;        }        enforceFullCrossUsersPermission(userHandle);    //检查调用者权限        synchronized (this) {    //加了进程锁,防止阻塞            return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;    //调用系统的getActiveAdminUncheckedLocked方法        }    }

接下来去看看getActiveAdminUncheckedLocked方法:

    ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {        ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);    //通过当前应用的componentName来得到一个ActiveAdmin对象        if (admin != null                && who.getPackageName().equals(admin.info.getActivityInfo().packageName)                && who.getClassName().equals(admin.info.getActivityInfo().name)) {            return admin;        }        return null;    }

getActiveAdminUncheckedLocked中通过getUserData(userHandle).mAdminMap.get(who)获取一个ActiveAdmin对象,

由于Android是支持多用户的,所以通过getUserData(userHandle)获取当前用户数据,默认的用户UserId是0,mAdminMap是一个ArrayMap, 系统中的声明是ArrayMap mAdminMap = new ArrayMap<>();

如果判断不是默认设备管理器就会调用DevicePolicyManager的setActiveAdmin方法

 /**     * @param adminReceiver The admin to add     * @param refreshing true = update an active admin, no error     */    @Override    public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {        if (!mHasFeature) {            return;        }        setActiveAdmin(adminReceiver, refreshing, userHandle, null);    //这里调用的是私有方法setActiveAdmin    } private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle,            Bundle onEnableData) {        mContext.enforceCallingOrSelfPermission(                android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);    //权限检查,这里检查的是用户是否有android.Manifest.permission.MANAGE_DEVICE_ADMINS权限,这个权限是需要签名权限或者priv-app下的应用才能使用        enforceFullCrossUsersPermission(userHandle);    //权限检查,这里检查的是不同用户之间的权限        DevicePolicyData policy = getUserData(userHandle);    //获取当前用户的DevicePolicyData        DeviceAdminInfo info = findAdmin(adminReceiver, userHandle,                /* throwForMissionPermission= */ true);    //获取当前用户的ComponentName获取DeviceAdminInfo        if (info == null) {            throw new IllegalArgumentException("Bad admin: " + adminReceiver);        }        if (!info.getActivityInfo().applicationInfo.isInternal()) {            throw new IllegalArgumentException("Only apps in internal storage can be active admin: "                    + adminReceiver);        }        synchronized (this) {            long ident = mInjector.binderClearCallingIdentity();            try {                final ActiveAdmin existingAdmin                        = getActiveAdminUncheckedLocked(adminReceiver, userHandle);    //取出系统当前默认的设备管理器                if (!refreshing && existingAdmin != null) {                    throw new IllegalArgumentException("Admin is already added");    //如果refreshing为false,并且不存在默认设备管理器,直接报错~                }                if (policy.mRemovingAdmins.contains(adminReceiver)) {    //如果设置当前用户DevicePolicyData中已经移除过的设备管理器,直接报错                    throw new IllegalArgumentException(                            "Trying to set an admin which is being removed");                }                ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false);    //新创建一个设备管理器                newAdmin.testOnlyAdmin =                        (existingAdmin != null) ? existingAdmin.testOnlyAdmin                                : isPackageTestOnly(adminReceiver.getPackageName(), userHandle);                policy.mAdminMap.put(adminReceiver, newAdmin);    //把componentName和ActiveAdmin放到当前用户的DevicePolicyData的ArrayMap中                int replaceIndex = -1;                final int N = policy.mAdminList.size();    //获取当前DevicePolicyData中的mAdminList的大小                for (int i=0; i < N; i++) {                    ActiveAdmin oldAdmin = policy.mAdminList.get(i);                    if (oldAdmin.info.getComponent().equals(adminReceiver)) {    //找到默认设备管理器的位置,并将位置标记                        replaceIndex = i;                        break;                    }                }                if (replaceIndex == -1) {                    policy.mAdminList.add(newAdmin);    //如果替换位置没有找到,添加新的AdminActive到mAdminList中                    enableIfNecessary(info.getPackageName(), userHandle);                } else {                    policy.mAdminList.set(replaceIndex, newAdmin);    //如果替换位置已经找到,就将当前的ActiveAdmin插入到该位置,替换为新的默认设备管理器                }                saveSettingsLocked(userHandle);    //保存当前用户的设置                sendAdminCommandLocked(newAdmin,     DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,                        onEnableData, null);    //发送通知给新的默认设备管理器            } finally {                mInjector.binderRestoreCallingIdentity(ident);            }        }    }   

如此如此就设置默认设备管理器完成了~

下面介绍有权查看使用情况的应用这个权限,这个权限是由AppOpsManager进行管理的:

    AppOpsManager mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);    ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(pkgName, PackageManager.GET_ACTIVITIES);            mAppOps.setMode(AppOpsManager.OP_GET_USAGE_STATS, info.uid, pkgName, AppOpsManager.MODE_ALLOWED);

这样就可以将应用的有权查看使用情况的应用权限打开了,拥有这个权限可以打印其他应用的使用情况,比如运行时间等等~

还有一个常见的权限是允许在其他应用上层显示,如何申请呢?

    AppOpsManager mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);    ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(pkgName, PackageManager.GET_ACTIVITIES);       mAppOps.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,                info.uid, PkgName, AppOpsManager.MODE_ALLOWED);

声明一下,AppOpsManager需要在系统service中调用才能生效,如果在普通系统应用中调用也是不可以的,比如SystemUI中,请注意这一点,我一般是在自定义的service中调用,自定义service请看我之前的文章~

更多相关文章

  1. 读取android手机流量信息
  2. android调用shell命令及权限问题
  3. Win7上Git安装及简单配置过程
  4. FAQ00366]如何使Android应用程序获取系统权限
  5. Android(安卓)RadioGroup设置默认选中项
  6. 关机重启代码
  7. gradle android基本配置详解
  8. android项目源码异步加载远程图片的小例子
  9. Android(安卓)打开系统蓝牙设置

随机推荐

  1. Android 蓝牙对等通信初探
  2. Android(安卓)View/ViewRoot泄漏但Activi
  3. Android(安卓)3D旋转动画——Rotate3dAni
  4. Android属性动画(详解)
  5. Android远程图片获取和本地缓存
  6. 详解C#开发Android应用程序的流程
  7. Android面试题(华为):Android 的优势与不足
  8. Android的消息处理机制——Looper,Handle
  9. Android studio 使用心得(八)----测试程
  10. View篇之View的滑动