Android M
runtime permissions
Never ask again
app development
permission request

Android M - How to determine if the user checked Never ask again when denying my app's runtime permission request?

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms

Introduction

On Android runtime permissions, you do not get a direct callback saying “the user checked Never ask again.” Instead, you infer that state by combining the permission result with shouldShowRequestPermissionRationale(...) and, in many cases, tracking whether you have asked before. The important subtlety is that shouldShowRequestPermissionRationale(...) returns false both before the first request and after a denial with “Never ask again,” so it cannot be interpreted in isolation.

The key API behavior

When requesting a dangerous permission, the user can:

  • grant it
  • deny it
  • deny it and select “Never ask again”

After a denial, this helper becomes important:

java
ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)

Rough meaning:

  • 'true: the app should explain why it needs the permission before asking again'
  • 'false: either it is the first request, or the user has denied in a way that suppresses future prompts'

That is why people get confused. false does not uniquely mean “Never ask again.”

The usual detection pattern

The common approach is:

  1. track that you have requested the permission before
  2. check the result in onRequestPermissionsResult
  3. if permission is denied and shouldShowRequestPermissionRationale(...) is false, infer that future prompts are blocked
java
1if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_DENIED) {
2    boolean showRationale = ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA);
3
4    if (!showRationale) {
5        // likely “Never ask again” after at least one prior request
6    } else {
7        // normal denial without permanent suppression
8    }
9}

Why you should track prior requests

Before the app has ever asked for the permission, shouldShowRequestPermissionRationale(...) may also be false. So the real logic is often:

  • if denied
  • and you already asked before
  • and rationale is now false
  • then treat it as “Never ask again” or equivalent permanent denial behavior

A simple SharedPreferences flag can store that the permission was previously requested.

java
SharedPreferences prefs = getSharedPreferences("perm", MODE_PRIVATE);
prefs.edit().putBoolean("camera_asked", true).apply();

Then combine that flag with the permission result and rationale check.

A practical flow

Typical runtime flow:

  • if permission is granted, continue normally
  • if denied and rationale is true, explain and optionally ask again later
  • if denied and rationale is false after a prior request, direct the user to app settings instead of repeatedly requesting

At that point the system dialog usually will not appear again, so the app should stop behaving as if another requestPermissions(...) call will solve it.

Sending the user to app settings

java
1Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
2Uri uri = Uri.fromParts("package", getPackageName(), null);
3intent.setData(uri);
4startActivity(intent);

This is the normal fallback once the permission prompt is effectively blocked.

At that point the app should explain clearly why the permission is needed, because the system dialog itself is no longer the place where that explanation will appear.

Modern Android nuance

The exact UI wording and some permission flows vary across Android versions, and newer Android releases introduced additional permission-specific behaviors. But the core Marshmallow-style rationale pattern is still the important base logic for classic dangerous permissions.

Common Pitfalls

A common mistake is treating shouldShowRequestPermissionRationale(...) == false as definitive proof of “Never ask again.” It can also mean the permission has never been requested yet.

Another mistake is repeatedly calling requestPermissions(...) after the dialog has effectively been suppressed.

A third mistake is not offering a clear settings redirect path once the permission is permanently blocked.

Summary

  • Android does not provide a single direct “Never ask again” flag.
  • Use the denial result together with shouldShowRequestPermissionRationale(...).
  • Track whether the app has requested the permission before.
  • After a prior denial, rationale == false is the key signal that future prompts are blocked.
  • At that point, guide the user to system settings instead of re-requesting blindly.

Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Basis Lab
No course covers this one yet

Basis Lab writes one for you from a sentence about what you want to be able to do, then teaches it and checks you understood. Your first course is free.

Build my course
Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms