[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:

committed by
Chromium LUCI CQ

parent
b108bb5010
commit
ea17bbdc76
chrome
android
BUILD.gnchrome_java_sources.gni
features
tab_ui
public
java
src
org
chromium
chrome
browser
compositor
bottombar
layouts
eventfilter
overlays
scene_layer
offlinepages
indicator
payments
javatests
src
org
chromium
chrome
browser
compositor
overlays
strip
junit
src
org
chromium
chrome
browser
compositor
layouts
eventfilter
overlays
scene_layer
browser
ui
android
theme
toolbar
java
src
org
chromium
chrome
browser
toolbar
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();
|
||||
}
|
||||
|
95
chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
95
chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java
@ -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;
|
||||
}
|
||||
}
|
||||
|
44
chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
44
chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
@ -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);
|
||||
|
30
chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayer.java
30
chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabStripSceneLayer.java
@ -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;
|
||||
|
63
chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java
63
chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java
@ -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
|
||||
|
Reference in New Issue
Block a user