0

[APS] Update tab container visibility and color on tab hover events

TODO (crbug.com/1469949): Add fade-in animation on the TSR tab container on hover.

Demo: https://drive.google.com/file/d/1tuqrtr-LkzOdiYoVv7ORR8yvIbAuSYyo/view?usp=sharing

Screenshots:

GM2:
Light: https://screenshot.googleplex.com/APnXK87WCC56T8s
Dark: https://screenshot.googleplex.com/48pRov7iwiiRDg5
Incognito: https://screenshot.googleplex.com/3Xp67zZNxbpbzAB

Folio:
Light: https://screenshot.googleplex.com/4xpqG8fZ3gwEBoK
Dark: https://screenshot.googleplex.com/KbYjZph9AQv5E8c
Incognito: https://screenshot.googleplex.com/3Xd3LtjhwM6yjmY

Detached:
Light: https://screenshot.googleplex.com/39vA7ohVPWkMLGu
Dark: https://screenshot.googleplex.com/YAaoz2qf3xZeaw4
Incognito: https://screenshot.googleplex.com/9aE7dgb4tESg8hX

Low-Coverage-Reason: Tests for updates in this CL require execution on a tablet, that is not available in the CQ; adequate test coverage has been added for these changes.
Bug: 1451925
Change-Id: Ied4a403e46669a5b3bc9f95d33fe482919842411
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4717726
Reviewed-by: Theresa Sullivan <twellington@chromium.org>
Commit-Queue: Aishwarya Rajesh <aishwaryarj@google.com>
Reviewed-by: Neil Coronado <nemco@google.com>
Cr-Commit-Position: refs/heads/main@{#1180649}
This commit is contained in:
Aishwarya Rajesh
2023-08-08 02:11:15 +00:00
committed by Chromium LUCI CQ
parent b108bb5010
commit ea17bbdc76
26 changed files with 374 additions and 111 deletions
chrome
android
BUILD.gnchrome_java_sources.gni
features
tab_ui
public
BUILD.gn
android
java
res
src
org
chromium
chrome
browser
tasks
tab_management
java
javatests
src
org
chromium
chrome
browser
compositor
overlays
junit
src
browser
ui
android
theme
BUILD.gn
java
src
org
chromium
chrome
toolbar
java
src
org
chromium
chrome
docs/ui/android

@ -293,6 +293,7 @@ if (current_toolchain == default_toolchain) {
"//chrome/android/features/start_surface:public_java",
"//chrome/android/features/tab_ui:tab_suggestions_java",
"//chrome/android/features/tab_ui/public:java",
"//chrome/android/features/tab_ui/public:ui_java_resources",
"//chrome/android/modules/cablev2_authenticator/public:java",
"//chrome/android/modules/image_editor/provider:java",
"//chrome/android/modules/stack_unwinder/provider:java",

@ -22,7 +22,6 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/ChromeInactivityTracker.java",
"java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java",
"java/src/org/chromium/chrome/browser/ChromeLocalizationUtils.java",
"java/src/org/chromium/chrome/browser/ChromeSemanticColorUtils.java",
"java/src/org/chromium/chrome/browser/ChromeStrictMode.java",
"java/src/org/chromium/chrome/browser/ChromeStringConstants.java",
"java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java",

@ -33,6 +33,7 @@ android_library("java") {
deps = [
":ui_java_resources",
"//chrome/browser/flags:java",
"//chrome/browser/ui/android/theme:java",
"//components/browser_ui/styles/android:java",
"//components/browser_ui/styles/android:java_resources",
"//third_party/androidx:androidx_annotation_annotation_java",

@ -9,4 +9,10 @@ found in the LICENSE file.
<!-- Tab strip container alpha values -->
<item name="bg_tabstrip_tab_detached_startup_alpha" format="float" type="dimen">0.03</item>
<item name="bg_tabstrip_tab_folio_startup_alpha" format="float" type="dimen">0.05</item>
<!-- Tab strip container hover color alpha values -->
<item name="gm2_tab_inactive_hover_alpha" format="float" type="dimen">0.08</item>
<item name="tsr_detached_tab_inactive_hover_alpha_light" format="float" type="dimen">0.05</item>
<item name="tsr_detached_tab_inactive_hover_alpha_dark" format="float" type="dimen">0.12</item>
<item name="tsr_folio_tab_inactive_hover_alpha" format="float" type="dimen">0.08</item>
</resources>

@ -8,8 +8,10 @@ import android.content.Context;
import android.graphics.Color;
import androidx.annotation.ColorInt;
import androidx.core.content.res.ResourcesCompat;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
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;
@ -54,23 +56,27 @@ public class TabUiThemeUtil {
/**
* Returns the color for the tab container based on experiment arm, incognito mode, foreground,
* reordering, and placeholder state.
* reordering, placeholder, and hover state.
*
* @param context {@link Context} used to retrieve color.
* @param isIncognito Whether the color is used for incognito mode.
* @param foreground Whether the tab is in the foreground.
* @param isReordering Whether the tab is being reordered.
* @param isPlaceholder Whether the tab is a placeholder "ghost" tab
* @param isPlaceholder Whether the tab is a placeholder "ghost" tab.
* @param isHovered Whether the tab is hovered on.
* @return The color for the tab container.
*/
public static @ColorInt int getTabStripContainerColor(Context context, boolean isIncognito,
boolean foreground, boolean isReordering, boolean isPlaceholder) {
// TODO (crbug.com/1469465): Encapsulate tab properties in a state object.
public static int getTabStripContainerColor(Context context, boolean isIncognito,
boolean foreground, boolean isReordering, boolean isPlaceholder, boolean isHovered) {
if (foreground) {
if (TabManagementFieldTrial.isTabStripFolioEnabled()) {
return ChromeColors.getDefaultThemeColor(context, isIncognito);
} else if (TabManagementFieldTrial.isTabStripDetachedEnabled()) {
return getTabStripDetachedTabColor(context, isIncognito, isReordering);
}
} else if (isHovered) {
return getHoveredTabContainerColor(context, isIncognito);
} else if (isPlaceholder) {
return getTabStripStartupContainerColor(context);
} else {
@ -85,6 +91,24 @@ public class TabUiThemeUtil {
return Color.TRANSPARENT;
}
/** Returns the color for the hovered tab container. */
private static @ColorInt int getHoveredTabContainerColor(Context context, boolean isIncognito) {
int baseColor = isIncognito ? context.getColor(R.color.baseline_primary_80)
: ChromeSemanticColorUtils.getTabInactiveHoverColor(context);
float alpha;
if (TabManagementFieldTrial.isTabStripFolioEnabled()) {
alpha = ResourcesCompat.getFloat(
context.getResources(), R.dimen.tsr_folio_tab_inactive_hover_alpha);
} else {
alpha = ColorUtils.inNightMode(context) || isIncognito
? ResourcesCompat.getFloat(context.getResources(),
R.dimen.tsr_detached_tab_inactive_hover_alpha_dark)
: ResourcesCompat.getFloat(context.getResources(),
R.dimen.tsr_detached_tab_inactive_hover_alpha_light);
}
return ColorUtils.setAlphaComponent(baseColor, (int) (alpha * 255));
}
/**
* Returns the color for the tab strip startup "ghost" containers.
*/

@ -861,7 +861,7 @@ public class OverlayPanel extends OverlayPanelAnimation
public void onHoverMove(float x, float y) {}
@Override
public void onHoverExit(float x, float y) {}
public void onHoverExit() {}
// SwipeHandler implementation.

@ -18,9 +18,9 @@ import org.chromium.base.MathUtils;
import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSemanticColorUtils;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
import org.chromium.chrome.browser.ui.theme.ChromeSemanticColorUtils;
import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.ui.base.LocalizationUtils;
import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
@ -984,7 +984,6 @@ abstract class OverlayPanelBase {
// Determine fading element opacities. The arrow icon needs to finish fading out before
// the close icon starts fading in. Any other elements fading in or fading out should use
// the same percentage.
float fadingOutPercentage = Math.min(percentage, .5f) / .5f;
float fadingInPercentage = Math.max(percentage - .5f, 0.f) / .5f;
// Close Icon.

@ -16,7 +16,6 @@ import android.widget.TextView;
import org.chromium.base.MathUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSemanticColorUtils;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelAnimation;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelInflater;
@ -26,6 +25,7 @@ import org.chromium.chrome.browser.contextualsearch.ContextualSearchPreferenceFr
import org.chromium.chrome.browser.contextualsearch.ContextualSearchUma;
import org.chromium.chrome.browser.layouts.animation.CompositorAnimator;
import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
import org.chromium.chrome.browser.ui.theme.ChromeSemanticColorUtils;
import org.chromium.components.browser_ui.settings.SettingsLauncher;
import org.chromium.ui.base.LocalizationUtils;
import org.chromium.ui.base.ViewUtils;

@ -262,7 +262,7 @@ public class GestureEventFilter extends EventFilter {
} else if (action == MotionEvent.ACTION_HOVER_MOVE) {
mHandler.onHoverMove(e.getX() * mPxToDp, e.getY() * mPxToDp);
} else if (action == MotionEvent.ACTION_HOVER_EXIT) {
mHandler.onHoverExit(e.getX() * mPxToDp, e.getY() * mPxToDp);
mHandler.onHoverExit();
}
return true;
}

@ -93,9 +93,6 @@ public interface GestureHandler {
/**
* Called on hover exit event.
*
* @param x The X position at the end of the event in the host view space in dp.
* @param y The Y position at the end of the event in the host view space in dp.
*/
void onHoverExit(float x, float y);
void onHoverExit();
}

@ -142,9 +142,11 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
private static final float NEW_TAB_BUTTON_BACKGROUND_HEIGHT_DP_TSR = 32.f;
private static final float NEW_TAB_BUTTON_PADDING_DP = 24.f;
private static final float NEW_TAB_BUTTON_TOUCH_TARGET_OFFSET = 12.f;
private static final float FOLIO_ATTACHED_BOTTOM_MARGIN_DP = 0.f;
@VisibleForTesting
static final float FOLIO_ATTACHED_BOTTOM_MARGIN_DP = 0.f;
private static final float FOLIO_ANIM_INTERMEDIATE_MARGIN_DP = -12.f;
private static final float FOLIO_DETACHED_BOTTOM_MARGIN_DP = 4.f;
@VisibleForTesting
static final float FOLIO_DETACHED_BOTTOM_MARGIN_DP = 4.f;
private static final float BUTTON_DESIRED_TOUCH_TARGET_SIZE = 48.f;
private static final float NEW_TAB_BUTTON_DEFAULT_PRESSED_OPACITY = 0.2f;
private static final float NEW_TAB_BUTTON_DARK_DETACHED_OPACITY = 0.15f;
@ -258,6 +260,7 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
private MultiInstanceManager mMultiInstanceManager;
private View mToolbarContainerView;
private StripLayoutTab mActiveClickedTab;
private StripLayoutTab mLastHoveredTab;
private TabDropTarget mTabDropTarget;
/**
@ -1038,10 +1041,12 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
}
}
private void setForegroundTabContainerVisible(StripLayoutTab tab, boolean selected) {
private void setTabContainerVisible(StripLayoutTab tab, boolean selected, boolean hovered) {
// Don't interrupt tab group background tab visibility.
if (tab.getContainerOpacity() != TAB_OPACITY_VISIBLE_BACKGROUND) {
float containerOpacity = selected || tab.getIsPlaceholder()
// The container will be visible if the tab is selected/hovered on or is a placeholder
// tab.
float containerOpacity = selected || tab.getIsPlaceholder() || hovered
? TAB_OPACITY_VISIBLE_FOREGROUND
: TAB_OPACITY_HIDDEN;
tab.setContainerOpacity(containerOpacity);
@ -1049,10 +1054,11 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
}
/**
* Called to show/hide dividers and the foreground tab container. Dividers are only necessary
* between tabs that both do not have a visible tab container (foreground or background).
* Called to show/hide dividers and the foreground/hovered tab container. Dividers are only
* necessary between tabs that both do not have a visible tab container (foreground or
* background).
*/
private void updateForegroundTabContainersAndDividers() {
private void updateTabContainersAndDividers() {
if (!ChromeFeatureList.sTabStripRedesign.isEnabled()) return;
// Validate the index. For example, the index can be {@link TabList.INVALID_TAB_INDEX} when
@ -1060,9 +1066,12 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
int selectedIndex = mTabStateInitialized ? mModel.index() : mActiveTabIndexOnStartup;
if (selectedIndex < 0 || selectedIndex >= mStripTabs.length) return;
int hoveredIndex = mLastHoveredTab != null ? findIndexForTab(mLastHoveredTab.getId())
: TabModel.INVALID_TAB_INDEX;
// Divider is never shown for the first tab.
mStripTabs[0].setStartDividerVisible(false);
setForegroundTabContainerVisible(mStripTabs[0], selectedIndex == 0);
setTabContainerVisible(mStripTabs[0], selectedIndex == 0, hoveredIndex == 0);
// End divider for first tab is only shown in reorder mode when tab has trailing margin and
// container is not visible.
boolean endDividerVisible = mInReorderMode
@ -1074,9 +1083,10 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
final StripLayoutTab prevTab = mStripTabs[i - 1];
final StripLayoutTab currTab = mStripTabs[i];
boolean currTabSelected = selectedIndex == i;
boolean currTabHovered = hoveredIndex == i;
// Set container opacity.
setForegroundTabContainerVisible(currTab, currTabSelected);
setTabContainerVisible(currTab, currTabSelected, currTabHovered);
/**
* Start divider should be visible when:
@ -1387,7 +1397,11 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
*/
public void onHoverEnter(float x, float y) {
if (!isPeripheralsSupportForTabStripEnabled()) return;
// TODO (crbug.com/1451925): Handle tab strip hover enter event.
StripLayoutTab hoveredTab = getTabAtPosition(x);
// Hovered into a non-tab region on the strip.
if (hoveredTab == null) return;
updateLastHoveredTab(hoveredTab);
mUpdateHost.requestUpdate();
}
/**
@ -1397,17 +1411,66 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
*/
public void onHoverMove(float x, float y) {
if (!isPeripheralsSupportForTabStripEnabled()) return;
// TODO (crbug.com/1451925): Handle tab strip hover move event.
StripLayoutTab hoveredTab = getTabAtPosition(x);
// Hovered into a non-tab region within the strip.
if (hoveredTab == null) {
clearLastHoveredTab();
mUpdateHost.requestUpdate();
return;
}
// Hovered within the same tab that was last hovered into.
if (hoveredTab == mLastHoveredTab) return;
// Hovered from one tab to another tab on the strip, clear the former tab's hover state.
clearLastHoveredTab();
updateLastHoveredTab(hoveredTab);
mUpdateHost.requestUpdate();
}
/**
* Called on hover exit event.
* @param x The x coordinate of the position of the hover exit event.
* @param y The y coordinate of the position of the hover exit event.
*/
public void onHoverExit(float x, float y) {
public void onHoverExit() {
if (!isPeripheralsSupportForTabStripEnabled()) return;
// TODO (crbug.com/1451925): Handle tab strip hover exit event.
clearLastHoveredTab();
mUpdateHost.requestUpdate();
}
void setLastHoveredTabForTesting(StripLayoutTab tab) {
mLastHoveredTab = tab;
}
StripLayoutTab getLastHoveredTab() {
return mLastHoveredTab;
}
private void clearLastHoveredTab() {
if (mLastHoveredTab == null) return;
// Remove the highlight from the last hovered tab.
updateHoveredFolioTabState(mLastHoveredTab, false);
mLastHoveredTab = null;
}
private void updateLastHoveredTab(StripLayoutTab hoveredTab) {
if (hoveredTab == null) return;
mLastHoveredTab = hoveredTab;
updateHoveredFolioTabState(mLastHoveredTab, true);
}
private void updateHoveredFolioTabState(StripLayoutTab tab, boolean hovered) {
if (tab == null || !TabManagementFieldTrial.isTabStripFolioEnabled()) return;
// Do not update the attached state of a selected folio tab that is hovered on.
int selectedTabIndex = mModel != null ? mModel.index() : mActiveTabIndexOnStartup;
if (selectedTabIndex >= 0 && mStripTabs[selectedTabIndex] == findTabById(tab.getId())) {
return;
}
// If a folio tab is hovered on, detach its container.
tab.setFolioAttached(!hovered);
tab.setBottomMargin(
hovered ? FOLIO_DETACHED_BOTTOM_MARGIN_DP : FOLIO_ATTACHED_BOTTOM_MARGIN_DP);
}
private boolean isPeripheralsSupportForTabStripEnabled() {
@ -1904,7 +1967,7 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
updateCloseButtons();
// 9. Show dividers between inactive tabs.
updateForegroundTabContainersAndDividers();
updateTabContainersAndDividers();
}
private void computeTabInitialPositions() {

@ -221,8 +221,8 @@ public class StripLayoutHelperManager implements SceneOverlay, PauseResumeWithNa
}
@Override
public void onHoverExit(float x, float y) {
getActiveStripLayoutHelper().onHoverExit(x, y);
public void onHoverExit() {
getActiveStripLayoutHelper().onHoverExit();
}
private long time() {
@ -472,9 +472,12 @@ public class StripLayoutHelperManager implements SceneOverlay, PauseResumeWithNa
Tab selectedTab = mTabModelSelector.getCurrentModel().getTabAt(
mTabModelSelector.getCurrentModel().index());
int selectedTabId = selectedTab == null ? TabModel.INVALID_TAB_INDEX : selectedTab.getId();
int hoveredTabId = getActiveStripLayoutHelper().getLastHoveredTab() == null
? TabModel.INVALID_TAB_INDEX
: getActiveStripLayoutHelper().getLastHoveredTab().getId();
mTabStripTreeProvider.pushAndUpdateStrip(this, mLayerTitleCacheSupplier.get(),
resourceManager, getActiveStripLayoutHelper().getStripLayoutTabsToRender(), yOffset,
selectedTabId);
selectedTabId, hoveredTabId);
return mTabStripTreeProvider;
}
@ -917,7 +920,11 @@ public class StripLayoutHelperManager implements SceneOverlay, PauseResumeWithNa
} else if (event == MotionEvent.ACTION_HOVER_MOVE) {
mTabStripEventHandler.onHoverMove(x, y);
} else if (event == MotionEvent.ACTION_HOVER_EXIT) {
mTabStripEventHandler.onHoverExit(x, y);
mTabStripEventHandler.onHoverExit();
}
}
void setTabStripTreeProviderForTesting(TabStripSceneLayer tabStripTreeProvider) {
mTabStripTreeProvider = tabStripTreeProvider;
}
}

@ -345,6 +345,10 @@ public class StripLayoutTab implements VirtualView {
mFolioAttached = folioAttached;
}
boolean getFolioAttachedForTesting() {
return mFolioAttached;
}
/**
* Sets the id of the {@link Tab} this {@link StripLayoutTab} represents.
*/
@ -389,30 +393,48 @@ public class StripLayoutTab implements VirtualView {
/**
* @param foreground Whether or not this tab is a foreground tab.
* @return The tint color resource that represents the tab background.
* @param hovered Whether or not this tab is hovered on.
* @return The tint color resource that represents the tab background. A foreground tab will
* have the same tint irrespective of its hover state.
*/
public int getTint(boolean foreground) {
public int getTint(boolean foreground, boolean hovered) {
hovered = ChromeFeatureList.isEnabled(
ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP)
&& hovered;
// TODO(https://crbug.com/1408276): Avoid calculating every time. Instead, store the tab's
// color and only re-determine when the color could have changed (i.e. on selection).
if (ChromeFeatureList.sTabStripRedesign.isEnabled()) {
return TabUiThemeUtil.getTabStripContainerColor(
mContext, mIncognito, foreground, mIsReordering, mIsPlaceholder);
mContext, mIncognito, foreground, mIsReordering, mIsPlaceholder, hovered);
}
if (foreground) {
return ChromeColors.getDefaultThemeColor(mContext, mIncognito);
}
// |defaultColor| represents the color of a background/inactive tab.
int defaultColor;
int overlayColor;
if (mIncognito) {
return mContext.getResources().getColor(
defaultColor = mContext.getResources().getColor(
R.color.baseline_neutral_10_with_neutral_0_alpha_30);
overlayColor = mContext.getColor(R.color.baseline_neutral_90);
} else {
final int baseColor = ChromeColors.getSurfaceColor(
mContext, R.dimen.compositor_background_tab_elevation);
final float overlayAlpha = ResourcesCompat.getFloat(
mContext.getResources(), R.dimen.compositor_background_tab_overlay_alpha);
defaultColor = ColorUtils.getColorWithOverlay(baseColor, Color.BLACK, overlayAlpha);
overlayColor = MaterialColors.getColor(mContext, R.attr.colorOnSurface, TAG);
}
final int baseColor =
ChromeColors.getSurfaceColor(mContext, R.dimen.compositor_background_tab_elevation);
final float overlayAlpha = ResourcesCompat.getFloat(
mContext.getResources(), R.dimen.compositor_background_tab_overlay_alpha);
return ColorUtils.getColorWithOverlay(baseColor, Color.BLACK, overlayAlpha);
if (hovered) {
return ColorUtils.getColorWithOverlay(defaultColor, overlayColor,
ResourcesCompat.getFloat(
mContext.getResources(), R.dimen.gm2_tab_inactive_hover_alpha));
}
return defaultColor;
}
/**
@ -426,7 +448,7 @@ public class StripLayoutTab implements VirtualView {
}
if (foreground) {
return getTint(true);
return getTint(true, false);
}
if (mIncognito) {
@ -434,7 +456,7 @@ public class StripLayoutTab implements VirtualView {
R.color.baseline_neutral_10_with_neutral_0_alpha_30_with_neutral_variant_60_alpha_15);
}
final int baseColor = getTint(false);
final int baseColor = getTint(false, false);
final int overlayColor = MaterialColors.getColor(mContext, R.attr.colorOutline, TAG);
final float overlayAlpha = ResourcesCompat.getFloat(
mContext.getResources(), R.dimen.compositor_background_tab_outline_alpha);

@ -71,10 +71,14 @@ public class TabStripSceneLayer extends SceneOverlayLayer {
* @param resourceManager A resource manager.
* @param stripLayoutTabsToRender Array of strip layout tabs.
* @param yOffset Current browser controls offset in dp.
* @param selectedTabId The ID of the selected tab.
* @param hoveredTabId The ID of the hovered tab, if any. If no tab is hovered on, this ID will
* be invalid.
*/
public void pushAndUpdateStrip(StripLayoutHelperManager layoutHelper,
LayerTitleCache layerTitleCache, ResourceManager resourceManager,
StripLayoutTab[] stripLayoutTabsToRender, float yOffset, int selectedTabId) {
StripLayoutTab[] stripLayoutTabsToRender, float yOffset, int selectedTabId,
int hoveredTabId) {
if (mNativePtr == 0) return;
final boolean visible = yOffset > -layoutHelper.getHeight();
// This will hide the tab strips if necessary.
@ -84,7 +88,7 @@ public class TabStripSceneLayer extends SceneOverlayLayer {
if (visible) {
pushButtonsAndBackground(layoutHelper, resourceManager, yOffset);
pushStripTabs(layoutHelper, layerTitleCache, resourceManager, stripLayoutTabsToRender,
selectedTabId);
selectedTabId, hoveredTabId);
}
TabStripSceneLayerJni.get().finishBuildingFrame(mNativePtr, TabStripSceneLayer.this);
}
@ -149,7 +153,7 @@ public class TabStripSceneLayer extends SceneOverlayLayer {
private void pushStripTabs(StripLayoutHelperManager layoutHelper,
LayerTitleCache layerTitleCache, ResourceManager resourceManager,
StripLayoutTab[] stripTabs, int selectedTabId) {
StripLayoutTab[] stripTabs, int selectedTabId, int hoveredTabId) {
final int tabsCount = stripTabs != null ? stripTabs.length : 0;
// TODO(https://crbug.com/1450380): Cleanup params, as some don't change and others are now
@ -157,19 +161,21 @@ public class TabStripSceneLayer extends SceneOverlayLayer {
for (int i = 0; i < tabsCount; i++) {
final StripLayoutTab st = stripTabs[i];
boolean isSelected = st.getId() == selectedTabId;
boolean isHovered = st.getId() == hoveredTabId;
TabStripSceneLayerJni.get().putStripTabLayer(mNativePtr, TabStripSceneLayer.this,
st.getId(), st.getCloseButton().getResourceId(), st.getDividerResourceId(),
st.getResourceId(), st.getOutlineResourceId(), st.getCloseButton().getTint(),
st.getDividerTint(), st.getTint(isSelected), st.getOutlineTint(isSelected),
isSelected, st.getClosePressed(), layoutHelper.getWidth() * mDpToPx,
st.getDrawX() * mDpToPx, st.getDrawY() * mDpToPx, st.getWidth() * mDpToPx,
st.getHeight() * mDpToPx, st.getContentOffsetY() * mDpToPx,
st.getDividerOffsetX() * mDpToPx, st.getBottomMargin() * mDpToPx,
st.getTopMargin() * mDpToPx, st.getCloseButtonPadding() * mDpToPx,
st.getCloseButton().getOpacity(), st.isStartDividerVisible(),
st.isEndDividerVisible(), st.isLoading(), st.getLoadingSpinnerRotation(),
st.getBrightness(), st.getContainerOpacity(), layerTitleCache, resourceManager);
st.getDividerTint(), st.getTint(isSelected, isHovered),
st.getOutlineTint(isSelected), isSelected, st.getClosePressed(),
layoutHelper.getWidth() * mDpToPx, st.getDrawX() * mDpToPx,
st.getDrawY() * mDpToPx, st.getWidth() * mDpToPx, st.getHeight() * mDpToPx,
st.getContentOffsetY() * mDpToPx, st.getDividerOffsetX() * mDpToPx,
st.getBottomMargin() * mDpToPx, st.getTopMargin() * mDpToPx,
st.getCloseButtonPadding() * mDpToPx, st.getCloseButton().getOpacity(),
st.isStartDividerVisible(), st.isEndDividerVisible(), st.isLoading(),
st.getLoadingSpinnerRotation(), st.getBrightness(), st.getContainerOpacity(),
layerTitleCache, resourceManager);
}
}

@ -20,8 +20,8 @@ import org.chromium.base.metrics.RecordUserAction;
import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSemanticColorUtils;
import org.chromium.chrome.browser.status_indicator.StatusIndicatorCoordinator;
import org.chromium.chrome.browser.ui.theme.ChromeSemanticColorUtils;
import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.content_public.common.ContentSwitches;
@ -262,7 +262,6 @@ public class OfflineIndicatorControllerV2 {
surfaceState = mCanAnimateBrowserControlsSupplier.get()
? UmaEnum.CAN_ANIMATE_NATIVE_CONTROLS
: UmaEnum.CANNOT_ANIMATE_NATIVE_CONTROLS;
;
}
RecordHistogram.recordEnumeratedHistogram(
"OfflineIndicator.ConnectivityChanged.DeviceState."

@ -16,9 +16,9 @@ import android.widget.TextView;
import androidx.annotation.ColorInt;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSemanticColorUtils;
import org.chromium.chrome.browser.omnibox.ChromeAutocompleteSchemeClassifier;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.ui.theme.ChromeSemanticColorUtils;
import org.chromium.components.browser_ui.widget.TintedDrawable;
import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.omnibox.OmniboxUrlEmphasizer;

@ -36,7 +36,7 @@ import androidx.gridlayout.widget.GridLayout;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSemanticColorUtils;
import org.chromium.chrome.browser.ui.theme.ChromeSemanticColorUtils;
import org.chromium.components.autofill.EditableOption;
import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.components.browser_ui.widget.DualControlLayout;

@ -24,7 +24,6 @@ import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
@ -33,11 +32,13 @@ import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabModelUtils;
import org.chromium.chrome.browser.tasks.tab_management.TabManagementFieldTrial;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.chrome.test.util.TabStripUtils;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.content_public.browser.test.util.DOMUtils;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.base.LocalizationUtils;
@ -858,45 +859,69 @@ public class TabStripTest {
}
/**
* Tests hover events associated with a strip tab.
* Tests hover events associated with a strip tab (with the tab strip redesign folio treatment
* enabled, for maximum coverage).
*/
@Test
@LargeTest
@EnableFeatures({ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP})
@Feature({"TabStrip"})
@EnableFeatures({ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP,
ChromeFeatureList.TAB_STRIP_REDESIGN})
@Restriction(UiRestriction.RESTRICTION_TYPE_TABLET)
public void testHoverOnTab() throws Exception {
public void
testHoverOnTab() throws Exception {
TabManagementFieldTrial.TAB_STRIP_REDESIGN_ENABLE_FOLIO.setForTesting(true);
// Open a few regular tabs.
ChromeTabUtils.newTabsFromMenu(
InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity(), 4);
// Select a tab to hover on.
// Select tabs to hover on.
TabModel model = sActivityTestRule.getActivity().getTabModelSelector().getModel(false);
StripLayoutTab tab = TabStripUtils.findStripLayoutTab(
StripLayoutTab tab1 = TabStripUtils.findStripLayoutTab(
sActivityTestRule.getActivity(), false, model.getTabAt(1).getId());
StripLayoutTab tab2 = TabStripUtils.findStripLayoutTab(
sActivityTestRule.getActivity(), false, model.getTabAt(2).getId());
assertTabVisibility(true, tab);
assertTabVisibility(true, tab1);
assertTabVisibility(true, tab2);
// Simulate a hover into this tab.
// Simulate a hover into tab1.
StripLayoutHelperManager stripLayoutHelperManager =
TabStripUtils.getStripLayoutHelperManager(sActivityTestRule.getActivity());
float xEnter = tab.getDrawX() + tab.getWidth() / 2;
float yEnter = tab.getDrawY() + tab.getHeight() / 2;
float xEnter = tab1.getDrawX() + tab1.getWidth() / 2;
float yEnter = tab1.getDrawY() + tab1.getHeight() / 2;
stripLayoutHelperManager.simulateHoverEventForTesting(
MotionEvent.ACTION_HOVER_ENTER, xEnter, yEnter);
StripLayoutTab lastHoveredTab =
stripLayoutHelperManager.getActiveStripLayoutHelper().getLastHoveredTab();
Assert.assertEquals("The last hovered tab is not set correctly.", tab1, lastHoveredTab);
Assert.assertFalse(
"|mFolioAttached| for tab1 should be false.", tab1.getFolioAttachedForTesting());
Assert.assertEquals("tab1 container bottom margin should match.",
StripLayoutHelper.FOLIO_DETACHED_BOTTOM_MARGIN_DP, tab1.getBottomMargin(), 0.f);
// Simulate a subsequent hover within the tab.
float xMove = tab.getDrawX() + tab.getWidth() / 3;
float yMove = tab.getDrawY() + tab.getHeight() / 3;
// Simulate a subsequent hover into the adjacent tab (tab2).
float xMove = tab2.getDrawX() + tab2.getWidth() / 3;
float yMove = tab2.getDrawY() + tab2.getHeight() / 3;
stripLayoutHelperManager.simulateHoverEventForTesting(
MotionEvent.ACTION_HOVER_MOVE, xMove, yMove);
lastHoveredTab = stripLayoutHelperManager.getActiveStripLayoutHelper().getLastHoveredTab();
Assert.assertEquals("The last hovered tab is not set correctly.", tab2, lastHoveredTab);
Assert.assertFalse(
"|mFolioAttached| for tab2 should be false.", tab2.getFolioAttachedForTesting());
Assert.assertTrue(
"|mFolioAttached| for tab1 should be true.", tab1.getFolioAttachedForTesting());
Assert.assertEquals("tab1 container bottom margin should match.",
StripLayoutHelper.FOLIO_ATTACHED_BOTTOM_MARGIN_DP, tab1.getBottomMargin(), 0.f);
// Simulate a subsequent hover outside the tab.
float xExit = tab.getDrawX() + 2 * tab.getWidth();
float yExit = tab.getDrawY() + 2 * tab.getHeight();
// Simulate a subsequent hover outside tab2.
float xExit = tab2.getDrawX() + 2 * tab2.getWidth();
float yExit = tab2.getDrawY() + 2 * tab2.getHeight();
stripLayoutHelperManager.simulateHoverEventForTesting(
MotionEvent.ACTION_HOVER_EXIT, xExit, yExit);
// TODO (crbug.com/1451925): Update verification in test(s) after hover handling is added in
// StripLayoutHelper.
lastHoveredTab = stripLayoutHelperManager.getActiveStripLayoutHelper().getLastHoveredTab();
Assert.assertNull("The last hovered tab is not set correctly.", lastHoveredTab);
Assert.assertTrue(
"|mFolioAttached| for tab2 should be true.", tab2.getFolioAttachedForTesting());
}
/**

@ -111,7 +111,7 @@ public class AreaGestureEventFilterUnitTest {
// Handle the hover exit event.
mEventFilter.onHoverEvent(mHoverExitEvent);
verify(mHandler).onHoverExit(mHoverExitEvent.getX(), mHoverExitEvent.getY());
verify(mHandler).onHoverExit();
}
@Test
@ -128,6 +128,6 @@ public class AreaGestureEventFilterUnitTest {
mEventFilter.onHoverEvent(mHoverMoveEvent);
// Moving outside the filter area will be considered an ACTION_HOVER_EXIT for further
// handling.
verify(mHandler).onHoverExit(mHoverMoveEvent.getX(), mHoverMoveEvent.getY());
verify(mHandler).onHoverExit();
}
}

@ -5,9 +5,11 @@
package org.chromium.chrome.browser.compositor.overlays.strip;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.graphics.RectF;
import android.view.ContextThemeWrapper;
import android.view.View;
@ -44,6 +46,7 @@ import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.multiwindow.MultiInstanceManager;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelFilterProvider;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tasks.tab_management.TabManagementFieldTrial;
@ -64,6 +67,8 @@ public class StripLayoutHelperManagerTest {
@Mock
private TabStripSceneLayer.Natives mTabStripSceneMock;
@Mock
private TabStripSceneLayer mTabStripTreeProvider;
@Mock
private LayoutManagerHost mManagerHost;
@Mock
private LayoutUpdateHost mUpdateHost;
@ -83,6 +88,12 @@ public class StripLayoutHelperManagerTest {
private TabCreatorManager mTabCreatorManager;
@Mock
private TabModelFilterProvider mTabModelFilterProvider;
@Mock
private TabModel mTabModel;
@Mock
private Tab mSelectedTab;
@Mock
private StripLayoutTab mHoveredStripTab;
private StripLayoutHelperManager mStripLayoutHelperManager;
private Context mContext;
@ -376,4 +387,32 @@ public class StripLayoutHelperManagerTest {
assertEquals("Unexpected incognito active tab index", expectedIncognitoActiveTabIndex,
incognitoHelper.getActiveTabIndexOnStartupForTesting());
}
@Test
public void testGetUpdatedSceneOverlayTree() {
// Setup and stub required mocks.
int hoveredTabId = 1;
int selectedTabId = 2;
mStripLayoutHelperManager.setTabStripTreeProviderForTesting(mTabStripTreeProvider);
when(mTabModelSelector.getCurrentModel()).thenReturn(mTabModel);
when(mTabModel.index()).thenReturn(selectedTabId);
when(mTabModel.getTabAt(selectedTabId)).thenReturn(mSelectedTab);
when(mSelectedTab.getId()).thenReturn(selectedTabId);
when(mHoveredStripTab.getId()).thenReturn(hoveredTabId);
var activeLayoutHelper = mStripLayoutHelperManager.getActiveStripLayoutHelper();
activeLayoutHelper.setLastHoveredTabForTesting(mHoveredStripTab);
// Invoke the method.
mStripLayoutHelperManager.getUpdatedSceneOverlayTree(
new RectF(), new RectF(), mRenderHost.getResourceManager(), 0f);
// Verify the call to #pushAndUpdateStrip.
verify(mTabStripTreeProvider)
.pushAndUpdateStrip(mStripLayoutHelperManager, mLayerTitleCacheSupplier.get(),
mRenderHost.getResourceManager(),
activeLayoutHelper.getStripLayoutTabsToRender(), 0f, selectedTabId,
hoveredTabId);
}
}

@ -27,7 +27,9 @@ import org.chromium.base.test.util.Feature;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.tasks.tab_management.TabManagementFieldTrial;
import org.chromium.chrome.browser.ui.theme.ChromeSemanticColorUtils;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.components.browser_ui.styles.ChromeColors;
import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.ui.util.ColorUtils;
@ -55,91 +57,151 @@ public class StripLayoutTabTest {
@Test
@Feature("Tab Strip Redesign")
@EnableFeatures({ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP})
public void testGetTint() {
int expectedColor;
// Normal active tab color.
expectedColor = MaterialColors.getColor(mContext, R.attr.colorSurface, TAG);
assertEquals("Normal active tab should match the Surface-0 color.", expectedColor,
mNormalTab.getTint(true));
mNormalTab.getTint(true, false));
// Normal inactive tab color.
expectedColor =
ChromeColors.getSurfaceColor(mContext, R.dimen.compositor_background_tab_elevation);
assertEquals("Normal inactive tab should match the Surface-4 color.", expectedColor,
mNormalTab.getTint(false));
mNormalTab.getTint(false, false));
// Normal inactive tab hover color.
expectedColor = ColorUtils.getColorWithOverlay(expectedColor,
MaterialColors.getColor(mContext, R.attr.colorOnSurface, TAG),
ResourcesCompat.getFloat(
mContext.getResources(), R.dimen.gm2_tab_inactive_hover_alpha));
assertEquals(
"Normal hovered inactive tab should match the Surface-4 color overlain by OnSurface @ 8%.",
expectedColor, mNormalTab.getTint(false, true));
// Incognito active tab color.
expectedColor = mContext.getColor(R.color.toolbar_background_primary_dark);
assertEquals("Incognito active tab should match the baseline color.", expectedColor,
mIncognitoTab.getTint(true));
mIncognitoTab.getTint(true, false));
// Incognito inactive tab color.
expectedColor = mContext.getResources().getColor(
R.color.baseline_neutral_10_with_neutral_0_alpha_30);
assertEquals("Incognito inactive tab should match the baseline color.", expectedColor,
mIncognitoTab.getTint(false));
mIncognitoTab.getTint(false, false));
// Incognito inactive tab hover color.
expectedColor = ColorUtils.getColorWithOverlay(expectedColor,
mContext.getColor(R.color.baseline_neutral_90),
ResourcesCompat.getFloat(
mContext.getResources(), R.dimen.gm2_tab_inactive_hover_alpha));
assertEquals(
"Incognito hovered inactive tab should match the baseline color overlain by the baseline equivalent of OnSurface @ 8%.",
expectedColor, mIncognitoTab.getTint(false, true));
}
@Test
@Feature("Tab Strip Redesign")
@Features.EnableFeatures({ChromeFeatureList.TAB_STRIP_REDESIGN})
public void testGetTint_TabStripRedesignFolio() {
@Features.EnableFeatures({ChromeFeatureList.TAB_STRIP_REDESIGN,
ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP})
public void
testGetTint_TabStripRedesignFolio() {
TabManagementFieldTrial.TAB_STRIP_REDESIGN_ENABLE_FOLIO.setForTesting(true);
int expectedColor;
// Normal active tab color.
expectedColor = MaterialColors.getColor(mContext, R.attr.colorSurface, TAG);
assertEquals("Normal active folio should match the Surface-0 color.", expectedColor,
mNormalTab.getTint(true));
mNormalTab.getTint(true, false));
// Normal inactive tab color.
expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_0);
assertEquals("Folio inactive tab containers should be Surface-0.", expectedColor,
mNormalTab.getTint(false));
mNormalTab.getTint(false, false));
// Normal inactive tab hover color.
expectedColor = ColorUtils.setAlphaComponent(
ChromeSemanticColorUtils.getTabInactiveHoverColor(mContext),
(int) (ResourcesCompat.getFloat(
mContext.getResources(), R.dimen.tsr_folio_tab_inactive_hover_alpha)
* 255));
assertEquals("Normal hovered inactive folio should be Primary @ 8%.", expectedColor,
mNormalTab.getTint(false, true));
// Incognito active tab color.
expectedColor = mContext.getColor(R.color.toolbar_background_primary_dark);
assertEquals("Incognito active folio should match the baseline color.", expectedColor,
mIncognitoTab.getTint(true));
mIncognitoTab.getTint(true, false));
// Incognito inactive tab color.
expectedColor = mContext.getColor(R.color.default_bg_color_dark);
assertEquals("Incognito inactive folio should be baseline Surface-0.", expectedColor,
mIncognitoTab.getTint(false));
mIncognitoTab.getTint(false, false));
// Incognito inactive tab hover color.
expectedColor = ColorUtils.setAlphaComponent(mContext.getColor(R.color.baseline_primary_80),
(int) (ResourcesCompat.getFloat(
mContext.getResources(), R.dimen.tsr_folio_tab_inactive_hover_alpha)
* 255));
assertEquals(
"Incognito hovered inactive folio should be the baseline equivalent of Primary @ 8%.",
expectedColor, mIncognitoTab.getTint(false, true));
}
@Test
@Feature("Tab Strip Redesign")
@Features.EnableFeatures({ChromeFeatureList.TAB_STRIP_REDESIGN})
public void testGetTint_TabStripRedesignDetached() {
@Features.EnableFeatures({ChromeFeatureList.TAB_STRIP_REDESIGN,
ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP})
public void
testGetTint_TabStripRedesignDetached() {
TabManagementFieldTrial.TAB_STRIP_REDESIGN_ENABLE_DETACHED.setForTesting(true);
int expectedColor;
// Normal active tab color.
expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_5);
assertEquals("Detached normal active should match the Surface-5 color.", expectedColor,
mNormalTab.getTint(true));
mNormalTab.getTint(true, false));
// Normal inactive tab color.
expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_5);
assertEquals("Detached inactive tab containers should be Surface-5.", expectedColor,
mNormalTab.getTint(false));
mNormalTab.getTint(false, false));
// Normal inactive tab hover color.
expectedColor = ColorUtils.setAlphaComponent(
ChromeSemanticColorUtils.getTabInactiveHoverColor(mContext),
(int) (ResourcesCompat.getFloat(mContext.getResources(),
R.dimen.tsr_detached_tab_inactive_hover_alpha_light)
* 255));
assertEquals("Normal hovered inactive folio should be Primary @ 5%.", expectedColor,
mNormalTab.getTint(false, true));
// Incognito active tab color.
expectedColor = Color.BLACK;
assertEquals("Detached incognito active should match the color black.", expectedColor,
mIncognitoTab.getTint(true));
mIncognitoTab.getTint(true, false));
// Incognito inactive tab color.
expectedColor = mContext.getColor(R.color.default_bg_color_dark_elev_5_gm3_baseline);
assertEquals("Detached incognito inactive should be baseline Surface-5.", expectedColor,
mIncognitoTab.getTint(false));
mIncognitoTab.getTint(false, false));
// Incognito inactive tab hover color.
expectedColor = ColorUtils.setAlphaComponent(mContext.getColor(R.color.baseline_primary_80),
(int) (ResourcesCompat.getFloat(mContext.getResources(),
R.dimen.tsr_detached_tab_inactive_hover_alpha_dark)
* 255));
assertEquals(
"Incognito hovered inactive folio should be the baseline equivalent of Primary @ 12%.",
expectedColor, mIncognitoTab.getTint(false, true));
}
@Test
@Features.EnableFeatures(
{ChromeFeatureList.TAB_STRIP_REDESIGN, ChromeFeatureList.TAB_STRIP_STARTUP_REFACTORING})
{ChromeFeatureList.TAB_STRIP_REDESIGN, ChromeFeatureList.TAB_STRIP_STARTUP_REFACTORING,
ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP})
public void
testGetTint_Startup_TabStripRedesign() {
TabManagementFieldTrial.TAB_STRIP_REDESIGN_ENABLE_DETACHED.setForTesting(true);
@ -151,26 +213,27 @@ public class StripLayoutTabTest {
// Normal active tab color.
expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_5);
assertEquals("Detached normal active should match the regular foreground color.",
expectedColor, mNormalTab.getTint(true));
expectedColor, mNormalTab.getTint(true, false));
// Normal inactive tab color.
expectedColor = mContext.getColor(R.color.bg_tabstrip_tab_detached_startup_tint);
assertEquals("Normal inactive tab should match the placeholder color.", expectedColor,
mNormalTab.getTint(false));
mNormalTab.getTint(false, false));
// Incognito active tab color.
expectedColor = Color.BLACK;
assertEquals("Detached incognito active should match the regular foreground color.",
expectedColor, mIncognitoTab.getTint(true));
expectedColor, mIncognitoTab.getTint(true, false));
// Incognito inactive tab color.
expectedColor = mContext.getColor(R.color.bg_tabstrip_tab_detached_startup_tint);
assertEquals("Incognito inactive tab should match the placeholder color.", expectedColor,
mIncognitoTab.getTint(false));
mIncognitoTab.getTint(false, false));
}
@Test
@Feature("Tab Strip Redesign")
@Features.EnableFeatures({ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP})
public void testGetOutlineTint() {
int expectedColor;

@ -42,6 +42,8 @@ import org.chromium.chrome.browser.compositor.scene_layer.TabStripSceneLayerJni;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.layouts.scene_layer.SceneLayer;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.ui.resources.ResourceManager;
/** Tests for {@link TabStripSceneLayer}. */
@ -124,14 +126,16 @@ public class TabStripSceneLayerTest {
}
@Test
@Features.DisableFeatures(ChromeFeatureList.TAB_STRIP_REDESIGN)
@DisableFeatures(ChromeFeatureList.TAB_STRIP_REDESIGN)
@EnableFeatures(ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP)
public void testPushAndUpdateStrip() {
// Setup
boolean isSelected = false;
boolean isHovered = false;
// Call the method being tested.
mTabStripSceneLayer.pushAndUpdateStrip(mStripLayoutHelperManager, mLayerTitleCache,
mResourceManager, mStripLayoutTabs, 1.f, 0);
mResourceManager, mStripLayoutTabs, 1.f, 0, -1);
// Verify JNI calls.
verify(mTabStripSceneMock).beginBuildingFrame(1L, mTabStripSceneLayer, true);
@ -165,7 +169,8 @@ public class TabStripSceneLayerTest {
mStripLayoutTab.getDividerResourceId(), mStripLayoutTab.getResourceId(),
mStripLayoutTab.getOutlineResourceId(),
mStripLayoutTab.getCloseButton().getTint(),
mStripLayoutTab.getDividerTint(), mStripLayoutTab.getTint(isSelected),
mStripLayoutTab.getDividerTint(),
mStripLayoutTab.getTint(isSelected, isHovered),
mStripLayoutTab.getOutlineTint(isSelected), isSelected,
mStripLayoutTab.getClosePressed(), 0.f * mDpToPx,
mStripLayoutTab.getDrawX() * mDpToPx, mStripLayoutTab.getDrawY() * mDpToPx,
@ -190,10 +195,11 @@ public class TabStripSceneLayerTest {
@Test
@Feature("Tab Strip Redesign")
@EnableFeatures(ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP)
public void testPushAndUpdateStrip_TSR() {
// Call the method being tested.
mTabStripSceneLayer.pushAndUpdateStrip(mStripLayoutHelperManager, mLayerTitleCache,
mResourceManager, mStripLayoutTabs, 1.f, 0);
mResourceManager, mStripLayoutTabs, 1.f, 0, -1);
// Verify TSR JNI calls.
verify(mTabStripSceneMock)

@ -10,6 +10,7 @@ android_library("java") {
"java/src/org/chromium/chrome/browser/theme/ThemeUtils.java",
"java/src/org/chromium/chrome/browser/theme/TopUiThemeColorProvider.java",
"java/src/org/chromium/chrome/browser/ui/theme/BrandedColorScheme.java",
"java/src/org/chromium/chrome/browser/ui/theme/ChromeSemanticColorUtils.java",
]
deps = [
":java_resources",

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser;
package org.chromium.chrome.browser.ui.theme;
import android.content.Context;
@ -34,4 +34,9 @@ public class ChromeSemanticColorUtils {
public static @ColorInt int getOfflineIndicatorBackOnlineColor(Context context) {
return SemanticColorUtils.getDefaultControlColorActive(context);
}
}
/** Returns the semantic color value that corresponds to tab_inactive_hover_color. */
public static @ColorInt int getTabInactiveHoverColor(Context context) {
return SemanticColorUtils.getDefaultControlColorActive(context);
}
}

@ -152,7 +152,7 @@ public class ToolbarControlContainer extends OptimizedFrameLayout implements Con
Drawable bdgTabImage = ResourcesCompat.getDrawable(getContext().getResources(),
TabUiThemeUtil.getTSRTabResource(), getContext().getTheme());
bdgTabImage.setTint(TabUiThemeUtil.getTabStripContainerColor(
getContext(), incognito, true, false, false));
getContext(), incognito, true, false, false, false));
LayerDrawable backgroundDrawable =
new LayerDrawable(new Drawable[] {bgdColor, bdgTabImage});
// Set image size to match tab size.

@ -41,7 +41,7 @@ At the time of writing, there is no support for macros in Java code. So, we have
##### Location
While the most common semantic names are defined in [`semantic_colors_dynamic.xml`](https://source.chromium.org/chromium/chromium/src/+/main:components/browser_ui/styles/android/java/res/values/semantic_colors_dynamic.xml;drc=efb53ff2cb5ea3db8643840d7a9bde4ecdab1741), feature or surface specific semantic names can be defined in their relative modules or directories. Then, they can reference other macros or directly reference theme attributes. For example, [`suggestion_url_color`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/android/omnibox/java/res/values/colors.xml;drc=efb53ff2cb5ea3db8643840d7a9bde4ecdab1741;l=10) is defined in `chrome/browser/ui/android/omnibox/` and it references `@macro/default_text_color_link`, a common semantic name. If this semantic color needs to be accessed from Java code, a utility method can be added to the utility class for that directory, e.g. [ChromeSemanticColorUtils](https://source.chromium.org/chromium/chromium/src/+/main:chrome/android/java/src/org/chromium/chrome/browser/ChromeSemanticColorUtils.java;drc=a7ae6c6cf46bfc855c55de34ce319c9b9cab10e9).
While the most common semantic names are defined in [`semantic_colors_dynamic.xml`](https://source.chromium.org/chromium/chromium/src/+/main:components/browser_ui/styles/android/java/res/values/semantic_colors_dynamic.xml;drc=efb53ff2cb5ea3db8643840d7a9bde4ecdab1741), feature or surface specific semantic names can be defined in their relative modules or directories. Then, they can reference other macros or directly reference theme attributes. For example, [`suggestion_url_color`](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/android/omnibox/java/res/values/colors.xml;drc=efb53ff2cb5ea3db8643840d7a9bde4ecdab1741;l=10) is defined in `chrome/browser/ui/android/omnibox/` and it references `@macro/default_text_color_link`, a common semantic name. If this semantic color needs to be accessed from Java code, a utility method can be added to the utility class for that directory, e.g. [ChromeSemanticColorUtils](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/android/theme/java/src/org/chromium/chrome/browser/ui/theme/ChromeSemanticColorUtils.java).
#### Color state lists