Fenster android.view.ViewRoot$W@44da9bc0 kann nicht hinzugefügt werden - Berechtigung für diesen Fenstertyp verweigert

82

Ich habe diesen Beitrag zum Beispiel bevorzugt, aber ich habe den Fehler beim Hinzufügen einer Ansichtsgruppe zum Windowmanager-Objekt erhalten. Ich habe dieselbe Klasse für den Dienst verwendet, die in der Frage veröffentlicht wurde, ohne zu ändern, wo ich mich irren kann, dass ich sie nicht erhalten habe

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

wenn ich dem WindowManger eine Ansicht hinzufüge

Hier ist meine Manifestdatei

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

Antworten:

154

Versuchen Sie, diese Berechtigung in zu verwenden AndroidManifest.

android.permission.SYSTEM_ALERT_WINDOW

on API> = 23 siehe

Lalit Poptani
quelle
@ ceph3us wissen Sie, wie man es für> = M erreicht? ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW); Wird nichts abfeuern. Gleiches gilt für: ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW);
Martin Pfeffer
Darüber hinaus müssen Sie möglicherweise explizit die Berechtigung entweder programmgesteuert oder manuell über die Einstellungen Ihres Telefons erteilen. Ich habe Huawei Nexus 6p verwendet und in den Einstellungen für meine Anwendung beim Zeichnen auf andere Anwendungen im Bildschirmbereich auf "Ja" geklickt.
Emir
Eine gute Lösung finden Sie hier: github.com/facebook/react-native/issues/…
WiRa
144

" @ ceph3us wissen Sie, wie Sie es für> = M erreichen können? ActivityCompat.requestPermissions (dieser neue String [] {Manifest.permission.SYSTEM_ALERT_WINDOW} ..."

  1. SYSTEM_ALERT_WINDOW PERMISSION auf API> = 23 (Zeichnen über andere Apps usw.):

    • wird nicht mehr im Bildschirm "Berechtigungen" der App angezeigt.
    • Es erscheint nicht einmal im seltsam verwirrenden neuen Bildschirm "Alle Berechtigungen"
  2. Mit dieser Berechtigung Activity.requestPermissions () aufrufen,

    • zeigt dem Benutzer kein Dialogfeld zum Zulassen / Verweigern an.
    • Stattdessen wird der Rückruf Activity.onRequestPermissionsResult () sofort mit einem abgelehnten Flag aufgerufen.

Lösung:

Wenn die App auf API-Level 23 oder höher abzielt, muss der App-Benutzer der App diese Berechtigung explizit über einen Berechtigungsverwaltungsbildschirm erteilen. Die App fordert die Genehmigung des Benutzers an, indem sie eine Absicht mit der Aktion ACTION_MANAGE_OVERLAY_PERMISSION sendet . Die App kann überprüfen, ob sie über diese Berechtigung verfügt, indem sie Settings.canDrawOverlays () aufruft.

Beispielcode:

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

"Und wie kann der Benutzer diese Berechtigung deaktivieren? Sie wird in den Berechtigungen unter Einstellungen-> Apps ->" MyApp "-> Berechtigungen nicht angezeigt. Außerdem ... gibt es eine Erklärung, warum sich diese Berechtigung von den anderen in der Berechtigung unterscheidet Wie fordern wir es an? - Anonym 12. Februar um 21:01 "

Es gibt einige Berechtigungen, die sich nicht wie normale und gefährliche Berechtigungen verhalten. SYSTEM_ALERT_WINDOW und WRITE_SETTINGS sind besonders sensibel, daher sollten die meisten Apps sie nicht verwenden. Wenn eine App eine dieser Berechtigungen benötigt, muss sie die Berechtigung im Manifest deklarieren und eine Absicht senden, in der die Autorisierung des Benutzers angefordert wird. Das System reagiert auf die Absicht, indem es dem Benutzer einen detaillierten Verwaltungsbildschirm anzeigt.

Sondergenehmigungen

bearbeiten II:

Ich habe diesen Code in einer Aktivität verwendet, die FragmentActivity erweitert, und habe die Ausnahme java.lang.IllegalArgumentException erhalten: Kann nur niedrigere 16 Bit für requestCode verwenden, da der verwendete Anforderungscode nicht im Bereich von 0 .. 65535 liegt. Möglicherweise möchten Sie Ihren Anforderungscode in ändern ein angemessener Wert. - Mtsahakis

wie es heißt:

Der Anforderungscode muss im Bereich von 0 bis 65535 liegen .

