14

It's a easier way to grant permission by Scoped Directory Access,but Dialog will show a checkbox named "Don't ask again". If the user selects Don't ask again and denies the request, all future requests for the given directory from your app will be automatically denied, and no request UI will be presented to the user. if user regret or hit that checkbox by mistake,how can app remedy? app can't get permission dialog.

How can we handle this?

Ranjith Kumar
  • 258
  • 1
  • 4
  • 16
  • 2
    *how can app remedy* it can. What it can do, is that he can change his mind anytime and go to `app -> settings` and grant there the permissions. (Or at least that's what I would do) – Blackbelt Nov 17 '16 at 12:12
  • In my app without permission it will not open, So for first time i enter , Dialog appear . if user by mistake he checked "Don't ask again" .Then he enter next time, the dialog not showing. PERMISSION_GRANTED getting -1. is any way to change that flag ? – Ranjith Kumar Nov 17 '16 at 12:17
  • You accepted an answer that has nothing to do with [scoped directory access](https://developer.android.com/training/articles/scoped-directory-access.html). Are you *sure* that your problem pertains to Android 7.0's scoped directory access API? – CommonsWare Nov 18 '16 at 13:40
  • I am not asked how to access directory. I asked for how to show permission dialog, even after "Don't ask again" check box clicked. – Ranjith Kumar Nov 21 '16 at 03:58

7 Answers7

8

is any way to change that flag ?

A developer cannot change that flag. Otherwise, there would be no point in having the checkbox, as developers would just ignore it by changing the flag.

However, your question points out a fairly substantial flaw in the scoped directory access: the user has limited ability to change that flag. There does not appear to be a place in Settings to change this state specifically, the way the user can manually grant a rejected runtime permission.

On a Nexus 5X running the 7.1 preview, "Clear Data" will reset this flag, though that has broader effects. On a Google Pixel running 7.1, and on a Nexus 5X running Android 7.0, nothing will reset this flag, even a full uninstall of the app.

I have filed a bug report about this. I am skeptical that the situation will be improved much in the short term — at best, they might fix it so "Clear Data" works reliably.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Hey, almost a year later–has Google done anything to combat this? – Ruchir Baronia Jul 11 '17 at 22:32
  • 3
    @RuchirBaronia: No, as I was able to recreate the issue on the O Developer Previews. I filed [a fresh issue](https://issuetracker.google.com/issues/36522600), which is being freshly ignored. – CommonsWare Jul 11 '17 at 22:52
  • 1
    This is still an issue in Nexus 5X with Android 8.1 (for example). Uninstalling, Clearing data, restarting the phone, nothing works. The solution was to MANUALLY grant the permission, run the app, then MANUALLY disable the permission. Then the dialog shows again, still... in 2019. :) – Martin Marconcini Jul 04 '19 at 19:39
3

Open Up the App's Permission Settings.

You cannot show another permissions dialog if the User has checked off "Don't ask again."

However, you can help the user and open up the App's Settings where the User can manually enable the Permissions required.

To do that you'll need to launch an intent, similar to this:

public void openAppSettings() {

    Uri packageUri = Uri.fromParts( "package", getApplicationContext().getPackageName(), null );

    Intent applicationDetailsSettingsIntent = new Intent();

    applicationDetailsSettingsIntent.setAction( Settings.ACTION_APPLICATION_DETAILS_SETTINGS );
    applicationDetailsSettingsIntent.setData( packageUri );
    applicationDetailsSettingsIntent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );

    getApplicationContext().startActivity( applicationDetailsSettingsIntent );

}

Now, in order to know when the User has checked off the "Don't ask again" checkbox is another matter and can done with this StackOverflow answer.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
2

I think what you need to do is use the method shouldShowRequestPermissionRationale(String) it would return false if user has denied the permission and checked "Don't ask again".

What you should do is show an alert explaining the user why you need the permission or implement a fallback, like disable some feature.

Hope to be helpful.

1

We should use shouldShowRequestPermissionRationale.Please go through this:

private void insertDummyContactWrapper() {
        int hasWriteContactsPermission = checkSelfPermission(Manifest.permission.WRITE_CONTACTS);
        if (hasWriteContactsPermission != PackageManager.PERMISSION_GRANTED) {
                if (!shouldShowRequestPermissionRationale(Manifest.permission.WRITE_CONTACTS)) {
                    showMessageOKCancel("You need to allow access to Contacts",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                                            REQUEST_CODE_ASK_PERMISSIONS);
                                }
                            });
                    return;
                }
            requestPermissions(new String[] {Manifest.permission.WRITE_CONTACTS},
                    REQUEST_CODE_ASK_PERMISSIONS);
            return;
        }
        insertDummyContact();
    }
Lips_coder
  • 686
  • 1
  • 5
  • 17
  • Thanks. This shouldShowRequestPermissionRationale only used check a flag is set or not. So i used to show alert using this "Manually need to give permission from settings" – Ranjith Kumar Nov 18 '16 at 05:14
1
public class AccessDenied implements View.OnClickListener{

    public Dialog dialog;
    private LinearLayout contentLayout;
    private Activity context;
    private EditText password;
    private String passwordStr;
    private Runnable doOnAccessPermitted;
    private int wrongColor = Color.RED, defColor = Color.parseColor("#80000000");


    public AccessDenied(Activity con, String pwd) {
        passwordStr = pwd;
        context = con;
        dialog = new Dialog(context, R.style.AnimatedDialog);
        setCancelable(false);
        //init the dialog with content view/animations etc.
        dialog.setContentView(R.layout.access_denied_layout);
        contentLayout = dialog.findViewById(R.id.layoutIconDialogLinearLayout);
        password = dialog.findViewById(R.id.accessdeniedlayoutpassword);
        Button ok = dialog.findViewById(R.id.accessdeniedlayoutok);
        ok.setOnClickListener(this);
        //now the dialog is ready
    }

    public void setActionOnAccess(Runnable doOnAccess) {
        doOnAccessPermitted = doOnAccess;
    }

    public void setCancelable(boolean set) {
        dialog.setCancelable(set);
    }

    public void show() {
        dialog.show();
    }

    public void cancel() {
        dialog.cancel();
    }

    public void setPassword(String pwrd) {
        passwordStr = pwrd;
    }

    public void tryPassword(String tryp) {
        if(passwordStr.equals(tryp)){
            cancel();
            if(doOnAccessPermitted != null)
                doOnAccessPermitted.run();
        }
    }

    @Override
    public void onClick(View view) {
        if(passwordStr.equals(password.getText().toString())) {
            cancel();
            if(doOnAccessPermitted != null)
                doOnAccessPermitted.run();
        }else{
            password.getText().clear();
            Animation anim = AnimationUtils.loadAnimation(context, R.anim.edittext_shake);
            anim.setDuration(200);
            anim.setRepeatCount(5);
            decView().startAnimation(anim);
            decView().setBackgroundColor(wrongColor);
            new android.os.Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    decView().setBackgroundColor(defColor);
                }
            }, 1000);
        }
    }

    private View decView() {
        return password;
    }
}
Dmitriy
  • 5,525
  • 12
  • 25
  • 38
larsaars
  • 2,065
  • 3
  • 21
  • 32
1

I found a CLEAN AND WORKING SOLUTION for this ( but there is no code example here, - read and understand it why) making sure there is no scenario when taking action that normally ask for permission, doesn't do anything.

The flag shouldShowPermission() - alone, there is no difference between the first time the app ask for given permission and after "dont show again was clicked", it will return false in both cases. It will keep returning true each time until the permission has been set do Dont Ask Again. Meaning starting a second time we ask for permission to infinity or until user clicks on dont ask again.

So to differentiate first time a permission is asked for, and the time when its asked for, after the user has already set Dont Ask Again, you can use a custom flag.

It is a clean and simple workaround to that that will determine if the don't ask again option was set. ( tested and working in 2 productions apps)

The solution:

Add a flag called "rationaleDisplayed" (or whatever you want, that will be indication of permissionRationeDialog being shown to user) - with default value false, store it in prefs. After presenting to user the rationale dialog at least once, set this flag to be true.

Now you have two params, and combination of them when shouldShowRationaleDialog = false, and rationalePermissionDisplayed = true, effectively is the indication of "Dont show again" being set.

Why this works? It works because the shouldShowRationale, will return false when first time asking for permission and the rationaleDisplayedFlag are both false, so the popup will show up correctly. (2 falses) - this is the case of asking for a permission first time.

Then if you deny the first time, sshouldShowRationale will be true, and rationaleDisplayed will be true - (2 trues), this will be the case until the dont set again option is used. - this is the case of asking for permission second time, after the first one was declined.

Finnaly, if you set Dont Ask Again - or on Android api 30 and decline permission 2 times, the flag shouldShowRationale will return false next time it is called.

There you have a case of shouldShowRationale = false, and your own flag rationaleDisplayed = true, which tells you that the Don't Ask Again was set. (otherwise, the shouldShowRationale would still be false). - this is the case when the user declined the permission twice (api 30) or set the Dont Show Again option while denying.

Having that logic case, you can now add a custom permission dialog, with instructions on how to manually enable permissions, and open the app settings with ok button. ( intent to open settings in dialog positive listener).

The flag rationaleDisplayed is basically there to make sure first time app ask for permission it will be shown correctly, but its value allows for determination of the state when user set to dont ask again.

Works like a charm.

0

I created a method to capture all the user actions by use of concatenated if...else if...else and it worked well for me.
First, to determine if both permission was denied and the Don't ask again was also 'ticked', I combined the permission status check and a shouldShowRequestPermissionRationale(Manifest.permission.SEND_SMS).
Then to determine if only the permission was denied without 'ticking' the Don't ask again, I used permission status check. Below snippet:

@RequiresApi(api = Build.VERSION_CODES.M) //this is added for API lower than 23

public void myPermissionRationale(){
        //This checks both permission status and the Don't ask again check box
        if (ContextCompat.checkSelfPermission(this,Manifest.permission.SEND_SMS )
                == PackageManager.PERMISSION_DENIED && !shouldShowRequestPermissionRationale(Manifest.permission.SEND_SMS)) {
            //open app permission settings here for instance 

        }
           //only checks permission status then shows permission request pop up again
           else if (ContextCompat.checkSelfPermission(this,Manifest.permission.SEND_SMS )
                    == PackageManager.PERMISSION_DENIED){
                            // Request the permission
                            ActivityCompat.requestPermissions(this,
                                    new String[]{Manifest.permission.SEND_SMS},
                                    10);

                        }
        }