No se puede agregar la ventana android.view.ViewRoot$W@44da9bc0 - permiso denegado para este tipo de ventana

82

Tengo prefieren este mensaje, por ejemplo, pero me dio el error en la adición de ViewGroup en el objeto gestor de ventanas, he utilizado la misma clase para el servicio tal como fue anunciado en la cuestión sin ningún cambio en el que puedo error que yo no gettting se

WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mView, params); // here

cuando agrego vista al WindowManger

aquí está mi archivo de manifiesto

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.searce.testoverlay"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="7" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name="TestOverlayActivity"
                      android:label="@string/app_name">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        <service android:enabled="true" android:name=".HUD"></service>
    </application>
</manifest>

error

09-27 18:49:23.561: ERROR/AndroidRuntime(653): Uncaught handler: thread main exiting due to uncaught exception
09-27 18:49:23.571: ERROR/AndroidRuntime(653): java.lang.RuntimeException: Unable to create service com.searce.testoverlay.HUD: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRoot$W@44da9bc0 -- permission denied for this window type
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at android.app.ActivityThread.handleCreateService(ActivityThread.java:2790)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at android.app.ActivityThread.access$3200(ActivityThread.java:119)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1917)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at android.os.Handler.dispatchMessage(Handler.java:99)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at android.os.Looper.loop(Looper.java:123)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at android.app.ActivityThread.main(ActivityThread.java:4363)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at java.lang.reflect.Method.invokeNative(Native Method)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at java.lang.reflect.Method.invoke(Method.java:521)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at dalvik.system.NativeStart.main(Native Method)
09-27 18:49:23.571: ERROR/AndroidRuntime(653): Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRoot$W@44da9bc0 -- permission denied for this window type
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at android.view.ViewRoot.setView(ViewRoot.java:492)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at com.searce.testoverlay.HUD.onCreate(HUD.java:41)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     at android.app.ActivityThread.handleCreateService(ActivityThread.java:2780)
09-27 18:49:23.571: ERROR/AndroidRuntime(653):     ... 10 more
Pratik
fuente

Respuestas:

154

Intente usar este permiso en AndroidManifest.

android.permission.SYSTEM_ALERT_WINDOW

en API> = 23 ver

Lalit Poptani
fuente
@ ceph3us ¿sabes cómo lograrlo para> = M? ActivityCompat.requestPermissions (este, nuevo String [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW); No disparará nada. Lo mismo con: ActivityCompat.requestPermissions (este, nuevo String [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW);
Martin Pfeffer
Además, es posible que deba otorgar permiso explícitamente, ya sea mediante programación o manualmente desde la configuración de su teléfono. Estaba usando Huawei Nexus 6p y en la configuración de mi aplicación hice clic en "Sí" para dibujar en otras aplicaciones en la sección de pantalla.
emir
vea esto para una buena solución: github.com/facebook/react-native/issues/…
WiRa
144

" @ ceph3us, ¿sabe cómo lograrlo para> = M? ActivityCompat.requestPermissions (esto, nueva Cadena [] {Manifest.permission.SYSTEM_ALERT_WINDOW} ..."

  1. SYSTEM_ALERT_WINDOW PERMISSION en API> = 23 (Dibujar sobre otras aplicaciones, etc.):

    • ya no aparece en la pantalla de permisos de la aplicación.
    • ni siquiera aparece en la nueva y extrañamente confusa pantalla "Todos los permisos"
  2. Llamando Activity.requestPermissions () con este permiso,

    • no mostrará ningún cuadro de diálogo para que el usuario permita / rechace.
    • en su lugar, la devolución de llamada Activity.onRequestPermissionsResult () se llamará inmediatamente con una marca denegada.

Solución:

Si la aplicación tiene como objetivo el nivel de API 23 o superior, el usuario de la aplicación debe otorgar explícitamente este permiso a la aplicación a través de una pantalla de administración de permisos. La aplicación solicita la aprobación del usuario enviando un intent con la acción ACTION_MANAGE_OVERLAY_PERMISSION . La aplicación puede verificar si tiene esta autorización llamando a Settings.canDrawOverlays ()

código de ejemplo:

/** code to post/handler request for permission */
public final static int REQUEST_CODE = -1010101; *(see edit II)*

public void checkDrawOverlayPermission() {
    /** check if we already  have permission to draw over other apps */
    if (!Settings.canDrawOverlays(Context)) {
        /** if not construct intent to request permission */
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:" + getPackageName()));
        /** request permission via start activity for result */
        startActivityForResult(intent, REQUEST_CODE);
    }
}

@Override 
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 (Settings.canDrawOverlays(this)) {
           // continue here - permission was granted 
       }
    }
}

"¿Y cómo puede el usuario deshabilitar este permiso? No se muestra en los permisos de configuración-> aplicaciones ->" MyApp "-> permisos. Además ... cualquier explicación de por qué este permiso es diferente de los demás en el cómo lo solicitamos? - Anónimo 12 de febrero a las 21:01 "

Hay un par de permisos que no se comportan como permisos normales y peligrosos. SYSTEM_ALERT_WINDOW y WRITE_SETTINGS son particularmente sensibles, por lo que la mayoría de las aplicaciones no deberían usarlos. Si una aplicación necesita uno de estos permisos, debe declarar el permiso en el manifiesto y enviar una intención solicitando la autorización del usuario. El sistema responde a la intención mostrando al usuario una pantalla de administración detallada.

