Skip to content

Instantly share code, notes, and snippets.

@pksokolowski
Created May 17, 2020 17:47
Show Gist options
  • Save pksokolowski/5574ae087aeba601f8aaf7b51c59cfe4 to your computer and use it in GitHub Desktop.
Save pksokolowski/5574ae087aeba601f8aaf7b51c59cfe4 to your computer and use it in GitHub Desktop.
A quick attempt at automatization and encapsulation of permissions handling on Android.
import android.app.Activity
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.github.pksokolowski.trainingplanner.di.PerApp
import javax.inject.Inject
/**
* A universal permissions helper. It should be injected both where you need to ask for a
* given permission and in the underlying activity. Within the activity, in
* onRequestPermissionsResult callback, pass all its parameters over to processResults()
*
* usage:
*
* Paste the following snippet in the activities which might be active when you want
* permission requests to be made.
*
* ```
* @Inject
* lateinit var permissionShop: PermissionsShop
* override fun onRequestPermissionsResult(
* requestCode: Int,
* permissions: Array<out String>,
* grantResults: IntArray
* ) {
* permissionShop.processResults(requestCode, permissions, grantResults)
* }
* ```
*/
@PerApp
class PermissionsShop @Inject constructor() {
private var lastPermissionCodeUsed = -1
private class Request(
val code: Int,
val onGranted: () -> Unit,
val onRefused: (() -> Unit)? = null
)
private val requestsCodesToCallbacks = HashMap<Int, Request>()
fun requestPermission(
activity: Activity,
permission: String,
onGranted: () -> Unit,
onRefused: (() -> Unit)? = null,
onRationaleRequired: (() -> Unit)? = null
) = requestPermissions(activity, arrayOf(permission), onGranted, onRefused, onRationaleRequired)
/**
* Call this in order to obtain an arbitrary permission
*
* @param permissions Permission codes of the permissions to ask the user for. Example:
* Manifest.permission.READ_CONTACTS
*/
fun requestPermissions(
activity: Activity,
permissions: Array<String>,
onGranted: () -> Unit,
onRefused: (() -> Unit)? = null,
onRationaleRequired: (() -> Unit)? = null
) {
val request = Request(++lastPermissionCodeUsed, onGranted, onRefused)
requestsCodesToCallbacks[request.code] = request
val missingPermissions = permissions.filter {
ContextCompat.checkSelfPermission(activity, it) != PackageManager.PERMISSION_GRANTED
}
if (missingPermissions.isEmpty()) {
onGranted()
return
}
val rationaleRequired = missingPermissions.any {
ActivityCompat.shouldShowRequestPermissionRationale(activity, it)
}
if (rationaleRequired) {
onRationaleRequired?.invoke()
return
}
ActivityCompat.requestPermissions(activity, permissions, 0)
}
/**
* You need to call this in activity's onRequestPermissionsResult() callback.
*/
fun processResults(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
val callbacks = requestsCodesToCallbacks[requestCode] ?: return
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
callbacks.onGranted()
} else {
callbacks.onRefused?.invoke()
}
return
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment