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/start_surface:public_java",
"//chrome/android/features/tab_ui:tab_suggestions_java", "//chrome/android/features/tab_ui:tab_suggestions_java",
"//chrome/android/features/tab_ui/public: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/cablev2_authenticator/public:java",
"//chrome/android/modules/image_editor/provider:java", "//chrome/android/modules/image_editor/provider:java",
"//chrome/android/modules/stack_unwinder/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/ChromeInactivityTracker.java",
"java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java", "java/src/org/chromium/chrome/browser/ChromeKeyboardVisibilityDelegate.java",
"java/src/org/chromium/chrome/browser/ChromeLocalizationUtils.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/ChromeStrictMode.java",
"java/src/org/chromium/chrome/browser/ChromeStringConstants.java", "java/src/org/chromium/chrome/browser/ChromeStringConstants.java",
"java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java", "java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java",

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

@@ -9,4 +9,10 @@ found in the LICENSE file.
<!-- Tab strip container alpha values --> <!-- 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_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> <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> </resources>

@@ -8,8 +8,10 @@ import android.content.Context;
import android.graphics.Color; import android.graphics.Color;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
import androidx.core.content.res.ResourcesCompat;
import org.chromium.chrome.browser.flags.ChromeFeatureList; 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.ChromeColors;
import org.chromium.components.browser_ui.styles.SemanticColorUtils; import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.ui.util.ColorUtils; 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, * 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 context {@link Context} used to retrieve color.
* @param isIncognito Whether the color is used for incognito mode. * @param isIncognito Whether the color is used for incognito mode.
* @param foreground Whether the tab is in the foreground. * @param foreground Whether the tab is in the foreground.
* @param isReordering Whether the tab is being reordered. * @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. * @return The color for the tab container.
*/ */
public static @ColorInt int getTabStripContainerColor(Context context, boolean isIncognito, // TODO (crbug.com/1469465): Encapsulate tab properties in a state object.
boolean foreground, boolean isReordering, boolean isPlaceholder) { public static int getTabStripContainerColor(Context context, boolean isIncognito,
boolean foreground, boolean isReordering, boolean isPlaceholder, boolean isHovered) {
if (foreground) { if (foreground) {
if (TabManagementFieldTrial.isTabStripFolioEnabled()) { if (TabManagementFieldTrial.isTabStripFolioEnabled()) {
return ChromeColors.getDefaultThemeColor(context, isIncognito); return ChromeColors.getDefaultThemeColor(context, isIncognito);
} else if (TabManagementFieldTrial.isTabStripDetachedEnabled()) { } else if (TabManagementFieldTrial.isTabStripDetachedEnabled()) {
return getTabStripDetachedTabColor(context, isIncognito, isReordering); return getTabStripDetachedTabColor(context, isIncognito, isReordering);
} }
} else if (isHovered) {
return getHoveredTabContainerColor(context, isIncognito);
} else if (isPlaceholder) { } else if (isPlaceholder) {
return getTabStripStartupContainerColor(context); return getTabStripStartupContainerColor(context);
} else { } else {
@@ -85,6 +91,24 @@ public class TabUiThemeUtil {
return Color.TRANSPARENT; 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. * 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) {} public void onHoverMove(float x, float y) {}
@Override @Override
public void onHoverExit(float x, float y) {} public void onHoverExit() {}
// SwipeHandler implementation. // SwipeHandler implementation.

@@ -18,9 +18,9 @@ import org.chromium.base.MathUtils;
import org.chromium.base.supplier.ObservableSupplier; import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.ObservableSupplierImpl; import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.chrome.R; 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.PanelState;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason; 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.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.ui.base.LocalizationUtils; import org.chromium.ui.base.LocalizationUtils;
import org.chromium.ui.resources.dynamics.DynamicResourceLoader; 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 // 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 close icon starts fading in. Any other elements fading in or fading out should use
// the same percentage. // the same percentage.
float fadingOutPercentage = Math.min(percentage, .5f) / .5f;
float fadingInPercentage = Math.max(percentage - .5f, 0.f) / .5f; float fadingInPercentage = Math.max(percentage - .5f, 0.f) / .5f;
// Close Icon. // Close Icon.

@@ -16,7 +16,6 @@ import android.widget.TextView;
import org.chromium.base.MathUtils; import org.chromium.base.MathUtils;
import org.chromium.chrome.R; 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.OverlayPanel;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelAnimation; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelAnimation;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelInflater; 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.contextualsearch.ContextualSearchUma;
import org.chromium.chrome.browser.layouts.animation.CompositorAnimator; import org.chromium.chrome.browser.layouts.animation.CompositorAnimator;
import org.chromium.chrome.browser.settings.SettingsLauncherImpl; 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.components.browser_ui.settings.SettingsLauncher;
import org.chromium.ui.base.LocalizationUtils; import org.chromium.ui.base.LocalizationUtils;
import org.chromium.ui.base.ViewUtils; import org.chromium.ui.base.ViewUtils;

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

@@ -93,9 +93,6 @@ public interface GestureHandler {
/** /**
* Called on hover exit event. * 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_BACKGROUND_HEIGHT_DP_TSR = 32.f;
private static final float NEW_TAB_BUTTON_PADDING_DP = 24.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 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_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 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_DEFAULT_PRESSED_OPACITY = 0.2f;
private static final float NEW_TAB_BUTTON_DARK_DETACHED_OPACITY = 0.15f; 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 MultiInstanceManager mMultiInstanceManager;
private View mToolbarContainerView; private View mToolbarContainerView;
private StripLayoutTab mActiveClickedTab; private StripLayoutTab mActiveClickedTab;
private StripLayoutTab mLastHoveredTab;
private TabDropTarget mTabDropTarget; 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. // Don't interrupt tab group background tab visibility.
if (tab.getContainerOpacity() != TAB_OPACITY_VISIBLE_BACKGROUND) { 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_VISIBLE_FOREGROUND
: TAB_OPACITY_HIDDEN; : TAB_OPACITY_HIDDEN;
tab.setContainerOpacity(containerOpacity); 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 * Called to show/hide dividers and the foreground/hovered tab container. Dividers are only
* between tabs that both do not have a visible tab container (foreground or background). * 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; if (!ChromeFeatureList.sTabStripRedesign.isEnabled()) return;
// Validate the index. For example, the index can be {@link TabList.INVALID_TAB_INDEX} when // 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; int selectedIndex = mTabStateInitialized ? mModel.index() : mActiveTabIndexOnStartup;
if (selectedIndex < 0 || selectedIndex >= mStripTabs.length) return; 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. // Divider is never shown for the first tab.
mStripTabs[0].setStartDividerVisible(false); 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 // End divider for first tab is only shown in reorder mode when tab has trailing margin and
// container is not visible. // container is not visible.
boolean endDividerVisible = mInReorderMode boolean endDividerVisible = mInReorderMode
@@ -1074,9 +1083,10 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
final StripLayoutTab prevTab = mStripTabs[i - 1]; final StripLayoutTab prevTab = mStripTabs[i - 1];
final StripLayoutTab currTab = mStripTabs[i]; final StripLayoutTab currTab = mStripTabs[i];
boolean currTabSelected = selectedIndex == i; boolean currTabSelected = selectedIndex == i;
boolean currTabHovered = hoveredIndex == i;
// Set container opacity. // Set container opacity.
setForegroundTabContainerVisible(currTab, currTabSelected); setTabContainerVisible(currTab, currTabSelected, currTabHovered);
/** /**
* Start divider should be visible when: * Start divider should be visible when:
@@ -1387,7 +1397,11 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
*/ */
public void onHoverEnter(float x, float y) { public void onHoverEnter(float x, float y) {
if (!isPeripheralsSupportForTabStripEnabled()) return; 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) { public void onHoverMove(float x, float y) {
if (!isPeripheralsSupportForTabStripEnabled()) return; 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. * 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; 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() { private boolean isPeripheralsSupportForTabStripEnabled() {
@@ -1904,7 +1967,7 @@ public class StripLayoutHelper implements StripLayoutTab.StripLayoutTabDelegate
updateCloseButtons(); updateCloseButtons();
// 9. Show dividers between inactive tabs. // 9. Show dividers between inactive tabs.
updateForegroundTabContainersAndDividers(); updateTabContainersAndDividers();
} }
private void computeTabInitialPositions() { private void computeTabInitialPositions() {

@@ -221,8 +221,8 @@ public class StripLayoutHelperManager implements SceneOverlay, PauseResumeWithNa
} }
@Override @Override
public void onHoverExit(float x, float y) { public void onHoverExit() {
getActiveStripLayoutHelper().onHoverExit(x, y); getActiveStripLayoutHelper().onHoverExit();
} }
private long time() { private long time() {
@@ -472,9 +472,12 @@ public class StripLayoutHelperManager implements SceneOverlay, PauseResumeWithNa
Tab selectedTab = mTabModelSelector.getCurrentModel().getTabAt( Tab selectedTab = mTabModelSelector.getCurrentModel().getTabAt(
mTabModelSelector.getCurrentModel().index()); mTabModelSelector.getCurrentModel().index());
int selectedTabId = selectedTab == null ? TabModel.INVALID_TAB_INDEX : selectedTab.getId(); 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(), mTabStripTreeProvider.pushAndUpdateStrip(this, mLayerTitleCacheSupplier.get(),
resourceManager, getActiveStripLayoutHelper().getStripLayoutTabsToRender(), yOffset, resourceManager, getActiveStripLayoutHelper().getStripLayoutTabsToRender(), yOffset,
selectedTabId); selectedTabId, hoveredTabId);
return mTabStripTreeProvider; return mTabStripTreeProvider;
} }
@@ -917,7 +920,11 @@ public class StripLayoutHelperManager implements SceneOverlay, PauseResumeWithNa
} else if (event == MotionEvent.ACTION_HOVER_MOVE) { } else if (event == MotionEvent.ACTION_HOVER_MOVE) {
mTabStripEventHandler.onHoverMove(x, y); mTabStripEventHandler.onHoverMove(x, y);
} else if (event == MotionEvent.ACTION_HOVER_EXIT) { } 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; mFolioAttached = folioAttached;
} }
boolean getFolioAttachedForTesting() {
return mFolioAttached;
}
/** /**
* Sets the id of the {@link Tab} this {@link StripLayoutTab} represents. * 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. * @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 // 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). // color and only re-determine when the color could have changed (i.e. on selection).
if (ChromeFeatureList.sTabStripRedesign.isEnabled()) { if (ChromeFeatureList.sTabStripRedesign.isEnabled()) {
return TabUiThemeUtil.getTabStripContainerColor( return TabUiThemeUtil.getTabStripContainerColor(
mContext, mIncognito, foreground, mIsReordering, mIsPlaceholder); mContext, mIncognito, foreground, mIsReordering, mIsPlaceholder, hovered);
} }
if (foreground) { if (foreground) {
return ChromeColors.getDefaultThemeColor(mContext, mIncognito); return ChromeColors.getDefaultThemeColor(mContext, mIncognito);
} }
// |defaultColor| represents the color of a background/inactive tab.
int defaultColor;
int overlayColor;
if (mIncognito) { if (mIncognito) {
return mContext.getResources().getColor( defaultColor = mContext.getResources().getColor(
R.color.baseline_neutral_10_with_neutral_0_alpha_30); 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 = if (hovered) {
ChromeColors.getSurfaceColor(mContext, R.dimen.compositor_background_tab_elevation); return ColorUtils.getColorWithOverlay(defaultColor, overlayColor,
final float overlayAlpha = ResourcesCompat.getFloat( ResourcesCompat.getFloat(
mContext.getResources(), R.dimen.compositor_background_tab_overlay_alpha); mContext.getResources(), R.dimen.gm2_tab_inactive_hover_alpha));
return ColorUtils.getColorWithOverlay(baseColor, Color.BLACK, overlayAlpha); }
return defaultColor;
} }
/** /**
@@ -426,7 +448,7 @@ public class StripLayoutTab implements VirtualView {
} }
if (foreground) { if (foreground) {
return getTint(true); return getTint(true, false);
} }
if (mIncognito) { 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); 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 int overlayColor = MaterialColors.getColor(mContext, R.attr.colorOutline, TAG);
final float overlayAlpha = ResourcesCompat.getFloat( final float overlayAlpha = ResourcesCompat.getFloat(
mContext.getResources(), R.dimen.compositor_background_tab_outline_alpha); mContext.getResources(), R.dimen.compositor_background_tab_outline_alpha);

@@ -71,10 +71,14 @@ public class TabStripSceneLayer extends SceneOverlayLayer {
* @param resourceManager A resource manager. * @param resourceManager A resource manager.
* @param stripLayoutTabsToRender Array of strip layout tabs. * @param stripLayoutTabsToRender Array of strip layout tabs.
* @param yOffset Current browser controls offset in dp. * @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, public void pushAndUpdateStrip(StripLayoutHelperManager layoutHelper,
LayerTitleCache layerTitleCache, ResourceManager resourceManager, LayerTitleCache layerTitleCache, ResourceManager resourceManager,
StripLayoutTab[] stripLayoutTabsToRender, float yOffset, int selectedTabId) { StripLayoutTab[] stripLayoutTabsToRender, float yOffset, int selectedTabId,
int hoveredTabId) {
if (mNativePtr == 0) return; if (mNativePtr == 0) return;
final boolean visible = yOffset > -layoutHelper.getHeight(); final boolean visible = yOffset > -layoutHelper.getHeight();
// This will hide the tab strips if necessary. // This will hide the tab strips if necessary.
@@ -84,7 +88,7 @@ public class TabStripSceneLayer extends SceneOverlayLayer {
if (visible) { if (visible) {
pushButtonsAndBackground(layoutHelper, resourceManager, yOffset); pushButtonsAndBackground(layoutHelper, resourceManager, yOffset);
pushStripTabs(layoutHelper, layerTitleCache, resourceManager, stripLayoutTabsToRender, pushStripTabs(layoutHelper, layerTitleCache, resourceManager, stripLayoutTabsToRender,
selectedTabId); selectedTabId, hoveredTabId);
} }
TabStripSceneLayerJni.get().finishBuildingFrame(mNativePtr, TabStripSceneLayer.this); TabStripSceneLayerJni.get().finishBuildingFrame(mNativePtr, TabStripSceneLayer.this);
} }
@@ -149,7 +153,7 @@ public class TabStripSceneLayer extends SceneOverlayLayer {
private void pushStripTabs(StripLayoutHelperManager layoutHelper, private void pushStripTabs(StripLayoutHelperManager layoutHelper,
LayerTitleCache layerTitleCache, ResourceManager resourceManager, LayerTitleCache layerTitleCache, ResourceManager resourceManager,
StripLayoutTab[] stripTabs, int selectedTabId) { StripLayoutTab[] stripTabs, int selectedTabId, int hoveredTabId) {
final int tabsCount = stripTabs != null ? stripTabs.length : 0; final int tabsCount = stripTabs != null ? stripTabs.length : 0;
// TODO(https://crbug.com/1450380): Cleanup params, as some don't change and others are now // 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++) { for (int i = 0; i < tabsCount; i++) {
final StripLayoutTab st = stripTabs[i]; final StripLayoutTab st = stripTabs[i];
boolean isSelected = st.getId() == selectedTabId; boolean isSelected = st.getId() == selectedTabId;
boolean isHovered = st.getId() == hoveredTabId;
TabStripSceneLayerJni.get().putStripTabLayer(mNativePtr, TabStripSceneLayer.this, TabStripSceneLayerJni.get().putStripTabLayer(mNativePtr, TabStripSceneLayer.this,
st.getId(), st.getCloseButton().getResourceId(), st.getDividerResourceId(), st.getId(), st.getCloseButton().getResourceId(), st.getDividerResourceId(),
st.getResourceId(), st.getOutlineResourceId(), st.getCloseButton().getTint(), st.getResourceId(), st.getOutlineResourceId(), st.getCloseButton().getTint(),
st.getDividerTint(), st.getTint(isSelected), st.getOutlineTint(isSelected), st.getDividerTint(), st.getTint(isSelected, isHovered),
isSelected, st.getClosePressed(), layoutHelper.getWidth() * mDpToPx, st.getOutlineTint(isSelected), isSelected, st.getClosePressed(),
st.getDrawX() * mDpToPx, st.getDrawY() * mDpToPx, st.getWidth() * mDpToPx, layoutHelper.getWidth() * mDpToPx, st.getDrawX() * mDpToPx,
st.getHeight() * mDpToPx, st.getContentOffsetY() * mDpToPx, st.getDrawY() * mDpToPx, st.getWidth() * mDpToPx, st.getHeight() * mDpToPx,
st.getDividerOffsetX() * mDpToPx, st.getBottomMargin() * mDpToPx, st.getContentOffsetY() * mDpToPx, st.getDividerOffsetX() * mDpToPx,
st.getTopMargin() * mDpToPx, st.getCloseButtonPadding() * mDpToPx, st.getBottomMargin() * mDpToPx, st.getTopMargin() * mDpToPx,
st.getCloseButton().getOpacity(), st.isStartDividerVisible(), st.getCloseButtonPadding() * mDpToPx, st.getCloseButton().getOpacity(),
st.isEndDividerVisible(), st.isLoading(), st.getLoadingSpinnerRotation(), st.isStartDividerVisible(), st.isEndDividerVisible(), st.isLoading(),
st.getBrightness(), st.getContainerOpacity(), layerTitleCache, resourceManager); 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.ObservableSupplier;
import org.chromium.base.supplier.Supplier; import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSemanticColorUtils;
import org.chromium.chrome.browser.status_indicator.StatusIndicatorCoordinator; 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.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.content_public.common.ContentSwitches; import org.chromium.content_public.common.ContentSwitches;
@@ -262,7 +262,6 @@ public class OfflineIndicatorControllerV2 {
surfaceState = mCanAnimateBrowserControlsSupplier.get() surfaceState = mCanAnimateBrowserControlsSupplier.get()
? UmaEnum.CAN_ANIMATE_NATIVE_CONTROLS ? UmaEnum.CAN_ANIMATE_NATIVE_CONTROLS
: UmaEnum.CANNOT_ANIMATE_NATIVE_CONTROLS; : UmaEnum.CANNOT_ANIMATE_NATIVE_CONTROLS;
;
} }
RecordHistogram.recordEnumeratedHistogram( RecordHistogram.recordEnumeratedHistogram(
"OfflineIndicator.ConnectivityChanged.DeviceState." "OfflineIndicator.ConnectivityChanged.DeviceState."

@@ -16,9 +16,9 @@ import android.widget.TextView;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeSemanticColorUtils;
import org.chromium.chrome.browser.omnibox.ChromeAutocompleteSchemeClassifier; import org.chromium.chrome.browser.omnibox.ChromeAutocompleteSchemeClassifier;
import org.chromium.chrome.browser.profiles.Profile; 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.browser_ui.widget.TintedDrawable;
import org.chromium.components.embedder_support.util.UrlConstants; import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.omnibox.OmniboxUrlEmphasizer; import org.chromium.components.omnibox.OmniboxUrlEmphasizer;

@@ -36,7 +36,7 @@ import androidx.gridlayout.widget.GridLayout;
import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R; 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.autofill.EditableOption;
import org.chromium.components.browser_ui.styles.SemanticColorUtils; import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.components.browser_ui.widget.DualControlLayout; 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.CriteriaHelper;
import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature; 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.base.test.util.Restriction;
import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton; import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton;
import org.chromium.chrome.browser.flags.ChromeFeatureList; 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.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabModelUtils; 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.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule; import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.chrome.test.util.TabStripUtils; 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.DOMUtils;
import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.base.LocalizationUtils; 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 @Test
@LargeTest @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) @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. // Open a few regular tabs.
ChromeTabUtils.newTabsFromMenu( ChromeTabUtils.newTabsFromMenu(
InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity(), 4); InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity(), 4);
// Select a tab to hover on. // Select tabs to hover on.
TabModel model = sActivityTestRule.getActivity().getTabModelSelector().getModel(false); 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()); 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 = StripLayoutHelperManager stripLayoutHelperManager =
TabStripUtils.getStripLayoutHelperManager(sActivityTestRule.getActivity()); TabStripUtils.getStripLayoutHelperManager(sActivityTestRule.getActivity());
float xEnter = tab.getDrawX() + tab.getWidth() / 2; float xEnter = tab1.getDrawX() + tab1.getWidth() / 2;
float yEnter = tab.getDrawY() + tab.getHeight() / 2; float yEnter = tab1.getDrawY() + tab1.getHeight() / 2;
stripLayoutHelperManager.simulateHoverEventForTesting( stripLayoutHelperManager.simulateHoverEventForTesting(
MotionEvent.ACTION_HOVER_ENTER, xEnter, yEnter); 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. // Simulate a subsequent hover into the adjacent tab (tab2).
float xMove = tab.getDrawX() + tab.getWidth() / 3; float xMove = tab2.getDrawX() + tab2.getWidth() / 3;
float yMove = tab.getDrawY() + tab.getHeight() / 3; float yMove = tab2.getDrawY() + tab2.getHeight() / 3;
stripLayoutHelperManager.simulateHoverEventForTesting( stripLayoutHelperManager.simulateHoverEventForTesting(
MotionEvent.ACTION_HOVER_MOVE, xMove, yMove); 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. // Simulate a subsequent hover outside tab2.
float xExit = tab.getDrawX() + 2 * tab.getWidth(); float xExit = tab2.getDrawX() + 2 * tab2.getWidth();
float yExit = tab.getDrawY() + 2 * tab.getHeight(); float yExit = tab2.getDrawY() + 2 * tab2.getHeight();
stripLayoutHelperManager.simulateHoverEventForTesting( stripLayoutHelperManager.simulateHoverEventForTesting(
MotionEvent.ACTION_HOVER_EXIT, xExit, yExit); MotionEvent.ACTION_HOVER_EXIT, xExit, yExit);
lastHoveredTab = stripLayoutHelperManager.getActiveStripLayoutHelper().getLastHoveredTab();
// TODO (crbug.com/1451925): Update verification in test(s) after hover handling is added in Assert.assertNull("The last hovered tab is not set correctly.", lastHoveredTab);
// StripLayoutHelper. Assert.assertTrue(
"|mFolioAttached| for tab2 should be true.", tab2.getFolioAttachedForTesting());
} }
/** /**

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

@@ -5,9 +5,11 @@
package org.chromium.chrome.browser.compositor.overlays.strip; package org.chromium.chrome.browser.compositor.overlays.strip;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.graphics.RectF;
import android.view.ContextThemeWrapper; import android.view.ContextThemeWrapper;
import android.view.View; 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.multiwindow.MultiInstanceManager;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabCreatorManager; 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.TabModelFilterProvider;
import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tasks.tab_management.TabManagementFieldTrial; import org.chromium.chrome.browser.tasks.tab_management.TabManagementFieldTrial;
@@ -64,6 +67,8 @@ public class StripLayoutHelperManagerTest {
@Mock @Mock
private TabStripSceneLayer.Natives mTabStripSceneMock; private TabStripSceneLayer.Natives mTabStripSceneMock;
@Mock @Mock
private TabStripSceneLayer mTabStripTreeProvider;
@Mock
private LayoutManagerHost mManagerHost; private LayoutManagerHost mManagerHost;
@Mock @Mock
private LayoutUpdateHost mUpdateHost; private LayoutUpdateHost mUpdateHost;
@@ -83,6 +88,12 @@ public class StripLayoutHelperManagerTest {
private TabCreatorManager mTabCreatorManager; private TabCreatorManager mTabCreatorManager;
@Mock @Mock
private TabModelFilterProvider mTabModelFilterProvider; private TabModelFilterProvider mTabModelFilterProvider;
@Mock
private TabModel mTabModel;
@Mock
private Tab mSelectedTab;
@Mock
private StripLayoutTab mHoveredStripTab;
private StripLayoutHelperManager mStripLayoutHelperManager; private StripLayoutHelperManager mStripLayoutHelperManager;
private Context mContext; private Context mContext;
@@ -376,4 +387,32 @@ public class StripLayoutHelperManagerTest {
assertEquals("Unexpected incognito active tab index", expectedIncognitoActiveTabIndex, assertEquals("Unexpected incognito active tab index", expectedIncognitoActiveTabIndex,
incognitoHelper.getActiveTabIndexOnStartupForTesting()); 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.R;
import org.chromium.chrome.browser.flags.ChromeFeatureList; import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.tasks.tab_management.TabManagementFieldTrial; 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;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.components.browser_ui.styles.ChromeColors; import org.chromium.components.browser_ui.styles.ChromeColors;
import org.chromium.components.browser_ui.styles.SemanticColorUtils; import org.chromium.components.browser_ui.styles.SemanticColorUtils;
import org.chromium.ui.util.ColorUtils; import org.chromium.ui.util.ColorUtils;
@@ -55,91 +57,151 @@ public class StripLayoutTabTest {
@Test @Test
@Feature("Tab Strip Redesign") @Feature("Tab Strip Redesign")
@EnableFeatures({ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP})
public void testGetTint() { public void testGetTint() {
int expectedColor; int expectedColor;
// Normal active tab color. // Normal active tab color.
expectedColor = MaterialColors.getColor(mContext, R.attr.colorSurface, TAG); expectedColor = MaterialColors.getColor(mContext, R.attr.colorSurface, TAG);
assertEquals("Normal active tab should match the Surface-0 color.", expectedColor, assertEquals("Normal active tab should match the Surface-0 color.", expectedColor,
mNormalTab.getTint(true)); mNormalTab.getTint(true, false));
// Normal inactive tab color. // Normal inactive tab color.
expectedColor = expectedColor =
ChromeColors.getSurfaceColor(mContext, R.dimen.compositor_background_tab_elevation); ChromeColors.getSurfaceColor(mContext, R.dimen.compositor_background_tab_elevation);
assertEquals("Normal inactive tab should match the Surface-4 color.", expectedColor, 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. // Incognito active tab color.
expectedColor = mContext.getColor(R.color.toolbar_background_primary_dark); expectedColor = mContext.getColor(R.color.toolbar_background_primary_dark);
assertEquals("Incognito active tab should match the baseline color.", expectedColor, assertEquals("Incognito active tab should match the baseline color.", expectedColor,
mIncognitoTab.getTint(true)); mIncognitoTab.getTint(true, false));
// Incognito inactive tab color. // Incognito inactive tab color.
expectedColor = mContext.getResources().getColor( expectedColor = mContext.getResources().getColor(
R.color.baseline_neutral_10_with_neutral_0_alpha_30); R.color.baseline_neutral_10_with_neutral_0_alpha_30);
assertEquals("Incognito inactive tab should match the baseline color.", expectedColor, 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 @Test
@Feature("Tab Strip Redesign") @Feature("Tab Strip Redesign")
@Features.EnableFeatures({ChromeFeatureList.TAB_STRIP_REDESIGN}) @Features.EnableFeatures({ChromeFeatureList.TAB_STRIP_REDESIGN,
public void testGetTint_TabStripRedesignFolio() { ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP})
public void
testGetTint_TabStripRedesignFolio() {
TabManagementFieldTrial.TAB_STRIP_REDESIGN_ENABLE_FOLIO.setForTesting(true); TabManagementFieldTrial.TAB_STRIP_REDESIGN_ENABLE_FOLIO.setForTesting(true);
int expectedColor; int expectedColor;
// Normal active tab color. // Normal active tab color.
expectedColor = MaterialColors.getColor(mContext, R.attr.colorSurface, TAG); expectedColor = MaterialColors.getColor(mContext, R.attr.colorSurface, TAG);
assertEquals("Normal active folio should match the Surface-0 color.", expectedColor, assertEquals("Normal active folio should match the Surface-0 color.", expectedColor,
mNormalTab.getTint(true)); mNormalTab.getTint(true, false));
// Normal inactive tab color. // Normal inactive tab color.
expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_0); expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_0);
assertEquals("Folio inactive tab containers should be Surface-0.", expectedColor, 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. // Incognito active tab color.
expectedColor = mContext.getColor(R.color.toolbar_background_primary_dark); expectedColor = mContext.getColor(R.color.toolbar_background_primary_dark);
assertEquals("Incognito active folio should match the baseline color.", expectedColor, assertEquals("Incognito active folio should match the baseline color.", expectedColor,
mIncognitoTab.getTint(true)); mIncognitoTab.getTint(true, false));
// Incognito inactive tab color. // Incognito inactive tab color.
expectedColor = mContext.getColor(R.color.default_bg_color_dark); expectedColor = mContext.getColor(R.color.default_bg_color_dark);
assertEquals("Incognito inactive folio should be baseline Surface-0.", expectedColor, 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 @Test
@Feature("Tab Strip Redesign") @Feature("Tab Strip Redesign")
@Features.EnableFeatures({ChromeFeatureList.TAB_STRIP_REDESIGN}) @Features.EnableFeatures({ChromeFeatureList.TAB_STRIP_REDESIGN,
public void testGetTint_TabStripRedesignDetached() { ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP})
public void
testGetTint_TabStripRedesignDetached() {
TabManagementFieldTrial.TAB_STRIP_REDESIGN_ENABLE_DETACHED.setForTesting(true); TabManagementFieldTrial.TAB_STRIP_REDESIGN_ENABLE_DETACHED.setForTesting(true);
int expectedColor; int expectedColor;
// Normal active tab color. // Normal active tab color.
expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_5); expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_5);
assertEquals("Detached normal active should match the Surface-5 color.", expectedColor, assertEquals("Detached normal active should match the Surface-5 color.", expectedColor,
mNormalTab.getTint(true)); mNormalTab.getTint(true, false));
// Normal inactive tab color. // Normal inactive tab color.
expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_5); expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_5);
assertEquals("Detached inactive tab containers should be Surface-5.", expectedColor, 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. // Incognito active tab color.
expectedColor = Color.BLACK; expectedColor = Color.BLACK;
assertEquals("Detached incognito active should match the color black.", expectedColor, assertEquals("Detached incognito active should match the color black.", expectedColor,
mIncognitoTab.getTint(true)); mIncognitoTab.getTint(true, false));
// Incognito inactive tab color. // Incognito inactive tab color.
expectedColor = mContext.getColor(R.color.default_bg_color_dark_elev_5_gm3_baseline); expectedColor = mContext.getColor(R.color.default_bg_color_dark_elev_5_gm3_baseline);
assertEquals("Detached incognito inactive should be baseline Surface-5.", expectedColor, 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 @Test
@Features.EnableFeatures( @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 public void
testGetTint_Startup_TabStripRedesign() { testGetTint_Startup_TabStripRedesign() {
TabManagementFieldTrial.TAB_STRIP_REDESIGN_ENABLE_DETACHED.setForTesting(true); TabManagementFieldTrial.TAB_STRIP_REDESIGN_ENABLE_DETACHED.setForTesting(true);
@@ -151,26 +213,27 @@ public class StripLayoutTabTest {
// Normal active tab color. // Normal active tab color.
expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_5); expectedColor = ChromeColors.getSurfaceColor(mContext, R.dimen.default_elevation_5);
assertEquals("Detached normal active should match the regular foreground color.", assertEquals("Detached normal active should match the regular foreground color.",
expectedColor, mNormalTab.getTint(true)); expectedColor, mNormalTab.getTint(true, false));
// Normal inactive tab color. // Normal inactive tab color.
expectedColor = mContext.getColor(R.color.bg_tabstrip_tab_detached_startup_tint); expectedColor = mContext.getColor(R.color.bg_tabstrip_tab_detached_startup_tint);
assertEquals("Normal inactive tab should match the placeholder color.", expectedColor, assertEquals("Normal inactive tab should match the placeholder color.", expectedColor,
mNormalTab.getTint(false)); mNormalTab.getTint(false, false));
// Incognito active tab color. // Incognito active tab color.
expectedColor = Color.BLACK; expectedColor = Color.BLACK;
assertEquals("Detached incognito active should match the regular foreground color.", assertEquals("Detached incognito active should match the regular foreground color.",
expectedColor, mIncognitoTab.getTint(true)); expectedColor, mIncognitoTab.getTint(true, false));
// Incognito inactive tab color. // Incognito inactive tab color.
expectedColor = mContext.getColor(R.color.bg_tabstrip_tab_detached_startup_tint); expectedColor = mContext.getColor(R.color.bg_tabstrip_tab_detached_startup_tint);
assertEquals("Incognito inactive tab should match the placeholder color.", expectedColor, assertEquals("Incognito inactive tab should match the placeholder color.", expectedColor,
mIncognitoTab.getTint(false)); mIncognitoTab.getTint(false, false));
} }
@Test @Test
@Feature("Tab Strip Redesign") @Feature("Tab Strip Redesign")
@Features.EnableFeatures({ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP})
public void testGetOutlineTint() { public void testGetOutlineTint() {
int expectedColor; 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.flags.ChromeFeatureList;
import org.chromium.chrome.browser.layouts.scene_layer.SceneLayer; 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;
import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.ui.resources.ResourceManager; import org.chromium.ui.resources.ResourceManager;
/** Tests for {@link TabStripSceneLayer}. */ /** Tests for {@link TabStripSceneLayer}. */
@@ -124,14 +126,16 @@ public class TabStripSceneLayerTest {
} }
@Test @Test
@Features.DisableFeatures(ChromeFeatureList.TAB_STRIP_REDESIGN) @DisableFeatures(ChromeFeatureList.TAB_STRIP_REDESIGN)
@EnableFeatures(ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP)
public void testPushAndUpdateStrip() { public void testPushAndUpdateStrip() {
// Setup // Setup
boolean isSelected = false; boolean isSelected = false;
boolean isHovered = false;
// Call the method being tested. // Call the method being tested.
mTabStripSceneLayer.pushAndUpdateStrip(mStripLayoutHelperManager, mLayerTitleCache, mTabStripSceneLayer.pushAndUpdateStrip(mStripLayoutHelperManager, mLayerTitleCache,
mResourceManager, mStripLayoutTabs, 1.f, 0); mResourceManager, mStripLayoutTabs, 1.f, 0, -1);
// Verify JNI calls. // Verify JNI calls.
verify(mTabStripSceneMock).beginBuildingFrame(1L, mTabStripSceneLayer, true); verify(mTabStripSceneMock).beginBuildingFrame(1L, mTabStripSceneLayer, true);
@@ -165,7 +169,8 @@ public class TabStripSceneLayerTest {
mStripLayoutTab.getDividerResourceId(), mStripLayoutTab.getResourceId(), mStripLayoutTab.getDividerResourceId(), mStripLayoutTab.getResourceId(),
mStripLayoutTab.getOutlineResourceId(), mStripLayoutTab.getOutlineResourceId(),
mStripLayoutTab.getCloseButton().getTint(), mStripLayoutTab.getCloseButton().getTint(),
mStripLayoutTab.getDividerTint(), mStripLayoutTab.getTint(isSelected), mStripLayoutTab.getDividerTint(),
mStripLayoutTab.getTint(isSelected, isHovered),
mStripLayoutTab.getOutlineTint(isSelected), isSelected, mStripLayoutTab.getOutlineTint(isSelected), isSelected,
mStripLayoutTab.getClosePressed(), 0.f * mDpToPx, mStripLayoutTab.getClosePressed(), 0.f * mDpToPx,
mStripLayoutTab.getDrawX() * mDpToPx, mStripLayoutTab.getDrawY() * mDpToPx, mStripLayoutTab.getDrawX() * mDpToPx, mStripLayoutTab.getDrawY() * mDpToPx,
@@ -190,10 +195,11 @@ public class TabStripSceneLayerTest {
@Test @Test
@Feature("Tab Strip Redesign") @Feature("Tab Strip Redesign")
@EnableFeatures(ChromeFeatureList.ADVANCED_PERIPHERALS_SUPPORT_TAB_STRIP)
public void testPushAndUpdateStrip_TSR() { public void testPushAndUpdateStrip_TSR() {
// Call the method being tested. // Call the method being tested.
mTabStripSceneLayer.pushAndUpdateStrip(mStripLayoutHelperManager, mLayerTitleCache, mTabStripSceneLayer.pushAndUpdateStrip(mStripLayoutHelperManager, mLayerTitleCache,
mResourceManager, mStripLayoutTabs, 1.f, 0); mResourceManager, mStripLayoutTabs, 1.f, 0, -1);
// Verify TSR JNI calls. // Verify TSR JNI calls.
verify(mTabStripSceneMock) 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/ThemeUtils.java",
"java/src/org/chromium/chrome/browser/theme/TopUiThemeColorProvider.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/BrandedColorScheme.java",
"java/src/org/chromium/chrome/browser/ui/theme/ChromeSemanticColorUtils.java",
] ]
deps = [ deps = [
":java_resources", ":java_resources",

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
package org.chromium.chrome.browser; package org.chromium.chrome.browser.ui.theme;
import android.content.Context; import android.content.Context;
@@ -34,4 +34,9 @@ public class ChromeSemanticColorUtils {
public static @ColorInt int getOfflineIndicatorBackOnlineColor(Context context) { public static @ColorInt int getOfflineIndicatorBackOnlineColor(Context context) {
return SemanticColorUtils.getDefaultControlColorActive(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(), Drawable bdgTabImage = ResourcesCompat.getDrawable(getContext().getResources(),
TabUiThemeUtil.getTSRTabResource(), getContext().getTheme()); TabUiThemeUtil.getTSRTabResource(), getContext().getTheme());
bdgTabImage.setTint(TabUiThemeUtil.getTabStripContainerColor( bdgTabImage.setTint(TabUiThemeUtil.getTabStripContainerColor(
getContext(), incognito, true, false, false)); getContext(), incognito, true, false, false, false));
LayerDrawable backgroundDrawable = LayerDrawable backgroundDrawable =
new LayerDrawable(new Drawable[] {bgdColor, bdgTabImage}); new LayerDrawable(new Drawable[] {bgdColor, bdgTabImage});
// Set image size to match tab size. // 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 ##### 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 #### Color state lists