Skip to content

Compile the Android port against API 37, which removed FingerprintManager (issue #5701) - #5723

Open
shai-almog wants to merge 1 commit into
masterfrom
fix/android-sdk37-fingerprintmanager
Open

Compile the Android port against API 37, which removed FingerprintManager (issue #5701)#5723
shai-almog wants to merge 1 commit into
masterfrom
fix/android-sdk37-fingerprintmanager

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Fixes #5701.

The bug

Android SDK Platform 37 removes android.hardware.fingerprint.FingerprintManager and Context.FINGERPRINT_SERVICE. cn1:buildAndroidGradleProject selects the newest installed platform, so a developer with 37 installed got compileSdkVersion 37 and 34 javac errors in AndroidBiometrics and AndroidSecureStorage — port sources they never wrote, in an unmodified Hello World.

The change

Neither Android biometric API can be named from a file every application compiles. FingerprintManager exists in API 23-36; BiometricPrompt exists from API 28, which is newer than the cn1-binaries android.jar the port jar is built against. So each moves into a package of its own, next to the ar, ai, cipher and nearby precedents:

  • com/codename1/impl/android/biometricsBiometricPrompt, excluded from the port jar compile and compiled in the generated app.
  • com/codename1/impl/android/fingerprintFingerprintManager, compiled everywhere and deleted by the builder from compileSdk 37.

AndroidBiometrics picks one at class-init through the new BiometricBackend interface, with the class name a constant string at the Class.forName call so R8 keeps it; a proguard keep rule states it outright as well. A build pinned to compileSdk 28 loses the modern package instead and falls back to the legacy one, which its devices still answer.

Reflection is not an option for either callback: both FingerprintManager.AuthenticationCallback and BiometricPrompt.AuthenticationCallback are abstract classes, and java.lang.reflect.Proxy implements interfaces only.

A second defect this uncovered

Deleting the legacy package makes the API 29+ path load-bearing, and it did not work. BiometricsApi29 reached BiometricPrompt by reflection and built its callback with Proxy — so every call threw IllegalArgumentException: ... is not an interface, was swallowed, and the caller was told the hardware was unavailable. The new backend subclasses the callback directly, which is only possible now that the file compiles against a modern platform. BiometricsApi29 is deleted with it, along with four cast-semantics-baseline.txt entries.

Behaviour change

One, and it is forced: from API 29, getAvailableBiometrics() reports FINGERPRINT when the device has the sensor and some biometric is enrolled. It used to ask FingerprintManager exactly, and Android exposes no per-modality enrolment query to replace it. Documented in the javadoc and the developer guide.

Verification

  • scripts/hellocodenameone builds an APK at compileSdkVersion 37 / targetSdkVersion 37; the APK carries biometrics/BiometricPromptBackend and no fingerprint package.
  • Non-vacuous: restoring the fingerprint sources into that generated project reproduces the reported failure exactly (package android.hardware.fingerprint does not exist).
  • A signature diff of android.jar 36 against 37, over the 258 android.* classes the port imports, finds FINGERPRINT_SERVICE as the only source-visible removal — so nothing else in the port is exposed at 37.
  • SpotBugs 0 on android and codenameone-maven-plugin; cast-semantics, control-character and copyright gates clean; Vale clean on the edited guide page.
  • Five new AndroidBiometricSourceSelectionTest cases.

Needs the builder half

BuildDaemon carries its own AndroidGradleBuilder and needs the same pruning, or a cloud build at compileSdk 28 will fail to compile the new biometrics package. That PR is codenameone/BuildDaemon#TBD.

Not done, deliberately

CI's local Android app build stays pinned to compileSdk 36. It works at 37, but AGP 8.13.2 is only tested up to 36 and targetSdk 37 would move the instrumentation suite's runtime behaviour; raising it is a separate, deliberate change. The comments that blamed the pin on FingerprintManager are updated.

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 6, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-06T18:41:08.760845Z b59c3eb New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog

shai-almog commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 151 screenshots: 151 matched.

Native Android coverage

  • 📊 Line coverage: 9.22% (9150/99286 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 8.97% (47063/524433), branch 3.54% (1756/49663), complexity 3.52% (1863/52966), method 5.41% (1507/27866), class 10.88% (406/3731)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6367 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1187 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/736 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/625 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.Frame – 0.00% (0/570 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 9.22% (9150/99286 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 8.97% (47063/524433), branch 3.54% (1756/49663), complexity 3.52% (1863/52966), method 5.41% (1507/27866), class 10.88% (406/3731)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6367 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1187 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/736 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/625 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.Frame – 0.00% (0/570 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend scalar fallback (no native SIMD)
SIMD int-add (64K x300) java 263ms / native 117ms = 2.2x speedup
SIMD float-mul (64K x300) java 191ms / native 82ms = 2.3x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 115.000 ms
Base64 CN1 decode 79.000 ms
Base64 native encode 563.000 ms
Base64 encode ratio (CN1/native) 0.204x (79.6% faster)
Base64 native decode 366.000 ms
Base64 decode ratio (CN1/native) 0.216x (78.4% faster)
Image encode benchmark status skipped (SIMD unsupported)

@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • build-hint-catalog: 0 findings (no issues)
    • build-hint-tools: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog

shai-almog commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 181 screenshots: 181 matched.
✅ JavaScript-port screenshot tests passed.

@shai-almog
shai-almog force-pushed the fix/android-sdk37-fingerprintmanager branch from 79ea3e0 to b535f01 Compare September 6, 2026 15:39

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b535f01af7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@shai-almog
shai-almog force-pushed the fix/android-sdk37-fingerprintmanager branch 2 times, most recently from d7e90f7 to c8276e3 Compare September 6, 2026 18:23

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c8276e358d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

…ager (issue #5701)

Android SDK Platform 37 removes android.hardware.fingerprint.FingerprintManager
and Context.FINGERPRINT_SERVICE. cn1:buildAndroidGradleProject picks the newest
installed platform, so a developer with 37 installed got compileSdkVersion 37
and 34 javac errors in AndroidBiometrics and AndroidSecureStorage -- port
sources they never wrote, in an unmodified Hello World.

Neither Android biometric API can be named from a file every application
compiles. FingerprintManager is gone from 37; BiometricPrompt arrives in API
28, which is newer than the cn1-binaries android.jar the port jar is built
against. So each moves into a package of its own, next to the ar, ai, cipher
and nearby precedents, and AndroidBiometrics picks one at class-init through
the new BiometricBackend interface:

- com/codename1/impl/android/biometrics reaches BiometricPrompt directly. It is
  excluded from the port jar compile and compiled in the generated app. Its
  floor is API 28, where BiometricPrompt itself arrives, which is also the
  bottom of compileSdkInt's ladder -- so the builder's prune never fires in
  practice. Everything newer that it needs (BiometricManager is 29,
  canAuthenticate(int) and Authenticators are 30) is reached by name instead of
  compiled against, verified by checking every android.* reference in the
  compiled class against the SDK's api-versions.xml: none is newer than 28.
  Keeping the floor at the bottom of the ladder is what stops a project pinned
  to 28 or 29 from losing the package, which would have left its APK with no
  biometrics at all on an API 37 device, where the legacy backend's platform
  API no longer exists.
- com/codename1/impl/android/fingerprint reaches the platform fingerprint API
  through the support library's FingerprintManagerCompat, so it compiles
  against every platform including 37 and is never deleted. That matters:
  an application compiled against 37 still RUNS on API 23-28, where the
  platform class it wraps is the only biometric API there is. The
  android.support.v4 spelling is what the port's other support-library users
  write; AndroidGradleBuilder rewrites it to androidx.core for every AndroidX
  app through androidx-class-mapping.csv, which was verified on the generated
  project rather than assumed.

The backend's class name is a constant string at the Class.forName call so R8
keeps it, and a proguard keep rule states it outright as well.

canAuthenticate asks for Authenticators.BIOMETRIC_STRONG where the platform
offers it. The deprecated no-argument call AOSP defines as
canAuthenticate(BIOMETRIC_WEAK) would advertise an authentication that cannot
happen: every prompt in the port carries a CryptoObject, and BiometricPrompt
defaults a crypto prompt to BIOMETRIC_STRONG and refuses anything weaker ("Only
Strong biometrics supported with crypto"), so a Class 2 face on an API 30+
device answers the weak query and then fails the prompt. API 29 falls back to
the no-argument call, which is the only query that platform has, and the
fallback is driven by the overload being absent rather than by a version check.

Making the fingerprint package compile at 37 also made the API 29+ path
load-bearing, and it did not work. BiometricsApi29 reached BiometricPrompt by
reflection and built its callback with java.lang.reflect.Proxy -- but
BiometricPrompt.AuthenticationCallback is an abstract class, and Proxy accepts
interfaces only, so every call threw IllegalArgumentException and the caller
was told the hardware was unavailable. The new backend subclasses it directly,
which is only possible now the file compiles against a modern platform.
BiometricsApi29 is deleted with it, along with four cast-semantics baseline
entries.

Behaviour otherwise stands still, with one forced exception: from API 29,
getAvailableBiometrics reports FINGERPRINT when the device has the sensor and
a usable biometric is enrolled. It used to ask FingerprintManager exactly, and
Android exposes no per-modality enrolment query to replace it.

The port has three compiles and the biometrics exclusion is stated in all
three: maven/android/pom.xml, Ports/Android/nbproject/project.properties and
Ports/Android/build.xml. The first already carried the same list for ar, ai,
cipher and nearby; the Ant pair is what build-test (8) runs.

Verified by building scripts/hellocodenameone for Android at compileSdkVersion
37 / targetSdkVersion 37: assembleDebug succeeds and the APK carries both
backends. A signature diff of android.jar 36 against 37, over the 258 android.*
classes the port imports, finds FINGERPRINT_SERVICE as the only source-visible
removal, so nothing else in the port is exposed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@shai-almog
shai-almog force-pushed the fix/android-sdk37-fingerprintmanager branch from c8276e3 to b59c3eb Compare September 6, 2026 18:37
@shai-almog

shai-almog commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 160 screenshots: 160 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 164 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 62ms / native 3ms = 20.6x speedup
SIMD float-mul (64K x300) java 60ms / native 3ms = 20.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 144.000 ms
Base64 CN1 decode 85.000 ms
Image encode benchmark iterations 100
Image createMask (SIMD off) 5.000 ms
Image createMask (SIMD on) 1.000 ms
Image createMask ratio (SIMD on/off) 0.200x (80.0% faster)
Image applyMask (SIMD off) 30.000 ms
Image applyMask (SIMD on) 20.000 ms
Image applyMask ratio (SIMD on/off) 0.667x (33.3% faster)
Image modifyAlpha (SIMD off) 23.000 ms
Image modifyAlpha (SIMD on) 20.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.870x (13.0% faster)
Image modifyAlpha removeColor (SIMD off) 26.000 ms
Image modifyAlpha removeColor (SIMD on) 21.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.808x (19.2% faster)

@shai-almog

shai-almog commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 149 screenshots: 149 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 1390 seconds

Build and Run Timing

Metric Duration
Simulator Boot 78000 ms
Simulator Boot (Run) 1000 ms
App Install 24000 ms
App Launch 1000 ms
Test Execution 436000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 89ms / native 4ms = 22.2x speedup
SIMD float-mul (64K x300) java 61ms / native 3ms = 20.3x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 557.000 ms
Base64 CN1 decode 178.000 ms
Base64 native encode 1201.000 ms
Base64 encode ratio (CN1/native) 0.464x (53.6% faster)
Base64 native decode 828.000 ms
Base64 decode ratio (CN1/native) 0.215x (78.5% faster)
Base64 SIMD encode 154.000 ms
Base64 encode ratio (SIMD/CN1) 0.276x (72.4% faster)
Base64 SIMD decode 80.000 ms
Base64 decode ratio (SIMD/CN1) 0.449x (55.1% faster)
Base64 encode ratio (SIMD/native) 0.128x (87.2% faster)
Base64 decode ratio (SIMD/native) 0.097x (90.3% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 23.000 ms
Image createMask (SIMD on) 11.000 ms
Image createMask ratio (SIMD on/off) 0.478x (52.2% faster)
Image applyMask (SIMD off) 171.000 ms
Image applyMask (SIMD on) 79.000 ms
Image applyMask ratio (SIMD on/off) 0.462x (53.8% faster)
Image modifyAlpha (SIMD off) 110.000 ms
Image modifyAlpha (SIMD on) 205.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.864x (86.4% slower)
Image modifyAlpha removeColor (SIMD off) 315.000 ms
Image modifyAlpha removeColor (SIMD on) 684.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 2.171x (117.1% slower)

@shai-almog

shai-almog commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 144 screenshots: 144 matched.
✅ Native Apple TV (tvOS, Metal) screenshot tests passed.

@shai-almog

shai-almog commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 217 screenshots: 217 matched.
✅ Native Apple Watch (watchOS, Core Graphics) screenshot tests passed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Compatibility] Local Android build fails with SDK 37 because CN1 sources reference FingerprintManager

1 participant