Commit 55509155 authored by Mei Liang's avatar Mei Liang Committed by Commit Bot

Add SelectableTabGridViewHolder

Change-Id: I7b9f5952f1cf16a2bc60699f8862ffe859f59837
Bug: 970267
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1643107
Commit-Queue: Mei Liang <meiliang@chromium.org>
Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#666511}
parent 15f310d0
...@@ -25,6 +25,7 @@ android_library("java") { ...@@ -25,6 +25,7 @@ android_library("java") {
"java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherMediator.java", "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/MultiThumbnailCardProvider.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/SelectableTabGridViewHolder.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridContainerViewBinder.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/TabGridDialogCoordinator.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogMediator.java",
......
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:maxLevel="@integer/list_item_level_default">
<shape android:shape="oval">
<stroke
android:width="2dp"
android:color="@android:color/black"/>
</shape>
</item>
<item android:maxLevel="@integer/list_item_level_selected">
<shape android:shape="oval">
<solid android:color="@color/light_active_color" />
</shape>
</item>
</level-list>
\ No newline at end of file
...@@ -20,4 +20,5 @@ ...@@ -20,4 +20,5 @@
<dimen name="tab_grid_thumbnail_favicon_background_padding">2dp</dimen> <dimen name="tab_grid_thumbnail_favicon_background_padding">2dp</dimen>
<dimen name="tab_grid_thumbnail_favicon_background_down_shift">2dp</dimen> <dimen name="tab_grid_thumbnail_favicon_background_down_shift">2dp</dimen>
<dimen name="swipe_to_dismiss_threshold">72dp</dimen> <dimen name="swipe_to_dismiss_threshold">72dp</dimen>
<dimen name="selection_tab_grid_toggle_button_inset">12dp</dimen>
</resources> </resources>
// 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.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.support.graphics.drawable.AnimatedVectorDrawableCompat;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.content.res.AppCompatResources;
import org.chromium.chrome.R;
/**
* A {@link TabGridViewHolder} with a checkable button. This is used in the manual selection mode.
*/
class SelectableTabGridViewHolder extends TabGridViewHolder {
public final int defaultLevel;
public final int selectedLevel;
public AnimatedVectorDrawableCompat mCheckDrawable;
public ColorStateList iconColorList;
SelectableTabGridViewHolder(TabGridView itemView) {
super(itemView);
defaultLevel = itemView.getResources().getInteger(
org.chromium.chrome.R.integer.list_item_level_default);
selectedLevel = itemView.getResources().getInteger(
org.chromium.chrome.R.integer.list_item_level_selected);
mCheckDrawable = AnimatedVectorDrawableCompat.create(
itemView.getContext(), R.drawable.ic_check_googblue_24dp_animated);
iconColorList = AppCompatResources.getColorStateList(
itemView.getContext(), org.chromium.chrome.R.color.default_icon_color_inverse);
Drawable selectedDrawable = new InsetDrawable(
ResourcesCompat.getDrawable(itemView.getResources(),
org.chromium.chrome.tab_ui.R.drawable.tab_grid_selection_list_icon,
itemView.getContext().getTheme()),
(int) itemView.getResources().getDimension(
org.chromium.chrome.tab_ui.R.dimen.selection_tab_grid_toggle_button_inset));
actionButton.setBackground(selectedDrawable);
actionButton.getBackground().setLevel(defaultLevel);
}
}
...@@ -14,6 +14,7 @@ import android.support.v4.content.res.ResourcesCompat; ...@@ -14,6 +14,7 @@ import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View; import android.view.View;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.Callback; import org.chromium.base.Callback;
import org.chromium.chrome.tab_ui.R; import org.chromium.chrome.tab_ui.R;
import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyKey;
...@@ -119,7 +120,27 @@ class TabGridViewBinder { ...@@ -119,7 +120,27 @@ class TabGridViewBinder {
private static void onBindSelectableTab( private static void onBindSelectableTab(
TabGridViewHolder holder, PropertyModel item, PropertyKey propertyKey) { TabGridViewHolder holder, PropertyModel item, PropertyKey propertyKey) {
// TODO(meiliang): Bind SELECTABLE_TAB properties assert holder instanceof SelectableTabGridViewHolder;
SelectableTabGridViewHolder selectionHolder = (SelectableTabGridViewHolder) holder;
if (TabProperties.IS_SELECTED == propertyKey) {
boolean isSelected = item.get(TabProperties.IS_SELECTED);
selectionHolder.actionButton.getBackground().setLevel(
isSelected ? selectionHolder.selectedLevel : selectionHolder.defaultLevel);
selectionHolder.actionButton.setImageDrawable(
isSelected ? selectionHolder.mCheckDrawable : null);
ApiCompatibilityUtils.setImageTintList(selectionHolder.actionButton,
isSelected ? selectionHolder.iconColorList : null);
if (isSelected) selectionHolder.mCheckDrawable.start();
} else if (TabProperties.SELECTABLE_TAB_CLICKED_LISTENER == propertyKey) {
selectionHolder.itemView.setOnClickListener(view -> {
item.get(TabProperties.SELECTABLE_TAB_CLICKED_LISTENER).run(holder.getTabId());
});
} else if (TabProperties.TITLE == propertyKey) {
String title = item.get(TabProperties.TITLE);
holder.actionButton.setContentDescription(holder.itemView.getResources().getString(
org.chromium.chrome.R.string.accessibility_tabstrip_btn_close_tab, title));
}
} }
private static void updateThumbnail(TabGridViewHolder holder, PropertyModel item) { private static void updateThumbnail(TabGridViewHolder holder, PropertyModel item) {
......
...@@ -60,8 +60,7 @@ class TabGridViewHolder extends RecyclerView.ViewHolder { ...@@ -60,8 +60,7 @@ class TabGridViewHolder extends RecyclerView.ViewHolder {
if (itemViewType == TabGridViewItemType.CLOSABLE_TAB) { if (itemViewType == TabGridViewItemType.CLOSABLE_TAB) {
return new ClosableTabGridViewHolder(view); return new ClosableTabGridViewHolder(view);
} else { } else {
// TODO(meiliang): Return SelectableTabGridViewHolder return new SelectableTabGridViewHolder(view);
return new TabGridViewHolder(view);
} }
} }
......
...@@ -200,6 +200,16 @@ class TabListMediator { ...@@ -200,6 +200,16 @@ class TabListMediator {
} }
}; };
private final TabActionListener mSelectableTabOnClickListener = new TabActionListener() {
@Override
public void run(int tabId) {
int index = mModel.indexFromId(tabId);
if (index == TabModel.INVALID_TAB_INDEX) return;
boolean selected = mModel.get(index).get(TabProperties.IS_SELECTED);
mModel.get(index).set(TabProperties.IS_SELECTED, !selected);
}
};
private final TabObserver mTabObserver = new EmptyTabObserver() { private final TabObserver mTabObserver = new EmptyTabObserver() {
@Override @Override
public void onDidStartNavigation(Tab tab, NavigationHandle navigationHandle) { public void onDidStartNavigation(Tab tab, NavigationHandle navigationHandle) {
...@@ -686,6 +696,8 @@ class TabListMediator { ...@@ -686,6 +696,8 @@ class TabListMediator {
.with(TabProperties.ALPHA, 1f) .with(TabProperties.ALPHA, 1f)
.with(TabProperties.CARD_ANIMATION_STATUS, .with(TabProperties.CARD_ANIMATION_STATUS,
TabListRecyclerView.ANIMATION_STATUS_RESTORE) TabListRecyclerView.ANIMATION_STATUS_RESTORE)
.with(TabProperties.SELECTABLE_TAB_CLICKED_LISTENER,
mSelectableTabOnClickListener)
.build(); .build();
if (index >= mModel.size()) { if (index >= mModel.size()) {
......
...@@ -48,9 +48,13 @@ public class TabProperties { ...@@ -48,9 +48,13 @@ public class TabProperties {
public static final PropertyModel.WritableIntPropertyKey CARD_ANIMATION_STATUS = public static final PropertyModel.WritableIntPropertyKey CARD_ANIMATION_STATUS =
new PropertyModel.WritableIntPropertyKey(); new PropertyModel.WritableIntPropertyKey();
public static final PropertyModel.WritableObjectPropertyKey<TabListMediator.TabActionListener>
SELECTABLE_TAB_CLICKED_LISTENER = new PropertyModel.WritableObjectPropertyKey<>();
public static final PropertyKey[] ALL_KEYS_TAB_GRID = new PropertyKey[] {TAB_ID, public static final PropertyKey[] ALL_KEYS_TAB_GRID = new PropertyKey[] {TAB_ID,
TAB_SELECTED_LISTENER, TAB_CLOSED_LISTENER, FAVICON, THUMBNAIL_FETCHER, IPH_PROVIDER, TAB_SELECTED_LISTENER, TAB_CLOSED_LISTENER, FAVICON, THUMBNAIL_FETCHER, IPH_PROVIDER,
TITLE, IS_SELECTED, IS_HIDDEN, CREATE_GROUP_LISTENER, ALPHA, CARD_ANIMATION_STATUS}; TITLE, IS_SELECTED, IS_HIDDEN, CREATE_GROUP_LISTENER, ALPHA, CARD_ANIMATION_STATUS,
SELECTABLE_TAB_CLICKED_LISTENER};
public static final PropertyKey[] ALL_KEYS_TAB_STRIP = new PropertyKey[] { public static final PropertyKey[] ALL_KEYS_TAB_STRIP = new PropertyKey[] {
TAB_ID, TAB_SELECTED_LISTENER, TAB_CLOSED_LISTENER, FAVICON, IS_SELECTED, TITLE}; TAB_ID, TAB_SELECTED_LISTENER, TAB_CLOSED_LISTENER, FAVICON, IS_SELECTED, TITLE};
......
...@@ -50,6 +50,10 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase { ...@@ -50,6 +50,10 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase {
private PropertyModel mStripModel; private PropertyModel mStripModel;
private PropertyModelChangeProcessor mStripMCP; private PropertyModelChangeProcessor mStripMCP;
private TabGridViewHolder mSelectableTabGridViewHolder;
private PropertyModel mSelectableModel;
private PropertyModelChangeProcessor mSelectableMCP;
private TabListMediator.ThumbnailFetcher mMockThumbnailProvider = private TabListMediator.ThumbnailFetcher mMockThumbnailProvider =
new TabListMediator.ThumbnailFetcher(new TabListMediator.ThumbnailProvider() { new TabListMediator.ThumbnailFetcher(new TabListMediator.ThumbnailProvider() {
@Override @Override
...@@ -93,11 +97,15 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase { ...@@ -93,11 +97,15 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase {
TestThreadUtils.runOnUiThreadBlocking(() -> { TestThreadUtils.runOnUiThreadBlocking(() -> {
getActivity().setContentView(view, params); getActivity().setContentView(view, params);
mTabGridViewHolder = TabGridViewHolder.create(view, 0); mTabGridViewHolder = TabGridViewHolder.create(
view, TabGridViewHolder.TabGridViewItemType.CLOSABLE_TAB);
mTabStripViewHolder = TabStripViewHolder.create(view, 0); mTabStripViewHolder = TabStripViewHolder.create(view, 0);
mSelectableTabGridViewHolder = TabGridViewHolder.create(
view, TabGridViewHolder.TabGridViewItemType.SELECTABLE_TAB);
view.addView(mTabGridViewHolder.itemView); view.addView(mTabGridViewHolder.itemView);
view.addView(mTabStripViewHolder.itemView); view.addView(mTabStripViewHolder.itemView);
view.addView(mSelectableTabGridViewHolder.itemView);
}); });
mGridModel = new PropertyModel.Builder(TabProperties.ALL_KEYS_TAB_GRID) mGridModel = new PropertyModel.Builder(TabProperties.ALL_KEYS_TAB_GRID)
...@@ -108,32 +116,34 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase { ...@@ -108,32 +116,34 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase {
.with(TabProperties.TAB_SELECTED_LISTENER, mMockSelectedListener) .with(TabProperties.TAB_SELECTED_LISTENER, mMockSelectedListener)
.with(TabProperties.TAB_CLOSED_LISTENER, mMockCloseListener) .with(TabProperties.TAB_CLOSED_LISTENER, mMockCloseListener)
.build(); .build();
mSelectableModel =
new PropertyModel.Builder(TabProperties.ALL_KEYS_TAB_GRID)
.with(TabProperties.SELECTABLE_TAB_CLICKED_LISTENER, mMockSelectedListener)
.build();
mGridMCP = PropertyModelChangeProcessor.create(mGridModel, mTabGridViewHolder, mGridMCP = PropertyModelChangeProcessor.create(mGridModel, mTabGridViewHolder,
new TestRecyclerViewSimpleViewBinder<>(TabGridViewBinder::onBindViewHolder)); new TestRecyclerViewSimpleViewBinder<>(TabGridViewBinder::onBindViewHolder));
mStripMCP = PropertyModelChangeProcessor.create(mStripModel, mTabStripViewHolder, mStripMCP = PropertyModelChangeProcessor.create(mStripModel, mTabStripViewHolder,
new TestRecyclerViewSimpleViewBinder<>(TabStripViewBinder::onBindViewHolder)); new TestRecyclerViewSimpleViewBinder<>(TabStripViewBinder::onBindViewHolder));
mSelectableMCP = PropertyModelChangeProcessor.create(mSelectableModel,
mSelectableTabGridViewHolder,
new TestRecyclerViewSimpleViewBinder<>(TabGridViewBinder::onBindViewHolder));
} }
@Test private void testGridSelected(TabGridViewHolder holder, PropertyModel model) {
@MediumTest
@UiThreadTest
public void testSelected() throws Exception {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
mGridModel.set(TabProperties.IS_SELECTED, true); model.set(TabProperties.IS_SELECTED, true);
Assert.assertTrue( Assert.assertTrue(((FrameLayout) (holder.itemView)).getForeground() != null);
((FrameLayout) (mTabGridViewHolder.itemView)).getForeground() != null); model.set(TabProperties.IS_SELECTED, false);
mGridModel.set(TabProperties.IS_SELECTED, false); Assert.assertFalse(((FrameLayout) (holder.itemView)).getForeground() != null);
Assert.assertFalse(
((FrameLayout) (mTabGridViewHolder.itemView)).getForeground() != null);
} else { } else {
mGridModel.set(TabProperties.IS_SELECTED, true); model.set(TabProperties.IS_SELECTED, true);
Drawable selectedDrawable = Drawable selectedDrawable =
mTabGridViewHolder.itemView.findViewById(R.id.background_view).getBackground(); holder.itemView.findViewById(R.id.background_view).getBackground();
Assert.assertTrue(selectedDrawable != null); Assert.assertTrue(selectedDrawable != null);
mGridModel.set(TabProperties.IS_SELECTED, false); model.set(TabProperties.IS_SELECTED, false);
Drawable elevationDrawable = Drawable elevationDrawable =
mTabGridViewHolder.itemView.findViewById(R.id.background_view).getBackground(); holder.itemView.findViewById(R.id.background_view).getBackground();
Assert.assertTrue(elevationDrawable != null); Assert.assertTrue(elevationDrawable != null);
Assert.assertNotSame(selectedDrawable, elevationDrawable); Assert.assertNotSame(selectedDrawable, elevationDrawable);
} }
...@@ -143,6 +153,29 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase { ...@@ -143,6 +153,29 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase {
Assert.assertFalse(((FrameLayout) (mTabStripViewHolder.itemView)).getForeground() != null); Assert.assertFalse(((FrameLayout) (mTabStripViewHolder.itemView)).getForeground() != null);
} }
@Test
@MediumTest
@UiThreadTest
public void testSelected() throws Exception {
testGridSelected(mTabGridViewHolder, mGridModel);
mStripModel.set(TabProperties.IS_SELECTED, true);
Assert.assertTrue(((FrameLayout) (mTabStripViewHolder.itemView)).getForeground() != null);
mStripModel.set(TabProperties.IS_SELECTED, false);
Assert.assertFalse(((FrameLayout) (mTabStripViewHolder.itemView)).getForeground() != null);
testGridSelected(mSelectableTabGridViewHolder, mSelectableModel);
mSelectableModel.set(TabProperties.IS_SELECTED, true);
Assert.assertTrue(
mSelectableTabGridViewHolder.actionButton.getBackground().getLevel() == 1);
Assert.assertTrue(mSelectableTabGridViewHolder.actionButton.getDrawable() != null);
mSelectableModel.set(TabProperties.IS_SELECTED, false);
Assert.assertTrue(
mSelectableTabGridViewHolder.actionButton.getBackground().getLevel() == 0);
Assert.assertTrue(mSelectableTabGridViewHolder.actionButton.getDrawable() == null);
}
@Test @Test
@MediumTest @MediumTest
@UiThreadTest @UiThreadTest
...@@ -150,6 +183,9 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase { ...@@ -150,6 +183,9 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase {
final String title = "Surf the cool webz"; final String title = "Surf the cool webz";
mGridModel.set(TabProperties.TITLE, title); mGridModel.set(TabProperties.TITLE, title);
Assert.assertEquals(mTabGridViewHolder.title.getText(), title); Assert.assertEquals(mTabGridViewHolder.title.getText(), title);
mSelectableModel.set(TabProperties.TITLE, title);
Assert.assertEquals(mSelectableTabGridViewHolder.title.getText(), title);
} }
@Test @Test
...@@ -303,6 +339,16 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase { ...@@ -303,6 +339,16 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase {
mStripModel.set(TabProperties.IS_SELECTED, true); mStripModel.set(TabProperties.IS_SELECTED, true);
mTabStripViewHolder.button.performClick(); mTabStripViewHolder.button.performClick();
Assert.assertFalse(mSelectClicked.get()); Assert.assertFalse(mSelectClicked.get());
mSelectClicked.set(false);
mSelectableModel.set(TabProperties.IS_SELECTED, false);
mSelectableTabGridViewHolder.itemView.performClick();
Assert.assertTrue(mSelectClicked.get());
mSelectClicked.set(false);
mSelectableModel.set(TabProperties.IS_SELECTED, true);
mSelectableTabGridViewHolder.itemView.performClick();
Assert.assertTrue(mSelectClicked.get());
} }
@Test @Test
...@@ -327,6 +373,7 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase { ...@@ -327,6 +373,7 @@ public class TabListViewHolderTest extends DummyUiActivityTestCase {
public void tearDownTest() throws Exception { public void tearDownTest() throws Exception {
mStripMCP.destroy(); mStripMCP.destroy();
mGridMCP.destroy(); mGridMCP.destroy();
mSelectableMCP.destroy();
super.tearDownTest(); super.tearDownTest();
} }
} }
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