Learn-Jetpack-Compose-By-Example icon indicating copy to clipboard operation
Learn-Jetpack-Compose-By-Example copied to clipboard

Add Example that requests permissions from a composable

Open dri94 opened this issue 5 years ago • 7 comments

It is apparent how we could request permissions from the MainActivity. However what if we are several layers deep in our app, how would we request runtime permission (such as location)?

dri94 avatar Jun 17 '20 02:06 dri94

Thanks for the request! This would be a very useful example so I'll add this soon. In the meantime, if you need something sooner, here's a related discussion - https://kotlinlang.slack.com/archives/CJLTWPH7S/p1590597865122200

vinaygaba avatar Jun 17 '20 06:06 vinaygaba

Hi @vinaygaba ,

I did something like this:

class PermissionHandler(
   private val activity: AppCompatActivity
) {

   fun requestPermission(
       permission: String,
       onResultReceived: (PermissionResult) -> Unit,
   ) {
       val requestPermissionLauncher = activity.registerForActivityResult(
           ActivityResultContracts.RequestPermission(),
       ) { granted ->
           onResultReceived(
               if (granted)
                   PermissionResult.Granted
               else
                   PermissionResult.Denied
           )
       }

       when {
           ContextCompat.checkSelfPermission(
               activity,
               permission
           ) == PackageManager.PERMISSION_GRANTED -> {
               onResultReceived(PermissionResult.Granted)
           }
           ActivityCompat.shouldShowRequestPermissionRationale(
               activity,
               permission
           ) -> {
               onResultReceived(PermissionResult.ShowRationale)
           }
           else -> requestPermissionLauncher.launch(permission)
       }
   }

}

@Composable
fun requestPermission(
   permission: String,
): State<PermissionResult> {
   val permissionHandler = AmbientPermissionHandler.current

   val permissionResult = remember(permission) {
       mutableStateOf<PermissionResult>(PermissionResult.Requesting)
   }

   remember(permission) {
       permissionHandler.requestPermission(permission) {
           permissionResult.value = it
       }
   }

   return permissionResult
}

sealed class PermissionResult {
   object Requesting : PermissionResult()

   object ShowRationale : PermissionResult()

   object Denied : PermissionResult()

   object Granted : PermissionResult()
}

val AmbientPermissionHandler: ProvidableAmbient<PermissionHandler> =
   staticAmbientOf { throw IllegalStateException("permission handler is not initialized") }

and then provide PermissionHandler as an ambient like so:

Providers(AmbientPermissionHandler provides permissionHandler) {
    ....
}

My idea was to be able to use it like:

val permissionResult by requestPermission(permission = Manifest.permission.CAMERA)
when (missionResult) {
     PermissionResult.Requesting -> Text("Requesting")
     PermissionResult.ShowRationale -> Text("Show Rationale")
     PermissionResult.Denied -> Text("Denied")
     PermissionResult.Granted -> FragmentContainer(fragment = SelfieFragment())
}

The problem is when I get to the Composable where the code above is located, I get the error:

LifecycleOwner ... is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.
        at androidx.activity.result.ActivityResultRegistry.register 
        ...

Not really sure how to solve the issue. It seems to me that at the point of a @Composable the lifecycle is already at LifecycleState.RESUMED and so registerForActivityResult(...) throws the error.

I was wondering whether you've already implemented permissions and maybe have some idea on how to solve this or do it a different way?

qrezet avatar Oct 15 '20 14:10 qrezet

@dri94 I am aware of this gist by one of the developers on Compose that shows how they are thinking about permission handling - https://gist.github.com/objcode/775fe45127fd40f17932f672ee203f72#file-permissions-kt-L78

vinaygaba avatar Oct 15 '20 15:10 vinaygaba

I think you tagged the wrong person but Thanks! It was the right call to ask about it here. Thank you very much.

qrezet avatar Oct 15 '20 15:10 qrezet

Oh my bad 🙈

vinaygaba avatar Oct 15 '20 15:10 vinaygaba

Update: You should probably be using Accompanist for permission support in Compose - https://github.com/google/accompanist/tree/main/permissions

vinaygaba avatar Aug 13 '21 05:08 vinaygaba

I'd like to work on this issue, please assign it to me. @vinaygaba

5AbhishekSaxena avatar Jan 09 '23 21:01 5AbhishekSaxena