shouldShowRequestPermissionRationale not working as expected

camera permission android
read external storage permission android
android request permission
onrequestpermissionsresult
how to ask permission (runtime) again if the user deny for the first time
multiple runtime permissions android example
android location permission
android permissions best practices

I'm working on checking and getting permission from user with API level 23 and above. So here is a confusing thing for me, android.com says:

shouldShowRequestPermissionRationale() method returns true if the app has requested this permission previously and the user denied the request. If the user turned down the permission request in the past and chose the Don't ask again option in the permission request system dialog, this method returns false

in other side it gives following code for checking permission and request permission if its neccessery

// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
            Manifest.permission.READ_CONTACTS)
    != PackageManager.PERMISSION_GRANTED) {

// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
        Manifest.permission.READ_CONTACTS)) {

    // Show an explanation to the user *asynchronously* -- don't block
    // this thread waiting for the user's response! After the user
    // sees the explanation, try again to request the permission.

} else {

    // No explanation needed, we can request the permission.

    ActivityCompat.requestPermissions(thisActivity,
            new String[]{Manifest.permission.READ_CONTACTS},
            MY_PERMISSIONS_REQUEST_READ_CONTACTS);

    // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
    // app-defined int constant. The callback method gets the
    // result of the request.
    }
}

else scope in above example runs if user doesn't allow permission and check Don't Ask Again, Right? So with this code user never being asked for permission at first time run. I tested that code and the result is what I expected. So How could I request permission for first time run and do something if user previously denied my request and do something if user deny my request and check Don't Ask Again?

You can do the following.

  1. Ask permission every time by only checking that permission is not granted already. Don't handle the "Don't ask again" in this method. (if user checks "Don't ask again" the OS will automatically handle and will not ask for permission again and will give a call back of permission denied)
  2. Handle the ActivityCompat.shouldShowRequestPermissionRationale() in the call back method onRequestPermissionsResult().

Here is my code in which I am asking for permission everytime

public void checkAndAskCameraPermission() {
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(context,
                    new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_ID);
        }
    }

This is how I handles the call back

@Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case CAMERA_PERMISSION_REQUEST_ID: {
                if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {

                  // Do something if permission is not granted and the user has also checked the **"Don't ask again"**
                } else if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {
                    // Do something if permission not granted
                }
            }
        }
    }

Your browser does not currently recognize any of the video formats available. call shouldShowRequestPermissionRationale() to check whether and your app shouldn't rely on permissions being within or outside of a specific permission group. permission for a specific feature to behave as expected. Some of the coronavirus test kits shipped to labs across the country are not working as they should, the US Centers for Disease Control and Prevention said.

first check if the permission is granted then do what you need else if permission is denied then check weather you should request the permission you need or not through shouldShowRequestPermissionRationale. if shouldShowRequestPermissionRationale return false then you can just show a message to the user to told them to enable the permission manually. other then if shouldShowRequestPermissionRationale return true then request the permission and get the result of granting permission in onRequestPermissionsResult

update , this is just a simple code to show the steps:

if (checkSelfPermission == granted){
 // do what you want 
 } else if (shouldShowRequestPermissionRationale == true) {
        // you can request the permission you want from the user, then check whether permission granted or not inside onRequestPermissionsResult method
 } else { 
        // here you know the permission is not granted , and also the user check on "Dont ask Again!" checkbox, so all you can to do is just tell the user to enable the permission manually from app permissions through Toast message or any thing else
        }

If the app is running on an older platform version that does not public static boolean shouldShowRequestPermissionRationale For example, if you write a camera app, requesting the camera permission would be expected  CheckSelfPermission method is not working as expected and it is always returning zero in android 6.0(Marshmallow). Because the target sdk is 22 and i am using http Client for network connection. Following is the code snippet.

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

      //initilize your views


    if(iscontactsAllowed){

    // do your code here

    } else {

     requestcontactsPermission();

    }

}
private void requestcontactsPermission() {

        if (ActivityCompat.shouldShowRequestPermissionRationale(this, android.Manifest.permission.READ_CONTACTS)) {
            //If the user has denied the permission previously your code will come to this block
            //Here you can explain why you need this permission
            //Explain here why you need this permission
            Log.d("scancode", "denied permission before");
        }

        Log.d("perm", "fourth");
        //And finally ask for the permission
        ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.READ_CONTACTS}, READ_CONTACTS_CODE /*can be any interge */);

    }

private boolean iscontactsAllowed() {
            //Getting the permission status
            int result = ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_CONTACTS);

            //If permission is granted returning true
            if (result == PackageManager.PERMISSION_GRANTED)

                return true;

            //If permission is not granted returning false
            return false;
        }


@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        //Checking the request code of our request

        if(requestCode == READ_CONTACTS_CODE){

if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

// you have the permission call yur method here

} else {

// permission denied show user why you need it or ask again by calling reuestpermission if you need the permission
}

}

Permission handling should be simple, but not the case in Android. This article aims to solve that problem. The key part here is the usage of shouldShowRequestPermissionRationale . It's not our expect permission For example, if you write a camera app, requesting the camera permission would be expected by the user and no rationale for why it is requested is needed. If however, the app needs location for tagging photos then a non-tech savvy user may wonder how location is related to taking photos.

@ArtinArtin I have expanded on @salmanyahya updated simple code and provided my logic with Alert Dialog's and one Snackbar (not a big fan of Snackbar's) any way see if this helps

       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            //.... write file into storage ...
            System.out.println("SDK > BuildVersion TRUE");
        } else {
            requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 666);  // Comment 26
            System.out.println("go to requestPermissions");
        }
    }
    onLoad();
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {

        case 666: // Allowed was selected so Permission granted
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                Snackbar s = Snackbar.make(findViewById(android.R.id.content),"Permission Granted",Snackbar.LENGTH_LONG);
                View snackbarView = s.getView();
                TextView textView = (TextView) snackbarView.findViewById(android.support.design.R.id.snackbar_text);
                textView.setTextColor(Color.RED);
                textView.setTextSize(18);
                textView.setMaxLines(6);
                s.show();

                // do your work here

            } else if (Build.VERSION.SDK_INT >= 23 && !shouldShowRequestPermissionRationale(permissions[0])) {
                // User selected the Never Ask Again Option Change settings in app settings manually
                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
                alertDialogBuilder.setTitle("Change Permissions in Settings");
                alertDialogBuilder
                        .setMessage("" +
                                "\nClick SETTINGS to Manually Set\n"+"Permissions to use Database Storage")
                        .setCancelable(false)
                        .setPositiveButton("SETTINGS", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                                Uri uri = Uri.fromParts("package", getPackageName(), null);
                                intent.setData(uri);
                                startActivityForResult(intent, 1000);     // Comment 3.
                            }
                        });

                AlertDialog alertDialog = alertDialogBuilder.create();
                alertDialog.show();

            } else {
                    // User selected Deny Dialog to EXIT App ==> OR <== RETRY to have a second chance to Allow Permissions
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {

                    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
                    alertDialogBuilder.setTitle("Second Chance");
                    alertDialogBuilder
                            .setMessage("Click RETRY to Set Permissions to Allow\n\n"+"Click EXIT to the Close App")
                            .setCancelable(false)
                            .setPositiveButton("RETRY", new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    //ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, Integer.parseInt(WRITE_EXTERNAL_STORAGE));
                                    Intent i = new Intent(MainActivity.this,MainActivity.class);
                                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                                    startActivity(i);
                                    }
                            })
                            .setNegativeButton("EXIT", new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int id) {
                                    finish();
                                    dialog.cancel();
                                }
                            });
                    AlertDialog alertDialog = alertDialogBuilder.create();
                    alertDialog.show();
                }
            }
            break;
    }};

Expected behavior. shouldShowRequestPermissionRationale to return true if permissions have not been accepted on Android. Or am I  In some cases you’ll notice that AutoArchive or Archive is not working as expected even when all settings appear to be correct. Use the steps below to troubleshoot and get AutoArchive and Archive working again. Changing AutoArchive or Archive settings. Archive command not available. Excluded from AutoArchive.

This code helps to handles the run time permission Management in Android

public String storagePermissions = Manifest.permission.READ_EXTERNAL_STORAGE;   
private static final int REQUEST_ACCESS =101;  

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
      if(checkSelfPermission(storagePermissions)== PackageManager.PERMISSION_GRANTED){
          result();    // result  is your block of code 
      }else {
          requestPermissions(new String[]{storagePermissions},REQUEST_ACCESS);
      }

    }
    else{
        result();    //so if user is lower than api verison M, no permission is requested
    } 

}

 private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
    new AlertDialog.Builder(MainActivity.this)
            .setMessage(message)
            .setTitle("Hi User..")
            .setPositiveButton("Ok", okListener)
            .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {        //idea calling showMessage funtion again
                    Snackbar mySnackbar = Snackbar.make( findViewById(R.id.coordinatorlayout),"You Press Cancel.. ", Snackbar.LENGTH_INDEFINITE);
                    mySnackbar.setAction("Exit", new cancelButton());
                    mySnackbar.show();

                }
            })
            .create()
            .show();
}


private void result(){
          //your code
}

    @RequiresApi(api = Build.VERSION_CODES.M)
public class NeverAskAgain implements View.OnClickListener{
    @Override
    public void onClick(View view)
    {
        goToSettings();
    }
}
@RequiresApi(api = Build.VERSION_CODES.M)
private void goToSettings() {
    Intent myAppSettings = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + getPackageName()));
    finish();
    myAppSettings.addCategory(Intent.CATEGORY_DEFAULT);
    myAppSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivityForResult(myAppSettings, REQUEST_APP_SETTINGS);
}
public class cancelButton implements View.OnClickListener{
    @Override
    public void onClick(View view){
        Toast.makeText(MainActivity.this,"To use this app , you must grant storage permission",Toast.LENGTH_SHORT);
        finish();
    }
    }


 @Override
@RequiresApi(api = Build.VERSION_CODES.M)
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode,permissions,grantResults);

    switch(requestCode) {
        case REQUEST_ACCESS:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission is granted
                    result();
                    break;
                }
                else if (!shouldShowRequestPermissionRationale(permissions[0])){
                    showMessageOKCancel("You choose Never Ask Again,option",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        Snackbar mySnackbar = Snackbar.make(findViewById(R.id.coordinatorlayout), "Permission=>Storage=>On", Snackbar.LENGTH_INDEFINITE);
                        mySnackbar.setAction("Settings", new NeverAskAgain());
                        mySnackbar.show();
                    }
                     });
                    break;
                }
                else {
                    showMessageOKCancel("You Denid permission Request..",
                    new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            requestPermissions(new String[]{storagePermissions}, REQUEST_ACCESS);
                        }
                    });
                    break;
                }
        }
}

shouldShowRequestPermissionRationale(p)) { when permission is granted,​should not show rationale dialog!! also should use ActivityComp GitHub is home to over 50 million developers working together to host and  Returns whether the the exit transition and enter transition overlap or not. boolean: getAllowReturnTransitionOverlap() Returns whether the the return transition and reenter transition overlap or not. final Bundle: getArguments() Return the arguments supplied when the fragment was instantiated, if any.

that your app behaves as expected when a user enables or disables a specific permission. The following best practices will help you avoid potential issues. you should call shouldShowRequestPermissionRationale . Based on Gallup's work with companies worldwide, only about half of employees strongly agree that they know what is expected of them at work. Helping employees to set and achieve goals is a manager's key responsibility, but Gallup analysis in Germany shows that many managers don't really own this task.

CheckSelfPermission method is not working as expected and it is always Option if (!shouldShowRequestPermissionRationale(permission)) return false; }  Describes an issue in which a mailbox can't map automatically in Office 365 hybrid environment. Provides a resolution. Auto-mapping doesn’t work as expected in an Office 365 hybrid environment

Even when running on lower versions, you get the expected behavior from the is not running Android Marshmallow, shouldShowRequestPermissionRationale  Unexpected definition is - not expected : unforeseen. How to use unexpected in a sentence.

Comments
  • "So with this code user never being asked for permission at first time run" shouldShowRequestPermissionRationale is supposed to return false if your app hasn't asked the user for the permission yet, so the else clause would be executed on the first run.
  • Possible duplicate of Android M Permissions : Confused on the usage of shouldShowRequestPermissionRationale() function
  • @Michael but android.com thinks differently : If the user turned down the permission request in the past and chose the Don't ask again option in the permission request system dialog, this method returns false.
  • @BhuvaneshBs I have read this, Mine is not duplicate
  • @ArtinArtin: Note the part where it says "returns true if the app has requested this permission previously and the user denied the request"
  • First I will check if permission is not granted, so in that scope I would check if I shouldShowRequestPermissionRationale so I tell user you denied my request for first time but again I ask you for it. in else I would tell user I can't offer you to allow my request because you checked the Dont ask Again! So How could I make my app ready for all situations?!
  • you are right, but in first app run time and in other hand when user checked Dont ask Again the else section will execute! Are you agree with that? else section will execute in two situation! If I tell user that should enable permission in settings in else section, it will appear at very first time run,too!
  • @ArtinArtin first, sorry about mistake in second condition, and about when user checked Dont ask Again the else section will execute? no, it will be executed only if user just deny the permission without checked Dont ask Again!, but if user checked the checkbox and also press on deny, then the last else statement will be executed.
  • else { // here you know the permission is not granted , and also the user check on "Dont ask Again!" checkbox, so all you can to do is just tell the user to enable the permission manually from app permissions through Toast message or any thing else } will execute in both first time run and when I check Dont Ask Again and deny the request!
  • no, it will not, last else will executed only when user check Don't Ask Again and also deny the request, because when you install the app, the system ask you to accept all permission that needed for the app before continue installing, so when you accept that and run your app for the first time, checkSelfPermission will be granted and execute code inside that condition, because as i said before you already have granted all permissions needed for the app before continue installing.