Commit 45cce5fc authored by Lijin Shen's avatar Lijin Shen Committed by Commit Bot

Add tab switcher longpress menu on bottom toolbar

Implemented the tab swithcer longpress menu on the bottom.
In the meanwhile, decreased the menu width to match the design spec.

Bug: 1011012
Change-Id: If1edc83bf9b10d332fc7627e9b88b2aed191a201
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1856729Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Commit-Queue: Lijin Shen <lazzzis@google.com>
Cr-Commit-Position: refs/heads/master@{#711504}
parent 9f934997
......@@ -1666,6 +1666,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsMediator.java",
"java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsProperties.java",
"java/src/org/chromium/chrome/browser/toolbar/bottom/BottomControlsViewBinder.java",
"java/src/org/chromium/chrome/browser/toolbar/bottom/BottomTabSwitcherActionMenuCoordinator.java",
"java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarNewTabButton.java",
"java/src/org/chromium/chrome/browser/toolbar/bottom/BottomToolbarCoordinator.java",
"java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarCoordinator.java",
......
......@@ -17,8 +17,7 @@
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:layout_width="match_parent"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="16dp">
android:paddingStart="16dp">
<org.chromium.ui.widget.ChromeImageView
android:id="@+id/menu_item_icon"
......@@ -31,11 +30,10 @@
android:id="@+id/menu_item_text"
android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:singleLine="true"
android:paddingStart="16dp"
android:paddingEnd="16dp" />
android:paddingStart="16dp" />
</LinearLayout>
\ No newline at end of file
......@@ -56,6 +56,8 @@
<!-- Custom Menu dimensions -->
<dimen name="menu_width">258dp</dimen>
<dimen name="tab_switcher_menu_width">222dp</dimen>
<!-- The amount to fade the edges of the menu to indicate more content is available
via scrolling. -->
<dimen name="menu_vertical_fade_distance">15dp</dimen>
......@@ -277,6 +279,11 @@
<dimen name="toolbar_identity_disc_size">24dp</dimen>
<dimen name="toolbar_identity_disc_size_duet">32dp</dimen>
<!-- Bottom Toolbar -->
<dimen name="split_toolbar_button_height">24dp</dimen>
<dimen name="split_toolbar_button_width">@dimen/split_toolbar_button_height</dimen>
<dimen name="bottom_toolbar_button_wrapper_width">56dp</dimen>
<dimen name="toolbar_edge_padding">8dp</dimen>
<dimen name="location_bar_vertical_margin">8dp</dimen>
<dimen name="location_bar_url_text_size">16sp</dimen>
......
......@@ -684,8 +684,8 @@
<item name="android:layout_gravity">center</item>
</style>
<style name="SplitToolbarButton" parent="BottomToolbarButton">
<item name="android:layout_height">24dp</item>
<item name="android:layout_width">24dp</item>
<item name="android:layout_height">@dimen/split_toolbar_button_height</item>
<item name="android:layout_width">@dimen/split_toolbar_button_width</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:clickable">false</item>
<item name="android:importantForAccessibility">no</item>
......@@ -695,7 +695,7 @@
<item name="android:textSize">12sp</item>
</style>
<style name="BottomToolbarButtonWrapper">
<item name="android:layout_width">56dp</item>
<item name="android:layout_width">@dimen/bottom_toolbar_button_wrapper_width</item>
<item name="android:paddingStart">4dp</item>
<item name="android:paddingEnd">4dp</item>
<item name="android:layout_height">match_parent</item>
......
......@@ -17,7 +17,6 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
import org.chromium.chrome.browser.toolbar.TabCountProvider.TabCountObserver;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
import org.chromium.ui.widget.Toast;
/**
* The controller for the tab switcher button. This class handles all interactions that the tab
......@@ -50,10 +49,6 @@ public class TabSwitcherButtonCoordinator {
final TabSwitcherButtonView view = root.findViewById(R.id.tab_switcher_button);
PropertyModelChangeProcessor.create(
mTabSwitcherButtonModel, view, new TabSwitcherButtonViewBinder());
CharSequence description = root.getResources().getString(R.string.open_tabs);
mTabSwitcherButtonModel.set(TabSwitcherButtonProperties.ON_LONG_CLICK_LISTENER,
v -> Toast.showAnchoredToast(root.getContext(), v, description));
}
/**
......
......@@ -53,6 +53,15 @@ public class TabSwitcherButtonView extends ImageView {
super.setOnClickListener(listener);
}
@Override
public void setOnLongClickListener(OnLongClickListener listener) {
if (mWrapper != null) {
mWrapper.setOnLongClickListener(listener);
setClickable(false);
}
super.setOnLongClickListener(listener);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
......
......@@ -91,6 +91,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.TabSelectionType;
import org.chromium.chrome.browser.toolbar.bottom.BottomControlsCoordinator;
import org.chromium.chrome.browser.toolbar.bottom.BottomTabSwitcherActionMenuCoordinator;
import org.chromium.chrome.browser.toolbar.top.ActionModeController;
import org.chromium.chrome.browser.toolbar.top.ActionModeController.ActionBarDelegate;
import org.chromium.chrome.browser.toolbar.top.Toolbar;
......@@ -775,7 +776,10 @@ public class ToolbarManager implements ScrimObserver, ToolbarTabController, UrlF
mBottomControlsCoordinator = new BottomControlsCoordinator(mActivity.getFullscreenManager(),
mActivity.findViewById(R.id.bottom_controls_stub),
mActivity.getActivityTabProvider(), homeButtonListener, searchAcceleratorListener,
shareButtonListener, mAppThemeColorProvider);
shareButtonListener,
BottomTabSwitcherActionMenuCoordinator.createOnLongClickListener(
id -> mActivity.onOptionsItemSelected(id, null)),
mAppThemeColorProvider);
mIsBottomToolbarVisible = FeatureUtilities.isBottomToolbarEnabled()
&& (!FeatureUtilities.isAdaptiveToolbarEnabled()
......
......@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.toolbar.bottom;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.ViewStub;
......@@ -70,6 +71,7 @@ public class BottomControlsCoordinator {
public BottomControlsCoordinator(ChromeFullscreenManager fullscreenManager, ViewStub stub,
ActivityTabProvider tabProvider, OnClickListener homeButtonListener,
OnClickListener searchAcceleratorListener, OnClickListener shareButtonListener,
OnLongClickListener tabSwitcherLongclickListener,
ThemeColorProvider themeColorProvider) {
final ScrollingBottomViewResourceFrameLayout root =
(ScrollingBottomViewResourceFrameLayout) stub.inflate();
......@@ -102,9 +104,10 @@ public class BottomControlsCoordinator {
mTabGroupUi = TabManagementModuleProvider.getDelegate().createTabGroupUi(
root.findViewById(R.id.bottom_container_slot), themeColorProvider);
} else {
mBottomToolbarCoordinator = new BottomToolbarCoordinator(
root.findViewById(R.id.bottom_toolbar_stub), tabProvider, homeButtonListener,
searchAcceleratorListener, shareButtonListener, themeColorProvider);
mBottomToolbarCoordinator =
new BottomToolbarCoordinator(root.findViewById(R.id.bottom_toolbar_stub),
tabProvider, homeButtonListener, searchAcceleratorListener,
shareButtonListener, tabSwitcherLongclickListener, themeColorProvider);
}
}
......
// 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.toolbar.bottom;
import android.content.Context;
import android.content.res.Resources;
import android.view.View;
import android.view.View.OnLongClickListener;
import org.chromium.base.Callback;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.toolbar.top.tab_switcher_action_menu.TabSwitcherActionMenuCoordinator;
import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
import org.chromium.ui.widget.RectProvider;
import org.chromium.ui.widget.ViewRectProvider;
/**
* The main coordinator for the Tab Switcher Action Menu on the bottom toolbar,
* responsible for creating the popup menu and building a list of menu items.
*/
public class BottomTabSwitcherActionMenuCoordinator extends TabSwitcherActionMenuCoordinator {
public static OnLongClickListener createOnLongClickListener(Callback<Integer> onItemClicked) {
return createOnLongClickListener(
new BottomTabSwitcherActionMenuCoordinator(), onItemClicked);
}
@Override
public ModelList buildMenuItems(Context context) {
ModelList itemList = new ModelList();
itemList.add(buildListItemByMenuItemType(context, MenuItemType.NEW_TAB));
itemList.add(buildListItemByMenuItemType(context, MenuItemType.NEW_INCOGNITO_TAB));
itemList.add(buildListItemByMenuItemType(context, MenuItemType.DIVIDER));
itemList.add(buildListItemByMenuItemType(context, MenuItemType.CLOSE_TAB));
return itemList;
}
@Override
protected RectProvider getRectProvider(View anchorView) {
ViewRectProvider rectProvider = new ViewRectProvider(anchorView);
rectProvider.setIncludePadding(true);
// space between the icon and the border of the wrapper
Resources resources = anchorView.getResources();
int paddingLeft =
resources.getDimensionPixelOffset(R.dimen.bottom_toolbar_button_wrapper_width)
- resources.getDimensionPixelOffset(R.dimen.split_toolbar_button_width);
rectProvider.setInsetPx(paddingLeft, 0, 0, 0);
return rectProvider;
}
}
......@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.toolbar.bottom;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.ViewStub;
......@@ -46,11 +47,13 @@ class BottomToolbarCoordinator {
*/
BottomToolbarCoordinator(ViewStub stub, ActivityTabProvider tabProvider,
OnClickListener homeButtonListener, OnClickListener searchAcceleratorListener,
OnClickListener shareButtonListener, ThemeColorProvider themeColorProvider) {
OnClickListener shareButtonListener, OnLongClickListener tabsSwitcherLongClickListner,
ThemeColorProvider themeColorProvider) {
View root = stub.inflate();
mBrowsingModeCoordinator = new BrowsingModeBottomToolbarCoordinator(root, tabProvider,
homeButtonListener, searchAcceleratorListener, shareButtonListener);
homeButtonListener, searchAcceleratorListener, shareButtonListener,
tabsSwitcherLongClickListner);
mTabSwitcherModeStub = root.findViewById(R.id.bottom_toolbar_tab_switcher_mode_stub);
......
......@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.toolbar.bottom;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import org.chromium.chrome.R;
......@@ -59,7 +60,7 @@ public class BrowsingModeBottomToolbarCoordinator {
*/
BrowsingModeBottomToolbarCoordinator(View root, ActivityTabProvider tabProvider,
OnClickListener homeButtonListener, OnClickListener searchAcceleratorListener,
OnClickListener shareButtonListener) {
OnClickListener shareButtonListener, OnLongClickListener tabSwitcherLongClickListner) {
BrowsingModeBottomToolbarModel model = new BrowsingModeBottomToolbarModel();
final ViewGroup toolbarRoot = root.findViewById(R.id.bottom_toolbar_browsing);
......@@ -86,9 +87,15 @@ public class BrowsingModeBottomToolbarCoordinator {
mTabSwitcherButtonCoordinator = new TabSwitcherButtonCoordinator(toolbarRoot);
// TODO(amaralp): Make this adhere to MVC framework.
((TabSwitcherButtonView) toolbarRoot.findViewById(R.id.tab_switcher_button))
.setWrapperView(toolbarRoot.findViewById(R.id.tab_switcher_button_wrapper));
TabSwitcherButtonView tabSwitcherButtonView =
toolbarRoot.findViewById(R.id.tab_switcher_button);
tabSwitcherButtonView.setWrapperView(
toolbarRoot.findViewById(R.id.tab_switcher_button_wrapper));
// TODO(lazzzis): Refactor the long click listener. Have to specify the handler view here
// in order to fix the anchor view of the long-tap menu
tabSwitcherButtonView.setOnLongClickListener(
(view) -> tabSwitcherLongClickListner.onLongClick(tabSwitcherButtonView));
mMenuButton = toolbarRoot.findViewById(R.id.menu_button_wrapper);
mMenuButton.setWrapperView(toolbarRoot.findViewById(R.id.labeled_menu_button_wrapper));
......
......@@ -26,6 +26,7 @@ import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
import org.chromium.ui.modelutil.ModelListAdapter;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.widget.AnchoredPopupWindow;
import org.chromium.ui.widget.RectProvider;
import org.chromium.ui.widget.ViewRectProvider;
import java.lang.annotation.Retention;
......@@ -33,7 +34,7 @@ import java.lang.annotation.RetentionPolicy;
/**
* The main coordinator for the Tab Switcher Action Menu, responsible for creating the popup menu
* (popup window) in general and building a list of menu items
* (popup window) in general and building a list of menu items.
*/
public class TabSwitcherActionMenuCoordinator {
@Retention(RetentionPolicy.SOURCE)
......@@ -43,6 +44,16 @@ public class TabSwitcherActionMenuCoordinator {
int MENU_ITEM = 1;
}
@Retention(RetentionPolicy.SOURCE)
@IntDef({MenuItemType.DIVIDER, MenuItemType.CLOSE_TAB, MenuItemType.NEW_TAB,
MenuItemType.NEW_INCOGNITO_TAB})
public @interface MenuItemType {
int DIVIDER = 0;
int CLOSE_TAB = 1;
int NEW_TAB = 2;
int NEW_INCOGNITO_TAB = 3;
}
private ListView mListView;
private AnchoredPopupWindow mPopup;
private View mContentView;
......@@ -52,9 +63,14 @@ public class TabSwitcherActionMenuCoordinator {
* @return a long click listener of the long press action of tab switcher button
*/
public static OnLongClickListener createOnLongClickListener(Callback<Integer> onItemClicked) {
return createOnLongClickListener(new TabSwitcherActionMenuCoordinator(), onItemClicked);
}
// internal helper function to create a long click listener
protected static OnLongClickListener createOnLongClickListener(
TabSwitcherActionMenuCoordinator menu, Callback<Integer> onItemClicked) {
return (view) -> {
Context context = view.getContext();
TabSwitcherActionMenuCoordinator menu = new TabSwitcherActionMenuCoordinator();
menu.displayMenu(context, view, menu.buildMenuItems(context), (id) -> {
recordUserActions(id);
onItemClicked.onResult(id);
......@@ -127,21 +143,15 @@ public class TabSwitcherActionMenuCoordinator {
mPopup.dismiss();
});
ViewRectProvider rectProvider = new ViewRectProvider(anchorView);
rectProvider.setIncludePadding(true);
int toolbarHeight = anchorView.getHeight();
int iconHeight = context.getResources().getDimensionPixelSize(R.dimen.toolbar_icon_height);
int paddingBottom = (toolbarHeight - iconHeight) / 2;
rectProvider.setInsetPx(0, 0, 0, paddingBottom);
int popupWidth =
context.getResources().getDimensionPixelSize(R.dimen.tab_switcher_menu_width);
mPopup = new AnchoredPopupWindow(context, anchorView,
ApiCompatibilityUtils.getDrawable(
context.getResources(), R.drawable.popup_bg_tinted),
mContentView, rectProvider);
mContentView, getRectProvider(anchorView));
mPopup.setFocusable(true);
mPopup.setAnimationStyle(R.style.OverflowMenuAnim);
int popupWidth = context.getResources().getDimensionPixelSize(R.dimen.menu_width);
mPopup.setMaxWidth(popupWidth);
mPopup.setHorizontalOverlapAnchor(true);
mPopup.show();
......@@ -155,21 +165,52 @@ public class TabSwitcherActionMenuCoordinator {
@VisibleForTesting
public ModelList buildMenuItems(Context context) {
ModelList itemList = new ModelList();
itemList.add(new ListItem(ListItemType.MENU_ITEM,
buildPropertyModel(
context, R.string.close_tab, R.id.close_tab, R.drawable.btn_close)));
itemList.add(new ListItem(ListItemType.DIVIDER,
new PropertyModel.Builder(TabSwitcherActionMenuItemProperties.ALL_KEYS).build()));
itemList.add(new ListItem(ListItemType.MENU_ITEM,
buildPropertyModel(context, R.string.menu_new_tab, R.id.new_tab_menu_id,
R.drawable.new_tab_icon)));
itemList.add(new ListItem(ListItemType.MENU_ITEM,
buildPropertyModel(context, R.string.menu_new_incognito_tab,
R.id.new_incognito_tab_menu_id, R.drawable.incognito_simple)));
itemList.add(buildListItemByMenuItemType(context, MenuItemType.CLOSE_TAB));
itemList.add(buildListItemByMenuItemType(context, MenuItemType.DIVIDER));
itemList.add(buildListItemByMenuItemType(context, MenuItemType.NEW_TAB));
itemList.add(buildListItemByMenuItemType(context, MenuItemType.NEW_INCOGNITO_TAB));
return itemList;
}
private PropertyModel buildPropertyModel(
/**
* Define how popup menu is positioned.
* @param anchorView The view which the popup menu anchors.
* @return Rect provider describing how to position the popup menu.
*/
protected RectProvider getRectProvider(View anchorView) {
ViewRectProvider rectProvider = new ViewRectProvider(anchorView);
rectProvider.setIncludePadding(true);
int toolbarHeight = anchorView.getHeight();
int iconHeight =
anchorView.getResources().getDimensionPixelSize(R.dimen.toolbar_icon_height);
int paddingBottom = (toolbarHeight - iconHeight) / 2;
rectProvider.setInsetPx(0, 0, 0, paddingBottom);
return rectProvider;
}
// internal helper function to build a list item given a menu item type
protected ListItem buildListItemByMenuItemType(Context context, @MenuItemType int type) {
switch (type) {
case MenuItemType.CLOSE_TAB:
return new ListItem(ListItemType.MENU_ITEM,
buildPropertyModel(
context, R.string.close_tab, R.id.close_tab, R.drawable.btn_close));
case MenuItemType.NEW_TAB:
return new ListItem(ListItemType.MENU_ITEM,
buildPropertyModel(context, R.string.menu_new_tab, R.id.new_tab_menu_id,
R.drawable.new_tab_icon));
case MenuItemType.NEW_INCOGNITO_TAB:
return new ListItem(ListItemType.MENU_ITEM,
buildPropertyModel(context, R.string.menu_new_incognito_tab,
R.id.new_incognito_tab_menu_id, R.drawable.incognito_simple));
case MenuItemType.DIVIDER:
default:
return new ListItem(ListItemType.DIVIDER, new PropertyModel());
}
}
protected PropertyModel buildPropertyModel(
Context context, @StringRes int titleId, @IdRes int menuId, @DrawableRes int iconId) {
return new PropertyModel.Builder(TabSwitcherActionMenuItemProperties.ALL_KEYS)
.with(TabSwitcherActionMenuItemProperties.TITLE, context.getString(titleId))
......
......@@ -68,7 +68,8 @@ public class TabSwitcherActionMenuRenderTest extends DummyUiActivityTestCase {
mView = coordinator.getContentView();
((ViewGroup) mView.getParent()).removeView(mView);
int popupWidth = activity.getResources().getDimensionPixelSize(R.dimen.menu_width);
int popupWidth =
activity.getResources().getDimensionPixelSize(R.dimen.tab_switcher_menu_width);
mView.setBackground(ApiCompatibilityUtils.getDrawable(
activity.getResources(), R.drawable.popup_bg_tinted));
activity.setContentView(mView, new LayoutParams(popupWidth, WRAP_CONTENT));
......
8066ac0ba94aefd4842aacb1e5a2acee2a77bed2
\ No newline at end of file
57cbc28c6fb6d6830ff7cf29b2b8693becc22fc0
\ No newline at end of file
93819341dffff9c2cc27feec9bf0f7af798487db
\ No newline at end of file
a9484970628468b041ea7e4fb140fb02dcbe1006
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment