Nie można dodać okna android.view.ViewRoot$W@44da9bc0 - odmowa uprawnień dla tego typu okna

82

Na przykład wolę ten post, ale wyskoczył mi błąd przy dodawaniu viewgroup do obiektu windowmanager, użyłem tej samej klasy dla usługi, co napisano w pytaniu, bez zmiany gdzie mogę się pomylić Nie dostałem

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

kiedy dodam widok do programu WindowManger

oto mój plik manifestu

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

błąd

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
źródło

Odpowiedzi:

154

Spróbuj użyć tego uprawnienia w AndroidManifest.

android.permission.SYSTEM_ALERT_WINDOW

na API> = 23 patrz

Lalit Poptani
źródło
@ ceph3us czy wiesz, jak to osiągnąć dla> = M? ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW); Nic nie odpali. To samo z: ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW);
Martin Pfeffer
Ponadto może być konieczne wyraźne udzielenie pozwolenia, programowo lub ręcznie w ustawieniach telefonu. Używałem Huawei Nexus 6p iw ustawieniach mojej aplikacji kliknąłem „Tak” podczas rysowania na innych aplikacjach w sekcji ekranu.
emir
zobacz to dobre rozwiązanie: github.com/facebook/react-native/issues/…
WiRa
144

@ ceph3us, czy wiesz, jak to osiągnąć dla> = M? ActivityCompat.requestPermissions (this, new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW} ...”

  1. SYSTEM_ALERT_WINDOW PERMISSION na API> = 23 (rysuj nad innymi aplikacjami itp.):

    • nie pojawia się już na ekranie uprawnień aplikacji.
    • nie pojawia się nawet na dziwnie zagmatwanym nowym ekranie „Wszystkie uprawnienia”
  2. Wywołanie Activity.requestPermissions () z tym uprawnieniem,

    • nie wyświetli żadnego okna dialogowego umożliwiającego użytkownikowi zezwolenie / odmowę.
    • zamiast tego wywołanie zwrotne Activity.onRequestPermissionsResult () zostanie wywołane natychmiast z flagą odmowy.

Rozwiązanie:

Jeśli aplikacja jest przeznaczona na poziom interfejsu API 23 lub wyższy, użytkownik aplikacji musi jawnie udzielić aplikacji tego uprawnienia na ekranie zarządzania uprawnieniami. Aplikacja prosi użytkownika o zgodę, wysyłając intencję z akcją ACTION_MANAGE_OVERLAY_PERMISSION . Aplikacja może sprawdzić, czy ma tę autoryzację, wywołując Settings.canDrawOverlays ()

przykładowy kod:

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

„A w jaki sposób użytkownik może wyłączyć to uprawnienie? Nie widać go w uprawnieniach w ustawieniach-> aplikacje ->„ Moja aplikacja ”-> uprawnienia. Poza tym… wszelkie wyjaśnienia, dlaczego to uprawnienie różni się od pozostałych w sposób, w jaki o to prosimy? - Anonimowy 12 lutego o 21:01 "

Istnieje kilka uprawnień, które nie zachowują się jak zwykłe i niebezpieczne uprawnienia. SYSTEM_ALERT_WINDOW i WRITE_SETTINGS są szczególnie wrażliwe, więc większość aplikacji nie powinna ich używać. Jeśli aplikacja potrzebuje jednego z tych uprawnień, musi zadeklarować to uprawnienie w manifeście i wysłać intencję żądającą autoryzacji użytkownika. System reaguje na zamiar, pokazując użytkownikowi szczegółowy ekran zarządzania.

Specjalne uprawnienia

edycja II:

Użyłem tego kodu w działaniu rozszerzającym FragmentActivity i otrzymałem wyjątek java.lang.IllegalArgumentException: można użyć tylko niższych 16 bitów dla requestCode, ponieważ używany kod żądania nie mieści się w zakresie 0 ... 65535. Możesz rozważyć zmianę kodu żądania na odpowiednią wartość. - mtsahakis

jak to mówi:

kod żądania musi mieścić się w zakresie 0… 65535 .

