Невозможно добавить окно 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 (this, new String [] {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 (this, new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW} ..."

  1. SYSTEM_ALERT_WINDOW PERMISSION на 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, и получил Exception java.lang.IllegalArgumentException: для requestCode можно использовать только младшие 16 бит, поскольку используемый код запроса не находится в диапазоне 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» -> разрешения. Также ... какие-либо объяснения того, почему это разрешение отличается от других в том, как мы его запрашиваем?
Anonymous

1
Я использовал этот код в Activity, расширяющем FragmentActivity, и получил Exception, 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/...
Martin Vyšný

-8

Вы можете изменить целевой SDK на 22 или меньше, тогда он также будет работать с API 23.

Измените его в Gradle.Build.


3
@Hulk Возможно, это не лучшее решение, но стоит указать на него.
Quark

Это не решит проблему, это быстрое решение, которое вы можете использовать, но вы никогда не сможете настроить таргетинг на api> 23
Аарон
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.