Skip to content

Pixplicity/overlay-android-bug

Repository files navigation

overlay-android-bug

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.

The issue

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.

Shortest possible demo

  1. Through the settings, allow your app to draw on top of other apps,
  2. Call Settings.canDrawOverlays(context),
  3. It will return false, even with the permission granted.

Screenshots

Models

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.

Details

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;

About

Demo of a bug in Android 7.1.2 (Nougat) on a Nexus 6P

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages