SYSTEM_ALERT_WINDOW - How to get this permission automatically on Android 6.0 and targetSdkVersion 23
It is a new behaviour introduced in Marshmallow 6.0.1.
Every app that requests the SYSTEM_ALERT_WINDOW
permission and that is installed through the Play Store (version 6.0.5 or higher is required), will have granted the permission automatically.
If instead the app is sideloaded, the permission is not automatically granted. You can try to download and install the Evernote APK from apkmirror.com. As you can see you need to manually grant the permission in Settings -> Apps -> Draw over other apps
.
These are the commits [1] [2] that allow the Play Store to give the automatic grant of the SYSTEM_ALERT_WINDOW
permission.
Runtime permission for SYSTEM_ALERT_WINDOW
there is no runtime permission/dialog for this purpose, you have to pass user to app settings
public boolean checkStartPermissionRequest() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
return false; // above will start new Activity with proper app setting
}
}
return true; // on lower OS versions granted during apk installation
}
more info HERE
Android SYSTEM_ALERT_WINDOW permission
It is a new behaviour introduced in Marshmallow 6.0.1.
Every app that requests the SYSTEM_ALERT_WINDOW permission and that is installed through the Play Store (version 6.0.5 or higher is required), will have granted the permission automatically.
If instead the app is sideloaded, the permission is not automatically granted. You can try to download and install the Evernote APK from apkmirror.com. As you can see you need to manually grant the permission in Settings -> Apps -> Draw over other apps.
[The above information is from this post.]
If you want the app to be sideloaded, you show manually show a prompt and direct the user to enable Draw over other apps permissions from the settings. Have a look at Requesting permissions
How to handle SYSTEM_ALERT_WINDOW permission not being auto-granted on some pre-Marshmallow devices
Checking if you have the drawOverlays permission is safer using this:
@SuppressLint("NewApi")
public static boolean canDrawOverlayViews(Context con){
if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP){return true;}
try {
return Settings.canDrawOverlays(con);
}
catch(NoSuchMethodError e){
return canDrawOverlaysUsingReflection(con);
}
}
public static boolean canDrawOverlaysUsingReflection(Context context) {
try {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
Class clazz = AppOpsManager.class;
Method dispatchMethod = clazz.getMethod("checkOp", new Class[] { int.class, int.class, String.class });
//AppOpsManager.OP_SYSTEM_ALERT_WINDOW = 24
int mode = (Integer) dispatchMethod.invoke(manager, new Object[] { 24, Binder.getCallingUid(), context.getApplicationContext().getPackageName() });
return AppOpsManager.MODE_ALLOWED == mode;
} catch (Exception e) { return false; }
}
Custom ROMs can have altered the OS so that that Settings.canDrawOverlays() is not available. This happened to me with Xiaomi devices and the app crashed.
Requesting the permission:
@SuppressLint("InlinedApi")
public static void requestOverlayDrawPermission(Activity act, int requestCode){
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + act.getPackageName()));
act.startActivityForResult(intent, requestCode);
}
Return to app after requesting SYSTEM_ALERT_WINDOW permission
It appears that there is no way to observe this setting, so there is really no elegant solution for this.
What you can do is just check the setting once per second using a Handler after you send the user to the Settings screen.
You can't truly "go back" programmatically from the Settings screen, so the only option is to re-launch the Activity and clear the previous ones (otherwise it will go back to the Settings screen on back press afterwards).
With the example below, within one second of enabling the setting, it will re-launch MainActivity.
First define the Runnable:
Handler handler = new Handler();
Runnable checkOverlaySetting = new Runnable() {
@Override
@TargetApi(23)
public void run() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return;
}
if (Settings.canDrawOverlays(MainActivity.this)) {
//You have the permission, re-launch MainActivity
Intent i = new Intent(MainActivity.this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
return;
}
handler.postDelayed(this, 1000);
}
};
Then start the Runnable when you send the user to the Settings screen:
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
//Add this here:
handler.postDelayed(checkOverlaySetting, 1000);
Note that you should set a timeout or max tries so that it doesn't go on forever if the user does not enable the overlay setting.
Related Topics
Singleton Object Becomes Null After App Is Resumed
Android: How to Auto-Restart an Application After It Has Been "Force Closed"
How to Handle a Lost Keystore Password in Android
Setbackground VS Setbackgrounddrawable (Android)
How to Create a Custom Navigation Drawer in Android
Bad Image Quality After Resizing/Scaling Bitmap
How to Control the Width and Height of the Default Alert Dialog in Android
Android: Detect When Scrollview Stops Scrolling
How to Set Mobile System Time and Date in Android
Calling a Fragment Method from a Parent Activity
How to Display the Current Value of an Android Preference in the Preference Summary
How to Send a Post Request Using Volley with String Body
Changing the Background Drawable of the Searchview Widget
Android Transparent Status Bar and Actionbar
Html.Fromhtml Deprecated in Android N
How to Pass a Variable from Activity to Fragment, and Pass It Back