When it comes to the M Developer Preview runtime permissions, according to Google:
If you have never asked for a certain permission before, just ask for it<
SO FINALLY MY TIME HAS COME TO ANSWER A QUESTION FROM COMMONSWARE
Business flow:-
1. When user clicks on "deny permission" for the first time, I will show rationale dialog to explain the necessity of the permission. Then if the user clicks on "cancel" button on the rationale dialog, I will show a toast showing message "Please give permission to get location".
2. After that when user clicks on deny permission(dont ask again) on the permissions dialog, I will show a message "Please give location permission from app settings". Notice that I have added the words "from app settings" because the user has checked the box of "dont ask again".
3. So from now on the permission dialog will not be shown.Also the rationale dialog will not be shown.
So the key here is that if both permission dialog and rationale dialog is not shown, then it means that user has checked the "dont ask again" checkbox.
The code:-
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.ACCESS_FINE_LOCATION)){
AlertDialogHelper.showDialogWithYesNoCallback(mContext, getString(R.string.confirm), getString(R.string.please_give_permission_to_get_location), new onItemClickReturnBoolean() {
@Override
public void onItemClick(Boolean status) {
if(status){
ActivityCompat.requestPermissions(SplashScreenActivity.this,permissions,AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE);
}
else{
ShowToast.showShortToast(SplashScreenActivity.this,getString(R.string.please_give_permission_to_get_location));
finish();
}
}
});
}
else{
ActivityCompat.requestPermissions(this,permissions,AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE);
}
}
else{
gettingLocationAfterPermissionGranted();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == AppConfig.FINE_LOCATION_PERMISSION_REQUEST_CODE){
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
gettingLocationAfterPermissionGranted();
}
else{
if(ActivityCompat.shouldShowRequestPermissionRationale(SplashScreenActivity.this,Manifest.permission.ACCESS_FINE_LOCATION)){
ShowToast.showShortToast(this,getString(R.string.please_give_permission_to_get_location));
}
else{
ShowToast.showShortToast(this,getString(R.string.please_give_location_permission_from_app_settings));
}
finish();
}
}
}
Check this repository: https://github.com/debChowdhury/PermissionHelperEasy
Easy peasy
After trying all the answer here and some other post over internet. I came to know that I have to use a sharedPreference isLocationPermissionDialogShown
(default false) and every thing works as per expected.
shouldShowRequestPermissionRationale
returns false
and isLocationPermissionDialogShown
also false
shouldShowRequestPermissionRationale
return true
and while showing dialog we set isLocationPermissionDialogShown
to true
. and when we check condition both will be true
shouldShowRequestPermissionRationale
return true
and isLocationPermissionDialogShown
returns true
shouldShowRequestPermissionRationale
return false
and isLocationPermissionDialogShown
returns true
. Which is what we need.Please check working example.
public class MainActivity extends AppCompatActivity {
SharedPreferences sharedPreferences;
String locationPermission;
String prefLocationPermissionKey = "isLocationPermissionDialogShown";
private final int PERMISSION_REQUEST_CODE_LOCATION = 1001;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
locationPermission = Manifest.permission.ACCESS_FINE_LOCATION;
sharedPreferences = getSharedPreferences("configuration", MODE_PRIVATE);
//check for android version
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//Check for permission
if (checkSelfPermission(locationPermission) != PackageManager.PERMISSION_GRANTED) {
//check if clarification dialog should be shown.
if (shouldShowRequestPermissionRationale(locationPermission)) {
showClarificationDialog(locationPermission, PERMISSION_REQUEST_CODE_LOCATION);
} else {
requestPermissions(new String[] { locationPermission}, PERMISSION_REQUEST_CODE_LOCATION);
}
} else {
Log.d("nets-debug", "permission already grranted");
}
}
}
@Override
@TargetApi(Build.VERSION_CODES.M)
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
//for location permission
if (requestCode == PERMISSION_REQUEST_CODE_LOCATION) {
boolean isLocationPermissionDialogShown = sharedPreferences.getBoolean(prefLocationPermissionKey, false);
if (!shouldShowRequestPermissionRationale(locationPermission) && isLocationPermissionDialogShown) {
// user selected Never Ask Again. do something
Log.d("nets-debug", "never ask again");
} else {
// all other conditions like first time asked, previously denied etc are captured here and can be extended if required.
Log.d("nets-debug", "all other cases");
}
}
}
}
@TargetApi(Build.VERSION_CODES.M)
public void showClarificationDialog(final String permission, final int requestCode) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Permission Required");
builder.setMessage("Please grant Location permission to use all features of this app");
builder.setPositiveButton("Grant", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(prefLocationPermissionKey, true);
editor.apply();
requestPermissions(new String[] {permission}, requestCode);
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(getApplicationContext(), "This permission required", Toast.LENGTH_LONG).show();
}
});
builder.create().show();
}
}
Hope this will help.
As per the current example: https://github.com/googlesamples/android-RuntimePermissions/blob/master/Application/src/main/java/com/example/android/system/runtimepermissions/MainActivity.java#L195
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
if (requestCode == REQUEST_CAMERA) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
doThing();
//STORE FALSE IN SHAREDPREFERENCES
} else {
//STORE TRUE IN SHAREDPREFERENCES
}
}
Store a boolean in SharedPreferences with key as your permission code and value as indicated above, to indicate whether that preference has been denied before.
Sadly, you probably can't check against a preference that has been accepted and later denied while your app is running. The final spec is not available, but there's a chance that your app either gets restarted or gets mock values until the next launch.
You can look here - there is a flowchart that explains the process quite good. It also explains when you should call shouldShowRequestPermissionRationale()
and when it returns true.
Basically according to Android's documentation, you should always ask for permission if you don't have it (Android will automatically return DENIED in the callback if the user said to never ask again) and you should display a short message if the user has already declined you once in the past but hasn't marked the never ask again option.