I am facing a strange issue with onRequestPermissionsResult in the fragment. Basically fragment asks for camera permission inside of onCreate:
override fun onCreate(savedInstanceState: Bundle?) {
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
super.onCreate(savedInstanceState)
if(!permissionsGranted){
requestPermissions(arrayOf(Manifest.permission.CAMERA),
PermissionsDelegateUtil.REQUEST_PERMISSIONS_CAMERA
)
}
}
Then I handle permissions in the onRequestPermissionsResult:
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
val resultResponse = permissionsDelegateUtil.resultGranted(requestCode=requestCode, permissions = permissions, grantResults = grantResults)
when(resultResponse){
PermissionResult.PermissionGranted -> {
setupCameraX()
}
PermissionResult.PermissionNotGrantedRetryAuto -> {
//retrying again
requestPermissions(arrayOf(Manifest.permission.CAMERA),
PermissionsDelegateUtil.REQUEST_PERMISSIONS_CAMERA
)
}
PermissionResult.PermissionNotGrantedCantRetry -> {
//show a screen that user must enabled permission
}
PermissionResult.PermissionNotGrantedDontAsk -> {
//Don't do anything, because you can't retry here, otherwise it will cause infinite loop.
}
}
}
Then permission delegate class handles permission logic:
fun resultGranted(requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray): PermissionResult {
if (requestCode != REQUEST_PERMISSIONS_CAMERA) {
return PermissionResult.PermissionNotGrantedDontAsk
}
if (grantResults.isEmpty()) {
return PermissionResult.PermissionNotGrantedDontAsk
}
if(permissions[0] != Manifest.permission.CAMERA){
return PermissionResult.PermissionNotGrantedDontAsk
}
return if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
PermissionResult.PermissionGranted
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (fragment.shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
PermissionResult.PermissionNotGrantedRetryAuto
} else{
///User selected don't show again checkbox.
PermissionResult.PermissionNotGrantedCantRetry
}
} else{
PermissionResult.PermissionNotGrantedRetryAuto
}
}
}
This code works perfectly fine until I force process death (I select don't keep activities checkbox in developer tools). After that, I return from background and the permission dialog is still present (because onCreate is triggered again and permission check is executed again).
The problem is that, after I press any button in the permission dialog, the onRequestPermissionsResult method is not being triggered in the fragment. I looked at logcat and found that permission result should be delivered, because of these logs:
2020-12-17 18:48:17.816 22496-22496/? V/GrantPermissionsActivity: Logged buttons presented and clicked permissionGroupName=android.permission-group.CAMERA uid=10135 package=com.test.app presentedButtons=25 clickedButton=8
2020-12-17 18:48:17.821 22496-22496/? V/GrantPermissionsActivity: Permission grant result requestId=-2584100455717644829 callingUid=10135 callingPackage=com.test.app permission=android.permission.CAMERA isImplicit=false result=6
I also tried to retry calling permissions after PermissionResult.PermissionNotGrantedDontAsk is returned. It would work, but it causes an infinite loop of permission requests and response triggering and as a result, it crashes the app.
EDIT
I add a fragment without using backstack:
fun addCameraSessionFragment(supportFragmentManager: FragmentManager) {
val fragment = supportFragmentManager.findFragmentByTag(CAMERA_SESSION_FRAGMENT_TAG)
if (fragment == null) {
val cameraSessionFragment =
CameraSessionFragment()
val fragmentTransaction = supportFragmentManager.beginTransaction()
fragmentTransaction.replace(getTranscationRootId(), cameraSessionFragment, CAMERA_SESSION_FRAGMENT_TAG).commitNow()
}
}
The thing is that this addition logic is triggered by ViewModel as LiveData Event. After process death occurs, addition actually occurs two times. The first is because it is the last fragment and it is restored after process death. The second is triggered by ViewModel action.
EDIT
I created a new project and could reproduce this issue again even without using fragments, just activity. Here is the repository: https://github.com/wellbranding/AndroidPermissionIssue Try to force process death, while permission dialog is open. After returning to the application, the dialog is present, but if you press any button then onRequestPermissionsResult still will not be triggered, but it should.