Demo of a (now fixed) bug in Android 7.1.2 (Nougat) on a Nexus 6P.
Follow the issue on the issuetracker
Goshdarnit! Of course I created this test project on the very day Google released an OTA that fixed the issue. As you can see in the issue tracker, this bug is now solved in 7.1.2 build N2G47O.
Since Android M (23), there's a special security setting to allow apps to draw on top of other apps. Since Android 7.1.2, requesting the state of this setting always fails on the Nexus 6P.
- Through the settings, allow your app to draw on top of other apps,
- Call
Settings.canDrawOverlays(context)
, - It will return
false
, even with the permission granted.
Does not work:
- Nexus 6P 7.1.2-3783593
Works:
- Nexus 6P 7.1.2-3852959
- Pixel 7.1.2-3766409
- Nexus 5 6.0.2-3437181
Feel free to submit pull requests if you find more failing OS versions or models, and please star the issue if you are affected.
The internals of Settings.java
show a failure in the following code:
AppOpsManager appOpsMgr = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
int mode = AppOpsManager.MODE_DEFAULT;
if (makeNote) {
mode = appOpsMgr.noteOpNoThrow(appOpsOpCode, uid, callingPackage);
} else {
mode = appOpsMgr.checkOpNoThrow(appOpsOpCode, uid, callingPackage);
}
switch (mode) {
case AppOpsManager.MODE_ALLOWED:
return true;
case AppOpsManager.MODE_DEFAULT:
// this is the default operating mode after an app's installation
// In this case we will check all associated static permission to see
// if it is granted during install time.
for (String permission : permissions) {
if (context.checkCallingOrSelfPermission(permission) == PackageManager
.PERMISSION_GRANTED) {
// if either of the permissions are granted, we will allow it
return true;
}
}
default:
// this is for all other cases trickled down here...
if (!throwException) {
return false;
}
}
In the above, checkOpNoThrow
will always return MODE_IGNORED
instead of the expected MODE_ALLOWED
, meaning:
/**
* Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
* not allowed to perform the given operation, and this attempt should
* <em>silently fail</em> (it should not cause the app to crash).
*/
public static final int MODE_IGNORED = 1;