首先,感谢这两篇博文http://blog.youkuaiyun.com/cankingapp/article/details/51569576
http://blog.youkuaiyun.com/cool_fuwei/article/details/53070232
了解知识:
1.首先要知道6.0版本权限模型跟原来版本是不同的,不再是统一在manifest中默认系统授权,而是有需要的时候,向系统请求授权,提高用户体验。
2.了解权限检测流程,一点注意点是如果系统权限弹窗提示框被不再提醒了,需要我们自定义提示弹窗,引导用户去授权。
3.明白权限类型,分为normal和dangerous类型,同时,在dangerous中还需要注意一点,SYSTEM_ALERT_WINDOW 和 WRITE_SETTINGS这两个特殊授权请求方式,跟一般授权请求方式不同。
4.在判断APP是否运行在Android M上,可以用版本号来判断,可以准确点。
问题一:在安卓开发中处理悬浮窗权限时,发现魅族和小米手机无论android4.4.4、android5.1.1还是android6.0,权限manifest中:android.permission.SYSTEM_ALERT_WINDOW权限也加过了,就是弹不起。这个权限也不是android 6.0中的敏感权限,所以android 6.0动态申请权限也是行不通的,这个问题很难通过diamante打开悬浮窗,没辙之后想到,调用应用的设置界面引导用户去手动的打开。
问题二:在三星6.0或android6.0及android 6.0以上的手机(小米和魅族处理方式另外处理同上),未处理弹窗问题可能会引发以下问题,
android.view.WindowManager$BadTokenException: Unable to add window
android.view.ViewRootImpl$W@a299900 -- permission denied for this window type
at android.view.ViewRootImpl.setView(ViewRootImpl.java:879)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:337)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
at android.app.Dialog.show(Dialog.java:350)
话不多说,直接上代码处理以上两个疑问。
@Override
public void onClick(View view) {
String user = edit_user.getText().toString();
String pwd = edit_pwd.getText().toString();
if (user.equals("123") && pwd.equals("123")) {
editor = pref.edit();
editor.putString("user", user);
editor.putString("pwd", pwd);
editor.commit();
//开启悬浮窗前先请求权限
if ("Xiaomi".equals(Build.MANUFACTURER)) {//小米手机
LogUtil.E("小米手机");
requestPermission();
} else if ("Meizu".equals(Build.MANUFACTURER)) {//魅族手机
LogUtil.E("魅族手机");
requestPermission();
} else {//其他手机
LogUtil.E("其他手机");
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivityForResult(intent, 12);
} else {
switchActivity();
}
} else {
switchActivity();
}
}
} else {
ToastUtil.show(this, "这么简单都出错,脑子呢?");
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 11) {
if (isFloatWindowOpAllowed(this)) {//已经开启
switchActivity();
} else {
ToastUtil.show(this, "开启悬浮窗失败");
}
} else if (requestCode == 12) {
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(LoginActivity.this)) {
ToastUtil.show(this, "权限授予失败,无法开启悬浮窗");
} else {
switchActivity();
}
}
}
}
/**
* 跳转Activity
*/
private void switchActivity() {
startActivity(new Intent(LoginActivity.this, Main2Activity.class));
ToastUtil.show(LoginActivity.this, "吆,竟然蒙对了!");
finish();
}
/**
* 判断悬浮窗权限
*
* @param context
* @return
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
public static boolean isFloatWindowOpAllowed(Context context) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
return checkOp(context, 24); // AppOpsManager.OP_SYSTEM_ALERT_WINDOW
} else {
if ((context.getApplicationInfo().flags & 1 << 27) == 1 << 27) {
return true;
} else {
return false;
}
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
public static boolean checkOp(Context context, int op) {
final int version = Build.VERSION.SDK_INT;
if (version >= 19) {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
try {
Class<?> spClazz = Class.forName(manager.getClass().getName());
Method method = manager.getClass().getDeclaredMethod("checkOp", int.class, int.class, String.class);
int property = (Integer) method.invoke(manager, op,
Binder.getCallingUid(), context.getPackageName());
Log.e("399", " property: " + property);
if (AppOpsManager.MODE_ALLOWED == property) {
return true;
} else {
return false;
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
Log.e("399", "Below API 19 cannot invoke!");
}
return false;
}
/**
* 请求用户给予悬浮窗的权限
*/
public void requestPermission() {
if (isFloatWindowOpAllowed(this)) {//已经开启
switchActivity();
} else {
openSetting();
}
}
/**
* 打开权限设置界面
*/
public void openSetting() {
try {
Intent localIntent = new Intent(
"miui.intent.action.APP_PERM_EDITOR");
localIntent.setClassName("com.miui.securitycenter",
"com.miui.permcenter.permissions.AppPermissionsEditorActivity");
localIntent.putExtra("extra_pkgname", getPackageName());
startActivityForResult(localIntent, 11);
LogUtil.E("启动小米悬浮窗设置界面");
} catch (ActivityNotFoundException localActivityNotFoundException) {
Intent intent1 = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent1.setData(uri);
startActivityForResult(intent1, 11);
LogUtil.E("启动悬浮窗界面");
}
}