Search code examples
androidpermissions

I cannot get the permission window to appear using "requestPermissionLauncher.launch(permissions)"


I'm trying to request the permissions that my app needs but I can't get the permission window to appear. Here is my composable :

@Composable
fun IntroScreen(
    introViewModel: IntroViewModel = hiltViewModel(),
    navController: NavController
){

    val requestPermissionLauncher = rememberLauncherForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissionsMap ->
        permissionsMap.forEach { (permission, isGranted) ->
            Log.i("tag", "Permission: $permission, Granted: $isGranted")
        }
    }

    val permissions = introViewModel.permissions
    val permissionsState by introViewModel.permissionsState.collectAsState()

    Column(
        modifier = Modifier
            .fillMaxWidth(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally

    ){
        Button(onClick = {
            Log.i("tag", "Permissions state: ${permissionsState.joinToString(separator = ", ")}")
            val allPermissionsGranted = permissionsState.all { it }
            Log.i("tag", "All permissions granted: $allPermissionsGranted")

            if (!allPermissionsGranted) {
                // Request permissions
                Log.i("tag", "Requesting permissions inside if statement: ${permissions.joinToString(", ")}")
                requestPermissionLauncher.launch(permissions)
            } else {
                Log.i("tag", "All permissions already granted")
            }
       }, shape = Shapes.small) {
            Text(text = "Ask Permissions")

    }
}

Here is my view model:

@HiltViewModel
class IntroViewModel @Inject constructor(private val context: Context, introInteractor:IntroInteractor):ViewModel(){

    private val _permissionsState = MutableStateFlow(emptyList<Boolean>())
    val permissionsState: StateFlow<List<Boolean>> get() = _permissionsState

    val permissions = arrayOf(
        Manifest.permission.ACCESS_COARSE_LOCATION,
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.ACCESS_BACKGROUND_LOCATION,
        Manifest.permission.BLUETOOTH,
        Manifest.permission.BLUETOOTH_ADMIN,
        Manifest.permission.BLUETOOTH_SCAN,
        Manifest.permission.BLUETOOTH_ADVERTISE,
        Manifest.permission.POST_NOTIFICATIONS,
        Manifest.permission.CAMERA,
        Manifest.permission.INTERNET
    )

    init {
        updatePermissionsState()
    }

    fun updatePermissionsState() {
        val permissionsStateList = permissions.map { permission ->
            ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
        }
        _permissionsState.value = permissionsStateList
    }
}

I made the code as simple as I could. And all the logged statement returns the expected results. The Internet, bluetooth and bluetooth permissions are true and the rest are false. I tried removing the ones that are true, but I didn't get the window to appear. My code reaches the "requestPermissionLauncher.launch(permissions)" and the parameters for the launch() are correct. Why can't I get the window to appear?

This is the log result inside my if statement before my launcher: "Requesting permissions inside if statement: android.permission.ACCESS_COARSE_LOCATION, android.permission.ACCESS_FINE_LOCATION, android.permission.ACCESS_BACKGROUND_LOCATION, android.permission.BLUETOOTH, android.permission.BLUETOOTH_ADMIN, android.permission.BLUETOOTH_SCAN, android.permission.BLUETOOTH_ADVERTISE, android.permission.POST_NOTIFICATIONS, android.permission.CAMERA, android.permission.INTERNET ".

N.B.: I'm testing on a real Galaxy A14 and my manifest file is :

<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />


<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false"/>

Solution

  • After spending few hours got the root cost of the issue , that is ACCESS_BACKGROUND_LOCATION permission.

    From here

    ACCESS_BACKGROUND_LOCATION permission shouldn't be requested before the general location permission was granted (ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION). Otherwise, the system will just ignore the request.

    so create separate ACCESS_BACKGROUND_LOCATION permission launcher and run after success of (ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION)

    More details Background location access checklist