das liegt daran:

  • Ganzzahl in Java wird durch 32 Bit dargestellt
  • Sie dürfen für requestCode niedrigere 16 Bit verwenden
  • andere Bits werden bei der Anforderungsverarbeitung verwendet

so zum Beispiel:

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

Code zur einfachen Verwendung in einem bestimmten Bereich

bearbeiten III:

für Apps, die auf die AOSP API 26 abzielen (android oreo / 8+)

Apps, die die Berechtigung SYSTEM_ALERT_WINDOW verwenden, können die folgenden Fenstertypen nicht mehr verwenden, um Warnfenster über anderen Apps und Systemfenstern anzuzeigen:

TYPE_PHONE TYPE_PRIORITY_PHONE TYPE_SYSTEM_ALERT TYPE_SYSTEM_OVERLAY TYPE_SYSTEM_ERROR

Stattdessen müssen Apps einen neuen Fenstertyp namens TYPE_APPLICATION_OVERLAY verwenden.

TYPE_APPLICATION_OVERLAY

Fenstertyp: Anwendungsüberlagerungsfenster werden über allen Aktivitätsfenstern (Typen zwischen FIRST_APPLICATION_WINDOW und LAST_APPLICATION_WINDOW) angezeigt, jedoch unter kritischen Systemfenstern wie der Statusleiste oder IME.

Das System kann die Position, Größe oder Sichtbarkeit dieser Fenster jederzeit ändern, um die visuelle Unordnung für den Benutzer zu verringern und Ressourcen zu verwalten.

Erfordert die Berechtigung SYSTEM_ALERT_WINDOW.

Das System passt die Wichtigkeit von Prozessen mit diesem Fenstertyp an, um die Wahrscheinlichkeit zu verringern, dass der Killer mit geringem Speicherbedarf sie tötet. In Mehrbenutzersystemen wird nur auf dem Bildschirm des besitzenden Benutzers angezeigt.

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
quelle
2
Und wie kann der Benutzer diese Berechtigung deaktivieren? Es wird nicht in den Berechtigungen unter Einstellungen-> Apps -> "MyApp" -> Berechtigungen angezeigt. Auch ... eine Erklärung, warum sich diese Erlaubnis von den anderen in der Art und Weise unterscheidet, wie wir sie anfordern?
Anonym
1
Ich habe diesen Code in einer Aktivität verwendet, die FragmentActivity erweitert, und ich habe eine Ausnahme erhalten, java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCodeda der verwendete Anforderungscode nicht im Bereich von 0 bis 65355 liegt. Sie können Ihren Anforderungscode möglicherweise in einen geeigneten Wert ändern.
Mtsahakis
1
Verwenden Sie diesen Anforderungscode ....... public final static int REQUEST_CODE = 5463 & 0xffffff00;
Muhammad Adil
@ MuhammadAdil was ist der Zweck von bitweise hier? u ändern Sie den Wert auf 5376
ceph3us
@ ceph3us hier erhalten wir diesen Fehler, wenn wir diesen REQUEST_CODE verwenden ..... java.lang.IllegalArgumentException: Kann nur niedrigere 16 Bit für requestCode verwenden ........ Also ich dachte, es sollte behoben werden.
Muhammad Adil
3

Nach der Antwort von ceph3us zum Hinzufügen eines Warnungsdialogs funktionierte dies einwandfrei

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

Die Verwendung von TYPE_SYSTEM_ALERT kann jedoch die Google-Abschaltrichtlinie für Apps mit gefährlichen Berechtigungen auslösen. Stellen Sie sicher, dass Sie eine gültige Begründung haben, falls Google dies benötigt.

Aashish Vivekanand
quelle
Die Verwendung von TYPE_APPLICATION_OVERLAY, aber eines anderen Typs (in meinem Fall TYPE_PHONE) für Telefone mit Android 7.1.1 oder niedriger hat mir geholfen, diese lästige BadTokenException in meinem Fall loszuwerden. Siehe stackoverflow.com/questions/32224452/…
Martin Vysny
-8

Sie können Ihr Ziel-SDK auf 22 oder weniger ändern, dann funktioniert es auch mit API 23.

Ändern Sie es in Gradle.Build.

SolarTurtle
quelle
3
@Hulk Es ist vielleicht nicht die beste Lösung, aber es ist gut, darauf hinzuweisen.
Quark
Dies wird das Problem nicht beheben, es ist eine schnelle Problemumgehung, die Sie verwenden können, aber Sie können nie API> 23
Aaron