Не вдається додати вікно android.view.ViewRoot$W@44da9bc0 - дозвіл відмовлено для цього типу вікна


82

Наприклад, я віддаю перевагу цій публікації, але я отримав помилку при додаванні групи перегляду в об'єкт windowmanager, я використовував той самий клас для Служби, який був опублікований у питанні, без змін, де я можу помилитися, я його не отримав

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

коли я додаю подання до WindowManger

ось мій файл маніфесту

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

помилка

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

Відповіді:


154

Спробуйте використати цей дозвіл у AndroidManifest.

android.permission.SYSTEM_ALERT_WINDOW

на API> = 23 див


@ ceph3us ти знаєш, як цього досягти для> = M? ActivityCompat.requestPermissions (цей, новий рядок [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW); Нічого не стрілятиме. Те саме з: ActivityCompat.requestPermissions (цей, новий рядок [] {Manifest.permission.SYSTEM_ALERT_WINDOW}, Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW);
— Мартін Пфеффер,

Крім того, вам може знадобитися надати дозвіл явно, програмно або вручну із налаштувань вашого телефону. Я використовував Huawei Nexus 6p і в налаштуваннях свого додатка натиснув "Так", малюючи в інших програмах у розділі екрана.
— емір

див. це для хорошого рішення: github.com/facebook/react-native/issues/…
— WiRa

144

" @ ceph3us, чи знаєте ви, як цього досягти для> = M? ActivityCompat.requestPermissions (цей, новий рядок [] {Manifest.permission.SYSTEM_ALERT_WINDOW} ..."

  1. ДОЗВОЛЕННЯ SYSTEM_ALERT_WINDOW на API> = 23 (Намалюйте інші програми тощо):

    • більше не відображається на екрані дозволів програми.
    • це навіть не відображається на дивно заплутаному новому екрані "Усі дозволи"
  2. Виклик Activity.requestPermissions () з цим дозволом,

    • не покаже жодного діалогового вікна для користувача Дозволити / Заборонити.
    • натомість зворотний виклик Activity.onRequestPermissionsResult () буде негайно викликаний із забороненим прапором.

Рішення:

Якщо програма націлена на API рівня 23 або вище, користувач програми повинен явно надати цей дозвіл програмі через екран управління дозволами. Додаток запитує схвалення користувача, надіславши намір з дією ACTION_MANAGE_OVERLAY_PERMISSION . Додаток може перевірити, чи має він цю авторизацію, зателефонувавши Settings.canDrawOverlays ()

приклад коду:

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

"А як користувач може відключити цей дозвіл? Він не відображається у дозволах у налаштуваннях -> програми ->" MyApp "-> дозволи. Також ... будь-яке пояснення, чому цей дозвіл відрізняється від інших у як ми просимо про це? - Анонім 12 лютого о 21:01 "

Є кілька дозволів, які не поводяться як звичайні та небезпечні дозволи. SYSTEM_ALERT_WINDOW та WRITE_SETTINGS особливо чутливі, тому більшість програм не повинні їх використовувати. Якщо додатку потрібен один із цих дозволів, він повинен оголосити дозвіл у маніфесті та надіслати намір із запитом на авторизацію користувача. Система реагує на намір, показуючи користувачеві докладний екран управління.

Спеціальні дозволи

редагувати II:

Я використав цей код у Activity, що розширює FragmentActivity, і отримав виняток java.lang.IllegalArgumentException: Можна використовувати лише нижчі 16 бітів для requestCode, оскільки код запиту не знаходиться в діапазоні 0 .. 65535. Ви можете розглянути можливість зміни коду запиту на відповідне значення. - мцахакіс

як сказано:

код запиту повинен бути в діапазоні 0 .. 65535 .

це ось що:

  • ціле число в Java представлено 32 бітами
  • ви можете використовувати нижчі 16 біт для requestCode
  • інші біти використовуються при обробці запитів

так наприклад:

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

простий код використання в заданому діапазоні

редагувати III:

для програм, націлених на AOSP API 26 (android oreo / 8+)

Додатки, які використовують дозвіл SYSTEM_ALERT_WINDOW, більше не можуть використовувати такі типи вікон для відображення вікон попереджень над іншими програмами та системними вікнами:

TYPE_PHONE TYPE_PRIORITY_PHONE TYPE_SYSTEM_ALERT TYPE_SYSTEM_OVERLAY TYPE_SYSTEM_ERROR

Натомість програми повинні використовувати новий тип вікна під назвою TYPE_APPLICATION_OVERLAY.

TYPE_APPLICATION_OVERLAY

Тип вікна: Вікна накладання програм відображаються над усіма вікнами активності (типи між FIRST_APPLICATION_WINDOW і LAST_APPLICATION_WINDOW), але під критичними системними вікнами, такими як рядок стану або IME.

Система може в будь-який час змінити положення, розмір або видимість цих вікон, щоб зменшити візуальну метушню для користувача, а також керувати ресурсами.

Потрібен дозвіл SYSTEM_ALERT_WINDOW.

Система відрегулює важливість процесів з цим типом вікон, щоб зменшити ймовірність того, що вбивця з низьким обсягом пам'яті їх вб'є. У багатокористувацьких системах відображається лише на екрані власника користувача.

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

Window.setAttributes(WindowManager.LayoutParams)

2
І як користувач може відключити цей дозвіл? Це не відображається в дозволах у налаштуваннях -> програми -> «MyApp» -> дозволи. Також ... будь-яке пояснення, чому цей дозвіл відрізняється від інших тим, як ми просимо про це?
— Анонім

1
Я використав цей код у Activity, що розширює FragmentActivity, і я отримав виняток, java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCodeоскільки використовуваний код запиту не знаходиться в діапазоні 0 .. 65535. Ви можете розглянути можливість зміни коду запиту на відповідне значення.
— mtsahakis

1
Використовуйте цей код запиту ....... public final static int REQUEST_CODE = 5463 & 0xffffff00;
— Мухаммед Аділ

@MuhammadAdil яка мета тут побітового? u змініть значення на 5376
— ceph3us

@ ceph3us тут ми отримуємо цю помилку, якщо використовуємо REQUEST_CODE ..... java.lang.IllegalArgumentException: Може використовувати лише нижчі 16 біт для requestCode ........ Тому я хоч це слід виправити.
— Мухаммед Аділ

3

Після відповіді ceph3us на додавання діалогового вікна попередження це спрацювало нормально

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

Але використання TYPE_SYSTEM_ALERT може спричинити політику Google щодо видалення програм, які використовують небезпечні дозволи. Переконайтеся, що у вас є дійсне обґрунтування на випадок, якщо Google цього вимагає.


Не використовувати TYPE_APPLICATION_OVERLAY, але якийсь інший тип (TYPE_PHONE у моєму випадку) для телефонів з Android 7.1.1 або старішою версією допоміг мені позбутися цього докучливого BadTokenException у моєму випадку. Дивіться stackoverflow.com/questions/32224452/…
— Мартін Висний,

-8

Ви можете змінити цільовий SDK на 22 або менше, тоді він також працює на API 23.

Змініть це в Gradle.Build.


3
@Hulk Це, можливо, не найкраще рішення, але добре на це вказати.
— Кварк

Це не вирішить проблему, це швидкий обхідний шлях, який ви можете використовувати, але ви ніколи не можете націлити api> 23
— Аарон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.