Runtime Permissions – Android Marshmallow Tutorial

Runtime Permissions is a new permission model introduced in Android Marshmallow 6.0. Users are able to grant permissions during the app’s runtime, rather than during app install. Let’s look at leveraging the new runtime permissions for Android Marshmallow.

The Runtime Permission Model

As always, lets first see what good it does. The new permission model allows users to take control of permissions and decide what to grant when. This can be controlled from the App Info > App permissions section.

runtime-permissions-list

App permissions list

 Good for users, not for developers

In pre Marshmallow, all permissions had to be granted during install time. An app at any point of time had access to ALL permissions it requested. The user had no choice but to accept them. But that has changed now. Runtime permissions give users control over the sensitive information they provide. They chose which apps can access what, and when they cannot.

While this is good news for users, for a developer, it is not. Earlier we simply declared permissions in AndroidManifest.xml and we were on our way. But now apart from that, we need to check every time for a permission related task. Such as requesting the camera, calendar, contacts and so on. In addition, if the user denies the request permission, we need to handle that too.

Phew! That’s a lot of checking.

You may wonder, “If I’m using the new permission model, what about pre Marshmallow devices?”. Thankfully, implementing this gracefully falls back to the previous permission model on older devices. Great! That’s one less to worry about.

Guidelines

Runtime permissions add a new dimension to your app’s user experience. As an Android developer, you need to know WHEN and HOW to ask users for one, without annoying them.

Design patterns for runtime permissions.


Getting Started

If there’s one way to lessen our worries, its using a library. Like this one. The Permission Helper library will help us implement runtime permissions a whole lot easier!

Start by adding the library to your apps’ build.gradle file:

compile 'com.github.k0shk0sh:PermissionHelper:1.0.7'

Normal and Dangerous Permissions

That’s how Android’s permissions are categorized into two groups. The full list is here.

Cover areas where your app needs to access data or resources outside the app’s sandbox, but where there’s very little risk to the user’s privacy  – Normal Permissions

Dangerous permissions cover areas where the app wants data or resources that involve the user’s private information – Dangerous Permissions

Android will automatically grant access for Normal Permissions. So runtime permissions really come into play for the Dangerous Permissions.


Requesting Runtime Permissions

I’m going to request the ‘dangerous’ permission of reading the calendar. So for reference sake, I declare it like this:

final String PERMISSION = Manifest.permission.READ_CALENDAR;

Let’s bring the library’s magic into play. Implement OnPermissionCallback in your Activity. You’ll get the following methods:

  1. onPermissionGranted() – permission requested, and successfully granted by user
  2. onPermissionDeclined() – permission requested, but declined by user
  3. onPermissionPreGranted() – requested permission is already granted (allowed via app permissions screen)
  4. onPermissionNeedExplanation() – requested permission was denied, tell the user why you need it
  5. onPermissionReallyDeclined() – requested permission was denied, and future requests were denied too. ( Can only be allowed from Settings now)
  6. onNoPermissionNeeded() – fallback method for pre Marshmallow devices (older permissions model)

Firstly, initialize your PermissionsHelper:

permissionHelper = PermissionHelper.getInstance(this);

Then request your permission, say in your button’s OnClickListener.

permissionHelper.setForceAccepting(false).request(PERMISSION);

setForceAccepting() helps ensure that the request doesn’t force the user to grant permission.

Next, override the Activity’s onRequestPermissionsResult() method.

@Override
   public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
       permissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults);

   }

 Handling Requested Permission

After requesting the permission, we need to handle:

  1. Permission grant
  2. Permission denial

runtime permissions user flow

1. Permission Grant

Override the Activity’s onRequestPermissionsResult()

@Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

        permissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults);

    }

If the user granted permission, then onPermissionGranted() is used, otherwise onPermissionDeclined() is called.

In the user flow diagram, you can see that a denied permission can be requested again. If requested again, this time a system dialog doesn’t appear. But the permission will be added to your app’s Permissions screen, from where you can manually enable disable requested permissions.

[su_row][su_column size=”1/2″]

runtime permissions system dialo

System dialog shown first time

[/su_column] [su_column size=”1/2″]

system dialog with checkbox

System dialog after first time

[/su_column] [/su_row]

So if you want to request a denied permission, use the onPermissionNeedExplanation() method. Use this to tell the user WHY you need that permission. I do it with a simple dialog explaining why.

AlertDialog dialog = new AlertDialog.Builder(this)
          .setTitle(title)
          .setMessage(message)
          .setPositiveButton("Request", new DialogInterface.OnClickListener() {
              @Override
              public void onClick(DialogInterface dialog, int which) {

                  permissionHelper.requestAfterExplanation(permission);

              }
          })
          .create();

  dialog.show();

Finally, if you’re requesting for a permission that is already granted, then the onPermissionPreGranted() method comes really handy.

2. Permission Denial

Now what if the user denied permission? You need to handle that too. Since I’m requesting to read the calendar, if the user refuses to grant my request, I need a contingency plan.

You can handle denial with the onPermissionDeclined() method.

See the system dialog above, on the right? If the user checks ‘Never ask again‘, then that permission can ONLY be enabled via the app’s permissions screen found here:

[su_row][su_column size=”1/2″]

app-info-settings

[/su_column] [su_column size=”1/2″]

runtime-permissions-list

[/su_column] [/su_row]

You can handle this condition using the onPermissionReallyDeclined() method.

Fallback

Like I mentioned earlier. Devices running pre Marshmallow reverts to using the older permission model. This is automatically managed, since permissions are defined in AndroidManifest.xml. One less worry for us. Cheers!


Final Output

With everything in it’s place, let’s finally run our app and watch Runtime Permissions in action! In my demo, I’ve printed logs to a TextView. This way, you can see which methods are called when.

Source code on GitHub.

That’s all for this post. I hope runtime permissions with Android Marshmallow is clear now. Especially thanks to the Permission Helper library.

If this post helped you handle runtime permissions like a pro, considering sharing so others can benefit too.

Cheers!

Suleiman

Product Designer who occasionally writes code.

You may also like...

6 Responses

  1. Gonzo says:

    Hey Suleiman, I just found your blog and find it very helpful! I am having an issue with the new permissions when requesting them from nested fragment. I’m requesting a location permission, but when i request it from the inner nested fragment, the onRequestPermissionsResult method doesn’t get called. Got any solution or good workaround for me?

    How it looks so you can get the picture:
    Main activity holds a tabs fragment and a map fragment,
    the tabs fragment holds 2 fragment, which use a search based on location.

    • Suleiman19 says:

      Hey Gonzo,
      Delighted to know its helpful to you.
      About your issue, the onRequestPermissionsResult() method can only be overridden in an Activity. Use an Interface in your Fragment to communicate back to the Activity. http://developer.android.com/training/basics/fragments/communicating.html

      PS: If you think communicating like this is too hard, especially with Nested Fragments, try out EventBus

      • Gonzo says:

        Oh, I didn’t know it doesn’t work from fragments as I thought it does work with FragmentCompat (but that doesn’t take a support fragment so doesn’t help me either).

        I’ll take a look at the interface option as I don’t know anything about EventBus. You don’t happen to have a tutorial about that as well, do you? 🙂

      • Suleiman19 says:

        Hey Gonzo,
        Fragment to Activity communication via an Interface is pretty common, the link in my previous comment will help you out. For support Fragments, you need to import the support.v4 Fragment. No tutorials with Event Bus, yet 😉

  2. Gonzo says:

    Hey Suleiman, I just found your blog and find it very helpful! I am having an issue with the new permissions when requesting them from nested fragment. I’m requesting a location permission, but when i request it from the inner nested fragment, the onRequestPermissionsResult method doesn’t get called. Got any solution or good workaround for me?

    How it looks so you can get the picture:
    Main activity holds a tabs fragment and a map fragment,
    the tabs fragment holds 2 fragment, which use a search based on location.

Leave a Reply

Your email address will not be published. Required fields are marked *