无法添加窗口android.view.ViewRoot$W@44da9bc0-拒绝此窗口类型的权限


82

例如,我更喜欢这篇文章,但是在将viewgroup添加到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

Answers:


154

尝试在中使用此权限 AndroidManifest.

android.permission.SYSTEM_ALERT_WINDOW

在API> = 23上


@ ceph3us您知道如何为> = M实现它吗?ActivityCompat.requestPermissions(此为新的String [] {Manifest.permission.SYSTEM_ALERT_WINDOW},Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW);不会射击任何东西。与此相同:ActivityCompat.requestPermissions(此为新的String [] {Manifest.permission.SYSTEM_ALERT_WINDOW},Perm.PERMISSIONS_REQUEST_SYSTEM_ALERT_WINDOW);
Martin Pfeffer 2015年

另外,您可能需要通过电话上的设置以编程方式或手动方式明确授予权限。我使用的是华为Nexus 6p,在应用程序设置中,我点击了屏幕部分其他应用程序上的“是”。
emir

看到这样一个很好的解决方案:github.com/facebook/react-native/issues/...
威拉

144

@ ceph3us您知道如何为> = M实现它吗?ActivityCompat.requestPermissions(这是新的String [] {Manifest.permission.SYSTEM_ALERT_WINDOW} ...”

  1. API> = 23上的SYSTEM_ALERT_WINDOW PERMISSION(覆盖其他应用程序等):

    • 不再出现在“应用程序的权限”屏幕中。
    • 它甚至没有出现在令人困惑的新“所有权限”屏幕中
  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 
       }
    }
}

“以及用户如何禁用此权限?它不会显示在settings-> apps->“ MyApp”-> permissions中。此外...关于此权限为何与其他权限不同的任何解释我们要求的方式吗?–匿名2月12日在21:01“

有一些权限的行为与正常和危险的权限不同。SYSTEM_ALERT_WINDOW和WRITE_SETTINGS特别敏感,因此大多数应用程序不应使用它们。如果应用程序需要这些权限之一,则它必须在清单中声明该权限,并发送请求用户授权的意图。系统通过向用户显示详细的管理屏幕来响应此意图。

特殊权限

编辑二:

我在扩展FragmentActivity的Activity中使用了此代码,但遇到了异常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
我在扩展FragmentActivity的Activity中使用了此代码,但java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCode由于使用的请求代码不在0范围内,因此得到了Exception。65535 。您可能考虑将请求代码更改为适当的值。
mtsahakis

1
使用此请求代码....... public final static int REQUEST_CODE = 5463&0xffffff00;
穆罕默德·阿迪尔

@MuhammadAdil这里按位的目的是什么?您将值更改为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要求。


对于Android 7.1.1或更低版本的手机,不使用TYPE_APPLICATION_OVERLAY,而是使用其他一些类型(在我的情况下为TYPE_PHONE)可以帮助我摆脱这种讨厌的BadTokenException。见stackoverflow.com/questions/32224452/...
马丁Vysny

-8

您可以将目标SDK更改为22以下,然后也可以在API 23上使用。

在Gradle.Build中更改它。


3
@Hulk也许这不是最好的解决方案,但是指出它是很好的。
Quark

这不会解决这个问题,这是一个快速的解决方法,你可以使用,但你永远无法针对API> 23
阿伦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.