Initial changes for TabGridDialog component.
This change contains the following:
* Introduce the skeleton for the TabGridDialog component.
* Expose TabGridDialog component to GridTabSwitcher.
* Introduce GridCardClickListener to trigger the opening of
TabGridDialog.
* This feature is hidden behind "Tab Groups UI Improvement" flag.
Bug: 956205
Change-Id: Iaa7acf6cca278b35987300f0584e49dc41744f36
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1582526
Commit-Queue: Yue Zhang <[email protected]>
Reviewed-by: Wei-Yin Chen (陳威尹) <[email protected]>
Reviewed-by: Yusuf Ozuysal <[email protected]>
Cr-Commit-Position: refs/heads/master@{#655656}
diff --git a/chrome/android/features/tab_ui/BUILD.gn b/chrome/android/features/tab_ui/BUILD.gn
index 8e21108..4dea80a 100644
--- a/chrome/android/features/tab_ui/BUILD.gn
+++ b/chrome/android/features/tab_ui/BUILD.gn
@@ -20,6 +20,9 @@
"java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediator.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/MultiThumbnailCardProvider.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinder.java",
+ "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java",
+ "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java",
+ "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetMediator.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetContent.java",
@@ -34,6 +37,7 @@
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarViewBinder.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabListContainerProperties.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java",
+ "java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabListModel.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabListRecyclerView.java",
@@ -43,7 +47,6 @@
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabStripToolbarViewProperties.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabStripViewBinder.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabStripViewHolder.java",
- "java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java",
]
deps = [
diff --git a/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml b/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml
index e9314d1..5c4d46a 100644
--- a/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml
+++ b/chrome/android/features/tab_ui/java/res/layout/bottom_tab_grid_toolbar.xml
@@ -14,7 +14,8 @@
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_peek_height"
android:orientation="horizontal"
- android:gravity="center_vertical">
+ android:gravity="center_vertical"
+ android:clickable="true">
<org.chromium.ui.widget.ChromeImageView
android:id="@+id/toolbar_left_button"
style="@style/BottomToolbarButton"
diff --git a/chrome/android/features/tab_ui/java/res/values/dimens.xml b/chrome/android/features/tab_ui/java/res/values/dimens.xml
index 4578919..d31dd44 100644
--- a/chrome/android/features/tab_ui/java/res/values/dimens.xml
+++ b/chrome/android/features/tab_ui/java/res/values/dimens.xml
@@ -10,6 +10,8 @@
<dimen name="tab_list_mini_card_radius">4dp</dimen>
<dimen name="tab_list_mini_card_frame_size">1dp</dimen>
<dimen name="tab_grid_close_button_size">18dp</dimen>
+ <dimen name="tab_grid_dialog_side_margin">16dp</dimen>
+ <dimen name="tab_grid_dialog_top_margin">85dp</dimen>
<dimen name="tab_grid_thumbnail_card_default_size">152dp</dimen>
<dimen name="tab_grid_thumbnail_favicon_frame_padding">16dp</dimen>
<dimen name="tab_grid_thumbnail_favicon_padding">24dp</dimen>
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java
index b7641780..474a57e4 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java
@@ -14,10 +14,12 @@
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.lifecycle.Destroyable;
import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
import org.chromium.chrome.browser.tabmodel.TabList;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.toolbar.ToolbarManager;
+import org.chromium.chrome.browser.util.FeatureUtilities;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
@@ -35,15 +37,32 @@
private final TabListCoordinator mTabGridCoordinator;
private final GridTabSwitcherMediator mMediator;
private final MultiThumbnailCardProvider mMultiThumbnailCardProvider;
+ private final TabGridDialogCoordinator mTabGridDialogCoordinator;
public GridTabSwitcherCoordinator(Context context,
ActivityLifecycleDispatcher lifecycleDispatcher, ToolbarManager toolbarManager,
TabModelSelector tabModelSelector, TabContentManager tabContentManager,
- CompositorViewHolder compositorViewHolder, ChromeFullscreenManager fullscreenManager) {
+ CompositorViewHolder compositorViewHolder, ChromeFullscreenManager fullscreenManager,
+ TabCreatorManager tabCreatorManager) {
PropertyModel containerViewModel = new PropertyModel(TabListContainerProperties.ALL_KEYS);
+ TabListMediator.GridCardOnClickListenerProvider gridCardOnClickListenerProvider;
+ if (FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled()) {
+ mTabGridDialogCoordinator = new TabGridDialogCoordinator(context, tabModelSelector,
+ tabContentManager, tabCreatorManager, new CompositorViewHolder(context), this);
- mMediator = new GridTabSwitcherMediator(this, containerViewModel, tabModelSelector,
- fullscreenManager, compositorViewHolder);
+ mMediator = new GridTabSwitcherMediator(this, containerViewModel, tabModelSelector,
+ fullscreenManager, compositorViewHolder,
+ mTabGridDialogCoordinator.getResetHandler());
+
+ gridCardOnClickListenerProvider = mMediator::getGridCardOnClickListener;
+ } else {
+ mTabGridDialogCoordinator = null;
+
+ mMediator = new GridTabSwitcherMediator(this, containerViewModel, tabModelSelector,
+ fullscreenManager, compositorViewHolder, null);
+
+ gridCardOnClickListenerProvider = null;
+ }
mMultiThumbnailCardProvider =
new MultiThumbnailCardProvider(context, tabContentManager, tabModelSelector);
@@ -60,8 +79,8 @@
mTabGridCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context,
tabModelSelector, mMultiThumbnailCardProvider, titleProvider, true,
- mMediator::getCreateGroupButtonOnClickListener, compositorViewHolder, true,
- COMPONENT_NAME);
+ mMediator::getCreateGroupButtonOnClickListener, gridCardOnClickListenerProvider,
+ compositorViewHolder, true, COMPONENT_NAME);
mContainerViewChangeProcessor = PropertyModelChangeProcessor.create(containerViewModel,
mTabGridCoordinator.getContainerView(), TabGridContainerViewBinder::bind);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediator.java
index 31c7bfc..1c3d82a9 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediator.java
@@ -38,6 +38,8 @@
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.ui.modelutil.PropertyModel;
+import java.util.List;
+
/**
* The Mediator that is responsible for resetting the tab grid based on visibility and model
* changes.
@@ -55,6 +57,7 @@
private final TabModelSelectorObserver mTabModelSelectorObserver;
private final ObserverList<OverviewModeObserver> mObservers = new ObserverList<>();
private final ChromeFullscreenManager mFullscreenManager;
+ private final TabGridDialogMediator.ResetHandler mTabGridDialogResetHandler;
private final ChromeFullscreenManager.FullscreenListener mFullscreenListener =
new ChromeFullscreenManager.FullscreenListener() {
@Override
@@ -99,7 +102,8 @@
*/
GridTabSwitcherMediator(ResetHandler resetHandler, PropertyModel containerViewModel,
TabModelSelector tabModelSelector, ChromeFullscreenManager fullscreenManager,
- CompositorViewHolder compositorViewHolder) {
+ CompositorViewHolder compositorViewHolder,
+ TabGridDialogMediator.ResetHandler tabGridDialogResetHandler) {
mResetHandler = resetHandler;
mContainerViewModel = containerViewModel;
mTabModelSelector = tabModelSelector;
@@ -150,6 +154,7 @@
BOTTOM_CONTROLS_HEIGHT, fullscreenManager.getBottomControlsHeight());
mCompositorViewHolder = compositorViewHolder;
+ mTabGridDialogResetHandler = tabGridDialogResetHandler;
}
private void setVisibility(boolean isVisible) {
@@ -245,6 +250,14 @@
}
@Nullable
+ TabListMediator.TabActionListener getGridCardOnClickListener(Tab tab) {
+ if (!ableToOpenDialog(tab)) return null;
+ return tabId -> {
+ mTabGridDialogResetHandler.resetWithListOfTabs(getRelatedTabs(tabId));
+ };
+ }
+
+ @Nullable
TabListMediator.TabActionListener getCreateGroupButtonOnClickListener(Tab tab) {
if (!ableToCreateGroup(tab)) return null;
@@ -261,10 +274,18 @@
private boolean ableToCreateGroup(Tab tab) {
return FeatureUtilities.isTabGroupsAndroidEnabled()
&& mTabModelSelector.isIncognitoSelected() == tab.isIncognito()
- && mTabModelSelector.getTabModelFilterProvider()
- .getCurrentTabModelFilter()
- .getRelatedTabList(tab.getId())
- .size()
- == 1;
+ && getRelatedTabs(tab.getId()).size() == 1;
+ }
+
+ private boolean ableToOpenDialog(Tab tab) {
+ return FeatureUtilities.isTabGroupsAndroidEnabled()
+ && mTabModelSelector.isIncognitoSelected() == tab.isIncognito()
+ && getRelatedTabs(tab.getId()).size() != 1;
+ }
+
+ private List<Tab> getRelatedTabs(int tabId) {
+ return mTabModelSelector.getTabModelFilterProvider()
+ .getCurrentTabModelFilter()
+ .getRelatedTabList(tabId);
}
}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java
new file mode 100644
index 0000000..5b9ecf11
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogCoordinator.java
@@ -0,0 +1,84 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// 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.tasks.tab_management;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.view.ViewGroup;
+
+import org.chromium.chrome.browser.compositor.CompositorViewHolder;
+import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.ui.modelutil.PropertyModel;
+
+import java.util.List;
+
+/**
+ * A coordinator for TabGridDialog component. Manages the communication with
+ * {@link TabListCoordinator} as well as the life-cycle of shared component
+ * objects.
+ */
+public class TabGridDialogCoordinator {
+ final static String COMPONENT_NAME = "TabGridDialog";
+ private final Context mContext;
+ private final TabListCoordinator mTabListCoordinator;
+ private final TabGridDialogMediator mMediator;
+ private final PropertyModel mToolbarPropertyModel;
+ private TabGridSheetToolbarCoordinator mToolbarCoordinator;
+ private ViewGroup mParentView;
+ private TabGridDialogParent mParentLayout;
+
+ TabGridDialogCoordinator(Context context, TabModelSelector tabModelSelector,
+ TabContentManager tabContentManager, TabCreatorManager tabCreatorManager,
+ CompositorViewHolder compositorViewHolder,
+ GridTabSwitcherMediator.ResetHandler resetHandler) {
+ mContext = context;
+
+ mToolbarPropertyModel = new PropertyModel(TabGridSheetProperties.ALL_KEYS);
+
+ mTabListCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context,
+ tabModelSelector, tabContentManager::getTabThumbnailWithCallback, null, false, null,
+ null, compositorViewHolder, false, COMPONENT_NAME);
+
+ mMediator = new TabGridDialogMediator(context, this::resetWithListOfTabs,
+ mToolbarPropertyModel, tabModelSelector, tabCreatorManager, resetHandler);
+
+ mParentView = compositorViewHolder;
+
+ mParentLayout = new TabGridDialogParent(context);
+ }
+
+ /**
+ * Destroy any members that needs clean up.
+ */
+ public void destroy() {
+ mTabListCoordinator.destroy();
+ mMediator.destroy();
+ }
+
+ private void updateDialogContent(List<Tab> tabs) {
+ if (tabs != null) {
+ TabListRecyclerView recyclerView = mTabListCoordinator.getContainerView();
+ mToolbarCoordinator = new TabGridSheetToolbarCoordinator(
+ mContext, recyclerView, mToolbarPropertyModel, mParentView, mParentLayout);
+ } else {
+ if (mToolbarCoordinator != null) {
+ mToolbarCoordinator.destroy();
+ }
+ }
+ }
+
+ TabGridDialogMediator.ResetHandler getResetHandler() {
+ return this::resetWithListOfTabs;
+ }
+
+ public void resetWithListOfTabs(@Nullable List<Tab> tabs) {
+ mTabListCoordinator.resetWithListOfTabs(tabs);
+ updateDialogContent(tabs);
+ mMediator.onReset(tabs == null ? null : tabs.get(0).getId());
+ }
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
new file mode 100644
index 0000000..a777fa501
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java
@@ -0,0 +1,192 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// 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.tasks.tab_management;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+import android.view.View;
+
+import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.chrome.browser.UrlConstants;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
+import org.chromium.chrome.browser.tabmodel.TabLaunchType;
+import org.chromium.chrome.browser.tabmodel.TabModelObserver;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tabmodel.TabSelectionType;
+import org.chromium.chrome.browser.widget.ScrimView;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.ui.modelutil.PropertyModel;
+
+import java.util.List;
+
+/**
+ * A mediator for the TabGridDialog component, responsible for communicating
+ * with the components' coordinator as well as managing the business logic
+ * for dialog show/hide.
+ */
+public class TabGridDialogMediator {
+ /**
+ * Defines an interface for a {@link TabGridDialogMediator} reset event handler.
+ */
+ interface ResetHandler {
+ /**
+ * Handles a reset event originated from {@link TabGridDialogMediator} and {@link
+ * GridTabSwitcherMediator}.
+ *
+ * @param tabs List of Tabs to reset.
+ */
+ void resetWithListOfTabs(@Nullable List<Tab> tabs);
+ }
+
+ private final Context mContext;
+ private final PropertyModel mModel;
+ private final TabModelSelector mTabModelSelector;
+ private final TabModelObserver mTabModelObserver;
+ private final TabCreatorManager mTabCreatorManager;
+ private final TabGridDialogMediator.ResetHandler mDialogResetHandler;
+ private final GridTabSwitcherMediator.ResetHandler mGridTabSwitcherResetHandler;
+ private int mCurrentTabId = Tab.INVALID_TAB_ID;
+
+ TabGridDialogMediator(Context context, TabGridDialogMediator.ResetHandler dialogResetHandler,
+ PropertyModel model, TabModelSelector tabModelSelector,
+ TabCreatorManager tabCreatorManager,
+ GridTabSwitcherMediator.ResetHandler gridTabSwitcherResetHandler) {
+ mContext = context;
+ mModel = model;
+ mTabModelSelector = tabModelSelector;
+ mTabCreatorManager = tabCreatorManager;
+ mDialogResetHandler = dialogResetHandler;
+ mGridTabSwitcherResetHandler = gridTabSwitcherResetHandler;
+
+ // Register for tab model.
+ mTabModelObserver = new EmptyTabModelObserver() {
+ @Override
+ public void didAddTab(Tab tab, @TabLaunchType int type) {
+ updateDialog();
+ updateGridTabSwitcher();
+ }
+
+ @Override
+ public void tabClosureUndone(Tab tab) {
+ updateDialog();
+ updateGridTabSwitcher();
+ }
+
+ @Override
+ public void didSelectTab(Tab tab, int type, int lastId) {
+ if (type == TabSelectionType.FROM_USER)
+ mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, false);
+ }
+
+ @Override
+ public void willCloseTab(Tab tab, boolean animate) {
+ updateDialog();
+ updateGridTabSwitcher();
+ List<Tab> relatedTabs = getRelatedTabs(tab.getId());
+ // If current tab is closed and tab group is not empty, hand over ID of the next
+ // tab in the group to mCurrentTabId.
+ if (relatedTabs.size() == 0) return;
+ if (tab.getId() == mCurrentTabId) {
+ mCurrentTabId = relatedTabs.get(0).getId();
+ }
+ }
+ };
+ mTabModelSelector.getTabModelFilterProvider().addTabModelFilterObserver(mTabModelObserver);
+
+ // Setup toolbar property model.
+ setupToolbarClickHandlers();
+
+ // Setup ScrimView observer.
+ setupScrimViewObserver();
+ }
+
+ void onReset(Integer tabId) {
+ if (tabId != null) {
+ mCurrentTabId = tabId;
+ updateDialog();
+ mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, true);
+ } else {
+ mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, false);
+ }
+ }
+
+ /**
+ * Destroy any members that needs clean up.
+ */
+ public void destroy() {
+ if (mTabModelObserver != null) {
+ mTabModelSelector.getTabModelFilterProvider().removeTabModelFilterObserver(
+ mTabModelObserver);
+ }
+ }
+
+ private void updateGridTabSwitcher() {
+ mGridTabSwitcherResetHandler.resetWithTabList(
+ mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter());
+ }
+
+ private void updateDialog() {
+ if (mCurrentTabId == Tab.INVALID_TAB_ID) return;
+ List<Tab> relatedTabs = getRelatedTabs(mCurrentTabId);
+ int tabsCount = relatedTabs.size();
+ if (tabsCount == 0) {
+ mDialogResetHandler.resetWithListOfTabs(null);
+ return;
+ }
+ mModel.set(TabGridSheetProperties.HEADER_TITLE,
+ mContext.getResources().getQuantityString(
+ org.chromium.chrome.R.plurals.bottom_tab_grid_title_placeholder, tabsCount,
+ tabsCount));
+ }
+
+ private void setupToolbarClickHandlers() {
+ mModel.set(
+ TabGridSheetProperties.COLLAPSE_CLICK_LISTENER, getCollapseButtonClickListener());
+ mModel.set(TabGridSheetProperties.ADD_CLICK_LISTENER, getAddButtonClickListener());
+ }
+
+ private void setupScrimViewObserver() {
+ ScrimView.ScrimObserver scrimObserver = new ScrimView.ScrimObserver() {
+ @Override
+ public void onScrimClick() {
+ mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, false);
+ }
+ @Override
+ public void onScrimVisibilityChanged(boolean visible) {}
+ };
+ mModel.set(TabGridSheetProperties.SCRIMVIEW_OBSERVER, scrimObserver);
+ }
+
+ private View.OnClickListener getCollapseButtonClickListener() {
+ return view -> {
+ RecordUserAction.record("TabGroup.DialogMinimizedFromGrid");
+ mModel.set(TabGridSheetProperties.IS_DIALOG_VISIBLE, false);
+ };
+ }
+
+ private View.OnClickListener getAddButtonClickListener() {
+ return view -> {
+ Tab currentTab = mTabModelSelector.getTabById(mCurrentTabId);
+ List<Tab> relatedTabs = getRelatedTabs(currentTab.getId());
+
+ assert relatedTabs.size() > 0;
+
+ Tab parentTabToAttach = relatedTabs.get(relatedTabs.size() - 1);
+ mTabCreatorManager.getTabCreator(currentTab.isIncognito())
+ .createNewTab(new LoadUrlParams(UrlConstants.NTP_URL),
+ TabLaunchType.FROM_CHROME_UI, parentTabToAttach);
+ RecordUserAction.record(
+ "MobileNewTabOpened." + TabGridDialogCoordinator.COMPONENT_NAME);
+ };
+ }
+
+ private List<Tab> getRelatedTabs(int tabId) {
+ return mTabModelSelector.getTabModelFilterProvider()
+ .getCurrentTabModelFilter()
+ .getRelatedTabList(tabId);
+ }
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java
new file mode 100644
index 0000000..632f0200
--- /dev/null
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java
@@ -0,0 +1,130 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// 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.tasks.tab_management;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.PopupWindow;
+
+import org.chromium.chrome.browser.widget.ScrimView;
+import org.chromium.chrome.tab_ui.R;
+import org.chromium.ui.interpolators.BakedBezierInterpolator;
+
+/**
+ * Parent for TabGridDialog component.
+ * TODO(yuezhanggg): Add animations of card scales up to dialog and dialog scales down to card when
+ * show/hide dialog.
+ */
+public class TabGridDialogParent {
+ private PopupWindow mPopupWindow;
+ private LinearLayout mDialogContainerView;
+ private ScrimView mScrimView;
+ private ScrimView.ScrimParams mScrimParams;
+ private ValueAnimator mDialogFadeIn;
+ private ValueAnimator mDialogFadeOut;
+ private Animator mCurrentAnimator;
+
+ TabGridDialogParent(Context context) {
+ setUpDialog(context);
+ }
+
+ private void setUpDialog(Context context) {
+ FrameLayout backgroundView = new FrameLayout(context);
+ mDialogContainerView = new LinearLayout(context);
+ FrameLayout.LayoutParams containerParams = new FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ int sideMargin =
+ (int) context.getResources().getDimension(R.dimen.tab_grid_dialog_side_margin);
+ int topMargin =
+ (int) context.getResources().getDimension(R.dimen.tab_grid_dialog_top_margin);
+ containerParams.setMargins(sideMargin, topMargin, sideMargin, topMargin);
+ mDialogContainerView.setLayoutParams(containerParams);
+ mDialogContainerView.setBackgroundColor(Color.WHITE);
+ mDialogContainerView.setOrientation(LinearLayout.VERTICAL);
+ backgroundView.addView(mDialogContainerView);
+
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay()
+ .getMetrics(displayMetrics);
+ mPopupWindow = new PopupWindow(
+ backgroundView, displayMetrics.widthPixels, displayMetrics.heightPixels);
+ mScrimView = new ScrimView(context, null, backgroundView);
+
+ mDialogFadeIn = ObjectAnimator.ofFloat(mDialogContainerView, View.ALPHA, 0f, 1f);
+ mDialogFadeIn.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE);
+ mDialogFadeIn.setDuration(TabListRecyclerView.BASE_ANIMATION_DURATION_MS);
+ mDialogFadeIn.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCurrentAnimator = null;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCurrentAnimator = null;
+ }
+ });
+
+ mDialogFadeOut = ObjectAnimator.ofFloat(mDialogContainerView, View.ALPHA, 1f, 0f);
+ mDialogFadeOut.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
+ mDialogFadeOut.setDuration(TabListRecyclerView.BASE_ANIMATION_DURATION_MS);
+ mDialogFadeOut.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mPopupWindow.dismiss();
+ mCurrentAnimator = null;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mPopupWindow.dismiss();
+ mCurrentAnimator = null;
+ }
+ });
+ }
+
+ void setScrimViewObserver(ScrimView.ScrimObserver scrimViewObserver) {
+ mScrimParams =
+ new ScrimView.ScrimParams(mDialogContainerView, false, true, 0, scrimViewObserver);
+ }
+
+ void updateDialog(View toolbarView, View recyclerView) {
+ mDialogContainerView.removeAllViews();
+ mDialogContainerView.addView(toolbarView);
+ mDialogContainerView.addView(recyclerView);
+ recyclerView.setVisibility(View.VISIBLE);
+ }
+
+ void showDialog(View parent) {
+ if (mCurrentAnimator != null && mCurrentAnimator != mDialogFadeIn) {
+ mCurrentAnimator.cancel();
+ }
+ mPopupWindow.showAtLocation(parent, Gravity.CENTER, 0, 0);
+ mScrimView.showScrim(mScrimParams);
+ mDialogFadeIn.start();
+ mCurrentAnimator = mDialogFadeIn;
+ }
+
+ void hideDialog() {
+ if (mCurrentAnimator != null && mCurrentAnimator != mDialogFadeOut) {
+ mCurrentAnimator.cancel();
+ }
+ mScrimView.hideScrim(true);
+ mDialogFadeOut.start();
+ mCurrentAnimator = mDialogFadeOut;
+ }
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java
index bf65a036..504d183 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetCoordinator.java
@@ -44,7 +44,7 @@
mTabGridCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context,
tabModelSelector, tabContentManager::getTabThumbnailWithCallback, null, false, null,
- bottomSheetController.getBottomSheet(), false, COMPONENT_NAME);
+ null, bottomSheetController.getBottomSheet(), false, COMPONENT_NAME);
mMediator = new TabGridSheetMediator(mContext, bottomSheetController,
this::resetWithListOfTabs, mToolbarPropertyModel, tabModelSelector,
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetMediator.java
index 36d84f28..a98353a 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetMediator.java
@@ -30,7 +30,7 @@
import java.util.List;
/**
- * A mediator for the TabGridSheet component, respoonsible for communicating
+ * A mediator for the TabGridSheet component, responsible for communicating
* with the components' coordinator as well as managing the state of the bottom
* sheet.
*/
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetProperties.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetProperties.java
index d8897903..6f94201 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetProperties.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetProperties.java
@@ -7,6 +7,7 @@
import android.content.res.ColorStateList;
import android.view.View.OnClickListener;
+import org.chromium.chrome.browser.widget.ScrimView;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel;
@@ -25,7 +26,13 @@
new PropertyModel.WritableIntPropertyKey();
public static final PropertyModel.WritableObjectPropertyKey<ColorStateList> TINT =
new PropertyModel.WritableObjectPropertyKey<>();
+ public static final PropertyModel.WritableBooleanPropertyKey IS_DIALOG_VISIBLE =
+ new PropertyModel.WritableBooleanPropertyKey();
+ public static final PropertyModel
+ .WritableObjectPropertyKey<ScrimView.ScrimObserver> SCRIMVIEW_OBSERVER =
+ new PropertyModel.WritableObjectPropertyKey<>();
- public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {COLLAPSE_CLICK_LISTENER,
- ADD_CLICK_LISTENER, HEADER_TITLE, CONTENT_TOP_MARGIN, PRIMARY_COLOR, TINT};
+ public static final PropertyKey[] ALL_KEYS =
+ new PropertyKey[] {COLLAPSE_CLICK_LISTENER, ADD_CLICK_LISTENER, HEADER_TITLE,
+ CONTENT_TOP_MARGIN, PRIMARY_COLOR, TINT, IS_DIALOG_VISIBLE, SCRIMVIEW_OBSERVER};
}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetToolbarCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetToolbarCoordinator.java
index 557c080..3aada02 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetToolbarCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetToolbarCoordinator.java
@@ -33,10 +33,16 @@
*/
TabGridSheetToolbarCoordinator(
Context context, ViewGroup contentView, PropertyModel toolbarPropertyModel) {
+ this(context, contentView, toolbarPropertyModel, null, null);
+ }
+
+ TabGridSheetToolbarCoordinator(Context context, ViewGroup contentView,
+ PropertyModel toolbarPropertyModel, ViewGroup parentView, TabGridDialogParent dialog) {
mToolbarView = (TabGroupUiToolbarView) LayoutInflater.from(context).inflate(
R.layout.bottom_tab_grid_toolbar, contentView, false);
mModelChangeProcessor = PropertyModelChangeProcessor.create(toolbarPropertyModel,
- new TabGridSheetViewBinder.ViewHolder(mToolbarView, contentView),
+ new TabGridSheetViewBinder.ViewHolder(
+ mToolbarView, contentView, parentView, dialog),
TabGridSheetViewBinder::bind);
}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetViewBinder.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetViewBinder.java
index 6c39e67d..458f9c8 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetViewBinder.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridSheetViewBinder.java
@@ -8,10 +8,14 @@
import static org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties.COLLAPSE_CLICK_LISTENER;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties.CONTENT_TOP_MARGIN;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties.HEADER_TITLE;
+import static org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties.IS_DIALOG_VISIBLE;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties.PRIMARY_COLOR;
+import static org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties.SCRIMVIEW_OBSERVER;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridSheetProperties.TINT;
+import android.support.annotation.Nullable;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.FrameLayout;
import org.chromium.ui.modelutil.PropertyKey;
@@ -27,10 +31,17 @@
public static class ViewHolder {
public final TabGroupUiToolbarView toolbarView;
public final View contentView;
+ @Nullable
+ public ViewGroup parentView;
+ @Nullable
+ public TabGridDialogParent dialogView;
- ViewHolder(TabGroupUiToolbarView toolbarView, View contentView) {
+ ViewHolder(TabGroupUiToolbarView toolbarView, View contentView,
+ @Nullable ViewGroup parentView, @Nullable TabGridDialogParent dialogView) {
this.toolbarView = toolbarView;
this.contentView = contentView;
+ this.parentView = parentView;
+ this.dialogView = dialogView;
}
}
@@ -56,6 +67,15 @@
viewHolder.contentView.setBackgroundColor(model.get(PRIMARY_COLOR));
} else if (TINT == propertyKey) {
viewHolder.toolbarView.setTint(model.get(TINT));
+ } else if (SCRIMVIEW_OBSERVER == propertyKey) {
+ viewHolder.dialogView.setScrimViewObserver(model.get(SCRIMVIEW_OBSERVER));
+ } else if (IS_DIALOG_VISIBLE == propertyKey) {
+ if (model.get(IS_DIALOG_VISIBLE)) {
+ viewHolder.dialogView.updateDialog(viewHolder.toolbarView, viewHolder.contentView);
+ viewHolder.dialogView.showDialog(viewHolder.parentView);
+ } else {
+ viewHolder.dialogView.hideDialog();
+ }
}
}
}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
index 0ddf740..32bf5b1 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiCoordinator.java
@@ -74,7 +74,7 @@
TabContentManager tabContentManager = activity.getTabContentManager();
mTabStripCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.STRIP,
- mContext, tabModelSelector, null, null, false, null,
+ mContext, tabModelSelector, null, null, false, null, null,
mTabStripToolbarCoordinator.getTabListContainerView(), true, COMPONENT_NAME);
mTabGridSheetCoordinator =
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java
index 87657a0..78f9939 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGroupUiToolbarView.java
@@ -50,6 +50,10 @@
mRightButton.setOnClickListener(listener);
}
+ void setTitleOnClickListener(OnClickListener listener) {
+ mTitleTextView.setOnClickListener(listener);
+ }
+
ViewGroup getViewContainer() {
return mContainerView;
}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
index 12fcb47..5824872 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListCoordinator.java
@@ -71,6 +71,8 @@
TabListMediator.ThumbnailProvider thumbnailProvider,
TabListMediator.TitleProvider titleProvider, boolean closeRelatedTabs,
@Nullable TabListMediator.CreateGroupButtonProvider createGroupButtonProvider,
+ @Nullable TabListMediator
+ .GridCardOnClickListenerProvider gridCardOnClickListenerProvider,
@NonNull ViewGroup parentView, boolean attachToParent, String componentName) {
TabListModel tabListModel = new TabListModel();
mMode = mode;
@@ -122,7 +124,7 @@
mMediator = new TabListMediator(tabListModel, tabModelSelector, thumbnailProvider,
titleProvider, tabListFaviconProvider, closeRelatedTabs, createGroupButtonProvider,
- componentName);
+ gridCardOnClickListenerProvider, componentName);
if (mMode == TabListMode.GRID) {
ItemTouchHelper touchHelper = new ItemTouchHelper(mMediator.getItemTouchHelperCallback(
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
index c72995a..92768311c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediator.java
@@ -120,6 +120,18 @@
TabActionListener getCreateGroupButtonOnClickListener(Tab tab);
}
+ /**
+ * An interface to get the onClickListener for opening dialog when click on a grid card.
+ */
+ public interface GridCardOnClickListenerProvider {
+ /**
+ * @return {@link TabActionListener} to open tabgrid dialog. If the given {@link Tab} is not
+ * able to create group, return null;
+ */
+ @Nullable
+ TabActionListener getGridCardOnClickListener(Tab tab);
+ }
+
@IntDef({TabClosedFrom.TAB_STRIP, TabClosedFrom.TAB_GRID_SHEET, TabClosedFrom.GRID_TAB_SWITCHER,
TabClosedFrom.GRID_TAB_SWITCHER_GROUP})
@Retention(RetentionPolicy.SOURCE)
@@ -141,6 +153,7 @@
private final TabActionListener mTabClosedListener;
private final TitleProvider mTitleProvider;
private final CreateGroupButtonProvider mCreateGroupButtonProvider;
+ private final GridCardOnClickListenerProvider mGridCardOnClickListenerProvider;
private final String mComponentName;
private boolean mCloseAllRelatedTabs;
private ComponentCallbacks mComponentCallbacks;
@@ -239,7 +252,9 @@
public TabListMediator(TabListModel model, TabModelSelector tabModelSelector,
@Nullable ThumbnailProvider thumbnailProvider, @Nullable TitleProvider titleProvider,
TabListFaviconProvider tabListFaviconProvider, boolean closeRelatedTabs,
- @Nullable CreateGroupButtonProvider createGroupButtonProvider, String componentName) {
+ @Nullable CreateGroupButtonProvider createGroupButtonProvider,
+ @Nullable GridCardOnClickListenerProvider gridCardOnClickListenerProvider,
+ String componentName) {
mTabModelSelector = tabModelSelector;
mThumbnailProvider = thumbnailProvider;
mModel = model;
@@ -247,6 +262,7 @@
mComponentName = componentName;
mTitleProvider = titleProvider != null ? titleProvider : Tab::getTitle;
mCreateGroupButtonProvider = createGroupButtonProvider;
+ mGridCardOnClickListenerProvider = gridCardOnClickListenerProvider;
mCloseAllRelatedTabs = closeRelatedTabs;
mTabModelObserver = new EmptyTabModelObserver() {
@@ -502,6 +518,13 @@
if (mCloseAllRelatedTabs && !mShownIPH) {
showIPH = getRelatedTabsForId(tab.getId()).size() > 1;
}
+ TabActionListener tabSelectedListener;
+ if (mGridCardOnClickListenerProvider == null
+ || getRelatedTabsForId(tab.getId()).size() == 1) {
+ tabSelectedListener = mTabSelectedListener;
+ } else {
+ tabSelectedListener = mGridCardOnClickListenerProvider.getGridCardOnClickListener(tab);
+ }
PropertyModel tabInfo =
new PropertyModel.Builder(TabProperties.ALL_KEYS_TAB_GRID)
@@ -511,7 +534,7 @@
mTabListFaviconProvider.getDefaultFaviconDrawable())
.with(TabProperties.IS_SELECTED, isSelected)
.with(TabProperties.IPH_PROVIDER, showIPH ? mIphProvider : null)
- .with(TabProperties.TAB_SELECTED_LISTENER, mTabSelectedListener)
+ .with(TabProperties.TAB_SELECTED_LISTENER, tabSelectedListener)
.with(TabProperties.TAB_CLOSED_LISTENER, mTabClosedListener)
.with(TabProperties.CREATE_GROUP_LISTENER, createGroupButtonOnClickListener)
.with(TabProperties.ALPHA, 1f)
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementModuleImpl.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementModuleImpl.java
index 3c94a78..5879a14 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementModuleImpl.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementModuleImpl.java
@@ -29,7 +29,7 @@
return new GridTabSwitcherCoordinator(activity, activity.getLifecycleDispatcher(),
activity.getToolbarManager(), activity.getTabModelSelector(),
activity.getTabContentManager(), activity.getCompositorViewHolder(),
- activity.getFullscreenManager());
+ activity.getFullscreenManager(), activity);
}
@Override
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java
index 97fb1ae7..f0d4773f 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediatorUnitTest.java
@@ -156,7 +156,7 @@
mModel = new PropertyModel(TabListContainerProperties.ALL_KEYS);
mModel.addObserver(mPropertyObserver);
mMediator = new GridTabSwitcherMediator(mResetHandler, mModel, mTabModelSelector,
- mFullscreenManager, mCompositorViewHolder);
+ mFullscreenManager, mCompositorViewHolder, null);
mMediator.addOverviewModeObserver(mOverviewModeObserver);
}
diff --git a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
index 6bdf32a..ff94d4d 100644
--- a/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
+++ b/chrome/android/features/tab_ui/junit/src/org/chromium/chrome/browser/tasks/tab_management/TabListMediatorUnitTest.java
@@ -131,7 +131,7 @@
mModel = new TabListModel();
mMediator = new TabListMediator(mModel, mTabModelSelector,
mTabContentManager::getTabThumbnailWithCallback, null, mTabListFaviconProvider,
- false, null, getClass().getSimpleName());
+ false, null, null, getClass().getSimpleName());
}
@After
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index ed32631..2a64da80 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -313,6 +313,8 @@
public static final String QUERY_IN_OMNIBOX = "QueryInOmnibox";
public static final String TAB_ENGAGEMENT_REPORTING_ANDROID = "TabEngagementReportingAndroid";
public static final String TAB_GROUPS_ANDROID = "TabGroupsAndroid";
+ public static final String TAB_GROUPS_UI_IMPROVEMENTS_ANDROID =
+ "TabGroupsUiImprovementsAndroid";
public static final String TAB_GRID_LAYOUT_ANDROID = "TabGridLayoutAndroid";
public static final String TAB_PERSISTENT_STORE_TASK_RUNNER = "TabPersistentStoreTaskRunner";
public static final String TAB_REPARENTING = "TabReparenting";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
index 24f6322..0313ce6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -316,6 +316,13 @@
public static final String TAB_GROUPS_ANDROID_ENABLED_KEY = "tab_group_android_enabled";
/**
+ * Whether or not the tab group UI improvement is enabled.
+ * Default value is false.
+ */
+ public static final String TAB_GROUPS_UI_IMPROVEMENTS_ANDROID_ENABLED_KEY =
+ "tab_group_ui_improvements_android_enabled";
+
+ /**
* Key for whether PrefetchBackgroundTask should load native in service manager only mode.
* Default value is false.
*/
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
index 477b1887..67e707d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -83,6 +83,7 @@
private static Boolean sShouldPrioritizeBootstrapTasks;
private static Boolean sIsGridTabSwitcherEnabled;
private static Boolean sIsTabGroupsAndroidEnabled;
+ private static Boolean sIsTabGroupUiImprovementsAndroidEnabled;
private static Boolean sFeedEnabled;
private static Boolean sServiceManagerForBackgroundPrefetch;
private static Boolean sIsNetworkServiceWarmUpEnabled;
@@ -213,6 +214,7 @@
if (isHighEndPhone()) cacheGridTabSwitcherEnabled();
if (isHighEndPhone()) cacheTabGroupsAndroidEnabled();
+ if (isHighEndPhone()) cacheTabGroupsAndroidUiImprovementsEnabled();
// Propagate REACHED_CODE_PROFILER feature value to LibraryLoader. This can't be done in
// LibraryLoader itself because it lives in //base and can't depend on ChromeFeatureList.
@@ -639,6 +641,34 @@
ContextUtils.getApplicationContext());
}
+ private static void cacheTabGroupsAndroidUiImprovementsEnabled() {
+ ChromePreferenceManager.getInstance().writeBoolean(
+ ChromePreferenceManager.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID_ENABLED_KEY,
+ !DeviceClassManager.enableAccessibilityLayout()
+ && (ChromeFeatureList.isEnabled(
+ ChromeFeatureList.DOWNLOAD_TAB_MANAGEMENT_MODULE)
+ || ChromeFeatureList.isEnabled(
+ ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID))
+ && TabManagementModuleProvider.getTabManagementModule() != null
+ && ChromeFeatureList.isEnabled(
+ ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID));
+ }
+
+ /**
+ * @return Whether the tab group ui improvement feature is enabled and available for use.
+ */
+ public static boolean isTabGroupsAndroidUiImprovementsEnabled() {
+ if (!isTabGroupsAndroidEnabled()) return false;
+
+ if (sIsTabGroupUiImprovementsAndroidEnabled == null) {
+ ChromePreferenceManager preferenceManager = ChromePreferenceManager.getInstance();
+
+ sIsTabGroupUiImprovementsAndroidEnabled = preferenceManager.readBoolean(
+ ChromePreferenceManager.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID_ENABLED_KEY, false);
+ }
+ return sIsTabGroupUiImprovementsAndroidEnabled;
+ }
+
/**
* @return Whether this device is running Android Go. This is assumed when we're running Android
* O or later and we're on a low-end device.
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ec1d9ac..e727a763 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3074,6 +3074,11 @@
flag_descriptions::kTabGroupsAndroidDescription, kOsAndroid,
FEATURE_VALUE_TYPE(chrome::android::kTabGroupsAndroid)},
+ {"enable-tab-groups-ui-improvements",
+ flag_descriptions::kTabGroupsUiImprovementsAndroidName,
+ flag_descriptions::kTabGroupsUiImprovementsAndroidDescription, kOsAndroid,
+ FEATURE_VALUE_TYPE(chrome::android::kTabGroupsUiImprovementsAndroid)},
+
{"enable-tab-switcher-on-return",
flag_descriptions::kTabSwitcherOnReturnName,
flag_descriptions::kTabSwitcherOnReturnDescription, kOsAndroid,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index c4269ed..5c84557 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -170,6 +170,7 @@
&kSpecialUserDecision,
&kTabEngagementReportingAndroid,
&kTabGroupsAndroid,
+ &kTabGroupsUiImprovementsAndroid,
&kTabGridLayoutAndroid,
&kTabPersistentStoreTaskRunner,
&kTabReparenting,
@@ -499,6 +500,9 @@
const base::Feature kTabGroupsAndroid{"TabGroupsAndroid",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kTabGroupsUiImprovementsAndroid{
+ "TabGroupsUiImprovementsAndroid", base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kTabGridLayoutAndroid{"TabGridLayoutAndroid",
base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 4296287..0d6c4d1 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -101,6 +101,7 @@
extern const base::Feature kSpecialUserDecision;
extern const base::Feature kTabEngagementReportingAndroid;
extern const base::Feature kTabGroupsAndroid;
+extern const base::Feature kTabGroupsUiImprovementsAndroid;
extern const base::Feature kTabGridLayoutAndroid;
extern const base::Feature kTabPersistentStoreTaskRunner;
extern const base::Feature kTabReparenting;
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index d77e410..c19ce9b 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1716,6 +1716,11 @@
"expiry_milestone": 80
},
{
+ "name": "enable-tab-groups-ui-improvements",
+ "owners": [ "[email protected]" ],
+ "expiry_milestone": 80
+ },
+ {
"name": "enable-tab-switcher-on-return",
"owners": [ "[email protected]" ],
"expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 4026c19d..e935e0f 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1851,6 +1851,10 @@
const char kTabGroupsAndroidDescription[] =
"Allows users to create groups to better organize their tabs.";
+const char kTabGroupsUiImprovementsAndroidName[] = "Tab Groups UI Improvements";
+const char kTabGroupsUiImprovementsAndroidDescription[] =
+ "Allows users to access new features in Tab Group UI.";
+
const char kTabGroupsName[] = "Tab Groups";
const char kTabGroupsDescription[] =
"Allows users to organize tabs into visually distinct groups, e.g. to "
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 032284e5..8450a5b7 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1104,6 +1104,9 @@
extern const char kTabGroupsAndroidName[];
extern const char kTabGroupsAndroidDescription[];
+extern const char kTabGroupsUiImprovementsAndroidName[];
+extern const char kTabGroupsUiImprovementsAndroidDescription[];
+
extern const char kTabGroupsName[];
extern const char kTabGroupsDescription[];
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 48263e8..ec44b9e 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -32950,6 +32950,7 @@
<int value="-1160941363" label="AffiliationBasedMatching:disabled"/>
<int value="-1160026273" label="enable-web-notification-custom-layouts"/>
<int value="-1159563774" label="enable-accessibility-script-injection"/>
+ <int value="-1159369873" label="TabGroupsUiImprovementsAndroid:disabled"/>
<int value="-1158993534" label="PrintScaling:enabled"/>
<int value="-1156179600" label="OmniboxRichEntitySuggestions:enabled"/>
<int value="-1155543191" label="CopylessPaste:disabled"/>
@@ -33307,6 +33308,7 @@
<int value="-612480090" label="FasterLocationReload:enabled"/>
<int value="-610411643" label="enable-printer-app-search"/>
<int value="-606898702" label="MaterialDesignSettings:disabled"/>
+ <int value="-606696801" label="TabGroupsUiImprovementsAndroid:enabled"/>
<int value="-606431158" label="DrawVerticallyEdgeToEdge:enabled"/>
<int value="-604814313" label="enable-pinch"/>
<int value="-604269405"