androidandroid-permissionsandroid-6.0-marshmallow

How Do We Distinguish Never-Asked From Stop-Asking in Android M's Runtime Permissions?


When it comes to the M Developer Preview runtime permissions, according to Google:

  1. If you have never asked for a certain permission before, just ask for it

  2. If you asked before, and the user said "no", and the user then tries doing something that needs the rejected permission, you should prompt the user to explain why you need the permission, before you go on to request the permission again

  3. If you asked a couple of times before, and the user has said "no, and stop asking" (via the checkbox on the runtime permission dialog), you should just stop bothering (e.g., disable the UI that requires the permission)

However, we only have one method, shouldShowRequestPermissionRationale(), returning a boolean, and we have three states. We need a way to distinguish the never-asked state from the stop-asking state, as we get false from shouldShowRequestPermissionRationale() for both.

For permissions being requested on first run of the app, this is not a big problem. There are plenty of recipes for determining that this is probably the first run of your app (e.g., boolean value in SharedPreferences), and so you assume that if it's the first run of your app, you're in the never-asked state.

However, part of the vision of runtime permissions is that you might not ask for all of them up front. Permissions tied to fringe features you might only ask for later on, when the user taps on something that requires that permission. Here, the app may have been run many times, for months, before we all of a sudden need to request another permission.

In those cases, are we supposed to track whether or not we asked for the permission ourselves? Or is there something in the Android M API that I am missing that tells us whether we asked before or not?


Solution

  • As per the current example: https://github.com/googlesamples/android-RuntimePermissions/blob/master/Application/src/main/java/com/example/android/system/runtimepermissions/MainActivity.java#L195

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
            int[] grantResults) {
        if (requestCode == REQUEST_CAMERA) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                doThing();
                //STORE FALSE IN SHAREDPREFERENCES
            } else {
                //STORE TRUE IN SHAREDPREFERENCES
            }
        }
    

    Store a boolean in SharedPreferences with key as your permission code and value as indicated above, to indicate whether that preference has been denied before.

    Sadly, you probably can't check against a preference that has been accepted and later denied while your app is running. The final spec is not available, but there's a chance that your app either gets restarted or gets mock values until the next launch.