thunderbird / thunderbird/thunderbird-android
Android 17 — Plan behaviour changes updates
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 14k
- Forks
- 2.8k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 57
Description
Description
The following report was created with the help of both Claude and Codex, with all the possible Android 17 behaviour changes that could affect our codebase.
In this task, we should:
- Verify each reported behaviour change and check if they are valid
- Create a GitHub issue to address such a change
- Re-verify the Android 17 behaviour changes documentation to ensure we didn't miss anything:
Report
[!IMPORTANT]
Do not treat this report as absolute truth. We must verify each point with the actual entry on the Android 17 Behaviour changes page before assuming it is correct.
Android 17 compatibility report
Scope
This report assesses Thunderbird for Android against:
- Behaviour changes for apps targeting Android 17
- Behaviour changes affecting all apps on Android 17
- Android 17 features and changes summary
- Android 17 release notes and supporting documentation where the main behaviour-change pages are incomplete
Thunderbird currently compiles with API 37 but targets API 36:
Therefore:
- Changes marked “target API 37” are not active yet.
- Changes marked “all apps” can affect Thunderbird whenever it runs on Android 17.
1. Local-network permission
Impact: High
Status: Confirmed functional impact for LAN and self-hosted mail servers
Activation: Thunderbird targets API 37
Code evidence
Thunderbird declares INTERNET, but not the new ACCESS_LOCAL_NETWORK permission:
Users can configure arbitrary IMAP, SMTP, and POP3 servers. The protocol implementations resolve the configured hostname and establish direct socket connections:
- IMAP: RealImapConnection.kt
- SMTP: SmtpTransport.kt
- POP3: Pop3Connection.java
IMAP Push maintains long-lived connections through a foreground service:
JMAP, autoconfiguration, and WebView requests can also target local-network endpoints.
Android 17 change
Apps targeting API 37 cannot access the local network without the new ACCESS_LOCAL_NETWORK runtime permission. The restriction covers:
- Incoming and outgoing TCP
- Incoming and outgoing UDP
.localname resolution- Java sockets
- OkHttp
- WebView
References:
Affected account configurations include:
- Private IPv4 addresses such as
192.168.x.xand10.x.x.x - Private or link-local IPv6 addresses
.localhostnames- Other hostnames that resolve to a local-network address
A TCP connection may appear to time out rather than immediately returning a clear permission error.
Mitigation
Implement this together with the target-API-37 change:
- Declare
android.permission.ACCESS_LOCAL_NETWORK. - Add it to Thunderbird’s permission abstraction and UI.
- Request it contextually when the user configures or uses a local mail server.
- Provide a migration prompt for existing local-server accounts.
- Handle denial and revocation without uncontrolled background retries.
- Present an actionable error without logging hostnames, addresses, email addresses, or account details.
- Ensure internet-hosted accounts continue working when permission is denied.
Test:
- IMAP, POP3, SMTP, and IMAP Push
- JMAP and autoconfiguration
- Private IPv4 and IPv6 servers
.localhostnames- Permission granted, denied, and revoked
- Existing accounts upgrading from target API 36
- Local remote-image URLs in message content
Android recommends that apps targeting API 36 or lower do not request this permission yet.
2. Complex IME accessibility metadata
Impact: Medium
Status: Potential compatibility gap
Activation: Thunderbird targets API 37
CJKV means Chinese, Japanese, Korean, and Vietnamese. Keyboards for these languages commonly keep text in a composing state while the user chooses a character or conversion candidate.
Code evidence
The recipient token editor supplies a custom InputConnection:
- Connection creation: TokenCompleteTextView.java
- Wrapper implementation: TokenCompleteTextView.java
The wrapper overrides the older two-argument setComposingText() method:
It does not override the newer overload that includes a TextAttribute. Calls to that overload could bypass the token editor's composing-text processing.
RecipientSelectView also customizes input-connection behaviour:
Android 17 change
Android 17 allows complex input methods to pass candidate-selection information through TextAttribute. Custom editors must preserve this information and provide the appropriate text-change type to accessibility services.
Standard TextView handles this automatically. Thunderbird requires additional review because its recipient editor uses a custom connection.
Mitigation
- Implement the three-argument
setComposingText(text, position, textAttribute)method. - Share composing-text normalization between the old and new overloads.
- Preserve and forward the original
TextAttribute. - When the token editor dispatches its own
TYPE_VIEW_TEXT_CHANGEDevent, set the correct text-change type usingAccessibilityEvent.setTextChangeTypes(). - Confirm that normal
TextViewdelegation does not result in duplicate accessibility events.
Test To, Cc, and Bcc entry with:
- Chinese, Japanese, Korean, and Vietnamese keyboards
- Conversion-candidate selection
- Physical keyboards
- TalkBack
3. Lock-free MessageQueue
Impact: Medium — no production code affected, but blocks the compileSdk/targetSdk bump
Status: Required test-infrastructure update
Activation: Platform change activates at targetSdk 37; the Robolectric breakage activates at compileSdk 37
[!IMPORTANT]
Two independent triggers, often conflated:
- The platform change applies only to apps targeting API 37+ (
sdkTarget).- The Robolectric breakage triggers as soon as
compileSdkis 37, because Robolectric emulates the compiled SDK. Robolectric 4.16.1 ships no SDK 37 runtime, so unit tests fail whilesdkTargetis still 36.Upgrading Robolectric is therefore a prerequisite for raising
compileSdk, independent of the targetSdk decision.
Code evidence
Robolectric is pinned to 4.16.1:
Robolectric 4.16.1's DefaultSdkProvider supports SDK 21–36; SDK 37 first appears in 4.17-beta-1.
Four test classes use the legacy looper mode:
- MessageBuilderTest.java#L61
- PgpMessageBuilderTest.kt#L80
- RecipientPresenterTest.kt#L51
- MessageCryptoHelperTest.java#L55
Espresso is at 3.7.0 — exactly the documented minimum, so any downgrade reintroduces the problem.
No production Kotlin/Java source references MessageQueue.
Android 17 change
Beginning with Android 17, apps targeting Android 17 (API level 37) or higher receive a new lock-free implementation of
android.os.MessageQueue. The new implementation improves performance and reduces missed frames, but may break clients that reflect onMessageQueueprivate fields and methods.
Concretely, MessageQueue.mMessages is now always null, breaking reflection-based inspection of pending messages.
Mitigation
- Upgrade Robolectric to 4.17-beta-2. No stable 4.17 has shipped as of 2026-08-10 — Maven Central has only
4.17-beta-1and4.17-beta-2. Accepting a prerelease is currently unavoidable for compileSdk 37. - Add the JVM argument
--add-opens=java.base/jdk.internal.access=ALL-UNNAMEDto all unit-test tasks. Under SDK 37 emulation Robolectric'sFileDescriptorInterceptorreflects intojdk.internal.access.SharedSecretsviaApplicationSharedMemory.create(); without it every Robolectric test fails with "Failed to interact with raw FileDescriptor internals; perhaps JRE has changed?" - Delete
@LooperMode(LooperMode.Mode.LEGACY)from the four classes — do not replace it withPAUSED. - Replace LEGACY-only scheduler APIs.
Robolectric.getBackgroundThreadScheduler()does not exist outside LEGACY:.pause()/.unPause()→ aPausedExecutorServiceinstalled viaShadowPausedAsyncTask.overrideExecutor(...), drained withrunAll().runOneTask()→PausedExecutorService.runNext()- After draining the executor, idle the main looper (
shadowOf(Looper.getMainLooper()).idle()) soAsyncTask.onPostExecuteruns.
- Add explicit main-looper idling where async delivery was previously implicit.
MessageCryptoHelperTestuses noAsyncTask— its async step is OpenPGP service binding, delivered through the main looper — so it needsidle()after each asyncStartOrResumeProcessingMessage(...)` and no executor override. - Run the full unit-test suite, not just the affected modules — the JVM argument in step 2 is global.
- Before raising
targetSdkto 37, exercise debug builds with the compatibility toggle:
Also available under Developer Options → App Compatibility Changes.adb am compat enable USE_NEW_MESSAGEQUEUE net.thunderbird.android.debug adb am compat disable USE_NEW_MESSAGEQUEUE net.thunderbird.android.debug
4. Application memory limits
Impact: Medium
Status: Requires profiling; no confirmed failure found
Activation: All applications running on Android 17
Code evidence
Potential high-allocation paths include:
- Long HTML messages displayed in
WebView: MessageWebView.kt - OpenPGP processing that creates multiple in-memory copies of message data: MessageCryptoHelper.java
- Contact-photo decoding without sampling to the displayed size: ContactPhotoLoader.kt
These are profiling candidates, not proof that Thunderbird currently exceeds Android 17’s limits.
Android 17 change
Android 17 introduces conservative process memory limits on a subset of devices. Applications that exceed the device-specific limit can be terminated.
A memory-limiter termination can be identified through ApplicationExitInfo, whose description contains MemoryLimiter.
Mitigation
Profile Android 17 builds with:
- Very large HTML messages
- Large inline encrypted or signed messages
- Oversized contact photos
- Many configured accounts
- Multiple active Push connections
If profiling identifies a problem:
- Stream or temporarily store large decrypted data instead of retaining multiple byte-array copies.
- Decode contact images at the required display size.
- Ensure WebView instances and message resources are released promptly.
- Use Android’s documented memory-limiter developer command and inspect
ApplicationExitInfo.
Diagnostics must not include message contents, email addresses, or account information.
5. OpenPGP background activity launches
Impact: Low
Status: Security hardening; no confirmed functional failure
Activation: Target API 37
Code evidence
The OpenPGP launcher grants MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS on newer Android versions:
Current callers generally originate from visible activities or fragments:
Android 17 change
Android 17 extends background activity-launch protections to IntentSender and recommends replacing broad legacy allowances with more specific modes.
Mitigation
Use MODE_BACKGROUND_ACTIVITY_START_ALLOW_IF_VISIBLE where available.
Retain ALLOW_ALWAYS only if a verified OpenPGP provider flow must launch while Thunderbird is not visible. Test:
- Encryption
- Decryption
- Key selection
- Provider authorization
- Provider consent and error screens
6. Encrypted Client Hello and Certificate Transparency
Impact: Low or conditional
Status: TLS compatibility and security-policy validation
Activation: Target API 37
Code evidence
HTTPS consumers include:
- OkHttp-based autoconfiguration: OkHttpFetcher.kt
- JMAP downloads: CommandSync.kt
- WebView remote images: MessageWebView.kt
The network-security configuration trusts system and user-installed certificates:
Mail protocols have separate socket and certificate handling:
Android 17 changes
Android 17 enables:
ECH only applies when the networking library and remote server support it.
Android documents that Certificate Transparency is automatically disabled for configurations using user-installed or inline trust anchors unless CT is explicitly enabled:
The current user-anchor configuration therefore likely prevents CT from being enabled automatically for Network Security Configuration consumers. Custom mail TLS needs separate validation.
Mitigation
- Preserve ECH by default.
- Add an ECH opt-out only for a specific, reproducibly incompatible endpoint.
- Do not disable ECH globally.
- Make an explicit Certificate Transparency policy decision.
- Do not add a blanket CT opt-out merely to preserve current behaviour.
Test:
- Publicly trusted certificates
- User-installed certificate authorities
- Thunderbird’s accepted self-signed certificate flow
- IMAP, POP3, SMTP, JMAP, and autoconfiguration
- Remote message images
7. Keyboard visibility after rotation
Impact: Low
Status: User-experience regression risk
Activation: All applications running on Android 17
Code evidence
MainActivity uses adjustResize, but does not automatically restore keyboard visibility:
The legacy message-compose activity does not handle orientation changes itself:
Recipient entry explicitly requests the keyboard when focused, which may already protect that field:
Android 17 change
Android 17 no longer restores the previous keyboard visibility after an unhandled configuration change. The default visibility mode is used instead.
Mitigation
Test rotation while editing:
- Recipients
- Subject
- Message body
- Account setup fields
- Server settings
- Search and settings fields
Where preserving the visible keyboard is required:
- Record whether it was visible before recreation.
- Restore focus.
- Request the keyboard after the new view and window are ready.
Avoid enabling an application-wide “always show keyboard” mode.
8. Physical-keyboard password hiding
Impact: Expected privacy improvement
Status: No code change anticipated
Activation: Target API 37
Code evidence
Thunderbird uses standard password transformations and input types:
- Compose password field: TextFieldOutlinedPassword.kt
- Import-password dialog: password_prompt_dialog.xml
Android 17 change
Android 17 hides password characters immediately when they are entered using a physical keyboard.
Mitigation
No implementation change is expected. Test:
- Physical-keyboard password entry
- Password visibility toggles
- Account setup
- Incoming and outgoing server settings
- Settings import
Thunderbird should not override this system privacy behaviour.
9. WebView user-agent reduction
Impact: Low
Status: Server compatibility testing
Activation: Target API 37
Code evidence
Thunderbird uses WebView to display HTML messages and optionally load remote images:
No Thunderbird code was found overriding WebSettings.userAgentString.
Android 17 change
Android 17 reduces the identifying information in the default WebView user-agent string for applications targeting API 37. Device-specific information such as the actual Android version and model is replaced with generic values.
Mitigation
- Test remote message images on Android 17.
- Test any WebView content that might depend on user-agent detection.
- Do not restore the device model, build, or actual OS version through a custom user-agent string.
- If a server fails, address the server compatibility issue rather than weakening the privacy improvement globally.
10. Custom notification view memory restrictions
Impact: No direct impact found
Status: Thunderbird uses standard system templates
Activation: Target API 37
Code evidence
Thunderbird has application-specific notification infrastructure, but its Android system notifications use standard templates.
The new notification implementation creates a standard NotificationCompat.Builder:
It uses standard BigTextStyle and InboxStyle templates:
Legacy notifications also use standard templates:
BigTextStyle: SingleMessageNotificationCreator.ktInboxStyle: SummaryNotificationCreator.kt- Contact photos use
setLargeIcon(): SingleMessageNotificationCreator.kt
The legacy controller coordinates notification state but does not create notification layouts:
A repository-wide search found no notification use of:
RemoteViewsNotificationCompat.DecoratedCustomViewStylesetCustomContentView()setCustomBigContentView()setCustomHeadsUpContentView()
Existing RemoteViews belong to home-screen widgets:
Those widgets are not notification views.
Android 17 change
Android 17 introduces stricter size and memory checks for custom notification views and closes a loophole that allowed resources referenced through URIs to bypass existing limits.
Android defines a custom notification layout as a RemoteViews supplied through APIs such as:
NotificationCompat.DecoratedCustomViewStyle()
setCustomContentView(remoteViews)
setCustomBigContentView(expandedRemoteViews)
References:
The Android 17 summary currently points to a nonexistent section on the main behaviour-change page. That broken anchor is not used as evidence in this report.
Mitigation
No code migration is currently required.
Before releasing with target API 37, test:
- Collapsed and expanded notifications
- Heads-up notifications
- Grouped and summary notifications
- Lock-screen and public notifications
- Notifications with contact pictures
- Notifications with multiple actions
Reassess this behaviour if Thunderbird introduces notification layouts backed by RemoteViews.
Changes reviewed with no expected impact
| Android 17 change | Thunderbird assessment |
|---|---|
| Static final fields become unmodifiable | No production code was found modifying static final fields through reflection or JNI. |
| Safer native dynamic code loading | No System.load() or System.loadLibrary() call was found in application source. |
| Restricted Contacts Provider fields | Thunderbird’s reviewed projections do not request ACCOUNT_NAME, ACCOUNT_TYPE, or ACCOUNT_TYPE_AND_DATA_SET from ContactsContract.Data. |
| Strict Contacts Provider SQL checks | Reviewed contact queries check permission and do not use the newly restricted columns. Denied-permission testing remains advisable. |
| Background audio hardening | Thunderbird does not perform background media playback or directly manage audio focus. Notification sounds are handled by Android notification channels. |
| Large-screen orientation restrictions | Activities are already configured as resizable and do not impose incompatible orientation or aspect-ratio restrictions. |
| Bluetooth RFCOMM behaviour | No Bluetooth RFCOMM socket use was found. |
| SMS OTP protections | Thunderbird does not read SMS or extract SMS one-time passwords. |
| Touchpad pointer capture | No pointer-capture API use was found. |
| Per-application Android Keystore limits | No Android Keystore key-generation path likely to approach the new limit was found. |
| NPU feature declaration | Thunderbird does not access neural processing unit APIs. |
| Autonomous Bluetooth repairing | No Bluetooth bond-management code was found. |
| Global keyboard shortcuts | No conflict with the newly reserved shortcuts was identified. |
| Cleartext traffic deprecation plan | This is a future change rather than an Android 17 enforcement change. Thunderbird already has a Network Security Configuration file. |
Relevant documentation:
- Static final fields
- Safer native dynamic code loading
- Contacts Provider PII restrictions
- Strict Contacts Provider SQL checks
- Background audio hardening
- Large-screen restrictions
- Bluetooth RFCOMM behaviour
- SMS OTP protection
Recommended implementation order
- Implement local-network permission handling.
- Upgrade Robolectric and migrate legacy looper tests.
- Update the recipient editor’s custom
InputConnection. - Run Android 17 memory profiling.
- Test keyboard behaviour after configuration changes.
- Narrow the OpenPGP background activity-launch allowance.
- Complete ECH and Certificate Transparency interoperability testing.
- Run the complete Android 17 notification and WebView test matrix.
Verification status
This was a static compatibility audit.
- No repository files were changed.
- No Gradle tasks were run because no implementation was performed.
- Android 17 device and emulator validation remains required for the runtime-dependent findings.
- Existing local modifications to
ThunderbirdProjectConfig.ktandgradle/gradle-daemon-jvm.propertieswere left unchanged.
Verification status
This was a static compatibility audit.
- No repository files were changed.
- No Gradle tasks were run because no implementation was performed.
- Android 17 device and emulator validation remains required for the runtime-dependent findings.
- Existing local modifications to
ThunderbirdProjectConfig.ktandgradle/gradle-daemon-jvm.propertieswere left
unchanged.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the Android 17 behaviour-change pages and ThunderbirdProjectConfig.kt, then verify the report against the named AndroidManifest.xml, protocol connection classes, TokenCompleteTextView.java, RecipientSelectView.java, libs.versions.toml, and the four listed test classes. Done means each valid compatibility change has a separate GitHub issue and the behaviour-change documentation has been rechecked for omissions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, java, kotlin
- Domain
- build-system, mobile-dev, testing-qa
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100