Skip to content

Commit a380db6

Browse files
kubafloCopilot
authored andcommitted
[release/10.0.1xx-sr10] Fix Material 3 status bar contrast (#37730)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1e7f77e3-4862-4b92-a662-d12b5918bb59
1 parent 2dc09e6 commit a380db6

2 files changed

Lines changed: 64 additions & 10 deletions

File tree

src/Core/src/Platform/Android/WindowExtensions.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,26 +59,34 @@ internal static void ConfigureTranslucentSystemBars(this Window? window, Activit
5959
var isLightTheme = configuration is null ||
6060
(configuration.UiMode & UiMode.NightMask) != UiMode.NightYes;
6161

62-
// Resolve the actual status bar background color from the current theme and
63-
// choose icon/text appearance based on its luminance. If the theme color cannot
64-
// be resolved, preserve the previous theme-based behavior.
65-
if (TryGetThemeColor(activity, global::Android.Resource.Attribute.ColorPrimary, out var statusBarColor))
66-
windowInsetsController.AppearanceLightStatusBars = IsLightColor(statusBarColor);
67-
else
68-
windowInsetsController.AppearanceLightStatusBars = isLightTheme;
62+
windowInsetsController.AppearanceLightStatusBars =
63+
GetStatusBarAppearance(activity, isLightTheme, RuntimeFeature.IsMaterial3Enabled);
6964

7065
windowInsetsController.AppearanceLightNavigationBars = isLightTheme;
7166
}
7267
}
7368

74-
static bool TryGetThemeColor(Activity activity, int attribute, out AColor color)
69+
internal static bool GetStatusBarAppearance(Context context, bool isLightTheme, bool isMaterial3)
70+
{
71+
// Material 3 draws its surface behind the transparent edge-to-edge status bar.
72+
// The Material 2 app bar uses colorPrimary in the same area.
73+
var backgroundAttribute = isMaterial3
74+
? Resource.Attribute.colorSurface
75+
: global::Android.Resource.Attribute.ColorPrimary;
76+
77+
return TryGetThemeColor(context, backgroundAttribute, out var backgroundColor)
78+
? IsLightColor(backgroundColor)
79+
: isLightTheme;
80+
}
81+
82+
static bool TryGetThemeColor(Context context, int attribute, out AColor color)
7583
{
7684
color = default;
7785

78-
if (activity.Theme is null)
86+
if (context.Theme is null)
7987
return false;
8088

81-
using var ta = activity.Theme.ObtainStyledAttributes([attribute]);
89+
using var ta = context.Theme.ObtainStyledAttributes([attribute]);
8290

8391
if (!ta.HasValue(0))
8492
return false;

src/Core/tests/DeviceTests/Handlers/Window/WindowHandlerTests.Android.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
using System;
22
using System.Threading.Tasks;
33
using Android.App;
4+
using Android.Content.Res;
45
using AndroidX.AppCompat.App;
56
using Microsoft.Extensions.DependencyInjection;
67
using Microsoft.Maui.Controls;
78
using Microsoft.Maui.DeviceTests.Stubs;
89
using Microsoft.Maui.Hosting;
910
using Xunit;
11+
using ContextThemeWrapper = Android.Views.ContextThemeWrapper;
1012

1113
namespace Microsoft.Maui.DeviceTests
1214
{
@@ -47,6 +49,50 @@ await InvokeOnMainThreadAsync(() =>
4749
});
4850
}
4951

52+
[Theory]
53+
[InlineData(false, true)]
54+
[InlineData(true, false)]
55+
public async Task Material3StatusBarAppearanceUsesSurfaceColor(bool isDarkTheme, bool expectedLightAppearance)
56+
{
57+
await InvokeOnMainThreadAsync(() =>
58+
{
59+
var activity = (AppCompatActivity)MauiProgramDefaults.DefaultContext;
60+
using var configuration = new Configuration(activity.Resources?.Configuration);
61+
configuration.UiMode = (configuration.UiMode & ~UiMode.NightMask) |
62+
(isDarkTheme ? UiMode.NightYes : UiMode.NightNo);
63+
using var configurationContext = activity.CreateConfigurationContext(configuration);
64+
using var themedContext = new ContextThemeWrapper(
65+
configurationContext,
66+
Resource.Style.Maui_Material3_Theme_NoActionBar);
67+
68+
var appearance = WindowExtensions.GetStatusBarAppearance(
69+
themedContext,
70+
isLightTheme: isDarkTheme,
71+
isMaterial3: true);
72+
73+
Assert.Equal(expectedLightAppearance, appearance);
74+
});
75+
}
76+
77+
[Fact]
78+
public async Task Material2StatusBarAppearanceUsesPrimaryColor()
79+
{
80+
await InvokeOnMainThreadAsync(() =>
81+
{
82+
var activity = (AppCompatActivity)MauiProgramDefaults.DefaultContext;
83+
using var themedContext = new ContextThemeWrapper(
84+
activity,
85+
Resource.Style.Maui_MainTheme_NoActionBar);
86+
87+
var appearance = WindowExtensions.GetStatusBarAppearance(
88+
themedContext,
89+
isLightTheme: true,
90+
isMaterial3: false);
91+
92+
Assert.False(appearance);
93+
});
94+
}
95+
5096

5197
[Fact]
5298
public async Task TitleSetsOnWindow()

0 commit comments

Comments
 (0)