androidandroid-overlay

How to handle SYSTEM_ALERT_WINDOW permission not being auto-granted on some pre-Marshmallow devices


I've been getting reports of some Xiaomi devices (e.g. Mi 2, running API level 21) not showing overlays. My app targets API 23.

There are several posts out there regarding this. It seems that MIUI devices do not enable this permission at install time (unlike other pre-Marshmallow devices).

Unfortunately, Settings.canDrawOverlays() only works on Android 23+.

  1. What is the correct way to check whether this permission has not yet been enabled pre-Marshmallow?
  2. Is there an Intent to take the user to the relevant MUIU settings page? Maybe: new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION", packageName) but I have no means to test this.

Solution

  • Checking if you have the drawOverlays permission is safer using this:

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

    Custom ROMs can have altered the OS so that that Settings.canDrawOverlays() is not available. This happened to me with Xiaomi devices and the app crashed.

    Requesting the permission:

    @SuppressLint("InlinedApi")
    public static void requestOverlayDrawPermission(Activity act, int requestCode){
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + act.getPackageName()));
        act.startActivityForResult(intent, requestCode);
    
    }