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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions