Peko

Additional

Language
Kotlin
Version
N/A
Created
Feb 24, 2018
Updated
Sep 1, 2019
Owner
Marko Devcic (deva666)
Contributors
Marko Devcic (deva666)
lucasvalenteds
Dmitry Borodin (Dmitry-Borodin)
3
Activity
Badge
Generate
Download
Source code
APK file

Blurb

Or use one of the extension functions on an Activity or a Fragment:

launch {
    val result = requestPermissionsAsync(Manifest.permission.READ_CONTACTS) 
    
    if (result is PermissionResult.Granted) {
        // we have contacts permission
    } else {
        // permission denied
    }
}

Request multiple permissions:

launch {
    val result = requestPermissionsAsync(Manifest.permission.READ_CONTACTS, Manifest.permission.CAMERA) 
    
    if (result is PermissionResult.Granted) {
        // we have both permissions
    } else if (result is PermissionResult.Denied) {
        result.deniedPermissions.forEach { p ->
            // this one was denied
        }
    }
}

Denied Result has three subtypes which can be checked to see if we need Permission Rationale or user Clicked Do Not Ask Again:

launch {
    val result = requestPermissionsAsync(Manifest.permission.BLUETOOTH, Manifest.permission.CAMERA) 
    
    when (result) {
        is PermissionResult.Granted -> { } // woohoo, all requested permissions granted
        is PermissionResult.Denied.JustDenied -> { } // at least one permission was denied, maybe we forgot to register it in the AndroidManifest?
        is PermissionResult.Denied.NeedsRationale -> { } // user clicked Deny, let's show a rationale
        is PermissionResult.Denied.DeniedPermanently -> { } // Android System won't show Permission dialog anymore, let's tell the user we can't proceed 
    }
}

LiveData

Hate Coroutines? No problem ... just create an instance of PermissionsLiveData and observe the results with your LifecycleOwner

In a ViewModel ... if you need to support orientation changes, or anywhere else if not (Presenter)

    val permissionLiveData = PermissionsLiveData()
    
    fun checkPermissions(vararg permissions: String) {
        permissionLiveData.checkPermissions(*permissions)
    }

In your LifecycleOwner, for example in an Activity

override fun onCreate(savedInstanceState: Bundle?) {
    viewModel = ViewModelProviders.of(this).get(YourViewModel::class.java)
    // observe has to be called before checkPermissions, so we can get the LifecycleOwner
    viewModel.permissionLiveData.observe(this, Observer { r: PermissionResult ->
        // do something with permission results
    })
}

private fun askContactsPermissions() {
    viewModel.checkPermissions(Manifest.permission.READ_CONTACTS)
}

Screen rotations

Library has support for screen rotations. To avoid memory leaks, all Coroutines that have not completed yet, should be cancelled in the onDestroy function. When you detect a orientation change, cancel the Job of a CoroutineScope with an instance of ActivityRotatingException. Internally, this will retain the current request that is in progress. The request is then resumed with calling resumeRequest method.

Example:

First:

// job that will be cancelled in onDestroy
private val job = Job()

private fun requestPermission(vararg permissions: String) {
    launch { 
        val result = Peko.requestPermissionsAsync(this@MainActivity, *permissions)
        // check granted permissions
    }
}

Then in onDestroy of an Activity:

if (isChangingConfigurations) {
    job.cancel(ActivityRotatingException()) // screen rotation, retain the results
} else { 
    job.cancel() // no rotation, just cancel the Coroutine
}

And when this Activity gets recreated in one of the Activity lifecycle functions, e.g.onCreate:

// check if we have a request already (or some other way you detect screen orientation)
if (Peko.isRequestInProgress()) {
    launch {
        // get the existing request and await the result
        val result = Peko.resumeRequest() 
        // check granted permissions
    }
}

LiveData and screen rotations

You don't have to do anything, this logic is already inside the PermissionsLiveData class. You just have to call observe in the onCreate method and of course use androidx.lifecycle.ViewModel.

License

Copyright 2019 Marko Devcic

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.