mobiledevpro / Android-Kotlin-MVVM-Template

AppTemplate | MVVM + Clean Architecture | Kotlin, Coroutines, LiveData, Koin, Databinding, Navigation components, Room, Crashlytics, Circle CI config, commons classes for UI.
https://bento.me/mobiledevpro
Apache License 2.0
554 stars 51 forks source link

Add a common lifecycle observer to check and request runtime permissions using a new Result API #28

Closed dmitriy-chernysh closed 3 years ago

dmitriy-chernysh commented 3 years ago

Required dependencies

androidx.activity:activity-ktx androidx.fragment:fragment-ktx


class RuntimePermissionObserver(
    private val activity: FragmentActivity
) : LifecycleObserver {

    private var onGranted: () -> Unit = {}
    private var onDenied: () -> Unit = {}
    private var onShouldShowRationale: () -> Unit = {}

    private lateinit var launcher: ActivityResultLauncher<Array<String>>

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreate() {
        launcher = activity
            .activityResultRegistry
            .register(this.javaClass.name, ActivityResultContracts.RequestMultiplePermissions()) {

                var isGranted = false

                for (result in it) {
                    isGranted = result.value
                }

                if (isGranted)
                    onGranted()
                else
                    onDenied()

            }
    }

    fun launch(
        permissions: Array<String>,
        onGranted: () -> Unit = {},
        onDenied: () -> Unit = {},
        onShouldShowRationale: () -> Unit = {}
    ) {
        this.onGranted = onGranted
        this.onDenied = onDenied
        this.onShouldShowRationale = onShouldShowRationale

        when {
            // You can use the API that requires the permission.
            permissions.checkSelfPermission() -> onGranted()
            // In an educational UI, explain to the user why your app requires this
            // permission for a specific feature to behave as expected. In this UI,
            // include a "cancel" or "no thanks" button that allows the user to
            // continue using your app without granting the permission.
            permissions.checkShouldShowRationale(activity) -> onShouldShowRationale()

            else -> launcher.launch(permissions)
        }
    }

    private fun Array<String>.checkSelfPermission(): Boolean {

        var isGranted = false

        for (permission in this) {

            isGranted = ContextCompat.checkSelfPermission(
                activity,
                permission
            ) == PackageManager.PERMISSION_GRANTED

            //if at least one permission is not granted, stop checking
            if (!isGranted) break
        }

        return isGranted
    }

    private fun Array<String>.checkShouldShowRationale(
        activity: FragmentActivity
    ): Boolean {

        var isShouldShow = false

        for (permission in this) {
            isShouldShow = ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)

            //if at least one permission should be rationale, stop checking
            if (isShouldShow) break
        }

        return isShouldShow
    }
}
//request permissions
        permissionsObserver.launch(
            arrayOf(Manifest.permission.CAMERA),
            onShouldShowRationale = {
                //....
            },
            onGranted = {
              //....
            },
            onDenied = {
              //....
            }
        )
dmitriy-chernysh commented 3 years ago

Done