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
- Search the entire codebase for
TJManifest_permission and Androidapi.JNI.Os references.
- Replace each found instance with the equivalent
System.Permissions constant (e.g., sCamera, sReadExternalStorage, sAccessFineLocation).
- Add the rationale callback parameter where missing — provide a simple
ShowMessage or TDialogService.MessageDialog rationale for each permission as a training example.
- Remove
Androidapi.JNI.Os and Androidapi.Helpers from uses clauses where they were only needed for permission constants.
- Ensure each lab consistently handles the three permission outcomes: Granted, Denied, and Never Ask Again — showing appropriate UI messages for each.
- Use
PermissionsService.IsPermissionGranted(sCamera) to check permission state before requesting, avoiding redundant permission dialogs.
Test Plan
Overview
The codebase uses two different patterns for requesting Android runtime permissions: the modern
System.Permissionsframework and direct JNI calls viaAndroidapi.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 useSystem.Permissions.RequestPermissionsconsistently across all labs.Background
Current Mixed Pattern
Old pattern (JNI direct — found in early labs):
Modern pattern (System.Permissions — found in later labs):
The modern pattern also supports the rationale callback (third parameter) required on Android 11+ for some permissions where
shouldShowRequestPermissionRationaleis true. The old pattern ignores this.Permissions to Standardize
CAMERA→sCameraPermission/sCameraREAD_EXTERNAL_STORAGE→sReadExternalStorage(deprecated, see Issue Modernize Android storage permissions for Scoped Storage (API 29+) #4)ACCESS_FINE_LOCATION→sAccessFineLocationACCESS_COARSE_LOCATION→sAccessCoarseLocationFiles Affected
Steps to Address
TJManifest_permissionandAndroidapi.JNI.Osreferences.System.Permissionsconstant (e.g.,sCamera,sReadExternalStorage,sAccessFineLocation).ShowMessageorTDialogService.MessageDialogrationale for each permission as a training example.Androidapi.JNI.OsandAndroidapi.Helpersfromusesclauses where they were only needed for permission constants.PermissionsService.IsPermissionGranted(sCamera)to check permission state before requesting, avoiding redundant permission dialogs.Test Plan
TJManifest_permissionreferences remain in any source file (verify with project-wide search).Androidapi.JNI.Osinusesclauses unless required for non-permission purposes.shouldShowRequestPermissionRationaleis true (can be tested by denying once then trying again).