Невозможно добавить окно 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.