Permisos especiales

editar II:

Usé este código en una actividad que extendía FragmentActivity y obtuve la excepción java.lang.IllegalArgumentException: solo puedo usar 16 bits inferiores para requestCode porque el código de solicitud utilizado no está en el rango de 0 .. 65535. Podría considerar cambiar su código de solicitud a un valor apropiado. - mtsahakis

como dice:

El código de solicitud debe estar en el rango de 0 .. 65535 .

esto es porque:

  • el entero en java está representado por 32 bits
  • se le permite utilizar 16 bits inferiores para requestCode
  • otros bits se utilizan en el procesamiento de solicitudes

así por ejemplo:

integer value:  5463             ///hi 16 bits //   |    // lo 16 bits //
as binary string will look like: 0000 0000 0000 0000 0001 0101 0101 0111 

código de uso simple en un rango dado

editar III:

para aplicaciones dirigidas a AOSP API 26 (android oreo / 8+)

Las aplicaciones que usan el permiso SYSTEM_ALERT_WINDOW ya no pueden usar los siguientes tipos de ventana para mostrar ventanas de alerta sobre otras aplicaciones y ventanas del sistema:

TYPE_PHONE TYPE_PRIORITY_PHONE TYPE_SYSTEM_ALERT TYPE_SYSTEM_OVERLAY TYPE_SYSTEM_ERROR

En su lugar, las aplicaciones deben usar un nuevo tipo de ventana llamado TYPE_APPLICATION_OVERLAY.

TYPE_APPLICATION_OVERLAY

Tipo de ventana: las ventanas de superposición de aplicaciones se muestran encima de todas las ventanas de actividad (tipos entre FIRST_APPLICATION_WINDOW y LAST_APPLICATION_WINDOW) pero debajo de las ventanas críticas del sistema, como la barra de estado o IME.

El sistema puede cambiar la posición, el tamaño o la visibilidad de estas ventanas en cualquier momento para reducir el desorden visual para el usuario y también administrar los recursos.

Requiere permiso SYSTEM_ALERT_WINDOW.

El sistema ajustará la importancia de los procesos con este tipo de ventana para reducir la posibilidad de que el asesino de poca memoria los mate. En los sistemas multiusuario, solo se muestra en la pantalla del usuario propietario.

WindowManager.LayoutParams wLp = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
      ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
      : WindowManager.LayoutParams.TYPE_PHONE;

Window.setAttributes(WindowManager.LayoutParams)
ceph3us
fuente
2
¿Y cómo puede el usuario desactivar este permiso? No se muestra en los permisos en la configuración-> aplicaciones -> "MyApp" -> permisos. Además ... ¿alguna explicación de por qué este permiso es diferente a los demás en la forma en que lo solicitamos?
Anónimo
1
Usé este código en una actividad que extendía FragmentActivity y obtuve una excepción java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCodeporque el código de solicitud usado no está en el rango de 0 .. 65535. Puede considerar cambiar su código de solicitud a un valor apropiado.
mtsahakis
1
Utilice este código de solicitud ....... public final static int REQUEST_CODE = 5463 & 0xffffff00;
Muhammad Adil
@MuhammadAdil ¿cuál es el propósito de bitwise aquí? u cambia el valor a 5376
ceph3us
@ ceph3us aquí obtenemos este error si usamos ese REQUEST_CODE ..... java.lang.IllegalArgumentException: Solo se pueden usar 16 bits inferiores para requestCode ........ Así que pensé que debería ser arreglado.
Muhammad Adil
3

Siguiendo la respuesta de ceph3us para agregar un diálogo de alerta, esto funcionó bien

final AlertDialog dialog = dialogBuilder.create();
                final Window dialogWindow = dialog.getWindow();
                final WindowManager.LayoutParams dialogWindowAttributes = dialogWindow.getAttributes();

                // Set fixed width (280dp) and WRAP_CONTENT height
                final WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
                lp.copyFrom(dialogWindowAttributes);
                lp.width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 280, getResources().getDisplayMetrics());
                lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
                dialogWindow.setAttributes(lp);

                // Set to TYPE_SYSTEM_ALERT so that the Service can display it
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    dialogWindow.setType(WindowManager.LayoutParams.TYPE_TOAST);
                }
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    dialogWindow.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
                }
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
                {
                    dialogWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
                }
                dialog.show();

Pero el uso de TYPE_SYSTEM_ALERT podría activar la política de eliminación de Google de aplicaciones que usan permisos peligrosos. Asegúrese de tener una justificación válida en caso de que Google lo requiera.

Aashish Vivekanand
fuente
No usar TYPE_APPLICATION_OVERLAY pero algún otro tipo (TYPE_PHONE en mi caso) para teléfonos con Android 7.1.1 o inferior me ayudó a deshacerme de esta molesta BadTokenException en mi caso. Ver stackoverflow.com/questions/32224452/…
Martin Vysny
-8

Puede cambiar su SDK de destino a 22 o menos, luego también funciona en API 23.

Cámbielo en Gradle.Build.

Tortuga Solar
fuente
3
@Hulk Quizás no sea la mejor solución, pero es bueno señalarlo.
Quark
Esto no solucionará el problema, es una solución rápida que puede usar, pero nunca puede apuntar a api> 23
Aaron