0

[Surface Color] Tablet Tab Strip

Light:
tab strip: surface container high
tab strip dividers: primary @30% light
selected tab + toolbar: surface

Dark:
tab strip: surface container
tab strip dividers: surface container highest
selected tab + toolbar: surface

selected tab is already set to surface.

Before:
https://screenshot.googleplex.com/7Kg358HQn5SD7oq
https://screenshot.googleplex.com/AP7oSewNRbGiP8g
https://screenshot.googleplex.com/3M8pegt2LbCbm8S

After:
https://screenshot.googleplex.com/BUM4Fa4aC6hkNgZ
https://screenshot.googleplex.com/4qJahJn9RW8ECRH
https://screenshot.googleplex.com/4TogL7zhv8CbAHy

Bug: 407859144
Change-Id: I32684b3c18883c80cfa73f14fc6c641e12d8f102
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6427359
Commit-Queue: Eleanor Lee <eleanorlee@google.com>
Reviewed-by: Wenyu Fu <wenyufu@chromium.org>
Reviewed-by: Sinan Sahin <sinansahin@google.com>
Cr-Commit-Position: refs/heads/main@{#1442777}
This commit is contained in:
Eleanor Lee
2025-04-04 11:01:30 -07:00
committed by Chromium LUCI CQ
parent 34d08aa00a
commit 6fffae50b6
7 changed files with 58 additions and 55 deletions
chrome
android
features
tab_ui
public
android
java
src
org
chromium
chrome
browser
tasks
tab_management
java
src
org
chromium
chrome
browser
compositor
overlays
junit
src
org
chromium
browser
ui
android
toolbar
java
src
org
chromium
chrome
components/browser_ui/styles/android/java/src/org/chromium/components/browser_ui/styles
ui/android/java/res/values

@ -10,11 +10,11 @@ import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.DimenRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.Px;
import androidx.core.content.res.ResourcesCompat;
import org.chromium.chrome.browser.ui.theme.ChromeSemanticColorUtils;
import org.chromium.components.browser_ui.styles.ChromeColors;
import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.ui.util.ColorUtils;
/**
@ -23,6 +23,7 @@ import org.chromium.ui.util.ColorUtils;
*/
public class TabUiThemeUtil {
private static final float MAX_TAB_STRIP_TAB_WIDTH_DP = 265.f;
private static final float DIVIDER_FOLIO_LIGHT_OPACITY = 0.3f;
/**
* Returns the tab strip background color based on the windowing mode and activity focus state.
@ -63,30 +64,21 @@ public class TabUiThemeUtil {
Context context, boolean isIncognito, boolean isActivityFocused) {
// Default spec for incognito, dark and light themes, used when not in desktop windowing
// mode or when the activity is focused in desktop windowing mode.
@ColorRes int incognitoColor = R.color.default_bg_color_dark_elev_2_baseline;
@Px
float darkThemeElevation =
context.getResources().getDimensionPixelSize(R.dimen.default_elevation_2);
@Px
float lightThemeElevation =
context.getResources().getDimensionPixelSize(R.dimen.default_elevation_3);
@ColorRes int incognitoColor = R.color.tab_strip_tablet_bg_incognito;
@ColorInt int darkThemeColor = SemanticColorUtils.getColorSurfaceContainer(context);
@ColorInt int lightThemeColor = SemanticColorUtils.getColorSurfaceContainerHigh(context);
// Spec for when the activity is in an unfocused desktop window.
if (!isActivityFocused) {
incognitoColor = R.color.default_bg_color_dark_elev_1_baseline;
darkThemeElevation =
context.getResources().getDimensionPixelSize(R.dimen.default_elevation_1);
lightThemeElevation =
context.getResources().getDimensionPixelSize(R.dimen.default_elevation_2);
incognitoColor = R.color.tab_strip_tablet_bg_unfocused_incognito;
darkThemeColor = SemanticColorUtils.getColorSurfaceContainerLow(context);
lightThemeColor = SemanticColorUtils.getColorSurfaceContainer(context);
}
if (isIncognito) {
return context.getColor(incognitoColor);
}
return ChromeColors.getSurfaceColor(
context,
ColorUtils.inNightMode(context) ? darkThemeElevation : lightThemeElevation);
return ColorUtils.inNightMode(context) ? darkThemeColor : lightThemeColor;
}
/**
@ -182,4 +174,26 @@ public class TabUiThemeUtil {
public static float getMaxTabStripTabWidthDp() {
return MAX_TAB_STRIP_TAB_WIDTH_DP;
}
/**
* @return The tint color resource for the tab divider.
*/
public static @ColorInt int getDividerTint(Context context, boolean isIncognito) {
if (isIncognito) {
return context.getColor(R.color.tab_strip_tablet_divider_bg_incognito);
}
if (!ColorUtils.inNightMode(context)) {
// This color will not be used at full opacity. We can't set this using the alpha
// component of the {@code @ColorInt}, since it is ignored when loading resources
// with a specified tint in the CC layer (instead retaining the alpha of the original
// image). Instead, this is reflected by setting the opacity of the divider itself.
// See https://crbug.com/1373634.
return ColorUtils.setAlphaComponentWithFloat(
SemanticColorUtils.getDefaultIconColorAccent1(context),
DIVIDER_FOLIO_LIGHT_OPACITY);
}
return SemanticColorUtils.getDividerLineBgColor(context);
}
}

@ -147,7 +147,6 @@ public class StripLayoutTab extends StripLayoutView {
// Close button hover highlight alpha
private static final float CLOSE_BUTTON_HOVER_BACKGROUND_PRESSED_OPACITY = 0.12f;
private static final float CLOSE_BUTTON_HOVER_BACKGROUND_DEFAULT_OPACITY = 0.08f;
@VisibleForTesting static final float DIVIDER_FOLIO_LIGHT_OPACITY = 0.2f;
// Tab's ID this view refers to.
private int mTabId;
@ -414,22 +413,7 @@ public class StripLayoutTab extends StripLayoutView {
* @return The tint color resource for the tab divider.
*/
public @ColorInt int getDividerTint() {
if (isIncognito()) {
return mContext.getColor(R.color.divider_line_bg_color_light);
}
if (!ColorUtils.inNightMode(mContext) && !isIncognito()) {
// This color will not be used at full opacity. We can't set this using the alpha
// component of the {@code @ColorInt}, since it is ignored when loading resources
// with a specified tint in the CC layer (instead retaining the alpha of the original
// image). Instead, this is reflected by setting the opacity of the divider itself.
// See https://crbug.com/1373634.
return ColorUtils.setAlphaComponentWithFloat(
SemanticColorUtils.getDefaultIconColorAccent1(mContext),
DIVIDER_FOLIO_LIGHT_OPACITY);
}
return SemanticColorUtils.getDividerLineBgColor(mContext);
return TabUiThemeUtil.getDividerTint(mContext, isIncognito());
}
/**

@ -96,7 +96,6 @@ import org.chromium.chrome.browser.ui.system.StatusBarColorController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.desktop_windowing.AppHeaderState;
import org.chromium.components.browser_ui.desktop_windowing.DesktopWindowStateManager;
import org.chromium.components.browser_ui.styles.ChromeColors;
import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.components.browser_ui.widget.scrim.ScrimProperties;
import org.chromium.components.collaboration.CollaborationService;
@ -250,13 +249,13 @@ public class StripLayoutHelperManagerTest {
ToolbarFeatures.setIsTabStripLayoutOptimizationEnabledForTesting(false);
assertEquals(
"Initial strip background color is incorrect.",
ChromeColors.getSurfaceColor(mActivity, R.dimen.default_elevation_3),
SemanticColorUtils.getColorSurfaceContainerHigh(mActivity),
mStripLayoutHelperManager.getBackgroundColor());
// Assume the current activity lost focus.
mStripLayoutHelperManager.onTopResumedActivityChanged(false);
assertEquals(
"Strip background color should not be updated when activity focus state changes.",
ChromeColors.getSurfaceColor(mActivity, R.dimen.default_elevation_3),
SemanticColorUtils.getColorSurfaceContainerHigh(mActivity),
mStripLayoutHelperManager.getBackgroundColor());
}
@ -266,14 +265,14 @@ public class StripLayoutHelperManagerTest {
when(mDesktopWindowStateManager.getAppHeaderState()).thenReturn(new AppHeaderState());
assertEquals(
"Initial strip background color is incorrect.",
ChromeColors.getSurfaceColor(mActivity, R.dimen.default_elevation_3),
SemanticColorUtils.getColorSurfaceContainerHigh(mActivity),
mStripLayoutHelperManager.getBackgroundColor());
// Assume the current activity lost focus.
mStripLayoutHelperManager.onTopResumedActivityChanged(false);
assertEquals(
"Strip background color should not be updated when activity focus state changes"
+ " while not in desktop window.",
ChromeColors.getSurfaceColor(mActivity, R.dimen.default_elevation_3),
SemanticColorUtils.getColorSurfaceContainerHigh(mActivity),
mStripLayoutHelperManager.getBackgroundColor());
}
@ -310,18 +309,18 @@ public class StripLayoutHelperManagerTest {
when(mDesktopWindowStateManager.getAppHeaderState()).thenReturn(appHeaderState);
@ColorInt
int focusedColor =
ChromeColors.getSurfaceColor(
mActivity,
isNightMode ? R.dimen.default_elevation_2 : R.dimen.default_elevation_3);
isNightMode
? SemanticColorUtils.getColorSurfaceContainer(mActivity)
: SemanticColorUtils.getColorSurfaceContainerHigh(mActivity);
@ColorInt
int unfocusedColor =
ChromeColors.getSurfaceColor(
mActivity,
isNightMode ? R.dimen.default_elevation_1 : R.dimen.default_elevation_2);
isNightMode
? SemanticColorUtils.getColorSurfaceContainerLow(mActivity)
: SemanticColorUtils.getColorSurfaceContainer(mActivity);
if (isIncognito) {
focusedColor = mActivity.getColor(R.color.default_bg_color_dark_elev_2_baseline);
unfocusedColor = mActivity.getColor(R.color.default_bg_color_dark_elev_1_baseline);
focusedColor = mActivity.getColor(R.color.tab_strip_tablet_bg_incognito);
unfocusedColor = mActivity.getColor(R.color.tab_strip_tablet_bg_unfocused_incognito);
}
// Initially use the default tab strip background.
@ -355,8 +354,7 @@ public class StripLayoutHelperManagerTest {
initializeTest();
@ColorInt
int unfocusedLightThemeColor =
ChromeColors.getSurfaceColor(mActivity, R.dimen.default_elevation_2);
int unfocusedLightThemeColor = SemanticColorUtils.getColorSurfaceContainer(mActivity);
assertEquals(
"Strip background color is incorrect.",
unfocusedLightThemeColor,

@ -39,6 +39,7 @@ import org.chromium.ui.util.ColorUtils;
public class StripLayoutTabTest {
private static final String TAG = "StripLayoutTabTest";
private static final float DIVIDER_FOLIO_LIGHT_OPACITY = 0.3f;
private Context mContext;
private StripLayoutTab mNormalTab;
@ -154,13 +155,13 @@ public class StripLayoutTabTest {
expectedColor =
ColorUtils.setAlphaComponentWithFloat(
SemanticColorUtils.getDefaultIconColorAccent1(mContext),
StripLayoutTab.DIVIDER_FOLIO_LIGHT_OPACITY);
DIVIDER_FOLIO_LIGHT_OPACITY);
assertEquals(
"Light mode divider uses 20% icon color",
expectedColor, mNormalTab.getDividerTint());
// Incognito.
expectedColor = mContext.getColor(R.color.divider_line_bg_color_light);
expectedColor = mContext.getColor(R.color.tab_strip_tablet_divider_bg_incognito);
assertEquals(
"Incognito dividers use the baseline color.",
expectedColor,

@ -36,7 +36,6 @@ import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Features.DisableFeatures;
import org.chromium.base.test.util.HistogramWatcher;
import org.chromium.cc.input.BrowserControlsState;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.browser_controls.BrowserStateBrowserControlsVisibilityDelegate;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.fullscreen.FullscreenManager;
@ -49,7 +48,7 @@ import org.chromium.chrome.browser.toolbar.top.CaptureReadinessResult.TopToolbar
import org.chromium.chrome.browser.toolbar.top.ToolbarControlContainer.ToolbarViewResourceAdapter;
import org.chromium.chrome.browser.toolbar.top.ToolbarControlContainer.ToolbarViewResourceAdapter.ToolbarInMotionStage;
import org.chromium.components.browser_ui.desktop_windowing.AppHeaderState;
import org.chromium.components.browser_ui.styles.ChromeColors;
import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.ui.base.TestActivity;
import java.util.concurrent.atomic.AtomicInteger;
@ -478,8 +477,7 @@ public class ToolbarControlContainerTest {
var stripBackgroundColorDrawable = (ColorDrawable) backgroundLayerDrawable.getDrawable(0);
assertEquals(
"Tab strip background color drawable color is incorrect.",
ChromeColors.getSurfaceColor(
controlContainer.getContext(), R.dimen.default_elevation_2),
SemanticColorUtils.getColorSurfaceContainer(activity),
stripBackgroundColorDrawable.getColor());
activity.finish();

@ -218,6 +218,11 @@ public class SemanticColorUtils {
return resolve(R.attr.colorSurfaceContainer, context);
}
/** Returns the semantic color values that correspond to colorSurfaceContainerHigh. */
public static @ColorInt int getColorSurfaceContainerHigh(Context context) {
return resolve(R.attr.colorSurfaceContainerHigh, context);
}
/** Returns the semantic color values that correspond to colorSurfaceContainerHighest. */
public static @ColorInt int getColorSurfaceContainerHighest(Context context) {
return resolve(R.attr.colorSurfaceContainerHighest, context);

@ -135,6 +135,9 @@ found in the LICENSE file.
<color name="ntp_incognito_icon_color" tools:ignore="UnusedResources">@color/baseline_neutral_95</color>
<color name="tab_strip_favicon_bg_incognito">@color/gm3_baseline_surface_container_highest_dark</color>
<color name="tab_strip_bg_incognito">@color/gm3_baseline_surface_container_high_dark</color>
<color name="tab_strip_tablet_bg_incognito">@color/gm3_baseline_surface_container_dark</color>
<color name="tab_strip_tablet_divider_bg_incognito">@color/gm3_baseline_surface_container_highest_dark</color>
<color name="tab_strip_tablet_bg_unfocused_incognito">@color/gm3_baseline_surface_container_low_dark</color>
<color name="omnibox_suggestion_bg_hover_incognito">@color/gm3_baseline_surface_container_low_dark</color>
<!-- Illustration -->