Skip to content

Conversation

@mzorz
Copy link
Contributor

@mzorz mzorz commented Aug 2, 2025

This PR sits on top of #1733

Fix

Checked the migration tool (Android SDK upgrade assistant) on Android Studio, the path "Android 14 / API level 34 -> Android 15 / API level 35"

These are the checcks performed.

Open JDK API:

  • 1) changes to formatting strings API

Validation of argument index, flags, width, and precision are now more strict when using the following String.format() and Formatter.format() APIs:
String.format(String, Object[])
String.format(Locale, String, Object[])
Formatter.format(String, Object[])
Formatter.format(Locale, String, Object[])
For example, the following exception is thrown when an argument index of 0 is used (%0 in the format string):

  • 2) Changes to component type of Arrays.asList().toArray()

When using Arrays.asList(...).toArray(), the component type of the resulting array is now an Object—not the type of the underlying array's elements. So the following code throws a ClassCastException:
String[] elements = (String[]) Arrays.asList("one", "two").toArray();
For this case, to preserve String as the component type in the resulting array, you could use Collection.toArray(Object[]) instead:
String[] elements = Arrays.asList("two", "one").toArray(new String[0]);

  • Changes to language code handling

When using the Locale API, language codes for Hebrew, Yiddish, and Indonesian are no longer converted to their obsolete forms (Hebrew: iw, Yiddish: ji, and Indonesian: in). When specifying the language code for one of these locales, use the codes from ISO 639-1 instead (Hebrew: he, Yiddish: yi, and Indonesian: id).

  • SequencedCollection collisions

The new SequencedCollection API can affect your app's compatibility after you update compileSdk in your app's build configuration to use Android 15 (API level 35):
Collision with MutableList.removeFirst() and MutableList.removeLast() extension functions in kotlin-stdlib
The List type in Java is mapped to the MutableList type in Kotlin. Because the List.removeFirst() and List.removeLast() APIs have been introduced in Android 15 (API level 35), the Kotlin compiler resolves function calls, for example list.removeFirst(), statically to the new List APIs instead of to the extension functions in kotlin-stdlib.

If an app is re-compiled with compileSdk set to 35 and minSdk set to 34 or lower, and then the app is run on Android 14 and lower, a runtime error is thrown:

We don't use those methods so all good.

  • Collision with other methods in Java

New methods have been added into the existing types, for example, List and Deque. These new methods might not be compatible with the methods with the same name and argument types in other interfaces and classes. In the case of a method signature collision with incompatibility, the javac compiler outputs a build-time error

Since it will fail at compile time, it's fine atm.

Secured background activity launches

In addition to the restriction for UID matching, these other changes are also included:
Change PendingIntent creators to block background activity launches by default. This helps prevent apps from accidentally creating a PendingIntent that could be abused by malicious actors.
Don't bring an app to the foreground unless the PendingIntent sender allows it. This change aims to prevent malicious apps from abusing the ability to start activities in the background. By default, apps are not allowed to bring the task stack to the foreground unless the creator allows backgrounds activity launch privileges or the sender has background activity launch privileges.
Control how the top activity of a task stack can finish its task. If the top activity finishes a task, Android will go back to whichever task was last active. Moreover, if a non-top activity finishes its task, Android will go back to the home screen; it won't block the finish of this non-top activity.
Prevent launching arbitrary activities from other apps into your own task. This change prevents malicious apps from phishing users by creating activities that appear to be from other apps.
Block non-visible windows from being considered for background activity launches. This helps prevent malicious apps from abusing background activity launches to display unwanted or malicious content to users.

  • Nothing outstanding in the app related to this.

Safer intents

Android 15 introduces new optional security measures to make intents safer and more robust. These changes are aimed at preventing potential vulnerabilities and misuse of intents that can be exploited by malicious apps. There are two main improvements to the security of intents in Android 15:
Match target intent-filters: Intents that target specific components must accurately match the target's intent-filter specifications. If you send an intent to launch another app's activity, the target intent component needs to align with the receiving activity's declared intent-filters.
Intents must have actions: Intents without an action will no longer match any intent-filters. This means that intents used to start activities or services must have a clearly defined action.
Important: a PendingIntent acts as a wrapper for a standard Intent, so these security measures apply to the Intent contained within the PendingIntent.

  • Checked our intents, didn't spot anything weird - it seems an action is defined every time I've seen Intent or PendingIntent being used.

⚠️ Window inset changes: edge-to-edge enforcement

The most important from what I could consider was edge to edge enforcement , and the deprecation of the folowing APIs:

The following APIs are deprecated and disabled:
R.attr#navigationBarColor (for gesture navigation)
R.attr#navigationBarDividerColor
R.attr#statusBarColor
Window#setDecorFitsSystemWindows
Window#getNavigationBarColor
Window#getNavigationBarDividerColor
Window#getStatusBarColor
Window#setNavigationBarColor (for gesture navigation)
Window#setNavigationBarDividerColor
Window#setStatusBarColor
  • This PR addresses this implementing ViewCompat.setOnApplyWindowInsetsListener.

Window inset changes: stable configuration

If your app targets Android 15 (API level 35) or higher, Configuration no longer excludes the system bars. If you use the screen size in the Configuration class for layout calculation, you should replace it with better alternatives like an appropriate ViewGroup, WindowInsets, or WindowMetricsCalculator depending on your need

  • The app doesn't use it to look for screen size but only to check orientation. Should be safe.

elegant TextHeight attribute defaults to true

  • We don't use this.

TextView width changes for complex letter shapes

In previous versions of Android, some cursive fonts or languages that have complex shaping might draw the letters in the previous or next character's area. In some cases, such letters were clipped at the beginning or ending position. Starting in Android 15, a TextView allocates width for drawing enough space for such letters and allows apps to request extra paddings to the left to prevent clipping.

  • this app doesn't use cursive fonts

Locale-aware default line height for EditText

image
  • tested on several locales, didn't observe a problem on Android 15.

Test

See a video testing dark mode, light mode, different settings, 3-button navigation, gesture navigation etc. here:
https://cloudup.com/c9IM1DZks44

Smoke test on Android 15 and Android < 15, visit all the screens:

  • splash screen
  • sign up
  • log in
  • settings
  • notes list
  • editor
  • lock screen ("enter code")
  • fingerprint check
  • about screen
  • collaborators list
  • tags list

Review

Release

@mzorz mzorz added this to the Future milestone Aug 2, 2025
@mzorz mzorz added the [Type] Debt Technical debt. label Aug 2, 2025
@dangermattic
Copy link
Collaborator

dangermattic commented Aug 2, 2025

1 Warning
⚠️ This PR is larger than 300 lines of changes. Please consider splitting it into smaller PRs for easier and faster reviews.

Generated by 🚫 Danger

@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Aug 2, 2025

📲 You can test the changes from this Pull Request in Simplenote Android by scanning the QR code below to install the corresponding build.

App Name Simplenote Android
Build TypeDebug
Commitdd575ff
Direct Downloadsimplenote-android-prototype-build-pr1737-dd575ff-01987b6b-2ce1-4d17-8edf-4e50efdd3568.apk

mzorz added 7 commits August 3, 2025 11:22
… behind the status bar since the deprecated statusBarColor API no longer works. By ensuring the AppBarLayout has the proper background color and extends behind the status bar, the blue system background is no longer visible.
…activities. Also fixed insets in About screen
@mzorz mzorz marked this pull request as ready for review August 3, 2025 12:05
@theck13
Copy link
Contributor

theck13 commented Aug 3, 2025

Thanks for updating Simplenote! Using the pull request APK above for testing, I saw some oddities that might be good to address before merging these changes.

The floating action button on the Collaborators and Edit Tags screens overlaps the system navigation bar. It's a little easier to see with three-button navigation, but it still happens with gesture navigation since the button shadow is clipped for API 32. I created #1739 and targeted the mzorz/update-targetsdk-35 branch with code changes to fix that.

When tapping the Add Collaborator floating action button on the Collaborators screen, the transition from floating action button to dialog no longer animates. The transition animation still occurs for the Add Tag floating action button on the Edit Tags screen though. See the videos below for illustration.

Videos

Collaborators Edit Tags
collaborators.mp4
tags.mp4

When logged out, the Log In button is behind the system navigation bar on API 36, but not API 32. See the screenshots below for illustration.

Screenshots

1737_update_android_15_credentials

If the device has a cutout, then multiple screens are displayed behind it in landscape orientation. Also, the ellipsis/overflow button in the top app bar is behind the system navigation bar on the note editor screen as shown in the first screenshot. See the screenshots below for illustration.

Note

The screenshots below are from a Pixel 9 API 36.

Screenshots

1737_update_android_15_landscape

@ParaskP7 ParaskP7 requested a review from Copilot August 4, 2025 07:45
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR updates the Simplenote Android app for Android 15 (API level 35) compatibility by addressing deprecated system bar APIs and implementing edge-to-edge display. The changes ensure compatibility with Android 15's enforcement of edge-to-edge design and removal of deprecated status bar and navigation bar color APIs.

  • Updates target SDK version from 34 to 35 for both main app and Wear module
  • Creates API 35-specific style resources that remove deprecated navigationBarColor and statusBarColor attributes
  • Implements comprehensive edge-to-edge display support with proper WindowInsets handling across all activities

Reviewed Changes

Copilot reviewed 30 out of 31 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Simplenote/build.gradle Updates targetSdkVersion to 35
Wear/build.gradle Updates targetSdkVersion to 35
Simplenote/src/main/res/values-v35/styles.xml API 35 compatible styles with deprecated attributes removed
Simplenote/src/main/res/values-night-v35/styles.xml Night theme API 35 compatible styles
SystemBarUtils.java New utility class for edge-to-edge display and system bar handling
DisplayUtils.java Added WindowInsets support for FloatingActionButton positioning
Multiple activity files Integration of edge-to-edge display with proper insets handling
Multiple layout files Layout adjustments for edge-to-edge compatibility
Comments suppressed due to low confidence (5)

Simplenote/src/main/java/com/automattic/simplenote/utils/SystemBarUtils.java:40

  • Build.VERSION_CODES.VANILLA_ICE_CREAM does not exist in the Android SDK. Android 15 uses API level 35, but this constant is not available. Use Build.VERSION_CODES.UPSIDE_DOWN_CAKE (API 34) + 1 or the numeric value 35 instead.
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {

Simplenote/src/main/java/com/automattic/simplenote/utils/SystemBarUtils.java:63

  • Build.VERSION_CODES.VANILLA_ICE_CREAM does not exist in the Android SDK. Use the numeric value 35 or Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1 instead.
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.VANILLA_ICE_CREAM) {

Simplenote/src/main/java/com/automattic/simplenote/authentication/SimplenoteAuthenticationActivity.java:68

  • Build.VERSION_CODES.VANILLA_ICE_CREAM does not exist in the Android SDK. Use the numeric value 35 for Android 15 instead.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {

Simplenote/src/main/java/com/automattic/simplenote/AddTagActivity.kt:45

  • Build.VERSION_CODES.VANILLA_ICE_CREAM does not exist in the Android SDK. Use the numeric value 35 for Android 15 instead.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {

PasscodeLock/src/main/java/org/wordpress/passcodelock/PasscodeManagePasswordActivity.java:26

  • Build.VERSION_CODES.VANILLA_ICE_CREAM does not exist in the Android SDK. Use the numeric value 35 for Android 15 instead.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {

…'t show too close to the sign up and login butons
@theck13
Copy link
Contributor

theck13 commented Aug 4, 2025

When tapping the Add Collaborator floating action button on the Collaborators screen, the transition from floating action button to dialog no longer animates. The transition animation still occurs for the Add Tag floating action button on the Edit Tags screen though. See the videos below for illustration.

Videos

Collaborators Edit Tags
collaborators.mp4
tags.mp4

Since this also occurs in Simplenote 2.35, the bug wasn't introduced with these changes. So, I created a new issue (#1740) to fix that separately.

There is something different with the Add Tag transition animation that is due to these changes. The dialog is not centered in the resized window when the virtual keyboard is shown. See the videos below for illustration.

Videos

Before After
before.mp4
after.mp4

That's most likely due to the window insets. It's not really a problem on some devices like the Pixel 9 in the videos above, but it may be a problem with shorter devices if the dialog is obscured behind the keyboard and the dialog buttons can't be tapped.

@mzorz
Copy link
Contributor Author

mzorz commented Aug 4, 2025

Thanks for the follow up @theck13 ! I'm so glad you're around to catch all these details 🙏

I updated the code to handle insets in the Add Tags screen in b75d859, solving both the animation and pushing the keyboard up now, as shown in the video here:

Screen.Recording.2025-08-04.at.9.40.07.PM.mov

@theck13
Copy link
Contributor

theck13 commented Aug 4, 2025

No problem, @mzorz! I'm so glad you're updating Simplenote.

I tested simplenote-android-prototype-build-pr1737-b75d859-0198769a-0772-4977-b549-1dca9c8ef171.apk on API 32 and 36. The only super minor thing I noticed was the status icon colors are dark now when they were light before. See the screenshots below for illustration.

Screenshots

1737_update_android_15_tags_dialog_36

I don't think that should hold up these changes though. So, it looks good to me! Approved!

@mzorz
Copy link
Contributor Author

mzorz commented Aug 4, 2025

The only super minor thing I noticed was the status icon colors are dark now when they were light before. See the screenshots below for illustration.

Another great catch 🙌 - addressed in e387f83 ❤️

I don't think that should hold up these changes though. So, it looks good to me! Approved!

😄 thanks much Tyler! You're awesome 😍

@mzorz
Copy link
Contributor Author

mzorz commented Aug 5, 2025

One thing @Twinsen81 caught in testing:

the first one is the login screen on prod, the second one - in the app (to repro, click LOG IN on the start screen):
Pixel 6 Pro, light mode, Android 16

Prod This PR
image image

I'm working on it, it may require changing things in the Simperium library.

@mzorz
Copy link
Contributor Author

mzorz commented Aug 5, 2025

Tracking the above separately in #1741 to produce another PR to keep this PR more contained.

@ParaskP7
Copy link
Contributor

ParaskP7 commented Aug 5, 2025

See a video testing dark mode, light mode, different settings, 3-button navigation, gesture navigation etc. here:

Oook, what you did here @mzorz is a brilliant, brilliant idea, thank you for posting the recording! ❤️ 🥇 💯

@ParaskP7
Copy link
Contributor

ParaskP7 commented Aug 5, 2025

👋 @theck13 so nice to hear from you, it's been a while, plus, many thanks for all the help! ❤️ 🙇 ❤️

Copy link
Contributor

@ParaskP7 ParaskP7 left a comment

Choose a reason for hiding this comment

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

👋 @mzorz !

I have (quickly) reviewed and (quickly) tested this PR, I'll just leave a 👍 here and move my focus on #1738 leaving the primary review and ✅ to the other reviewers. Great job with making this app work on Android 15, adding edge-to-edge support and all, this is awesome! 🌟 x 🌟 ^ 🌟


Just an FYI that during testing I noticed the following, which I am pretty sure you're already aware of:

  • The logged-out screens are a bit off, theme-wise, especially the login screen (context). 🤔
  • While trying to Publish a test note, I got an error at first, then noticed that the note is published anyway, then tried to unpublish/publish again and everything worked as expected this time around. Not sure if that's related to any changes you did here, most likely not, just just wanted to live a trace... 🤷

@mzorz
Copy link
Contributor Author

mzorz commented Aug 5, 2025

Thank you for your testing here @ParaskP7 !

Yes, that's being tackled separately in #1741 and will involve making changes to the Simperium library since it hosts the base authentication screens

  • While trying to Publish a test note, I got an error at first, then noticed that the note is published anyway, then tried to unpublish/publish again and everything worked as expected this time around. Not sure if that's related to any changes you did here, most likely not, just just wanted to live a trace... 🤷

That must be a backend issue 👍 - let's file it if we find it again

@ParaskP7
Copy link
Contributor

ParaskP7 commented Aug 5, 2025

Yes, that's being tackled separately in #1741 and will involve making changes to the Simperium library since it hosts the base authentication screens

Awesome, yes, noted @mzorz and thanks! 👍

That must be a backend issue 👍 - let's file it if we find it again

I agree! 👍

Base automatically changed from mzorz/update-compose-android-and-kotlin-libs to trunk August 5, 2025 15:04
@mzorz
Copy link
Contributor Author

mzorz commented Aug 5, 2025

  • ✅ this issue where content couldn't be scrolled and the virtual keyboard was hiding it was fixed in dd575ff in this PR

@ParaskP7
Copy link
Contributor

ParaskP7 commented Aug 6, 2025

✅ this #1738 (comment) where content couldn't be scrolled and the virtual keyboard was hiding it was fixed in dd575ff in this PR

Nicely done @mzorz , I just tested it and it works as expected, thank YOU! 🙇 ❤️ 🚀

Copy link

@obsantos obsantos left a comment

Choose a reason for hiding this comment

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

Thanks for all the changes, tested and works! 💯

@mzorz mzorz merged commit 50426bf into trunk Aug 7, 2025
15 checks passed
@mzorz mzorz deleted the mzorz/update-targetsdk-35 branch August 7, 2025 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants