我正在为家长开发MDM应用程序来控制孩子的设备,如果执行了禁止的操作,它将使用权限SYSTEM_ALERT_WINDOW
在设备上显示警告。在安装过程中,在使用SDK 23+ (Android6.0)的设备上,应用程序使用以下方法检查权限:
Settings.canDrawOverlays(getApplicationContext())
如果此方法返回false
,则应用程序将打开系统对话框,用户可以在该对话框中授予权限:
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, REQUEST_CODE);
但是在使用SDK 26 (Android8.0)的设备上,当用户成功地授予许可并按下“后退”按钮返回到应用程序时,方法canDrawOverlays()
仍然返回false
,直到用户不关闭该应用程序并再次启动它,或者只是在最近的“应用程序”对话框中选择它。我在Android中用Android 8在最新版本的虚拟设备上测试了它,因为我没有真正的设备。
我做了一些研究,另外还检查了AppOpsManager的权限:
AppOpsManager appOpsMgr = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
int mode = appOpsMgr.checkOpNoThrow("android:system_alert_window", android.os.Process.myUid(), getPackageName());
Log.d(TAG, "android:system_alert_window: mode=" + mode);
因此:
canDrawOverlays()
返回false
)canDrawOverlays()
返回false
)canDrawOverlays()
返回true
)拜托,有人能跟我解释一下这种行为吗?我可以依赖mode == 1
的操作"android:system_alert_window"
并假设用户已经授予了权限吗?
发布于 2017-09-12 11:09:09
我也遇到了同样的问题。我使用了一个解决方法,试图添加一个不可见的覆盖。如果抛出异常,则不授予权限。这可能不是最好的解决办法,但有效。我不能告诉您任何关于AppOps解决方案的信息,但是它看起来是可靠的。
编辑2020年10月:正如注释中提到的那样,当抛出WindowManager
时,可能会在SecurityException
中出现内存泄漏,导致解决方案视图不会被删除(即使是对removeView
的显式调用)。对于正常使用来说,这不是什么大问题,但是要避免在同一个应用程序会话中运行太多的检查(如果不对其进行测试,我认为任何低于100的都可以)。
/**
* Workaround for Android O
*/
public static boolean canDrawOverlays(Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true;
else if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
return Settings.canDrawOverlays(context);
} else {
if (Settings.canDrawOverlays(context)) return true;
try {
WindowManager mgr = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
if (mgr == null) return false; //getSystemService might return null
View viewToAdd = new View(context);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(0, 0, android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O ?
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
viewToAdd.setLayoutParams(params);
mgr.addView(viewToAdd, params);
mgr.removeView(viewToAdd);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
https://stackoverflow.com/questions/46173460
复制相似问题