web-dev-qa-db-fra.com

Impossible d'ajouter la fenêtre Android.view.ViewRoot$W@44da9bc0 - autorisation refusée pour ce type de fenêtre

J'ai préféré this post par exemple, mais j'ai eu une erreur lors de l'ajout du groupe de visualisation dans l'objet windowmanager. J'ai utilisé la même classe pour le service que celle publiée dans la question. ne pas y arriver

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

quand j'ajoute une vue au WindowManger

voici mon fichier manifeste

<?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>

erreur

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
81
Pratik

Essayez d'utiliser cette permission dans AndroidManifest.

Android.permission.SYSTEM_ALERT_WINDOW

sur API> = 23 voir

154
Lalit Poptani

" @ ceph3us savez-vous comment l'obtenir pour> = M? ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW} ..."

  1. AUTORISATION SYSTEM_ALERT_WINDOW sur API> = 23 (Dessinez d'autres applications, etc.):

    • n'apparaît plus dans l'écran Autorisations de l'application.
    • il n'apparaît même pas dans le nouvel écran "Toutes les autorisations" qui dérange étrangement
  2. Appelez Activity.requestPermissions () avec cette autorisation,

    • ne montrera aucune boîte de dialogue permettant à l'utilisateur d'autoriser/refuser.
    • au lieu de cela, le rappel Activity.onRequestPermissionsResult () sera appelé immédiatement avec un indicateur de refus.

Solution:

Si l'application cible une API de niveau 23 ou supérieur, l'utilisateur de l'application doit explicitement accorder cette autorisation à l'application via un écran de gestion des autorisations. L'application demande l'approbation de l'utilisateur en envoyant une intention avec l'action ACTION_MANAGE_OVERLAY_PERMISSION . L'application peut vérifier si elle dispose de cette autorisation en appelant Settings.canDrawOverlays ().

exemple de code:

/** 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 
       }
    }
}

"Et comment l’utilisateur peut-il désactiver cette autorisation? Il n’apparaît pas dans les autorisations de paramètres-> applications ->" MonApp "-> autorisations. En outre ... aucune explication sur la raison pour laquelle cette autorisation est différente de les autres comme nous le demandons? - Anonyme 12 fév à 21:01 "

Quelques autorisations ne se comportent pas comme des autorisations normales et dangereuses. SYSTEM_ALERT_WINDOW et WRITE_SETTINGS étant particulièrement sensibles, la plupart des applications ne doivent pas les utiliser. Si une application nécessite l'une de ces autorisations, elle doit l'indiquer dans le manifeste et envoyer une intention demandant l'autorisation de l'utilisateur. Le système répond à l'intention en affichant un écran de gestion détaillé à l'utilisateur.

Autorisations spéciales

edit II:

J'ai utilisé ce code dans une activité qui étend FragmentActivity et j'ai reçu une exception. Java.lang.IllegalArgumentException: le code de requête utilisé ne peut utiliser que 16 bits inférieurs, car le code de requête utilisé n'est pas compris entre 0 et 65535. Vous pouvez envisager de modifier votre code de demande à une valeur appropriée. - mtsahakis

comme il le dit:

Le code de demande doit être compris entre 0 et 65535 .

c'est parce que:

  • entier dans Java est représenté par 32 bits
  • vous êtes autorisé à utiliser les 16 bits inférieurs pour requestCode
  • d'autres bits sont utilisés dans le traitement de la requête

ainsi par exemple:

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

code d'utilisation simple dans une plage donnée

edit III:

pour les applications ciblant l'API 26 d'AOSP (Android oreo/8+)

Les applications qui utilisent l'autorisation SYSTEM_ALERT_WINDOW ne peuvent plus utiliser les types de fenêtre suivants pour afficher des fenêtres d'alerte au-dessus d'autres applications et fenêtres système:

TYPE_PHONE TYPE_PRIORITY_PHONE TYPE_SYSTEM_ALERT TYPE_SYSTEM_OVERLAY TYPE_SYSTEM_ERROR

Au lieu de cela, les applications doivent utiliser un nouveau type de fenêtre appelé TYPE_APPLICATION_OVERLAY.

TYPE_APPLICATION_OVERLAY

Type de fenêtre: les fenêtres de superposition d'applications sont affichées au-dessus de toutes les fenêtres d'activité (types compris entre FIRST_APPLICATION_WINDOW et LAST_APPLICATION_WINDOW) mais en dessous des fenêtres système critiques telles que la barre d'état ou l'IME.

Le système peut à tout moment modifier la position, la taille ou la visibilité de ces fenêtres afin de réduire l'encombrement visuel de l'utilisateur et de gérer les ressources.

Requiert l'autorisation SYSTEM_ALERT_WINDOW.

Le système ajustera l’importance des processus avec ce type de fenêtre afin de réduire les risques de destruction par le tueur à faible mémoire. Dans les systèmes multi-utilisateurs, n’affiche que sur l’écran de l’utilisateur propriétaire.

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

Window.setAttributes(WindowManager.LayoutParams)
137
ceph3us

Après ceph3us réponse pour ajouter un dialogue d'alerte, cela a bien fonctionné

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();

Toutefois, l'utilisation de TYPE_SYSTEM_ALERT peut déclencher la stratégie de retrait de Google des applications utilisant des autorisations dangereuses. Assurez-vous d'avoir une justification valable au cas où Google l'exigerait.

3
Aashish Vivekanand