窗口类型2038的权限被拒绝

时间:2018-10-21 15:59:14

标签: android android-windowmanager android-layoutparams

我正在修复一个不是由我开发的android应用程序,几天前,客户要求我将targetSdkVersion设置为26(在14之前),在我注意到某些情况下该应用程序崩溃后,显示ProgressDialog时,示例崩溃。这是此问题代码的一部分:

mProgressDialog.setTitle(getString(R.string.downloading_data));
mProgressDialog.setMessage(mAlertMsg);
Drawable icon = getActivity().getDrawable(android.R.drawable.ic_dialog_info);
icon.setColorFilter(Color.parseColor("#00cbac"), PorterDuff.Mode.SRC_ATOP);
mProgressDialog.setIcon(icon);
mProgressDialog.setIndeterminate(true);
mProgressDialog.setCancelable(false);
mProgressDialog.setButton(getString(R.string.cancel), loadingButtonListener);
mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
mProgressDialog.show();

执行最后一行时,应用程序崩溃并在Logcat中出现此错误:

android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@b784d3a -- permission denied for window type 2003

当应用程序在具有Android 8和9的设备中运行时,会发生此问题。 我在寻找类似问题的解决方案,但发现使用WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY而不是TYPE_SYSTEM_ALERT会更好,然后我修改了我在本文中编写的代码的倒数第二行,但没有更改任何内容,应用程序都会崩溃,并在日志中显示此错误:

android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@b784d3a -- permission denied for window type 2038

在清单中,我有权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

我还从设备设置中启用了该应用程序的所有权限。 我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

如前所述,

Android Oreo及更高版本严格限制了允许使用的重叠类型。奥利奥(Oreo)引入了新的TYPE_APPLICATION_OVERLAY常量供应用程序使用,同时弃用和禁止了旧常量。

但是,TYPE_APPLICATION_OVERLAY在牛轧糖及其以下版本中不存在,因此尝试在其中使用它会导致出现SecurityException。

替换

mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

使用

mProgressDialog.getWindow().setType(
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
        else 
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);

关于为什么在TYPE_APPLICATION_OVERLAY上Oreo及以上版本仍然崩溃的原因,SYSTEM_ALERT_WINDOW权限不是正常的运行时权限,并且不会显示在应用程序信息的“权限”部分下。面向用户的名称(通常是“覆盖其他应用程序”)在常规“应用程序信息”页面下或“设置” >>“应用程序”>“特殊访问”下。

您不能像在运行时权限中那样以编程方式授予它,在此处您有一个简单的对话框来授予它。相反,您需要检查是否已授予许可,如果没有,则启动“设置”页面以允许用户授予它:How to programmatically grant the "draw over other apps" permission in android?


但是,我真的不明白为什么简单的进度对话框需要是一个完整的覆盖。实际上,ProgressDialog已被完全弃用。您应该考虑迁移到简单的ProgressBar,或者如果要保留ProgressDialog,则删除setType()行。