重点关注AppOpsManager这个类。要想知道这个类是干嘛的,直接去谷歌官方开发者文档中去了解。
在AppOpsManager这个类中,可以看到
悬浮窗和修改系统设置的权限码是24和25。并且这个类的变量,方法都是隐藏的。
接下来,我们需要调用checkOp方法来返回真正的权限回调结果。
/**
* Do a quick check for whether an application might be able to perform an operation.
* This is <em>not</em> a security check; you must use {@link #noteOp(int, int, String)}
* or {@link #startOp(int, int, String)} for your actual security checks, which also
* ensure that the given uid and package name are consistent. This function can just be
* used for a quick check to see if an operation has been disabled for the application,
* as an early reject of some work. This does not modify the time stamp or other data
* about the operation.
* @param op The operation to check. One of the OP_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
* @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
* {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without
* causing the app to crash).
* @throws SecurityException If the app has been configured to crash on this op.
* @hide
*/
public int checkOp(int op, int uid, String packageName) {
try {
int mode = mService.checkOperation(op, uid, packageName);
if (mode == MODE_ERRORED) {
throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
return mode;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
由于这个方法是隐藏的,所以需要用反射的方法来调用。也可以用这个库来进行调用 https://github.com/anggrayudi/android-hidden-api
这个库只要直接将原本的SDK替换成这个库的SDK就能够不用通过反射来调用隐藏方法。
反射调用checkOp的步骤:
private static boolean isPermissionGranted(String permissionCode) {
try {
Object object = getSystemService(Context.APP_OPS_SERVICE);
if (object == null) {
return false;
}
Class localClass = object.getClass();
Class[] arrayOfClass = new Class[3];
arrayOfClass[0] = Integer.TYPE;
arrayOfClass[1] = Integer.TYPE;
arrayOfClass[2] = String.class;
Method method = localClass.getMethod("checkOp", arrayOfClass);
if (method == null) {
return false;
}
Object[] arrayOfObject = new Object[3];
arrayOfObject[0] = Integer.valueOf(permissionCode);
arrayOfObject[1] = Integer.valueOf(Binder.getCallingUid());
arrayOfObject[2] = getPackageName();
int m = ((Integer) method.invoke(object, arrayOfObject)).intValue();
return m == AppOpsManager.MODE_ALLOWED;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
然后将悬浮窗和修改系统设置的权限码传进去就好。
最后返回的结果既是真正的权限回调的结果。