Back to blog
FILE 0x02·THREE PERMISSION DIALOGS FOR A WORKING SAFETY APP ON ANDROID

Three permission dialogs for a working safety app on Android

May 22, 2026 · android, permissions, side-project

A safety app I shipped for personal use on Android needs three distinct runtime permissions to actually do its job. Walking a first-time user through them in the right order, with the right fallback if they say no, took more thought than any other part of the build.

What was happening

The three permissions:

  1. Notifications (POST_NOTIFICATIONS, Android 13+). Needed for any push at all — Expo push tokens require this on modern Android.
  2. Foreground location (ACCESS_FINE_LOCATION). The user has to grant this before background location is even askable.
  3. Background location (ACCESS_BACKGROUND_LOCATION). Required for the foreground service to keep tracking when the app isn't open. This is the one Android shows the scary "always allow" dialog for.

If you ask in the wrong order or all at once, Android either collapses them into one permission shelf the user doesn't understand, or pops the background dialog first and confuses the user.

What I found

The sequence that actually works for first-time users:

launch
  → check existing tokens (skip if signed in)
  → notification permission dialog (Allow)
       → Expo push token registers
  → foreground location dialog (Allow)
  → background location dialog ("Allow all the time")
       → foreground service starts
       → location ping posts every 60s, every 50m of movement

Each step has an explanation screen before the system dialog that says, in plain language, what the next dialog is for and what happens if they say no. Skipping the explanations means users panic at "always allow location."

Each permission also has a kill-switch in Settings — the user can turn the whole thing off without uninstalling the app, and each individual permission has an obvious "revoke" path that makes the app behave gracefully (no crashes, just degraded features).

The fix

The non-obvious thing is the order. Notifications first because they're the cheapest "yes" — most users say yes because they understand notifications. Foreground location second, with an explanation that "we need to know where you are when the app is open so we can detect arrival/departure." Background location last, with the most explanation, because "always allow" is genuinely a big ask.

Failure paths:

Each path is explicit in the code with a PermissionState enum, not implicit through "did this API call succeed?" The state drives a banner in the UI ("Background location is off — some features are disabled") so the user knows what they're missing without having to debug it themselves.

What I'd do differently

Start with the kill-switches. Build the "user revokes permission X" path before you build the "user grants permission X" path. The granted path is the happy case and will work whether you wrote it carefully or not. The revoked path is where users actually end up, and it's where bad apps crash or behave mysteriously.

Also: Android's permission UX changes every couple of releases. Background location was almost-but-not-quite available for a while. POST_NOTIFICATIONS was opt-in for older targets and mandatory for newer. Pinning your targetSdkVersion so you know which dialog set you'll see is worth the maintenance cost.