Android 11 permission "Ask every time" doesn't prompt the user to give camera permission again
See original GitHub issueDescribe the bug
On android 11 there is a possibility to set the camera permission to “Ask every time”. In case this permission is set plugins checkPermission method returns status denied set to true
, only if user sets the permission manually to “Allow only while using the app” in Settings -> Apps -> [app] it is possible to scan the codes again. The issue appears after the device goes to sleep mode.
To Reproduce Steps to reproduce the behavior:
- Call the
checkPermission
- On prompt select “Only this time”
- Code scanning works as expected
- Close the app and leave device until it goes to sleep mode or turn it off
- Open cell phone, open the app and call the
checkPermission
again (click on scann button) - Result object has property
denied
set totrue
Expected behavior If permission is set to “Ask every time” the app should prompt the window with question to set the permissions again.
Screenshots If applicable, add screenshots to help explain your problem.
Version v2.0.0
Smartphone (please complete the following information):
- Device: [Samsung A70]
- OS: [Android 11]
Additional context Add any other context about the problem here.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:6
- Comments:7
Top GitHub Comments
I am using the
checkPermissions
/requestPermissions
of the@capacitor/camera
module to check for permissions and then I use the barcode module to do the scanning.The cause of this is the (unfortunately apparently very common) misuse of the
shouldShowRequestPermissionRationale
method. It is used to detect the difference between “denied for now” and “denied forever”, which is not its function at all.Capacitor itself also makes this wrong assumption about the return value of this function: https://github.com/ionic-team/capacitor/blob/17a73ff60b3e0e1807db3a2349b83ca62d7fb83b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java#L899-L905 I don’t know if this issue is caused by that or not.
The guidelines regarding permissions in the readme also explicitly do it “the wrong way” compared to the official guidelines regarding “asking for permissions” on Android: https://developer.android.com/training/permissions/requesting#workflow_for_requesting_permissions
In my opinion the functionality (on Android) should be as follows:
checkPermission({ force: false })
to determine whether or not the permission is already granted. If yes, great. If not, keep going.CheckPermissionResult
gets a new propertyshowRationale
which is set to the result ofshouldShowRequestPermissionRationale
ifforce
is false.showRationale: true
fromcheckPermission({ force: false })
, it shows a rationale. If the user does not acknowledge the need, bail out here. If they do, keep going.checkPermission({ force: true })
. The Plugin unconditionally requests the permission if this happens.checkPermission({ force: true })
. Ifgranted
is false, we do not have the permission and need to gracefully degrate. Ifgranted
is true, great.In Pseudocode (App):
On iOS the story is simpler in the Plugin (see: https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/requesting_authorization_for_media_capture_on_ios section “Verify and Request Authorization for Capture”, this is already correct in the current implementation):
authorizationStatus(for:)
. If it returns granted, denied or restricted set the appropriate granted/denied/restricted property.authorizationStatus(for:)
returnednotDetermined
:force
is false, setshowRationale
to false and wait for the app to callcheckPermission
again withforce: true
force
is true, callrequestAccess
and wait for the completion handler.An Addendum: Doing this properly also simplifies things, mainly the need to keep track of “are we asking for the first time” on Android using SharedPreferences completely goes away as well as the code to open the settings app.