From f27ebe295f1e77b6ed88e2928f52fd2024833bdb Mon Sep 17 00:00:00 2001 From: KonradIT Date: Sat, 29 Aug 2026 12:24:17 +0200 Subject: [PATCH] fix: opt into edge-to-edge explicitly on both activities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Play flagged the app for relying on the implicit targetSdk-35 edge-to-edge default. Both activities now call enableEdgeToEdge(), which is the fix Google's notice asks for and also collapses two divergent layouts into one: before this, API 29-34 kept opaque system bars while 35+ went edge-to-edge, so whichever device you happened to test on told you nothing about the other. That gap is what let the preview screen ship with cream bars on Android 10 while looking correct on Android 17. The preview screen's Build.VERSION.SDK_INT < 35 branch for black bars is replaced by SystemBarStyle.dark(BLACK), which covers both routes in one call — it paints the scrim where the bars are opaque and goes transparent over the layout's black root where they are not. androidx.activity is pinned at 1.9.3 rather than taken transitively from appcompat, which was supplying 1.8.0. Also clamps the floating scrub-preview bubble to the status-bar inset instead of to y=0, so a short screen cannot push it under the clock, and corrects the themes.xml comment: those bar-colour items no longer decide anything now that enableEdgeToEdge owns bar appearance. Verified on Pixel 10 (API 37) and Mi Pad 4 (API 29): camera list on both, and the preview screen on the Mi Pad, which is the case that regressed. Co-Authored-By: Claude Opus 5 (1M context) --- app/build.gradle | 3 ++ .../konraditurbe/osmosis/ui/MainActivity.kt | 7 ++++ .../osmosis/ui/MediaPreviewActivity.kt | 39 +++++++++---------- app/src/main/res/values/themes.xml | 11 ++++-- 4 files changed, 36 insertions(+), 24 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3d71ee0..1782dd0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -68,6 +68,9 @@ android { dependencies { implementation 'androidx.core:core-ktx:1.9.0' + // Pinned rather than taken transitively from appcompat: enableEdgeToEdge() (used by both + // activities) landed in 1.8.0 and the edge-to-edge backport was refined for SDK 35 after it. + implementation 'androidx.activity:activity:1.9.3' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.10.0' implementation 'androidx.recyclerview:recyclerview:1.3.2' diff --git a/app/src/main/java/dev/konraditurbe/osmosis/ui/MainActivity.kt b/app/src/main/java/dev/konraditurbe/osmosis/ui/MainActivity.kt index 1a1f674..99d5fd1 100644 --- a/app/src/main/java/dev/konraditurbe/osmosis/ui/MainActivity.kt +++ b/app/src/main/java/dev/konraditurbe/osmosis/ui/MainActivity.kt @@ -23,6 +23,7 @@ import androidx.appcompat.app.AppCompatActivity import android.net.LinkProperties import android.net.Network import androidx.activity.OnBackPressedCallback +import androidx.activity.enableEdgeToEdge import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.core.view.ViewCompat @@ -271,6 +272,12 @@ class MainActivity : AppCompatActivity(), OsmoScanner.Listener, GattClient.Liste override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + // Opt in explicitly instead of inheriting the targetSdk-35 default, so every supported release + // behaves the same way. Without it, API 29-34 keeps opaque system bars while 35+ goes + // edge-to-edge, which is two layouts to reason about and only one of them gets tested on the + // device in front of you. The bar icon polarity auto()-picks off the system dark mode, matching + // what @bool/osmo_light_system_bars does for the pre-35 theme. + enableEdgeToEdge() setContentView(R.layout.activity_main) // targetSdk 35+ forces edge-to-edge: android:statusBarColor/navigationBarColor in the theme are // ignored and the window draws under the bars. Pad the root by the bar + cutout insets so the diff --git a/app/src/main/java/dev/konraditurbe/osmosis/ui/MediaPreviewActivity.kt b/app/src/main/java/dev/konraditurbe/osmosis/ui/MediaPreviewActivity.kt index 8c36eb2..cac504c 100644 --- a/app/src/main/java/dev/konraditurbe/osmosis/ui/MediaPreviewActivity.kt +++ b/app/src/main/java/dev/konraditurbe/osmosis/ui/MediaPreviewActivity.kt @@ -5,7 +5,8 @@ import android.content.Intent import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri -import android.os.Build +import androidx.activity.SystemBarStyle +import androidx.activity.enableEdgeToEdge import android.os.Bundle import android.os.Handler import android.os.Looper @@ -99,28 +100,22 @@ class MediaPreviewActivity : AppCompatActivity() { private lateinit var scrubTime: TextView private val scrubFrames by lazy { ScrubFrames { Log.i("Osmosis", it) } } + /** Newest status-bar/cutout inset, kept so the floating scrub bubble can clamp against it. */ + private var topInsetPx = 0 + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + // Full-screen media viewer: black bars with light icons on every supported release (the app's + // cream theme sets the opposite, which is unreadable over a dark preview). SystemBarStyle.dark + // is what makes this one call cover both platform routes — it paints the scrim on the API 29-34 + // devices, where the bars are opaque and used to need window.statusBarColor, and goes fully + // transparent over the layout's black root from 35 on, where those setters are ignored. + enableEdgeToEdge( + statusBarStyle = SystemBarStyle.dark(android.graphics.Color.BLACK), + navigationBarStyle = SystemBarStyle.dark(android.graphics.Color.BLACK), + ) setContentView(R.layout.activity_preview) - // Full-screen media viewer: light bar icons (the app's cream theme sets the opposite), so they - // stay readable over the dark preview. - // - // The bars go black by two different routes depending on the platform, and BOTH are needed - // because minSdk is 29. From targetSdk 35 the window is edge-to-edge, statusBarColor and - // navigationBarColor are ignored, and the bars are transparent over the layout's black root. - // On API 29-34 there is no edge-to-edge: the bars are opaque and painted from these setters, - // so dropping them leaves the theme's cream showing behind white icons. - if (Build.VERSION.SDK_INT < 35) { - @Suppress("DEPRECATION") - window.statusBarColor = android.graphics.Color.BLACK - @Suppress("DEPRECATION") - window.navigationBarColor = android.graphics.Color.BLACK - } - androidx.core.view.WindowCompat.getInsetsController(window, window.decorView).apply { - isAppearanceLightStatusBars = false - isAppearanceLightNavigationBars = false - } // The media itself is meant to run full-bleed under the bars; only the overlays get inset. The // insets are ADDED to each overlay's own layout padding, and the base padding is captured once // so re-dispatches (rotation, IME, bar show/hide) don't accumulate. @@ -134,6 +129,7 @@ class MediaPreviewActivity : AppCompatActivity() { androidx.core.view.WindowInsetsCompat.Type.systemBars() or androidx.core.view.WindowInsetsCompat.Type.displayCutout() ) + topInsetPx = bars.top for ((v, base) in basePadding) { val top = if (v in topOverlays) bars.top else 0 val bottom = if (v in bottomOverlays) bars.bottom else 0 @@ -648,7 +644,10 @@ class MediaPreviewActivity : AppCompatActivity() { val margin = 8 * resources.displayMetrics.density val maxX = (previewRoot.width - w - margin).coerceAtLeast(margin) scrubPreview.translationX = (thumbX - w / 2f).coerceIn(margin, maxX) - scrubPreview.translationY = (bar[1] - root[1] - h - margin).coerceAtLeast(0f) + // Floor at the status-bar inset, not at 0: the root runs edge-to-edge, so a bubble pushed to + // the top of the window (short screen, tall bubble) would otherwise land under the clock. + scrubPreview.translationY = + (bar[1] - root[1] - h - margin).coerceAtLeast(topInsetPx.toFloat()) } /** Once the thumb stops moving, pull the keyframe actually under it (debounced from the drag). */ diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 66d3855..ac9675b 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -17,10 +17,13 @@ @color/osmo_muted @color/osmo_track - + ?android:attr/colorBackground ?android:attr/colorBackground @bool/osmo_light_system_bars