4

Note that I'm talking about Android Lollipop. For android 6.0 we can use method canDrawOverlays() to check that SYSTEM_ALERT_WINDOW is granted or not.

With Android Lollipop, almost devices grant this permission by default. But on some devices of Xiaomi, Meizu.. it is not granted. Users need to go to the App info to allow it.

How can we check it programmatically to warn users?

TOP
  • 2,574
  • 5
  • 35
  • 60

2 Answers2

3

in MIUI use

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);
}
Fang
  • 3,652
  • 4
  • 16
  • 30
2

Reflection is risky because you take things for granted...and things can change in future versions of Android. The following method only uses reflection if the proper way fails.

@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;  }

 }
Anonymous
  • 4,470
  • 3
  • 36
  • 67
  • getting AppOpsManager.MODE_IGNORED or value 1 in xiaomi note3. Need further suggestions. – UMESH0492 Jul 14 '16 at 18:53
  • Then you don't have the permission....ask for it: Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + act.getPackageName())); startActivityForResult(intent, requestCode); – Anonymous Jul 14 '16 at 19:56
  • returns android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.settings.action.MANAGE_OVERLAY_PERMISSION dat=package:com.findmeout.android } – UMESH0492 Jul 16 '16 at 18:17
  • what device are you using for testing? I never had error using this in any of my devices or emulators including a Xiaomi redmi 3 phone – Anonymous Jul 16 '16 at 23:12
  • Why the need for reflection? The `checkOp` is from API 19, and then you return true anyway... – android developer Aug 13 '18 at 12:48