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

时间:2011-09-27 13:27:16

标签: android overlay

我更喜欢发布this帖子,但是我在将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

4 个答案:

答案 0 :(得分:152)

尝试在AndroidManifest.

中使用此权限
android.permission.SYSTEM_ALERT_WINDOW

<强> on API >= 23 see

答案 1 :(得分:134)

&#34; @ ceph3us你知道如何为&gt; = M实现它吗? ActivityCompat.requestPermissions(this,new String [] {Manifest.permission.SYSTEM_ALERT_WINDOW} ...&#34;

  1. API上的SYSTEM_ALERT_WINDOW权限&gt; = 23 (借过其他应用等):

    • 不再出现在App的权限屏幕中。
    • 它甚至不会出现在奇怪的混淆新&#34;所有权限&#34;屏
  2. 使用此权限调用Activity.requestPermissions(),

    • 不会显示用户允许/拒绝的任何对话框。
    • 相反,将立即使用拒绝标志调用Activity.onRequestPermissionsResult()回调。
  3. 解决方案:

      

    如果应用针对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 
           }
        }
    }
    

    &#34;用户如何禁用此权限?它没有在设置 - &gt; apps-&gt;&#34; MyApp&#34; - &gt;权限的权限中显示。还有...为什么这个权限与我们要求的方式不同的任何解释? - 匿名2月12日21:01&#34;

      

    有一些权限不像普通人那样行事   危险的权限。 SYSTEM_ALERT_WINDOW和WRITE_SETTINGS是   特别敏感,所以大多数应用程序不应该使用它们。如果一个应用程序   需要其中一个权限,它必须在中声明权限   显示,并发送请求用户授权的意图。该   系统通过显示详细的管理屏幕来响应意图   给用户。

    Special Permissions

    编辑II:

    我在Activity扩展FragmentActivity中使用了这段代码,我得到了异常java.lang.IllegalArgumentException:对于requestCode只能使用低16位,因为使用的请求代码不在0 .. 65535的范围内。你可能会考虑将您的请求代码更改为适当的值。 - mtsahakis

    因为它是sais:

      

    请求代码必须在 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 :(得分: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删除政策。如果谷歌要求,请确保您有正确的理由。

答案 3 :(得分:-9)

您可以将目标SDK更改为22或更低,然后它也适用于API 23.

在Gradle.Build中更改它。