Impact summary
Urgency: High. From 2027-01-27, Google Play policy requires apps targeting Android 17 (API level 37)+ to use the Android Contact Picker when broad READ_CONTACTS access is not essential to core functionality. Apps retaining broad access must pass a Play Console declaration explaining why the picker is insufficient.
Codename One's public contact-reading APIs currently expose only broad address-book access. Referencing them causes the generated manifest to request READ_CONTACTS, and the Android port requests that runtime permission before every read. CN1 users who only need a user-selected contact have no policy-minimized framework path.
Official requirement and deadline
Hard policy enforcement deadline: 2027-01-27.
First affected platform/store combination: Google Play apps targeting Android 17 / API 37+ that request READ_CONTACTS without an approved core-functionality justification.
Concrete Codename One applicability
Verified against codenameone/CodenameOne master at 134f6ec227792da11b595a77eda6c06d3c0a2b8f:
Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java
getAllContacts(...), getContactById(...), and related methods call checkForPermission(Manifest.permission.READ_CONTACTS, ...) before delegating to AndroidContactsManager.
Ports/Android/src/com/codename1/impl/android/AndroidContactsManager.java
- Reads directly from
ContactsContract.Contacts, ContactsContract.Data, phone, email, address, birthday, and note tables using ContentResolver.
maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/AndroidGradleBuilder.java
- Detects contact API use and emits
<uses-permission android:name="android.permission.READ_CONTACTS" ...> into the generated manifest.
codenameone/BuildDaemon master at 09cd713c6abe9455d0574ed0a1ff0776bee84754
AndroidBuilder and AndroidGradleBuilder mirror the same READ_CONTACTS permission injection in hosted builds.
- No
ContactsPickerSessionContract, ACTION_PICK_CONTACTS, or Contact Picker result handling exists on the default branch.
Deduplication across open and closed issues/PRs used Contact Picker, READ_CONTACTS, API 37, 2027-01-27, and the official notice name. No tracking item or completed migration was found.
Affected users and failure mode
- CN1 apps targeting API 37+ that use
Display.getAllContacts(), getContactById(), or equivalent broad read APIs.
- Apps that only need one or a few user-selected phone numbers, email addresses, or postal addresses cannot currently choose the policy-minimized picker path.
- Failure mode: Play Console declaration/review burden; update rejection or policy enforcement if broad access is not accepted as core functionality; or loss of the contact feature if users remove
READ_CONTACTS without a replacement API.
Proposed migration
- Investigation/API design
- Define a cross-platform contact-selection API with explicit requested fields, single/multiple selection, cancellation, and temporary-result semantics.
- Separate picker use from existing broad address-book management APIs so existing valid CRM/contact-manager cases remain possible.
- Implementation
- On Android 17+, launch
ContactsPickerSessionContract.ACTION_PICK_CONTACTS, request only selected MIME fields, parse the session URI, and copy required values before temporary access expires.
- Provide a documented compatible fallback on older Android versions, using system selection where possible.
- Ensure picker-only apps do not receive
READ_CONTACTS; keep broad permission injection only for broad APIs.
- Mirror builder/generated-project changes in BuildDaemon.
- CI and beta validation
- Unit-test API result mapping, cancellation, multi-select, requested-field filtering, and temporary URI handling.
- Add generated-manifest tests proving picker-only use omits
READ_CONTACTS while broad APIs still inject it.
- Run Android 17 emulator/device tests across personal/work profiles and old-version fallback tests.
- Release and communication
- Release framework, Maven builder, and BuildDaemon support together.
- Document which APIs require a Play declaration and provide a migration example from broad reads to user-selected contacts.
Internal target dates
- 90-day checkpoint / API design approved: 2026-10-29
- 60-day checkpoint / implementation complete: 2026-11-28
- CI, Android 17 beta, and hosted-build validation complete: 2026-12-14
- Release and customer communication no later than 2026-12-28, preserving the required 30-day buffer before 2027-01-27 enforcement
Risks, unknowns, and verification plan
- Contact Picker is Android 17-only and session URIs are temporary; lifecycle/process-death behavior must be tested.
- The framework must not silently turn a narrow picker call into broad permission access on older releases.
- CN1's existing
Contact model may not express partial-field/multiple-selection provenance cleanly; settle that before freezing the API.
- BuildCloud must have an API 37-capable toolchain before compiling direct Android 17 symbols, or the implementation must use a compatible AndroidX/reflection boundary until that image ships.
- Verify a release AAB in Play Console's pre-launch/policy checks, plus Android 17 personal/work-profile selection and API 23-36 fallback behavior.
Impact summary
Urgency: High. From 2027-01-27, Google Play policy requires apps targeting Android 17 (API level 37)+ to use the Android Contact Picker when broad
READ_CONTACTSaccess is not essential to core functionality. Apps retaining broad access must pass a Play Console declaration explaining why the picker is insufficient.Codename One's public contact-reading APIs currently expose only broad address-book access. Referencing them causes the generated manifest to request
READ_CONTACTS, and the Android port requests that runtime permission before every read. CN1 users who only need a user-selected contact have no policy-minimized framework path.Official requirement and deadline
READ_CONTACTSto submit a declaration or remove the permission and use the picker.ContactsPickerSessionContract.ACTION_PICK_CONTACTSgrants temporary access only to contacts/fields selected by the user; the picker is available on Android 17+.Hard policy enforcement deadline: 2027-01-27.
First affected platform/store combination: Google Play apps targeting Android 17 / API 37+ that request
READ_CONTACTSwithout an approved core-functionality justification.Concrete Codename One applicability
Verified against
codenameone/CodenameOnemasterat134f6ec227792da11b595a77eda6c06d3c0a2b8f:Ports/Android/src/com/codename1/impl/android/AndroidImplementation.javagetAllContacts(...),getContactById(...), and related methods callcheckForPermission(Manifest.permission.READ_CONTACTS, ...)before delegating toAndroidContactsManager.Ports/Android/src/com/codename1/impl/android/AndroidContactsManager.javaContactsContract.Contacts,ContactsContract.Data, phone, email, address, birthday, and note tables usingContentResolver.maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/AndroidGradleBuilder.java<uses-permission android:name="android.permission.READ_CONTACTS" ...>into the generated manifest.codenameone/BuildDaemonmasterat09cd713c6abe9455d0574ed0a1ff0776bee84754AndroidBuilderandAndroidGradleBuildermirror the sameREAD_CONTACTSpermission injection in hosted builds.ContactsPickerSessionContract,ACTION_PICK_CONTACTS, or Contact Picker result handling exists on the default branch.Deduplication across open and closed issues/PRs used
Contact Picker,READ_CONTACTS, API 37,2027-01-27, and the official notice name. No tracking item or completed migration was found.Affected users and failure mode
Display.getAllContacts(),getContactById(), or equivalent broad read APIs.READ_CONTACTSwithout a replacement API.Proposed migration
ContactsPickerSessionContract.ACTION_PICK_CONTACTS, request only selected MIME fields, parse the session URI, and copy required values before temporary access expires.READ_CONTACTS; keep broad permission injection only for broad APIs.READ_CONTACTSwhile broad APIs still inject it.Internal target dates
Risks, unknowns, and verification plan
Contactmodel may not express partial-field/multiple-selection provenance cleanly; settle that before freezing the API.