diff --git a/build/android/app/src/main/java/com/wails/app/MainActivity.java b/build/android/app/src/main/java/com/wails/app/MainActivity.java index 70b9c14..0840ded 100644 --- a/build/android/app/src/main/java/com/wails/app/MainActivity.java +++ b/build/android/app/src/main/java/com/wails/app/MainActivity.java @@ -31,9 +31,16 @@ import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; +import android.view.View; + import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.FileProvider; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsControllerCompat; import androidx.webkit.WebViewAssetLoader; import org.json.JSONObject; @@ -88,6 +95,10 @@ public class MainActivity extends AppCompatActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + // Before anything renders: the page is laid out inside the + // window, and on Android 15 the window is the whole screen. + applyWindowInsets(); + // Initialize the native Go library bridge = new WailsBridge(this); bridge.initialize(); @@ -892,8 +903,61 @@ public class MainActivity extends AppCompatActivity { } } + /** + * Keep the web content inside the safe area. + * + *

targetSdk 35 is Android 15, which lays every app out + * edge-to-edge and ignores the {@code statusBarColor} and + * {@code navigationBarColor} this app's theme still sets. The + * WebView is {@code match_parent}, so the page's bottom band -- the + * transport and, on a phone, the tab bar -- was drawn underneath the + * gesture bar and reported from a device as "I can't see the + * playback controls, they seem to be off screen". + * + *

No web-tier test can see this: a browser viewport has no system + * bars, so the phone specs at 390x844 render a shell that fits + * while the device does not. + * + *

The insets are applied as padding and the window insets are + * returned rather than consumed, so the WebView is laid out inside + * them. {@code ime()} is in the mask because the same reasoning + * covers the keyboard: a focused search box that the keyboard + * covers is the same bug one surface over. + */ + private void applyWindowInsets() { + final View container = findViewById(R.id.main_container); + + if (container == null) { + return; + } + + ViewCompat.setOnApplyWindowInsetsListener(container, (view, windowInsets) -> { + Insets insets = windowInsets.getInsets( + WindowInsetsCompat.Type.systemBars() + | WindowInsetsCompat.Type.displayCutout() + | WindowInsetsCompat.Type.ime()); + + view.setPadding(insets.left, insets.top, insets.right, insets.bottom); + + return windowInsets; + }); + + // The padded band shows the window background, which is dark + // (this app's own default ramp is black), so the system's icons + // have to be the light set or they vanish into it. The theme is + // DayNight and would otherwise ask for dark icons in light mode. + WindowInsetsControllerCompat controller = + WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView()); + + controller.setAppearanceLightStatusBars(false); + controller.setAppearanceLightNavigationBars(false); + } + @Override public void onBackPressed() { + // The frontend records every navigation as a history entry, so + // this is the app's own back stack: `canGoBack()` is false only + // at the launch entry, which is where back should leave. if (webView != null && webView.canGoBack()) { webView.goBack(); } else { diff --git a/build/android/app/src/main/res/values/colors.xml b/build/android/app/src/main/res/values/colors.xml index dd33f3b..96d4c17 100644 --- a/build/android/app/src/main/res/values/colors.xml +++ b/build/android/app/src/main/res/values/colors.xml @@ -2,7 +2,12 @@ #3574D4 #2C5FB8 - #1B2636 + + #000000 #FFFFFFFF #FF000000