Skip to content

Modernize runtime permission request pattern to use System.Permissions consistently #16

@jimmckeeth

Description

@jimmckeeth

Overview

The codebase uses two different patterns for requesting Android runtime permissions: the modern System.Permissions framework and direct JNI calls via Androidapi.JNI.Os (TJManifest_permission). The direct JNI approach is lower-level, harder to read, and bypasses Delphi's abstraction layer. All permission requests should be standardized to use System.Permissions.RequestPermissions consistently across all labs.

Background

Current Mixed Pattern

Old pattern (JNI direct — found in early labs):

uses Androidapi.JNI.Os, Androidapi.Helpers;

PermissionsService.RequestPermissions(
  [JStringToString(TJManifest_permission.JavaClass.CAMERA)],
  procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
  begin
    if AGrantResults[0] = TPermissionStatus.Granted then ...
  end
);

Modern pattern (System.Permissions — found in later labs):

uses System.Permissions;

PermissionsService.RequestPermissions(
  [sCamera],  // predefined constant
  procedure(const APermissions: TArray<string>; const AGrantResults: TArray<TPermissionStatus>)
  begin
    if AGrantResults[0] = TPermissionStatus.Granted then ...
  end,
  procedure(const APermission: string; const APostRationaleProc: TProc)
  begin
    // Show rationale dialog, then call APostRationaleProc
  end
);

The modern pattern also supports the rationale callback (third parameter) required on Android 11+ for some permissions where shouldShowRequestPermissionRationale is true. The old pattern ignores this.

Permissions to Standardize

Files Affected

lab-src/Lab05.../frames/uNewEntryFrame.pas
lab-src/Lab05.../forms/formMain.pas
lab-src/Lab06.../frames/uNewEntryFrame.pas
... (all labs with camera/location/storage permissions, Labs 05–12)

Steps to Address

  1. Search the entire codebase for TJManifest_permission and Androidapi.JNI.Os references.
  2. Replace each found instance with the equivalent System.Permissions constant (e.g., sCamera, sReadExternalStorage, sAccessFineLocation).
  3. Add the rationale callback parameter where missing — provide a simple ShowMessage or TDialogService.MessageDialog rationale for each permission as a training example.
  4. Remove Androidapi.JNI.Os and Androidapi.Helpers from uses clauses where they were only needed for permission constants.
  5. Ensure each lab consistently handles the three permission outcomes: Granted, Denied, and Never Ask Again — showing appropriate UI messages for each.
  6. Use PermissionsService.IsPermissionGranted(sCamera) to check permission state before requesting, avoiding redundant permission dialogs.

Test Plan

  • No TJManifest_permission references remain in any source file (verify with project-wide search).
  • No Androidapi.JNI.Os in uses clauses unless required for non-permission purposes.
  • On Android 13 emulator: camera permission dialog appears correctly with app name and reason.
  • On Android 13 emulator: denying camera permission shows a user-friendly message; no crash.
  • On Android 13 emulator: choosing "Don't ask again" then trying to use the camera: app directs the user to Settings.
  • Rationale dialog appears when shouldShowRequestPermissionRationale is true (can be tested by denying once then trying again).
  • All permission flows work identically across Labs 05 through 12.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions