diff --git a/src/Uno.UI/UI/Xaml/Application.Android.cs b/src/Uno.UI/UI/Xaml/Application.Android.cs index 408f4006fcba..3c1991f18086 100644 --- a/src/Uno.UI/UI/Xaml/Application.Android.cs +++ b/src/Uno.UI/UI/Xaml/Application.Android.cs @@ -10,6 +10,7 @@ using Microsoft.UI.Xaml.Controls.Primitives; using Windows.UI.ViewManagement; using Colors = Microsoft.UI.Colors; +using Uno.UI.Xaml.Controls; namespace Microsoft.UI.Xaml; @@ -33,10 +34,11 @@ static partial void StartPartial(ApplicationInitializationCallback callback) partial void ApplySystemOverlaysTheming() { - var requestedTheme = InternalRequestedTheme; - - StatusBar.GetForCurrentView().ForegroundColor = requestedTheme == ApplicationTheme.Dark - ? Colors.White - : Colors.Black; + // This is needed only due to the fact that currently Instance accessor creates the wrapper + // eagerly - which could then happen too early. Will no longer be needed when un-singletoned. + if (InitializationComplete) + { + NativeWindowWrapper.Instance.ApplySystemOverlaysTheming(); + } } } diff --git a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.Android.cs b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.Android.cs index c6f52471dd7b..9827a3405950 100644 --- a/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.Android.cs +++ b/src/Uno.UI/UI/Xaml/Window/Native/NativeWindowWrapper.Android.cs @@ -3,14 +3,12 @@ using Android.Runtime; using Android.Util; using Android.Views; -using AndroidX.AppCompat.App; using AndroidX.Core.View; using Uno.Disposables; using Uno.Foundation.Logging; using Uno.UI.Extensions; using Windows.ApplicationModel.Core; using Windows.Foundation; -using Windows.Graphics; using Windows.Graphics.Display; using Windows.UI.Core; using Windows.UI.ViewManagement; @@ -78,6 +76,7 @@ internal void RaiseNativeSizeChanged() Bounds = new Rect(default, windowSize); VisibleBounds = visibleBounds; Size = new((int)(windowSize.Width * RasterizationScale), (int)(windowSize.Height * RasterizationScale)); + ApplySystemOverlaysTheming(); if (_previousTrueVisibleBounds != visibleBounds) { @@ -88,7 +87,11 @@ internal void RaiseNativeSizeChanged() } } - protected override void ShowCore() => RemovePreDrawListener(); + protected override void ShowCore() + { + ApplySystemOverlaysTheming(); + RemovePreDrawListener(); + } private (Size windowSize, Rect visibleBounds) GetVisualBounds() { @@ -103,6 +106,9 @@ internal void RaiseNativeSizeChanged() Rect windowBounds; Rect visibleBounds; + var decorView = activity.Window.DecorView; + var fitsSystemWindows = decorView.FitsSystemWindows; + if ((int)Android.OS.Build.VERSION.SdkInt < 35) { var opaqueInsetsTypes = insetsTypes; @@ -134,9 +140,19 @@ internal void RaiseNativeSizeChanged() this.Log().LogDebug($"Insets: {insets}"); } - // Edge-to-edge is default on Android 15 and above - windowBounds = new Rect(default, GetWindowSize()); - visibleBounds = windowBounds.DeflateBy(insets); + if (fitsSystemWindows) + { + // The window bounds are the same as the display size, as the system insets are already taken into account by the layout + windowBounds = new Rect(default, GetWindowSize().Subtract(insets)); + visibleBounds = windowBounds; + } + else + { + // Edge-to-edge is default on Android 15 and above + windowBounds = new Rect(default, GetWindowSize()); + visibleBounds = windowBounds.DeflateBy(insets); + } + } if (this.Log().IsEnabled(LogLevel.Debug)) @@ -178,6 +194,25 @@ private WindowInsetsCompat GetWindowInsets(Activity activity) return null; } + internal void ApplySystemOverlaysTheming() + { + if ((int)Android.OS.Build.VERSION.SdkInt >= 35) + { + // In edge-to-edge experience we want to adjust the theming of status bar to match the app theme. + if ((ContextHelper.TryGetCurrent(out var context)) && + context is Activity activity && + activity.Window?.DecorView is { FitsSystemWindows: false } decorView) + { + var requestedTheme = Microsoft.UI.Xaml.Application.Current.RequestedTheme; + + var insetsController = WindowCompat.GetInsetsController(activity.Window, decorView); + + // "appearance light" refers to status bar set to light theme == dark foreground + insetsController.AppearanceLightStatusBars = requestedTheme == Microsoft.UI.Xaml.ApplicationTheme.Light; + } + } + } + private Size GetWindowSize() { if (ContextHelper.Current is not Activity activity) diff --git a/src/Uno.UWP/UI/ViewManagement/StatusBar/StatusBar.Android.cs b/src/Uno.UWP/UI/ViewManagement/StatusBar/StatusBar.Android.cs index f009a9ed0db7..30911e98dd50 100644 --- a/src/Uno.UWP/UI/ViewManagement/StatusBar/StatusBar.Android.cs +++ b/src/Uno.UWP/UI/ViewManagement/StatusBar/StatusBar.Android.cs @@ -143,7 +143,7 @@ internal void UpdateSystemUiVisibility() } } - // A bit confusingly, "appearance light" refers to light theme, so in dark foreground is used! + // A bit confusingly, "appearance light" refers to light theme, so dark foreground is used! insetsController.AppearanceLightStatusBars = _foregroundType == StatusBarForegroundType.Dark; } }