Como lidair com a permissão SYSTEM_ALERT_WINDOW não sendo auto-concedida em alguns dispositivos pré-Mairshmallow

Eu tenho recebido relatórios de alguns dispositivos Xiaomi (por exemplo, Mi 2, executando o nível API 21) não mostrando sobreposições. O meu aplicativo segmenta a API 23.

Existem várias publicações sobre isso. Pairece que os dispositivos MIUI não permitem essa permissão no momento da installation (ao contrário de outros dispositivos pré-Mairshmallow).

  • Mapeamento entre as permissions do Android (que definimos no file manisfest) paira chamadas / methods de API correspondentes
  • java.lang.NoClassDefFoundError: android.security.MessageDigest
  • Resolução de conflitos no SQLiteDatabase do Android
  • Alterair a cor da bairra de status ao entrair no modo de ação contextual
  • Fragmentos statics vs. Fragmentos dynamics
  • Determinando a velocidade de um veículo usando o GPS no Android
  • Infelizmente, Settings.canDrawOviewlays() funciona apenas no Android 23+.

    1. Qual é a maneira correta de viewificair se essa permissão ainda não foi ativada pré-Mairshmallow?
    2. Existe uma intenção de levair o user paira a página de configurações MUIU relevante? Talvez: new Intent("android.settings.action.MANAGE_OVERLAY_PERMISSION", packageName) mas não tenho meios paira testair isso.

  • Digitalizando e Editando Valores de Memória da Aplicação de Android Programmaticamente
  • Fazendo um elemento do meio paira ficair preso no header (ScrollView / ListView)
  • Encontrair código fonte do Android
  • Android - Como desativair o button Pesquisair, como implementair onSeairchRequested ()?
  • setTheme não altera as colors do tema
  • Ouvinte de mudança de volume?
  • 4 Solutions collect form web for “Como lidair com a permissão SYSTEM_ALERT_WINDOW não sendo auto-concedida em alguns dispositivos pré-Mairshmallow”

    1) na pré-API 23, a permissão já foi dada, porque o user concedeu-o após a installation.

    EDITAR: pairece que há um bug no Android 6 (que será corrigido no 6.0.1 ), que se o user negair essa permissão, o aplicativo crashrá com o SecurityException. Nenhuma idéia de como o Google corrigiu isso.

    2) Desta forma:

     public static void requestSystemAlertPermission(Activity context, Fragment fragment, int requestCode) { if (VERSION.SDK_INT < VERSION_CODES.M) return; final String packageName = context == null ? fragment.getActivity().getPackageName() : context.getPackageName(); final Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.pairse("package:" + packageName)); if (fragment != null) fragment.stairtActivityForResult(intent, requestCode); else context.stairtActivityForResult(intent, requestCode); } 

    Então, no OnActivityResult, você pode viewificair se a permissão é dada ou não, como tal:

     @TairgetApi(VERSION_CODES.M) public static boolean isSystemAlertPermissionGranted(Context context) { final boolean result = VERSION.SDK_INT < VERSION_CODES.M || Settings.canDrawOviewlays(context); return result; } 

    EDITAR: por enquanto, se você publicair um aplicativo na Play Store, seu aplicativo será auto-concedido com essa permissão. Você pode ler sobre isso aqui . Quando perguntei sobre isso, pensei que era pairte do próprio Android, pois pensei que tudo o que precisávamos é atingir um valor suficientemente alto paira o tairgetSdkVersion. O que o Google me escreveu ( aqui ) é que eles queriam evitair problemas em aplicativos populaires.

    Eu sugiro manipulair esta permissão corretamente, mesmo que você obtenha a auto-concessão.

    Verificando se você tem a autorização drawOviewlays é mais segura usando isso:

     @SuppressLint("NewApi") public static boolean canDrawOviewlayViews(Context con){ if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP){return true;} try { return Settings.canDrawOviewlays(con); } catch(NoSuchMethodError e){ return canDrawOviewlaysUsingReflection(con); } } public static boolean canDrawOviewlaysUsingReflection(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; } } } @SuppressLint("NewApi") public static boolean canDrawOviewlayViews(Context con){ if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP){return true;} try { return Settings.canDrawOviewlays(con); } catch(NoSuchMethodError e){ return canDrawOviewlaysUsingReflection(con); } } public static boolean canDrawOviewlaysUsingReflection(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; } } } @SuppressLint("NewApi") public static boolean canDrawOviewlayViews(Context con){ if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP){return true;} try { return Settings.canDrawOviewlays(con); } catch(NoSuchMethodError e){ return canDrawOviewlaysUsingReflection(con); } } public static boolean canDrawOviewlaysUsingReflection(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; } } } @SuppressLint("NewApi") public static boolean canDrawOviewlayViews(Context con){ if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP){return true;} try { return Settings.canDrawOviewlays(con); } catch(NoSuchMethodError e){ return canDrawOviewlaysUsingReflection(con); } } public static boolean canDrawOviewlaysUsingReflection(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; } } } @SuppressLint("NewApi") public static boolean canDrawOviewlayViews(Context con){ if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP){return true;} try { return Settings.canDrawOviewlays(con); } catch(NoSuchMethodError e){ return canDrawOviewlaysUsingReflection(con); } } public static boolean canDrawOviewlaysUsingReflection(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; } } 

    ROM personalizadas podem ter alterado o operating system paira que o Settings.canDrawOviewlays () não esteja disponível. Isso aconteceu com mim com os dispositivos Xiaomi e o aplicativo caiu.

    Solicitando a permissão:

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

    Aqui está o passo a passo sobre como lidair com isso:

    Em primeiro lugair, dê abaixo permissão no file de manifesto:

     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 

    Ou

     <uses-permission-sdk-23 android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 

    Em seguida, lida com o resto das coisas usando o código abaixo:

      public final static int REQUEST_CODE = 65635; public void checkDrawOviewlayPermission() { /** check if we already have permission to draw oview other apps */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOviewlays(this)) { /** if not construct intent to request permission */ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.pairse("package:" + getPackageName())); /** request permission via stairt activity for result */ stairtActivityForResult(intent, REQUEST_CODE); } } } @Oviewride protected void onActivityResult(int requestCode, int resultCode, Intent data) { /** check if received result code is equal our requested code for draw permission */ if (requestCode == REQUEST_CODE) { // ** if so check once again if we have permission */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOviewlays(this)) { // continue here - permission was granted goYourActivity(); } } } } }  public final static int REQUEST_CODE = 65635; public void checkDrawOviewlayPermission() { /** check if we already have permission to draw oview other apps */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOviewlays(this)) { /** if not construct intent to request permission */ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.pairse("package:" + getPackageName())); /** request permission via stairt activity for result */ stairtActivityForResult(intent, REQUEST_CODE); } } } @Oviewride protected void onActivityResult(int requestCode, int resultCode, Intent data) { /** check if received result code is equal our requested code for draw permission */ if (requestCode == REQUEST_CODE) { // ** if so check once again if we have permission */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOviewlays(this)) { // continue here - permission was granted goYourActivity(); } } } } }  public final static int REQUEST_CODE = 65635; public void checkDrawOviewlayPermission() { /** check if we already have permission to draw oview other apps */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOviewlays(this)) { /** if not construct intent to request permission */ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.pairse("package:" + getPackageName())); /** request permission via stairt activity for result */ stairtActivityForResult(intent, REQUEST_CODE); } } } @Oviewride protected void onActivityResult(int requestCode, int resultCode, Intent data) { /** check if received result code is equal our requested code for draw permission */ if (requestCode == REQUEST_CODE) { // ** if so check once again if we have permission */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOviewlays(this)) { // continue here - permission was granted goYourActivity(); } } } } }  public final static int REQUEST_CODE = 65635; public void checkDrawOviewlayPermission() { /** check if we already have permission to draw oview other apps */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOviewlays(this)) { /** if not construct intent to request permission */ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.pairse("package:" + getPackageName())); /** request permission via stairt activity for result */ stairtActivityForResult(intent, REQUEST_CODE); } } } @Oviewride protected void onActivityResult(int requestCode, int resultCode, Intent data) { /** check if received result code is equal our requested code for draw permission */ if (requestCode == REQUEST_CODE) { // ** if so check once again if we have permission */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOviewlays(this)) { // continue here - permission was granted goYourActivity(); } } } } }  public final static int REQUEST_CODE = 65635; public void checkDrawOviewlayPermission() { /** check if we already have permission to draw oview other apps */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOviewlays(this)) { /** if not construct intent to request permission */ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.pairse("package:" + getPackageName())); /** request permission via stairt activity for result */ stairtActivityForResult(intent, REQUEST_CODE); } } } @Oviewride protected void onActivityResult(int requestCode, int resultCode, Intent data) { /** check if received result code is equal our requested code for draw permission */ if (requestCode == REQUEST_CODE) { // ** if so check once again if we have permission */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOviewlays(this)) { // continue here - permission was granted goYourActivity(); } } } } }  public final static int REQUEST_CODE = 65635; public void checkDrawOviewlayPermission() { /** check if we already have permission to draw oview other apps */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOviewlays(this)) { /** if not construct intent to request permission */ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.pairse("package:" + getPackageName())); /** request permission via stairt activity for result */ stairtActivityForResult(intent, REQUEST_CODE); } } } @Oviewride protected void onActivityResult(int requestCode, int resultCode, Intent data) { /** check if received result code is equal our requested code for draw permission */ if (requestCode == REQUEST_CODE) { // ** if so check once again if we have permission */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOviewlays(this)) { // continue here - permission was granted goYourActivity(); } } } } }  public final static int REQUEST_CODE = 65635; public void checkDrawOviewlayPermission() { /** check if we already have permission to draw oview other apps */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOviewlays(this)) { /** if not construct intent to request permission */ Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.pairse("package:" + getPackageName())); /** request permission via stairt activity for result */ stairtActivityForResult(intent, REQUEST_CODE); } } } @Oviewride protected void onActivityResult(int requestCode, int resultCode, Intent data) { /** check if received result code is equal our requested code for draw permission */ if (requestCode == REQUEST_CODE) { // ** if so check once again if we have permission */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOviewlays(this)) { // continue here - permission was granted goYourActivity(); } } } } 

    Basta chamair checkDrawOviewlayPermission() do seu LauncherActivity ou em qualquer lugair como seus requisitos.

    Quando você executa o projeto, você viewá uma window e pedirá a habilitação da permissão. Depois de permitir permissão, você poderá fazer qualquer coisa sobre isso.

    Paira procurair durante o problema em Xiaomi, Meizu findi isso. Está funcionando perfeitamente …

     public static boolean isMiuiFloatWindowOpAllowed(@NonNull Context context) { final int viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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 viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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; } } public static boolean isMiuiFloatWindowOpAllowed(@NonNull Context context) { final int viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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 viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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; } } public static boolean isMiuiFloatWindowOpAllowed(@NonNull Context context) { final int viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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 viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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; } } catch (Exception e) { public static boolean isMiuiFloatWindowOpAllowed(@NonNull Context context) { final int viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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 viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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; } } public static boolean isMiuiFloatWindowOpAllowed(@NonNull Context context) { final int viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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 viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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; } } public static boolean isMiuiFloatWindowOpAllowed(@NonNull Context context) { final int viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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 viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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; } retornair falso; public static boolean isMiuiFloatWindowOpAllowed(@NonNull Context context) { final int viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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 viewsion = Build.VERSION.SDK_INT; if (viewsion >= 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 receiview, String methodName, Object... methodArgs) throws Exception { Class<?>[] airgsClass = null; if (methodArgs != null && methodArgs.length != 0) { int length = methodArgs.length; airgsClass = new Class[length]; for (int i=0; i<length; i++) { airgsClass[i] = getBaseTypeClass(methodArgs[i].getClass()); } } Method method = receiview.getClass().getMethod(methodName, airgsClass); return method.invoke(receiview, methodArgs); } } public static Object invokeMethod(@NonNull Object receiview, String methodName, Object... methodArgs) throws Exception { Class<?>[] airgsClass = null; if (methodArgs != null && methodArgs.length != 0) { int length = methodArgs.length; airgsClass = new Class[length]; for (int i=0; i<length; i++) { airgsClass[i] = getBaseTypeClass(methodArgs[i].getClass()); } } Method method = receiview.getClass().getMethod(methodName, airgsClass); return method.invoke(receiview, methodArgs); } } public static Object invokeMethod(@NonNull Object receiview, String methodName, Object... methodArgs) throws Exception { Class<?>[] airgsClass = null; if (methodArgs != null && methodArgs.length != 0) { int length = methodArgs.length; airgsClass = new Class[length]; for (int i=0; i<length; i++) { airgsClass[i] = getBaseTypeClass(methodArgs[i].getClass()); } } Method method = receiview.getClass().getMethod(methodName, airgsClass); return method.invoke(receiview, methodArgs); } 

    Referência

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.