Sid Patil

code
search
dark_mode
person_outline

Better permissions on Android

calendar_today favorite_border 3.4K views hourglass_empty 4 min read Android
Permission rationale dialogs on Android

Permissions request dialogs are a vital part of user’s experience on the app. When a user installs an application for the first time they may or may not be clear of what the app does and why the app requires a certain set of permissions for its functionality.

Many applications show a permission request dialog and a user can choose to grant or deny a permission. Often a user may deny a certain permission which may be required for the core functionality of the app.

Well, why are permission rationale dialog important?

They offer the user a clear explanation on why the permission is required which may have been unclear previously when the user had denied the permission.

In this article we’ll cover how to handle cases where a user has previously denied a permission and present them with a rationale or a reason on why the user should grant the permission by using best practices and taking advantage of shouldShowRequestPermissionRationale. Let’s get started!

In this example we’ll be making a simple app in Kotlin which requests permissions and presents the user with a rationale for granting a denied permission. We’ll take a case where the app requires READ_CONTACTS permission from the user.

Step 1: Define the permission in the Manifest

AndroidManifest.xml

<uses-permission android:name="android.permission.READ_CONTACTS"/>

Step 2: Define a function that checks for the permission

private fun checkContactsPermission() {
    if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_CONTACTS) !=
        PackageManager.PERMISSION_GRANTED
    ) {
        // Check if permission is not granted
        Log.d(TAG, "Permission for contacts is not granted")
        // This condition only becomes true if the user has denied the permission previously
        if (shouldShowRequestPermissionRationale(android.Manifest.permission.READ_CONTACTS)) {
            showRationaleDialog(getString(R.string.rationale_title),
                getString(R.string.rationale_desc),
                android.Manifest.permission.READ_CONTACTS,
                REQUEST_CONTACTS_STATE)
        } else {
            // Perform a permission check
            Log.d(TAG, "Checking permission")
            requestPermissions(arrayOf(android.Manifest.permission.READ_CONTACTS),REQUEST_CONTACTS_STATE)
        }
    } else {
        // Permission is already granted, do your magic here!
    }
}

Here the code will perform a check if the read contacts permission is granted or not. The following cases will occur:

  1. First time user who is opening the app will be presented with a standard request permission dialog.
  2. A user who has denied the permission previously will be presented with a rationale dialog.
  3. User has granted the permission.

Step 3: Define your function for showing a rationale dialog

We can acheive this with an AlertDialog as shown in the below function

private fun showRationaleDialog(title: String, message: String, permission: String, requestCode: Int) {
    val builder: AlertDialog.Builder = AlertDialog.Builder(this)
    builder.setTitle(title)
        .setMessage(message)
        .setPositiveButton("Ok", { dialog, which ->
            requestPermissions(arrayOf(permission), requestCode)
        })
    builder.create().show()
}

We’ll also add strings for the dialog. In this example our sample app needs read contacts permission for suggesting connections or people the user may know.

strings.xml

<string name="rationale_title">We need permission to read your contacts</string>
<string name="rationale_desc">This app relies on read access to your contacts. 
We require access to this permission to find your contacts in our database and suggest people you may know. 
We will not store any contact info in our data base if they are not a part of our platform. 
For further info read our privacy policy.</string>

Step 4: Let’s handle the permission results

We’ll display a Toast message once permission has been granted or denied by overriding onPermissionResults()

override fun onRequestPermissionsResult(requestCode: Int,
                                        permissions: Array<out String>,
                                        grantResults:IntArray) {
    when (requestCode) {
        REQUEST_CONTACTS_STATE -> {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show()
            } else {
                Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

All Done! Let’s see how this works

User denies the permission Rational dialog on next open

The user now sees a rationale dialog since the permission was previously denied and shouldShowRequestPermissionRationale for the given permission has now become true.

Once the user taps on the positive button, the app will request permissions again. Hopefully this time you have convinced your user on why the permission is required.

Here is a Github link for the above project as a sample for your reference.

Cheers! We have successfully implemented rationale dialogs for permissions by following best practices.

About the author

Siddhesh Patil is an Android Engineer at DeliveryHero. Building core ordering experiences at Foodpanda and Foodora. He is the organzier of Kotlin Mumbai, a developer community in Mumbai, India. Find talks, articles and latest developments in Android and Kotlin on this website siddroid.com

Sid Patil is an Android Engineer and Kotlin Advocate based in Berlin, Germany. He works at Delivery Hero, building ordering experiences for food delivery and Q-commerce brands like Foodpanda and Foodora.

Share on

book

More articles to read