when I press switch first and second time request dialog show and press Do not allow the switch work normally. But third time when I press switch the request dialog not showing and I always get the value of isGranted as false
What should I do? I want to create UI switch to enable/disable POST_NOTIFICATION
Is there any way of code to deny permission after user granted permission?.
class MainActivity : ComponentActivity() {
var mIsChecked = false
val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
mIsChecked = isGranted
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
var isSwitchChecked by remember { mutableStateOf(mIsChecked) }
MyComposeApplicationTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Switch(
checked = isSwitchChecked,
onCheckedChange = {
if (it) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
} else {
isSwitchChecked = it
}
}
)
}
}
}
}
}
You can only request Android runtime permissions a very limited amount of times. If you see the system Dialog requesting the permission from the User once, or at most twice, the next time you call permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
, the OS will ignore that permission request, as you cannot spam such requests.
Moreover, the moment you grant a permission through a permission request, then any subsequent calls to permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
will simply return granted
as a result.
Instead, what you should do is that you should keep track of the current permission state, and only surface the permission request whenever you intend for the User to grant it.
I would make the switch's state be equivalent to whatever you get out of ContextCompat.checkSelfPermission()
, and only request permissions with the intention of them granting them, and not with the intention of denying them. Similarly, I don't recommend you attempt to create a flow to manually deny permissions, as this is not standard or recommended practice; Users can always go into your app's settings and turn off any unwanted permissions manually.
Lastly, I would also recommend you read through their documentation for a more in-depth explanation of how permissions work, and what the best practices are for permission request flows.
UPDATE:
As per your comment, there is a way for manually revoking runtime permissions that was added on Android 13 (SDK 33).
In your switch logic, you could add a call to Context.revokeSelfPermissionOnKill(String)
to revoke the permission that you want, but again, this will only work for devices running Android 13 or higher. Make sure you read through the documentation of how this function works carefully as well, because this process does not happen instantly, and instead will wait to revoke the given permission(s) until "it is safe to do so."
Switch(
checked = isSwitchChecked,
onCheckedChange = { checked ->
if (checked) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
LocalContext.current.revokeSelfPermissionOnKill(Manifest.permission.POST_NOTIFICATIONS)
}
isSwitchChecked = checked
}
}
)
However, I still don't think this is a good idea, and you should probably talk to whoever is asking you to do this because permissions are not meant to be revoked during runtime; the OS is simply not built like that, and this will inevitably have a bad code smell since it's basically going against the usual paradigm of permissions in Android development.