jest to spowodowane:

  • liczba całkowita w java jest reprezentowana przez 32 bity
  • możesz używać niższych 16 bitów dla requestCode
  • inne bity są używane w przetwarzaniu żądań

więc na przykład:

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

prosty kod użycia w podanym zakresie

edycja III:

dla aplikacji przeznaczonych dla AOSP API 26 (Android oreo / 8+)

Aplikacje korzystające z uprawnienia SYSTEM_ALERT_WINDOW nie mogą już używać następujących typów okien do wyświetlania okien alertów nad innymi aplikacjami i oknami systemowymi:

TYPE_PHONE TYPE_PRIORITY_PHONE TYPE_SYSTEM_ALERT TYPE_SYSTEM_OVERLAY TYPE_SYSTEM_ERROR

Zamiast tego aplikacje muszą używać nowego typu okna o nazwie TYPE_APPLICATION_OVERLAY.

TYPE_APPLICATION_OVERLAY

Typ okna: Okna nakładek aplikacji są wyświetlane nad wszystkimi oknami aktywności (typy od FIRST_APPLICATION_WINDOW do LAST_APPLICATION_WINDOW), ale poniżej krytycznych okien systemowych, takich jak pasek stanu lub IME.

System może w dowolnym momencie zmienić położenie, rozmiar lub widoczność tych okien, aby zmniejszyć wizualny bałagan dla użytkownika, a także zarządzać zasobami.

Wymaga uprawnienia SYSTEM_ALERT_WINDOW.

System dostosuje ważność procesów z tym typem okna, aby zmniejszyć ryzyko zabicia ich przez zabójcę o małej ilości pamięci. W systemach z wieloma użytkownikami wyświetla się tylko na ekranie użytkownika będącego właścicielem.

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
źródło
2
Jak użytkownik może wyłączyć to uprawnienie? Nie pojawia się w uprawnieniach w ustawieniach-> aplikacje -> „Moja aplikacja” -> uprawnienia. Poza tym ... jakieś wyjaśnienie, dlaczego to zezwolenie różni się od pozostałych w sposobie, w jaki o nie prosimy?
Anonimowy
1
Użyłem tego kodu w działaniu rozszerzającym FragmentActivity i otrzymałem wyjątek, java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCodeponieważ używany kod żądania nie mieści się w zakresie 0 ... 65535. Możesz rozważyć zmianę kodu żądania na odpowiednią wartość.
mtsahakis
1
Użyj tego kodu żądania ....... public final static int REQUEST_CODE = 5463 & 0xffffff00;
Muhammad Adil
@MuhammadAdil, jaki jest tutaj cel bitwise? u zmień wartość na 5376
ceph3us
@ ceph3us tutaj otrzymujemy ten błąd, jeśli użyjemy tego REQUEST_CODE ..... java.lang.IllegalArgumentException: Może używać tylko niższych 16 bitów dla requestCode ........ Więc pomyślałem, że powinno to zostać naprawione.
Muhammad Adil
3

Po odpowiedzi ceph3us, aby dodać okno dialogowe alertów, to działało dobrze

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

Jednak użycie TYPE_SYSTEM_ALERT może wywołać politykę Google usuwania aplikacji korzystających z niebezpiecznych uprawnień. Upewnij się, że masz ważne uzasadnienie na wypadek, gdyby wymagało go Google.

Aashish Vivekanand
źródło
Nie używanie TYPE_APPLICATION_OVERLAY, ale innego typu (TYPE_PHONE w moim przypadku) dla telefonów z Androidem 7.1.1 lub niższym pomogło mi pozbyć się tego brzydkiego BadTokenException w moim przypadku. Zobacz stackoverflow.com/questions/32224452/…
Martin Vysny,
-8

Możesz zmienić docelowy SDK na 22 lub mniej, wtedy działa również z API 23.

Zmień to w Gradle.Build.

SolarTurtle
źródło
3
@Hulk To może nie jest najlepsze rozwiązanie, ale warto to wskazać.
Quark
To nie rozwiąże problemu, jest to szybkie obejście, którego możesz użyć, ale nigdy nie możesz kierować na api> 23
Aaron