Eazy Runtime Permission

A lightweight Android library which wraps boilerplate code of runtime permission and allows you to request permissions from coroutines (No callbacks yay) or request and observe permissions through LiveData.

Including in your project

Eazy permissions is available in the Jcenter and divided into two modules so that based on your need you can include either coroutines or livedata in your project

//For coroutines
implementation 'com.sagar:coroutinespermission:[latest_version]'

//For LiveData
implementation 'com.sagar:livedatapermission:[latest_version]'
  • latest_version for coroutines - Download
  • latest_version for livedata - Download

Coroutines support

Requesting permission is just a simple function call to suspending function requestPermissions of PermissionManager from your coroutines or other suspending function which will return PermissionResult. It takes 3 parameters.

  1. An instance of AppCompactActivity or Fragment depending on from where you are requesting permission.
  2. Request id.
  3. varargs of permission you want to request.

This is how you would request for permission within coroutines and get result sequentially.

.
.
.
launch {
    //CoroutineScope

    val permissionResult = PermissionManager.requestPermissions(           //Suspends the coroutine
                            this@Fragment,                                  
                            REQUEST_ID,
                            Manifest.permission.ACCESS_FINE_LOCATION,
                            Manifest.permission.READ_CONTACTS,
                            Manifest.permission.CAMERA
                        )
                        
    //Resume coroutine once result is ready
    when(permissionResult) {
        is PermissionResult.PermissionGranted -> {
            //Add your logic here after user grants permission(s)
        }
        is PermissionResult.PermissionDenied -> {
            //Add your logic to handle permission denial
        }
        is PermissionResult.PermissionDeniedPermanently -> {
            //Add your logic here if user denied permission(s) permanently.
            //Ideally you should ask user to manually go to settings and enable permission(s)
        }
        is PermissionResult.ShowRational -> {
            //If user denied permission frequently then she/he is not clear about why you are asking this permission.
            //This is your chance to explain them why you need permission.
        }
    }

}

You can request permission from coroutine launched using any dispatcher(IO/Default/Main).

Library exposes PermissionResult as result of permission request which is nothing but simple sealed class which wraps all possible outcomes.

sealed class PermissionResult {
    class PermissionGranted(val requestId: Int) : PermissionResult()
    class PermissionDenied(val requestId: Int, val deniedPermissions: List<String>) : PermissionResult()
    class ShowRational(val requestId: Int) : PermissionResult()
    class PermissionDeniedPermanently(val requestId: Int, val permanentlyDeniedPermissions: List<String>) : PermissionResult()
}

Notice PermissionDenied and PermissionDeniedPermanently are also exposing list of denied permissions and permanently denied permissions respectively so that you can decide your flow based on denied permissions if you want to.

LiveData support

Just in case of coroutine we saw above requesting permission is just a simple method call to PermissionManager from your Activity/Fragment. It takes 3 parameters.

  1. An instance of AppCompactActivity or Fragment depending from where you are requesting permission.
  2. Request id.
  3. varargs of permission you want to request.

This is how you request permissions from your Activity/Fragment.

PermissionManager.requestPermissions(
                this,
                REQUEST_ID,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.READ_CONTACTS
            )

Observing permission request result

With just one simple step(implementing an interface) you are ready to observe the result of request.
Your Activity/Fragment must implement setupObserver method of PermissionObserver interface which expose LiveData<PermissionResult>. Here is the definition of PermissionObserver

/**
 * Interface definition for a callback to get [LiveData] of [PermissionResult]
 *
 * Implement this interface to get [LiveData] for observing permission request result.
 */
interface PermissionObserver {
    fun setupObserver(permissionResultLiveData: LiveData<PermissionResult>)
}

The library will only call setupObserver method when you are requesting permission for the first time. All the successive call to requestPermissions method will use the same observer.

Just as you would observe other LiveData you can observe LiveData<PermissionResult> as follow

override fun setupObserver(permissionResultLiveData: LiveData<PermissionResult>) {
    permissionResultLiveData.observe(this, Observer<PermissionResult> {
        when (it) {
            is PermissionResult.PermissionGranted -> {
                if (it.requestId == REQUEST_ID) {
                    //Add your logic here after user grants permission(s)
                }
            }
            is PermissionResult.PermissionDenied -> {
                if (it.requestId == REQUEST_ID) {
                    //Add your logic to handle permission denial
                }
            }
            is PermissionResult.PermissionDeniedPermanently -> {
                if (it.requestId == REQUEST_ID) {
                    //Add your logic here if user denied permission(s) permanently.
                    //Ideally you should ask user to manually go to settings and enable permission(s)
                }
            }
            is PermissionResult.ShowRational -> {
                if (it.requestId == REQUEST_ID) {
                    //If user denied permission frequently then she/he is not clear about why you are asking this permission.
                    //This is your chance to explain them why you need permission.
                }
            }
        }
    })
}

It is mandatory to implement PermissionObserver from where you are requesting permission(either Activity or Fragment).
If you don't then library will throw IllegalArgumentException stating that you have to implement PermissionObserver

Library will take care of Activity/Fragment recreation so even if user rotates screen or due to some other reason if your Activity/Fragment gets recreated it will call setupObserver method to register new observer of LiveData.

eazypermissionss

GitHub