question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Android 11 permission "Ask every time" doesn't prompt the user to give camera permission again

See original GitHub issue

Describe 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:

  1. Call the checkPermission
  2. On prompt select “Only this time”
  3. Code scanning works as expected
  4. Close the app and leave device until it goes to sleep mode or turn it off
  5. Open cell phone, open the app and call the checkPermission again (click on scann button)
  6. Result object has property denied set to true

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:open
  • Created 2 years ago
  • Reactions:6
  • Comments:7

github_iconTop GitHub Comments

7reactions
jorritcommented, Dec 30, 2021

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.

4reactions
diesieben07commented, Aug 24, 2021

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:

  • App invokes Plugin method checkPermission({ force: false }) to determine whether or not the permission is already granted. If yes, great. If not, keep going.
  • CheckPermissionResult gets a new property showRationale which is set to the result of shouldShowRequestPermissionRationale if force is false.
  • If the App receives showRationale: true from checkPermission({ force: false }), it shows a rationale. If the user does not acknowledge the need, bail out here. If they do, keep going.
  • App invokes Plugin method checkPermission({ force: true }). The Plugin unconditionally requests the permission if this happens.
  • App receives result of checkPermission({ force: true }). If granted is false, we do not have the permission and need to gracefully degrate. If granted is true, great.

In Pseudocode (App):

async function hasPermission(): boolean {
    const passiveResult = await BarcodeScanner.checkPermission({force: false});
    // we already have the permission, great
    if (passiveResult.granted) return true;
    // we will never have the permission, even if we ask using force
    if (passiveResult.denied || passiveResult.restricted) return false;

    // if we don't need to show a rationale _or_ the user acknowledges our rationale, request the permission
    if (!passiveResult.showRationale || await showPermissionRationale()) {
        return (await BarcodeScanner.checkPermission({force: true})).granted;
    } else {
        // user denied our rationale
        return false;
    }
}

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):

  • First check authorizationStatus(for:). If it returns granted, denied or restricted set the appropriate granted/denied/restricted property.
  • If authorizationStatus(for:) returned notDetermined:
    • If force is false, set showRationale to false and wait for the app to call checkPermission again with force: true
    • If force is true, call requestAccess 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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Permissions updates in Android 11 - Android Developers
One-time permissions. Starting in Android 11, whenever your app requests a permission related to location, microphone, or camera, the user-facing permissions ...
Read more >
Change app permissions on your Android phone - Google Help
For location, camera and microphone permissions, you may be able to choose: All the time (location only): The app can use the permission...
Read more >
Android 11 One Time Permission - Medium
In Android 11 (API level 30) whenever your app requests permission related to location, microphone, or camera, permissions dialog will show ...
Read more >
How to ask again for permission if it was denied in android
Ok, turns out android 11 only asks for permission twice, as opposed to previous versions that ask over and over again (this is...
Read more >
How to Request Permissions in Android Application?
Else to use the feature, the app requests permission again. ... So to use the service, the app needs to check for permissions...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found