Как проверить разрешение SYSTEM_ALERT_WINDOW на Android Lollipop?
Обратите внимание, что я говорю об Android Lollipop. Для Android 6.0 мы можем использовать метод canDrawOverlays()
чтобы проверить это SYSTEM_ALERT_WINDOW
предоставлено или нет.
С Android Lollipop почти устройства предоставляют это разрешение по умолчанию. Но на некоторых устройствах Xiaomi, Meizu.. это не предоставляется. Пользователи должны перейти к информации о приложении, чтобы разрешить его.
Как мы можем проверить это программно, чтобы предупредить пользователей?
2 ответа
Решение
В MIUI использовать
public static boolean isMiuiFloatWindowOpAllowed(@NonNull Context context) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
return checkOp(context, OP_SYSTEM_ALERT_WINDOW); //See AppOpsManager.OP_SYSTEM_ALERT_WINDOW=24 /*@hide/
} else {
return (context.getApplicationInfo().flags & 1<<27) == 1;
}
}
public static boolean checkOp(Context context, int op, String packageName, int uid) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
try {
return (AppOpsManager.MODE_ALLOWED == (Integer) ReflectUtils.invokeMethod(manager, "checkOp", op, uid, packageName));
} catch (Exception e) {
e.printStackTrace();
}
} else {
Flog.e("Below API 19 cannot invoke!");
}
return false;
}
ReflectUtils.java
public static Object invokeMethod(@NonNull Object receiver, String methodName, Object... methodArgs) throws Exception {
Class<?>[] argsClass = null;
if (methodArgs != null && methodArgs.length != 0) {
int length = methodArgs.length;
argsClass = new Class[length];
for (int i=0; i<length; i++) {
argsClass[i] = getBaseTypeClass(methodArgs[i].getClass());
}
}
Method method = receiver.getClass().getMethod(methodName, argsClass);
return method.invoke(receiver, methodArgs);
}
Отражение рискованно, потому что вы принимаете вещи как должное... и все может измениться в будущих версиях Android. Следующий метод использует отражение только в случае сбоя правильного способа.
@SuppressLint("NewApi")
public static boolean canDrawOverlayViews(Context con){
if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP)
return true;
try {
return Settings.canDrawOverlays(con);
}
catch(NoSuchMethodError e){
return canDrawOverlaysUsingReflection(con);
}
}
public static boolean canDrawOverlaysUsingReflection(Context context) {
try {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
Class clazz = AppOpsManager.class;
Method dispatchMethod = clazz.getMethod("checkOp", new Class[] { int.class, int.class, String.class });
//AppOpsManager.OP_SYSTEM_ALERT_WINDOW = 24
int mode = (Integer) dispatchMethod.invoke(manager, new Object[] { 24, Binder.getCallingUid(), context.getApplicationContext().getPackageName() });
return AppOpsManager.MODE_ALLOWED == mode;
} catch (Exception e) { return false; }
}