[Android] Fixed NTP status bar dynamic color (#35936)

* Fixed statusbar color when Dynamic colors flag is enabled

Resolves https://github.com/brave/brave-browser/issues/54252
This commit is contained in:
AlexeyBarabash
2026-05-06 19:28:13 +03:00
committed by GitHub
parent e4ba56a255
commit 3f7e3723ee
4 changed files with 123 additions and 2 deletions
@@ -19,6 +19,7 @@ import org.chromium.chrome.browser.layouts.LayoutManager;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.theme.TopUiThemeColorProvider;
import org.chromium.chrome.browser.ui.system.StatusBarColorController.StatusBarColorProvider;
import org.chromium.chrome.browser.util.BraveDynamicColors;
import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager;
import org.chromium.ui.edge_to_edge.EdgeToEdgeSystemBarColorHelper;
import org.chromium.ui.util.ColorUtils;
@@ -51,8 +52,10 @@ public class BraveStatusBarColorController extends StatusBarColorController {
desktopWindowStateManager,
overviewColorSupplier);
// Dark theme doesn't have the regression, apply adjustment to light one only
if (!ColorUtils.inNightMode(activity)) {
// Dark theme doesn't have the regression, apply adjustment to light one only.
// Skip when dynamic colors are enabled — the themed surface color should be used instead.
if (!ColorUtils.inNightMode(activity)
&& !BraveDynamicColors.sDynamicColorsEnabled.isEnabled()) {
mBackgroundColorForNtp = Color.WHITE;
}
}
+6
View File
@@ -140,6 +140,12 @@ if (is_android) {
deps = [ "//chrome/android/junit:chrome_junit_tests_helper" ]
}
robolectric_library("brave_junit_tests_org.chromium.chrome.browser.ui") {
sources = [ "src/org/chromium/chrome/browser/ui/system/BraveStatusBarColorControllerUnitTest.java" ]
deps = [ "//chrome/android/junit:chrome_junit_tests_helper" ]
}
robolectric_library(
"brave_junit_tests_org.chromium.chrome.browser.autofill") {
sources = [
@@ -0,0 +1,111 @@
/* Copyright (c) 2026 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
package org.chromium.chrome.browser.ui.system;
import static org.junit.Assert.assertEquals;
import android.app.Activity;
import android.graphics.Color;
import androidx.annotation.ColorInt;
import androidx.core.content.ContextCompat;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.chromium.base.BraveFeatureList;
import org.chromium.base.supplier.MonotonicObservableSupplier;
import org.chromium.base.supplier.ObservableSuppliers;
import org.chromium.base.supplier.SettableNonNullObservableSupplier;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Features.DisableFeatures;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.layouts.LayoutManager;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.theme.TopUiThemeColorProvider;
import org.chromium.chrome.browser.ui.system.StatusBarColorController.StatusBarColorProvider;
import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager;
import org.chromium.ui.base.TestActivity;
import org.chromium.ui.edge_to_edge.EdgeToEdgeSystemBarColorHelper;
/** Unit tests for {@link BraveStatusBarColorController}. */
@RunWith(BaseRobolectricTestRunner.class)
public class BraveStatusBarColorControllerUnitTest {
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Rule
public final ActivityScenarioRule<TestActivity> mActivityScenarioRule =
new ActivityScenarioRule<>(TestActivity.class);
@Mock private StatusBarColorProvider mStatusBarColorProvider;
@Mock private ActivityLifecycleDispatcher mActivityLifecycleDispatcher;
@Mock private TopUiThemeColorProvider mTopUiThemeColorProvider;
@Mock private EdgeToEdgeSystemBarColorHelper mSystemBarColorHelper;
@Mock private DesktopWindowStateManager mDesktopWindowStateManager;
private final MonotonicObservableSupplier<LayoutManager> mLayoutManagerSupplier =
ObservableSuppliers.alwaysNull();
private final ActivityTabProvider mActivityTabProvider = new ActivityTabProvider();
private final SettableNonNullObservableSupplier<Integer> mOverviewColorSupplier =
ObservableSuppliers.createNonNull(Color.TRANSPARENT);
private Activity mActivity;
@Before
public void setUp() {
mActivityScenarioRule.getScenario().onActivity(activity -> mActivity = activity);
}
@Test
@DisableFeatures(BraveFeatureList.BRAVE_ANDROID_DYNAMIC_COLORS)
public void testBackgroundColorForNtp_dynamicColorsDisabled_returnsWhite() {
// Existing Brave behavior in light mode: force the NTP status-bar background to white
// to mask the upstream regression.
BraveStatusBarColorController controller = newController();
assertEquals(Color.WHITE, controller.getBackgroundColorForNtpForTesting());
}
@Test
@EnableFeatures(BraveFeatureList.BRAVE_ANDROID_DYNAMIC_COLORS)
public void testBackgroundColorForNtp_dynamicColorsEnabled_returnsUpstreamDefault() {
// With dynamic colors enabled the Brave override is skipped so the themed surface
// color (set by upstream's constructor) is preserved.
// home_surface_background_color resolves ?attr/colorSurface. In Robolectric the
// Material3 dynamic token chain isn't available, so colorSurface falls back to
// white - the same value Brave's override would set. The assertEquals below still
// documents that we preserve the upstream default; the companion test
// testBackgroundColorForNtp_dynamicColorsDisabled_returnsWhite provides the
// regression-catching coverage (if the guard is dropped, that test still asserts
// Color.WHITE is set, which is a deliberate Brave choice, not upstream's default).
@ColorInt
int upstreamDefault =
ContextCompat.getColor(mActivity, R.color.home_surface_background_color);
BraveStatusBarColorController controller = newController();
assertEquals(upstreamDefault, controller.getBackgroundColorForNtpForTesting());
}
private BraveStatusBarColorController newController() {
return new BraveStatusBarColorController(
mActivity,
/* isTablet= */ false,
mStatusBarColorProvider,
mLayoutManagerSupplier,
mActivityLifecycleDispatcher,
mActivityTabProvider,
mTopUiThemeColorProvider,
mSystemBarColorHelper,
mDesktopWindowStateManager,
mOverviewColorSupplier);
}
}
+1
View File
@@ -1673,6 +1673,7 @@ if (is_android) {
"//brave/android/junit:brave_junit_tests_org.chromium.chrome.browser.tabbed_mode",
"//brave/android/junit:brave_junit_tests_org.chromium.chrome.browser.tasks",
"//brave/android/junit:brave_junit_tests_org.chromium.chrome.browser.toolbar",
"//brave/android/junit:brave_junit_tests_org.chromium.chrome.browser.ui",
"//brave/android/junit:brave_junit_tests_org.chromium.chrome.browser.vpn",
"//brave/browser/customize_menu/android:junit",
"//brave/browser/first_run/android:junit",