Permission Dialogs Testing Checklist (2026)
Permission Dialogs Testing Checklist (2026) provides a structured way to verify that every permission request behaves correctly across devices, OS versions, and user contexts. Modern apps request acce
Permission Dialogs Testing Checklist (2026) provides a structured way to verify that every permission request behaves correctly across devices, OS versions, and user contexts. Modern apps request access to sensors, storage, location, camera, microphone, contacts, and more, and each request can appear as a system dialog or an in‑app rationale. Missing a single edge case can lead to crashes, privacy leaks, or poor store ratings, so a repeatable checklist is essential for both manual QA and automated pipelines. The following guide groups 30+ concrete items into logical areas, supplies pass/fail criteria, shows real‑world examples, and explains how an autonomous explorer can cover most of the list in a single pass.
1. Fundamentals of Permission Dialogs
1.1 Permission Types and Sources
Permissions fall into three categories: normal (granted at install), dangerous (runtime request), and special (system‑alert‑window, usage‑access, etc.). Normal permissions need no dialog; dangerous ones trigger the OS‑provided prompt; special permissions often require a settings‑screen route. Knowing which category a permission belongs to determines the expected UI and the test approach.
1.2 OS‑Specific Dialog Variants
Android 13+ introduces the “one‑time” option and a revised layout for runtime permissions. iOS 17 adds a provisional authorization state for location and a redesigned modal for camera/microphone. Testing must cover each OS version where the app is supported, because wording, button order, and accessibility traits differ.
1.3 Dialog Lifecycle Events
When a permission dialog appears, the underlying activity is paused, the system shows the overlay, and upon user action the activity resumes with a callback (onRequestPermissionsResult on Android, delegate methods on iOS). Tests must verify that the app correctly handles the pause/resume transition, preserves UI state, and acts on the result regardless of whether the dialog was shown or skipped due to a prior deny‑with‑“Don’t ask again”.
2. Permission Dialogs Testing Checklist (2026) – Happy Path
2.1 Standard Grant Flow
Action: Trigger the permission request (e.g., tap a button that needs camera).
Expected: System dialog appears with title, explanation, and two primary buttons: Allow and Deny.
Pass Criteria: Dialog is visible, focus lands on the Allow button by default (or respects system setting), and selecting Allow invokes the granted callback.
Example: In a photo‑editor app, tapping “Add Photo” launches the camera permission dialog; choosing Allow opens the camera preview instantly.
2.2 Standard Deny Flow
Action: Same as above, but select Deny.
Expected: Dialog dismisses, app receives a denied result, and UI reflects the lack of permission (e.g., shows a disabled button or an inline rationale).
Pass Criteria: No crash, no ANR, and the app gracefully degrades functionality.
Example: A fitness app denies location access; the map view stays grayed out and a toast explains that tracking is unavailable.
2.3 “Don’t Ask Again” Handling
Action: Trigger request, select Deny, then check the checkbox that prevents future prompts.
Expected: Subsequent attempts to request the same permission skip the dialog and immediately return a denied result.
Pass Criteria: No dialog appears, the app receives DENY, and the app can show a permanent rationale directing the user to Settings.
Example: After denying microphone with “Don’t ask again”, a voice‑note button shows a banner: “Enable microphone in Settings → Apps → AppName → Permissions”.
2.4 One‑Time Permission (Android 13+)
Action: Request a dangerous permission; user selects “Only this time”.
Expected: Permission granted for the current foreground session; after the app goes to background or is killed, the permission reverts to denied.
Pass Criteria: First use succeeds, subsequent use after backgrounding triggers the dialog again.
Example: A QR scanner grants camera for one scan, then after returning to the home screen and relaunching, the camera prompt appears again.
2.5 Rationale Presentation
Action: Before requesting, show an in‑app explanation if the system recommends it (e.g., after a prior deny).
Expected: Custom view appears, user can proceed to system dialog or cancel.
Pass Criteria: Rationale is accessible, does not block navigation, and leads to the system request when the user confirms.
Example: A social app shows a modal “We need your contacts to find friends” with a “Continue” button that then triggers the system contacts permission dialog.
2.6 Permission Group Behaviors
Action: Request a permission that belongs to a group already granted (e.g., requesting READ_CONTACTS after WRITE_CONTACTS was granted).
Expected: System automatically grants without showing a dialog.
Pass Criteria: No dialog appears, callback returns GRANTED instantly.
Example: An app that previously requested WRITE_CONTACTS for backup later requests READ_CONTACTS for profile import; the second request is silent.
2.7 Revoke‑and‑Re‑grant Cycle
Action: Grant a permission, then manually revoke it via Settings → Apps → AppName → Permissions. Return to the app and trigger the feature again.
Expected: System dialog reappears, user can grant or deny.
Pass Criteria: App handles the reappearing dialog correctly and does not assume a cached state.
Example: After revoking location, opening a “Nearby Stores” screen shows the location permission request again.
2.8 Multiple Simultaneous Requests
Action: Trigger two different permission requests in quick succession (e.g., camera then microphone).
Expected: OS queues the dialogs; user sees one at a time.
Pass Criteria: Each dialog is handled independently, state is preserved between them, and no dialog is lost.
Example: A video‑call flow first asks for camera, then after granting, immediately asks for microphone; the user sees two sequential prompts.
2.9 Permission Request from Background Service
Action: A background worker (e.g., a sync adapter) attempts to access a protected resource without a foreground activity.
Expected: On Android, the system automatically denies and logs a warning; on iOS, the request is ignored.
Pass Criteria: App does not crash, and preferably logs the denial for debugging.
Example: A backup service trying to read contacts while the app is in the background receives a silent denial and retries later when foreground.
2.10 Permission Grant via Intent (Settings Shortcut)
Action: From a denial rationale, provide a button that opens the system Settings page for the specific permission (ACTION_APPLICATION_DETAILS_SETTINGS).
Expected: Settings screen loads, user can toggle the permission, then returns to the app.
Pass Criteria: After returning, the app re‑checks the permission state and updates UI accordingly.
Example: A “Enable microphone” button launches Settings.ACTION_APPLICATION_DETAILS_SETTINGS with the app’s package name; upon return, the microphone button becomes active.
3. Error Handling and Failure Scenarios
3.1 System‑Level Denial (Device Policy)
Action: Device admin or enterprise policy disables a permission category (e.g., disallow camera).
Expected: Request instantly returns DENIED without showing a dialog.
Pass Criteria: App respects the result, shows appropriate UI, and does not retry endlessly.
Example: On a corporate‑owned tablet, the camera permission is blocked; attempting to scan a barcode yields a toast “Camera disabled by administrator”.
3.2 Runtime Permission Revocation During Flow
Action: User grants permission, then while the app is in the foreground, they go to Settings and revoke it.
Expected: Next API call that uses the permission throws a SecurityException (Android) or returns nil/error (iOS).
Pass Criteria: App catches the exception, displays a recovery prompt, and does not crash.
Example: A navigation app loses location permission mid‑route; it shows a dialog “Location access was removed. Enable it to continue navigation.”
3.3 Mis‑typed Permission String
Action: Developer passes an incorrect permission constant (e.g., Manifest.permission.READ_CONTACTS misspelled).
Expected: System throws IllegalArgumentException before showing any dialog.
Pass Criteria: Unit tests catch the mistake; QA verifies that the app logs the error and fails gracefully.
Example: Crashlytics reports IllegalArgumentException: Unknown permission name android.permission.READ_CONTACTTS.
3.4 Dialog Suppressed by Accessibility Service
Action: An accessibility service (e.g., screen overlay) intercepts the permission window.
Expected: Dialog may be delayed or not receive touch events.
Pass Criteria: App should not assume immediate response; it must rely on the callback, not on UI state.
Example: With a floating chat head overlay, the permission dialog appears but taps are ignored until the overlay is dismissed; the app still receives the result after the user finally interacts.
3.5 Activity Recreation During Dialog
Action: Device rotation occurs while the permission dialog is showing.
Expected: Dialog remains visible; activity is destroyed and recreated.
Pass Criteria: Permission result is delivered to the new instance via the saved instance state or via the framework’s automatic re‑delivery.
Example: Rotating the screen while waiting for camera permission does not lose the user’s choice; after rotation, the camera opens as expected.
3.6 Permission Request After Process Kill
Action: App is killed by low memory killer while waiting for user response to a permission dialog.
Expected: Upon restart, the system does not retain the pending request; the app must re‑initiate the flow.
Pass Criteria: App detects that it was restarted without a granted permission and shows the rationale again.
Example: A game requesting storage permission is killed; on relaunch it shows the “We need storage to save progress” rationale before asking again.
4. Edge and Boundary Cases
4.1 Rapid Toggle (Allow/Deny/Allow)
Action: User repeatedly taps Allow and Deny in quick succession before the dialog dismisses.
Expected: Only the final selection is honored; intermediate taps are ignored.
Pass Criteria: No multiple callbacks, state reflects the last choice.
Example: A tester double‑taps Deny then Allow quickly; the app receives a single GRANTED result.
4.2 Request When App Is Not in Foreground (Android)
Action: A broadcast receiver or widget tries to request a permission.
Expected: System automatically denies and logs a warning; no dialog appears.
Pass Criteria: App does not crash; it handles the denial as if the user had pressed Deny.
Example: A home‑screen widget attempting to read contacts receives a silent denial and shows placeholder data.
4.3 Request When App Is in Picture‑in‑Picture Mode
Action: While a video plays in PiP, the app requests microphone permission.
Expected: Dialog appears over the PiP window; user can interact.
Pass Criteria: PiP continues uninterrupted after decision; permission result is delivered correctly.
Example: A video‑chat app asks for microphone while the call is minimized to PiP; after granting, the audio resumes in the PiP window.
4.4 Request During System UI Interaction (Shade, Keyboard)
Action: Pull down the notification shade or open the soft keyboard exactly when a permission dialog appears.
Expected: Dialog remains on top; system UI does not interfere.
Pass Criteria: No visual glitches, touch events are correctly routed to the dialog.
Example: With the keyboard open, requesting camera permission still shows the dialog centered; tapping Allow works despite the keyboard covering part of the screen.
4.5 Locale‑Specific Text Length
Action: Run the app in a language with long strings (e.g., German) or right‑to‑left layout (e.g., Arabic).
Expected: Dialog layout adapts; no truncation or overlap.
Pass Criteria: All buttons fully visible, text readable, focus order logical.
Example: In Arabic, the “Allow” button appears on the right side as per RTL guidelines, and the explanation reads correctly.
4.6 Zero‑Duration Screen Timeout
Action: Set screen timeout to 15 seconds; trigger a permission request and do not interact for the full timeout.
Expected: Screen may dim or turn off; dialog should remain visible until user interaction or system auto‑dismiss (if applicable).
Pass Criteria: App does not assume the dialog disappeared; after screen turns back on, the dialog is still present and responsive.
Example: A kiosk mode device with short timeout still shows the permission prompt until an attendant interacts.
4.7 Concurrent Requests from Different Libraries
Action: Two third‑party SDKs (e.g., analytics and ads) each request the same permission at nearly the same time.
Expected: System coalesces the requests; user sees a single dialog.
Pass Criteria: Both SDKs receive the same result; no duplicate dialogs appear.
Example: An ad SDK and a crash‑reporting SDK both request READ_PHONE_STATE; the user sees one prompt, and both libraries get GRANTED or DENIED accordingly.
4.8 Permission Request After System Update
Action: OS updates while the app is installed; a previously granted dangerous permission may become “reset” on major version upgrades (rare but possible on some OEM skins).
Expected: App should re‑check permission at launch and treat missing grant as denied.
Pass Criteria: On first launch after OS upgrade, app shows rationale if needed and does not crash.
Example: After upgrading from Android 12 to 13 on a Xiaomi device, the app finds location permission reset and prompts the user again.
4.9 Request When Device Is Locked (Keyguard)
Action: Trigger a permission request while the device is locked (e.g., via a background alarm).
Expected: On Android, the request is postponed until the device is unlocked; on iOS, the app cannot show UI while locked.
Pass Criteria: App does not crash; it handles the delay gracefully, perhaps by queuing the request.
Example: An alarm app that tries to access the microphone on trigger waits until the user unlocks, then shows the permission dialog.
4.10 Request in Multi‑Window / Split‑Screen Mode
Action: App runs in split‑screen; a permission dialog appears.
Expected: Dialog is centered over the foreground portion; both apps remain responsive.
Pass Criteria: No visual tearing, user can interact with dialog without leaving split‑screen.
Example: A note‑taking app in left pane requests storage; the dialog appears over the note area, and the right‑pane app stays usable.
5. Accessibility Testing (Permission Dialogs Testing Checklist (2026))
5.1 Screen Reader Announcement
Action: Enable TalkBack (Android) or VoiceOver (iOS) and trigger a permission request.
Expected: The screen reader reads the dialog title, explanation, and button labels in a logical order.
Pass Criteria: All meaningful content is announced, no duplicate or missing pieces.
Example: TalkBack announces “Allow access to your camera? This lets the app take photos and videos. Buttons: Allow, Deny.”
5.2 Touch Target Size
Action: Measure the tap area of the Allow and Deny buttons.
Expected: Minimum 48 dp (Android) or 44 pt (iOS) as per accessibility guidelines.
Pass Criteria: Both buttons meet the size requirement; no overlapping touch targets.
Example: Using Android Studio’s Layout Inspector, the Allow button shows 56 dp × 48 dp, satisfying the guideline.
5.3 Color Contrast
Action: Verify contrast between button text and background, and between explanation text and dialog background.
Expected: Minimum 4.5:1 for normal text, 3:1 for large text (WCAG AA).
Pass Criteria: Contrast ratios pass automated tools (e.g., axe, Accessibility Scanner).
Example: In a dark theme, the Deny button text (#FFFFFF) on a #424242 background yields a contrast of 7.2:1.
5.4 Focus Order and Navigation
Action: Navigate the dialog using directional controls (DPad, keyboard, or assistive touch).
Expected: Focus moves logically from title → explanation → Allow → Deny → (optional checkbox) → back to title.
Pass Criteria: No focus traps, focus never disappears, and looping works correctly.
Example: With a Bluetooth keyboard, Tab moves focus from Allow to Deny, then Shift+Tab returns to Allow.
5.5 Accessibility Live Region Updates
Action: After the user makes a choice, check if any live region (toast, snack bar) announces the outcome.
Expected: Permission granted/denied status is announced for users who rely on audio feedback.
Pass Criteria: Live region notification is polite, not interruptive, and appears promptly.
Example: After granting location, a toast “Location access enabled” is spoken by TalkBack.
5.6 Reduced Motion Compatibility
Action: Enable “Reduce motion” in system settings and trigger a permission request.
Expected: Any animation (fade, slide) should be shortened or disabled.
Pass Criteria: Dialog appears instantly or with minimal motion, respecting the user preference.
Example: With reduced motion on, the dialog fades in over 50 ms instead of the default 250 ms.
5.7 Speech Input Activation
Action: Use voice commands (“Hey Google, tap Allow”) to respond to the permission dialog.
Expected: The system recognizes the command and activates the corresponding button.
Pass Criteria: Voice input works without requiring screen touch.
Example: Saying “Hey Google, tap Allow” while the camera permission dialog is showing results in the dialog dismissing and the camera opening.
6. Security and Privacy Considerations
6.1 Permission Escalation via Intent Spoofing
Action: A malicious app attempts to start the target app with an intent that fakes a permission grant.
Expected: The target app must validate the permission state via the API, not rely on intent extras.
Pass Criteria: App calls Context.checkSelfPermission (or equivalent) before using protected data.
Example: A spoofed ACTION_VIEW intent with extra EXTRA_PERMISSION_GRANTED=true is ignored because the app checks the real permission state.
6.2 Permission Phishing via Custom Dialog
Action: App shows a look‑alike dialog that mimics the system permission prompt to trick users.
Expected: Users should be educated to notice subtle differences (font, button elevation, system UI overlay).
Pass Criteria: App never substitutes a custom dialog for a system permission request; any custom rationale is clearly distinguished.
Example: The app’s rationale uses a distinct background color and includes the app logo, making it obvious it is not the system prompt.
6.3 Access to Sensitive Data After Denial
Action: After a user denies a permission, the app attempts to read the protected resource via a fallback (e.g., using a cached token).
Expected: Access must be blocked; any attempt should raise a security exception or return empty data.
Pass Criteria: Unit tests verify that post‑deny code paths do not succeed.
Example: After denying contacts, the app’s ContentResolver.query returns null and logs a warning.
6.4 Permission Use in Background Services
Action: A service starts and tries to use a permission that was only granted while the app was in the foreground.
Expected: On Android 10+, background location access requires the ACCESS_BACKGROUND_LOCATION permission; otherwise the call fails.
Pass Criteria: Service checks for the appropriate background permission before proceeding.
Example: A fitness tracker service verifies ACCESS_BACKGROUND_LOCATION before requesting periodic updates; if missing, it falls back to foreground-only updates.
6.5 Audit Logging of Permission Changes
Action: Track every grant/deny event in a secure log (e.g., encrypted file or backend).
Expected: Log contains timestamp, permission name, user ID, and outcome.
Pass Criteria: Log is tamper‑evident and does not leak sensitive data in plaintext.
Example: The app writes a JSON line to an EncryptedSharedPreferences store: {"time":1700000000,"perm":"CAMERA","result":"GRANTED"}.
6.6 Permission Request Frequency Limiting
Action: Prevent the app from spamming the user with repeated requests after a denial.
Expected: Implement a back‑off strategy (e.g., wait 24 h or until a meaningful app event).
Pass Criteria: After a deny, no further request appears until the condition is met.
Example: After denying microphone, the app stores a timestamp and only re‑asks after the user attempts to start a voice note.
7. Performance and Resource Impact
7.1 Dialog Inflation Time
Action: Measure the time from invoking requestPermissions to the dialog becoming visible.
Expected: Should be under 200 ms on median devices; spikes indicate heavy work on the UI thread.
Pass Criteria: Use Trace.beginSection/endSection or Android Studio Profiler to confirm UI thread is free.
Example: On a Pixel 6, the average inflation time is 112 ms; on a low‑end device it is 180 ms, still acceptable.
7.2 Memory Allocation During Dialog
Action: Track heap allocation while the permission dialog is on screen.
Expected: Minimal transient allocations (< 200 KB) to avoid GC pauses.
Pass Criteria: Allocation profiling shows no large objects created by the app’s code during the dialog.
Example: Allocation tracker shows only system‑created View objects; the app’s allocation stays at 0 KB.
7.3 Battery Impact of Repeated Prompts
Action: Simulate a scenario where the app repeatedly requests the same permission (e.g., due to a bug) over a 10‑minute period.
Expected: Battery drain should stay within normal app baseline (< 1 % extra).
Pass Criteria: Battery Historian shows no abnormal wake‑locks or sensor usage caused by the prompt loop.
Example: A bug causing a request every second results in a wake‑lock held by the PermissionController; fixing the bug removes the extra drain.
7.4 UI Thread Blocking Checks
Action: Use StrictMode or Looper.myQueue().addIdleHandler to ensure no work is done while the dialog waits for user input.
Expected: The app should be idle; any heavy lifting should be deferred to a background thread.
Pass Criteria: StrictMode detects no disk reads/writes or network calls on the main thread during the dialog wait.
Example: Enabling StrictMode reveals a premature database query in the onResume method; moving it to an AsyncTask resolves the violation.
7.5 Impact on Frame Rate (Jank)
Action: Record UI frame timing while the dialog is visible using adb shell gfxinfo.
Expected: The system renders the dialog at 60 fps; the app’s UI should not cause dropped frames.
Pass Criteria: 99th percentile frame time < 16 ms; no jank attributed to the app.
Example: adb shell gfxinfo com.example.app shows a stable 59.8 fps with a jank of 0.2 % during the permission prompt.
8. Release Readiness and Regression (Permission Dialogs Testing Checklist (2026))
8.1 Permission Manifest Audit
Action: Verify that every permission declared in AndroidManifest.xml or Info.plist has a corresponding runtime request (if dangerous) and a clear justification.
Expected: No unused or over‑privileged permissions.
Pass Criteria: Manifest lint passes; each dangerous permission appears in the codebase with a request call.
Example: The manifest includes READ_PHONE_STATE; a search reveals the app only uses it for telephony state in a background service, which is justified in the Play Store listing.
8.2 Automated Permission Test Suite
Action: Create a parameterized test that iterates over all dangerous permissions, invoking the feature that triggers each, and asserting the correct callback.
Expected: Each test runs in isolation, clears state (via adb shell pm clear or app reset), and reports PASS/FAIL.
Pass Criteria: 100 % pass rate on a matrix of devices (API 21‑34, multiple form factors).
Example: A JUnit 5 test using @ParameterizedTest and @EnumSource(android.Manifest.permission) runs 33 scenarios on Firebase Test Lab.
8.3 CI Permission Gate
Action: Add a step in the CI pipeline that runs the permission test suite on a device farm and fails the build on any regression.
Expected: No new permission‑related bugs slip into release branches.
Pass Criteria: The gate blocks merges when any test fails, prompting immediate investigation.
Example: GitHub Actions workflow uses firebase-test-loop to execute the permission suite; a failed step aborts the merge.
8.4 Version‑Specific Behavior Documentation
Action: Maintain a markdown file that lists known permission quirks per OS version (e.g., one‑time only on Android 13+, provisional auth on iOS 17).
Expected: Developers and QA can reference it to avoid re‑testing already‑known behavior.
Pass Criteria: Document is kept up‑to‑date; each entry includes a link to the relevant AOSP or Apple developer note.
Example: The file permission-quirks.md contains a table:
| OS Version | Quirk | Workaround |
|---|---|---|
| Android 13 | One‑time option appears | Handle RESULT_PERMISSION_DENIED and re‑request if needed |
| iOS 17 | Provisional location | Check CLAuthorizationStatus.provisional before requesting full access |
8.5 User‑Facing Permission Explanation Update
Action: Whenever a new permission is added, update the in‑app rationale and the store listing description.
Expected: Users see a clear, concise purpose before the system dialog appears.
Pass Criteria: Rationale text passes a readability score (e.g., Flesch‑Kincaid > 60) and matches the store description.
Example: Adding BLUETOOTH_CONNECT triggers a rationale: “We need Bluetooth to pair with your smartwatch for data sync.”
8.6 Regression Test for “Don’t Ask Again”
Action: After a deny‑with‑checkbox, verify that subsequent launches skip the dialog and that the app shows a permanent rationale.
Expected: No dialog appears; the app directs the user to Settings.
Pass Criteria: Automated test asserts isPermissionGranted == false and showsRationale == true after
Test Your App Autonomously
Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.
Try SUSA Free