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.
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:
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:
- track that you have requested the permission before
- check the result in
onRequestPermissionsResult - if permission is denied and
shouldShowRequestPermissionRationale(...)isfalse, infer that future prompts are blocked
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.
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
falseafter 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
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 == falseis the key signal that future prompts are blocked. - At that point, guide the user to system settings instead of re-requesting blindly.
Related reading
- Android M Permissions Confused on the usage of shouldShowRequestPermissionRationale function
- Android M Permissions onRequestPermissionsResult() not being called
- Android M Permissions onRequestPermissionsResult not being called
- Android map v2 zoom to show all the markers
- android maps asynchronous loading of overlay items
- Android Mapview Merging overlapping markers into a new marker
- Android marshmallow request permission?
- Android Material and appcompat Manifest merger failed
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseNo 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 courseData 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.