Не вдається додати вікно 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.