1

I am struggling with figure out how to close a dialog launched to explain denied permissions.

Using accompanist to ask for permissions:

val lifecycleOwner = LocalLifecycleOwner.current
DisposableEffect(key1 = lifecycleOwner, effect = {
   val observer = LifecycleEventObserver { _, event ->
      if (event == Lifecycle.Event.ON_START) {
         locationPermissionState.launchPermissionRequest()

      }
   }
   lifecycleOwner.lifecycle.addObserver(observer)

   onDispose {
      lifecycleOwner.lifecycle.removeObserver(observer)
   }
})

In the same composable I launch a dialog depending on denied permissions:

when {
   locationPermissionState.status.shouldShowRationale -> {
      AlertDialog(
         // Dialog to explain to users the permission
      )
   }
   !locationPermissionState.status.isGranted && !locationPermissionState.status.shouldShowRationale -> {
      AlertDialog(
         // dialog to tell user they need to go to settings to enable
      )
   }
}

I am stuck figuring out how to close on the dialog when the user click an OK button.

I have tried to use another state that survives recomposition:

   val openDialog by remember { mutableStateOf(false) }
   ....
   // if permission state denied
   openDialog = true
   ....
   // then in dialog ok
   openDialog = false

However when doing that and changing the state of openDialog the function is recomposed. Which just means when I check the permissions state again its still the same and my dialog opens again.

lostintranslation
  • 23,756
  • 50
  • 159
  • 262

1 Answers1

0

For a general solution handling location permissions requests in Compose you need to keep track of performed permissions requests. Android's permissions request system works in an iterative fashion, and at certain points in this iteration there is no state change to observe and to act upon besides the iteration count. The current Accompanist 0.24.12-rc has a permissions request callback that you can use to do this. Then you can structure your declarative Compose code to take action based on previously observed and saved iteration counts and the current iteration count. (And you could try to abstract it further, creating dedicated states based on iteration count values and differences, but that's not really necessary to make it work; my hope would be that someone will add this in Accompanist at some point.)

For example:

val locationPermissions: List<String> = listOf(ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION)

@Stable
interface LocationPermissionsState : MultiplePermissionsState {
    /**
     * Supplies a well-defined measure of time/progression
     */
    val requestCount: UInt
}

@Composable
fun rememberLocationPermissionsState(): LocationPermissionsState {
    val requestCountState: MutableState<UInt> = remember { mutableStateOf(0u) }

    val multiplePermissionsState: MultiplePermissionsState =
        rememberMultiplePermissionsState(locationPermissions) {
            if (it.isEmpty()) {
                // BUG in accompanist-permissions library upon configuration change
                return@rememberMultiplePermissionsState
            }

            requestCountState.value++
        }

    return object : LocationPermissionsState, MultiplePermissionsState by multiplePermissionsState {
        override val requestCount: UInt by requestCountState
    }
}

You can see this solution with a little more context at https://github.com/google/accompanist/issues/819

Uli
  • 2,828
  • 20
  • 23