Commit 86af7333 authored by Yue Zhang's avatar Yue Zhang Committed by Commit Bot

Fix TabGridDialog back press misbehavior

http://crrev.com/c/1815988 makes the PopupWindow focusable so that we
can focus on EditText within TabGridDialog. However, there seems to be
some inconsistent behavior when clicking back press in a focused
PopupWindow among different Android APIs. This CL fixes this issue and
adds a regression test.

Bug: 1013974
Change-Id: I07575bb493d8627c6af2e7a64eb47acd08876ca4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1874461
Commit-Queue: Yue Zhang <yuezhanggg@chromium.org>
Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709981}
parent 60060a35
...@@ -325,6 +325,7 @@ public class TabGridDialogMediator { ...@@ -325,6 +325,7 @@ public class TabGridDialogMediator {
mModel.set(TabGridPanelProperties.IS_TITLE_TEXT_FOCUSED, isShowing); mModel.set(TabGridPanelProperties.IS_TITLE_TEXT_FOCUSED, isShowing);
if (!isShowing) { if (!isShowing) {
saveCurrentGroupModifiedTitle(); saveCurrentGroupModifiedTitle();
mModel.set(TabGridPanelProperties.IS_POPUP_WINDOW_FOCUSABLE, false);
} }
}; };
KeyboardVisibilityDelegate.getInstance().addKeyboardVisibilityListener( KeyboardVisibilityDelegate.getInstance().addKeyboardVisibilityListener(
...@@ -348,6 +349,14 @@ public class TabGridDialogMediator { ...@@ -348,6 +349,14 @@ public class TabGridDialogMediator {
View.OnFocusChangeListener onFocusChangeListener = View.OnFocusChangeListener onFocusChangeListener =
(v, hasFocus) -> mIsUpdatingTitle = hasFocus; (v, hasFocus) -> mIsUpdatingTitle = hasFocus;
mModel.set(TabGridPanelProperties.TITLE_TEXT_ON_FOCUS_LISTENER, onFocusChangeListener); mModel.set(TabGridPanelProperties.TITLE_TEXT_ON_FOCUS_LISTENER, onFocusChangeListener);
View.OnTouchListener onTouchListener = (v, event) -> {
// When touching title text field, make the PopupWindow focusable and request focus.
mModel.set(TabGridPanelProperties.IS_POPUP_WINDOW_FOCUSABLE, true);
v.performClick();
return false;
};
mModel.set(TabGridPanelProperties.TITLE_TEXT_ON_TOUCH_LISTENER, onTouchListener);
} }
private void setupScrimViewObserver() { private void setupScrimViewObserver() {
......
...@@ -175,7 +175,6 @@ public class TabGridDialogParent ...@@ -175,7 +175,6 @@ public class TabGridDialogParent
mScrimView = new ScrimView(context, null, mTabGridDialogParentView); mScrimView = new ScrimView(context, null, mTabGridDialogParentView);
mPopupWindow = new PopupWindow(mTabGridDialogParentView, mPopupWindow = new PopupWindow(mTabGridDialogParentView,
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mPopupWindow.setFocusable(true);
updateDialogWithOrientation(context, context.getResources().getConfiguration().orientation); updateDialogWithOrientation(context, context.getResources().getConfiguration().orientation);
} }
...@@ -756,6 +755,17 @@ public class TabGridDialogParent ...@@ -756,6 +755,17 @@ public class TabGridDialogParent
mUngroupBarTextAppearance = textAppearance; mUngroupBarTextAppearance = textAppearance;
} }
/**
* Update whether the PopupWindow is focusable or not.
*
* @param focusable whether the PopupWindow is focusable.
*/
@VisibleForTesting
void setPopupWindowFocusable(boolean focusable) {
mPopupWindow.setFocusable(focusable);
mPopupWindow.update();
}
@VisibleForTesting @VisibleForTesting
PopupWindow getPopupWindowForTesting() { PopupWindow getPopupWindowForTesting() {
return mPopupWindow; return mPopupWindow;
......
...@@ -71,11 +71,17 @@ class TabGridPanelProperties { ...@@ -71,11 +71,17 @@ class TabGridPanelProperties {
new PropertyModel.WritableBooleanPropertyKey(); new PropertyModel.WritableBooleanPropertyKey();
public static final PropertyModel.WritableBooleanPropertyKey IS_TITLE_TEXT_FOCUSED = public static final PropertyModel.WritableBooleanPropertyKey IS_TITLE_TEXT_FOCUSED =
new PropertyModel.WritableBooleanPropertyKey(); new PropertyModel.WritableBooleanPropertyKey();
public static final PropertyModel.WritableBooleanPropertyKey IS_POPUP_WINDOW_FOCUSABLE =
new PropertyModel.WritableBooleanPropertyKey();
public static final PropertyModel
.WritableObjectPropertyKey<View.OnTouchListener> TITLE_TEXT_ON_TOUCH_LISTENER =
new PropertyModel.WritableObjectPropertyKey<View.OnTouchListener>();
public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {COLLAPSE_CLICK_LISTENER, public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {COLLAPSE_CLICK_LISTENER,
ADD_CLICK_LISTENER, HEADER_TITLE, CONTENT_TOP_MARGIN, PRIMARY_COLOR, TINT, ADD_CLICK_LISTENER, HEADER_TITLE, CONTENT_TOP_MARGIN, PRIMARY_COLOR, TINT,
IS_DIALOG_VISIBLE, SCRIMVIEW_OBSERVER, ANIMATION_PARAMS, UNGROUP_BAR_STATUS, IS_DIALOG_VISIBLE, SCRIMVIEW_OBSERVER, ANIMATION_PARAMS, UNGROUP_BAR_STATUS,
DIALOG_BACKGROUND_RESOUCE_ID, DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID, DIALOG_BACKGROUND_RESOUCE_ID, DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID,
DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID, DIALOG_UNGROUP_BAR_TEXT_APPEARANCE, DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID, DIALOG_UNGROUP_BAR_TEXT_APPEARANCE,
INITIAL_SCROLL_INDEX, IS_MAIN_CONTENT_VISIBLE, MENU_CLICK_LISTENER, TITLE_TEXT_WATCHER, INITIAL_SCROLL_INDEX, IS_MAIN_CONTENT_VISIBLE, MENU_CLICK_LISTENER, TITLE_TEXT_WATCHER,
TITLE_TEXT_ON_FOCUS_LISTENER, TITLE_CURSOR_VISIBILITY, IS_TITLE_TEXT_FOCUSED}; TITLE_TEXT_ON_FOCUS_LISTENER, TITLE_CURSOR_VISIBILITY, IS_TITLE_TEXT_FOCUSED,
IS_POPUP_WINDOW_FOCUSABLE, TITLE_TEXT_ON_TOUCH_LISTENER};
} }
...@@ -16,6 +16,7 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelPrope ...@@ -16,6 +16,7 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelPrope
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.INITIAL_SCROLL_INDEX; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.INITIAL_SCROLL_INDEX;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_DIALOG_VISIBLE; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_DIALOG_VISIBLE;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_MAIN_CONTENT_VISIBLE; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_MAIN_CONTENT_VISIBLE;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_POPUP_WINDOW_FOCUSABLE;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_TITLE_TEXT_FOCUSED; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.IS_TITLE_TEXT_FOCUSED;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.MENU_CLICK_LISTENER; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.MENU_CLICK_LISTENER;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.PRIMARY_COLOR; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.PRIMARY_COLOR;
...@@ -23,6 +24,7 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelPrope ...@@ -23,6 +24,7 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelPrope
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TINT; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TINT;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TITLE_CURSOR_VISIBILITY; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TITLE_CURSOR_VISIBILITY;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TITLE_TEXT_ON_FOCUS_LISTENER; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TITLE_TEXT_ON_FOCUS_LISTENER;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TITLE_TEXT_ON_TOUCH_LISTENER;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TITLE_TEXT_WATCHER; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.TITLE_TEXT_WATCHER;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.UNGROUP_BAR_STATUS; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.UNGROUP_BAR_STATUS;
...@@ -133,6 +135,10 @@ class TabGridPanelViewBinder { ...@@ -133,6 +135,10 @@ class TabGridPanelViewBinder {
if (!model.get(IS_TITLE_TEXT_FOCUSED)) { if (!model.get(IS_TITLE_TEXT_FOCUSED)) {
viewHolder.toolbarView.clearTitleTextFocus(); viewHolder.toolbarView.clearTitleTextFocus();
} }
} else if (IS_POPUP_WINDOW_FOCUSABLE == propertyKey) {
viewHolder.dialogView.setPopupWindowFocusable(model.get(IS_POPUP_WINDOW_FOCUSABLE));
} else if (TITLE_TEXT_ON_TOUCH_LISTENER == propertyKey) {
viewHolder.toolbarView.setTitleOnTouchListener(model.get(TITLE_TEXT_ON_TOUCH_LISTENER));
} }
} }
} }
...@@ -76,6 +76,10 @@ public class TabGroupUiToolbarView extends FrameLayout { ...@@ -76,6 +76,10 @@ public class TabGroupUiToolbarView extends FrameLayout {
mTitleTextView.clearFocus(); mTitleTextView.clearFocus();
} }
void setTitleOnTouchListener(View.OnTouchListener listener) {
mTitleTextView.setOnTouchListener(listener);
}
ViewGroup getViewContainer() { ViewGroup getViewContainer() {
return mContainerView; return mContainerView;
} }
......
...@@ -138,6 +138,20 @@ public class TabGridDialogParentTest extends DummyUiActivityTestCase { ...@@ -138,6 +138,20 @@ public class TabGridDialogParentTest extends DummyUiActivityTestCase {
Assert.assertEquals(0, params.bottomMargin); Assert.assertEquals(0, params.bottomMargin);
} }
@Test
@SmallTest
@UiThreadTest
public void testSetPopupWindowFocusable() {
PopupWindow popupWindow = mTabGridDialogParent.getPopupWindowForTesting();
popupWindow.setFocusable(false);
mTabGridDialogParent.setPopupWindowFocusable(true);
Assert.assertTrue(popupWindow.isFocusable());
mTabGridDialogParent.setPopupWindowFocusable(false);
Assert.assertFalse(popupWindow.isFocusable());
}
@Test @Test
@MediumTest @MediumTest
public void testUpdateUngroupBar() { public void testUpdateUngroupBar() {
......
// 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 static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.CardCountAssertion;
import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.clickFirstTabFromTabSwitcher;
import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.createOverviewHideWatcher;
import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.createTabGroup;
import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.createTabs;
import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.enterTabSwitcher;
import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyTabSwitcherCardCount;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.NoMatchingRootException;
import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.test.filters.MediumTest;
import android.widget.EditText;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.compositor.layouts.Layout;
import org.chromium.chrome.browser.flags.FeatureUtilities;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter;
import org.chromium.chrome.features.start_surface.StartSurfaceLayout;
import org.chromium.chrome.tab_ui.R;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.OverviewModeBehaviorWatcher;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.ui.test.util.UiRestriction;
import java.util.ArrayList;
import java.util.List;
/** End-to-end tests for TabGridDialog component. */
@RunWith(ChromeJUnit4ClassRunner.class)
// clang-format off
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
@Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID})
public class TabGridDialogTest {
// clang-format on
@Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
@Rule
public TestRule mProcessor = new Features.InstrumentationProcessor();
@Before
public void setUp() {
FeatureUtilities.setGridTabSwitcherEnabledForTesting(true);
FeatureUtilities.setTabGroupsAndroidEnabledForTesting(true);
mActivityTestRule.startMainActivityFromLauncher();
Layout layout = mActivityTestRule.getActivity().getLayoutManager().getOverviewLayout();
assertTrue(layout instanceof StartSurfaceLayout);
CriteriaHelper.pollUiThread(mActivityTestRule.getActivity()
.getTabModelSelector()
.getTabModelFilterProvider()
.getCurrentTabModelFilter()::isTabModelRestored);
}
@Test
@MediumTest
public void testBackPressCloseDialog() throws InterruptedException {
final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
createTabs(cta, false, 2);
enterTabSwitcher(cta);
verifyTabSwitcherCardCount(cta, 2);
// Create a tab group.
List<Tab> tabGroup = new ArrayList<>();
TabModel tabModel = cta.getTabModelSelector().getModel(false);
for (int i = 0; i < tabModel.getCount(); i++) {
tabGroup.add(tabModel.getTabAt(i));
}
createTabGroup(cta, false, tabGroup);
assertTrue(cta.getTabModelSelector().getTabModelFilterProvider().getCurrentTabModelFilter()
instanceof TabGroupModelFilter);
TabGroupModelFilter filter = (TabGroupModelFilter) cta.getTabModelSelector()
.getTabModelFilterProvider()
.getCurrentTabModelFilter();
assertEquals(1, filter.getCount());
verifyTabSwitcherCardCount(cta, 1);
// Open dialog and verify dialog is showing correct content.
clickFirstTabFromTabSwitcher(cta);
CriteriaHelper.pollInstrumentationThread(() -> isDialogShowing(cta));
verifyShowingDialog(cta, 2);
// Press back and dialog should be hidden.
Espresso.pressBack();
CriteriaHelper.pollInstrumentationThread(() -> !isDialogShowing(cta));
verifyTabSwitcherCardCount(cta, 1);
// Enter first tab page, open dialog from strip and verify dialog is showing correct
// content.
assertTrue(cta.getLayoutManager().overviewVisible());
clickFirstTabFromTabSwitcher(cta);
clickFirstTabFromDialog(cta);
showDialogFromStrip(cta);
CriteriaHelper.pollInstrumentationThread(() -> isDialogShowing(cta));
verifyShowingDialog(cta, 2);
// Press back and dialog should be hidden.
Espresso.pressBack();
CriteriaHelper.pollInstrumentationThread(() -> !isDialogShowing(cta));
}
private void verifyShowingDialog(ChromeTabbedActivity cta, int tabCount) {
onView(withId(R.id.tab_list_view))
.inRoot(withDecorView(not(cta.getWindow().getDecorView())))
.check(CardCountAssertion.havingTabCount(tabCount));
onView(allOf(withParent(withId(R.id.main_content)), withId(R.id.title)))
.inRoot(withDecorView(not(cta.getWindow().getDecorView())))
.check((v, noMatchException) -> {
if (noMatchException != null) throw noMatchException;
Assert.assertTrue(v instanceof EditText);
EditText titleText = (EditText) v;
String title = cta.getResources().getQuantityString(
R.plurals.bottom_tab_grid_title_placeholder, tabCount, tabCount);
Assert.assertEquals(title, titleText.getText().toString());
assertFalse(v.isFocused());
});
}
private boolean isDialogShowing(ChromeTabbedActivity cta) {
boolean isShowing = true;
try {
onView(withId(R.id.tab_list_view))
.inRoot(withDecorView(not(cta.getWindow().getDecorView())))
.check(matches(isDisplayed()));
} catch (NoMatchingRootException e) {
isShowing = false;
} catch (Exception e) {
assert false : "error when inspecting dialog recyclerView.";
}
return isShowing;
}
private void clickFirstTabFromDialog(ChromeTabbedActivity cta) {
OverviewModeBehaviorWatcher hideWatcher = createOverviewHideWatcher(cta);
onView(withId(R.id.tab_list_view))
.inRoot(withDecorView(not(cta.getWindow().getDecorView())))
.perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
hideWatcher.waitForBehavior();
}
private void showDialogFromStrip(ChromeTabbedActivity cta) {
assertFalse(cta.getLayoutManager().overviewVisible());
onView(withId(R.id.toolbar_left_button)).perform(click());
}
}
\ No newline at end of file
...@@ -8,6 +8,7 @@ import android.content.res.ColorStateList; ...@@ -8,6 +8,7 @@ import android.content.res.ColorStateList;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.os.Build; import android.os.Build;
import android.os.SystemClock;
import android.provider.Settings; import android.provider.Settings;
import android.support.test.annotation.UiThreadTest; import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
...@@ -17,10 +18,12 @@ import android.support.v7.widget.RecyclerView; ...@@ -17,10 +18,12 @@ import android.support.v7.widget.RecyclerView;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.EditText; import android.widget.EditText;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.PopupWindow;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
...@@ -438,6 +441,40 @@ public class TabGridPanelViewBinderTest extends DummyUiActivityTestCase { ...@@ -438,6 +441,40 @@ public class TabGridPanelViewBinderTest extends DummyUiActivityTestCase {
Assert.assertFalse(mTitleTextView.isFocused()); Assert.assertFalse(mTitleTextView.isFocused());
} }
@Test
@SmallTest
@UiThreadTest
public void testSetPopupWindowFocusable() {
PopupWindow popupWindow = mTabGridDialogParent.getPopupWindowForTesting();
Assert.assertFalse(popupWindow.isFocusable());
mModel.set(TabGridPanelProperties.IS_POPUP_WINDOW_FOCUSABLE, true);
Assert.assertTrue(popupWindow.isFocusable());
mModel.set(TabGridPanelProperties.IS_POPUP_WINDOW_FOCUSABLE, false);
Assert.assertFalse(popupWindow.isFocusable());
}
@Test
@SmallTest
@UiThreadTest
public void testSetTitleTextOnTouchListener() {
AtomicBoolean titleTextTouched = new AtomicBoolean();
titleTextTouched.set(false);
View.OnTouchListener listener = (view, event) -> {
titleTextTouched.set(true);
return false;
};
mModel.set(TabGridPanelProperties.TITLE_TEXT_ON_TOUCH_LISTENER, listener);
// Create a dummy MotionEvent.
MotionEvent e = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
MotionEvent.ACTION_DOWN, 0, 0, 0);
mTitleTextView.dispatchTouchEvent(e);
Assert.assertTrue(titleTextTouched.get());
}
@Override @Override
public void tearDownTest() throws Exception { public void tearDownTest() throws Exception {
mMCP.destroy(); mMCP.destroy();
......
// 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 static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static org.hamcrest.Matchers.allOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.ViewAssertion;
import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tasks.tab_groups.TabGroupModelFilter;
import org.chromium.chrome.tab_ui.R;
import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.chrome.test.util.OverviewModeBehaviorWatcher;
import org.chromium.content_public.browser.test.util.Criteria;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import java.util.List;
/**
* Utilities helper class for tab grid/group tests.
*/
public class TabUiTestHelper {
/**
* Create {@code tabsCount} tabs for {@code cta} in certain tab model based on {@code
* isIncognito}.
* @param cta A current running activity to create tabs.
* @param isIncognito Indicator for whether to create tabs in normal model or incognito
* model.
* @param tabsCount Number of tabs to be created.
*/
static void createTabs(ChromeTabbedActivity cta, boolean isIncognito, int tabsCount) {
for (int i = 0; i < (isIncognito ? tabsCount : tabsCount - 1); i++) {
ChromeTabUtils.newTabFromMenu(
InstrumentationRegistry.getInstrumentation(), cta, isIncognito, true);
}
}
/**
* Enter tab switcher from a tab page.
* @param cta The current running activity.
*/
static void enterTabSwitcher(ChromeTabbedActivity cta) {
OverviewModeBehaviorWatcher showWatcher = createOverviewShowWatcher(cta);
assertFalse(cta.getLayoutManager().overviewVisible());
onView(withId(R.id.tab_switcher_button)).perform(click());
showWatcher.waitForBehavior();
}
/**
* Click the first card in grid tab switcher. When group is enabled and the first card is a
* group, this will open up the dialog; otherwise this will open up the tab page.
* @param cta The current running activity.
*/
static void clickFirstTabFromTabSwitcher(ChromeTabbedActivity cta) {
assertTrue(cta.getLayoutManager().overviewVisible());
onView(allOf(withParent(withId(org.chromium.chrome.R.id.compositor_view_holder)),
withId(R.id.tab_list_view)))
.perform(RecyclerViewActions.actionOnItemAtPosition(0, click()));
}
/**
* Verify that current tab models hold correct number of tabs.
* @param cta The current running activity.
* @param normalTabs The correct number of normal tabs.
* @param incognitoTabs The correct number of incognito tabs.
*/
static void verifyTabModelTabCount(
ChromeTabbedActivity cta, int normalTabs, int incognitoTabs) {
CriteriaHelper.pollUiThread(Criteria.equals(
normalTabs, () -> cta.getTabModelSelector().getModel(false).getCount()));
CriteriaHelper.pollUiThread(Criteria.equals(
incognitoTabs, () -> cta.getTabModelSelector().getModel(true).getCount()));
}
/**
* Verify there are correct number of cards in tab switcher.
* @param cta The current running activity.
* @param count The correct number of cards in tab switcher.
*/
static void verifyTabSwitcherCardCount(ChromeTabbedActivity cta, int count) {
assertTrue(cta.getLayoutManager().overviewVisible());
onView(allOf(withParent(withId(org.chromium.chrome.R.id.compositor_view_holder)),
withId(R.id.tab_list_view)))
.check(CardCountAssertion.havingTabCount(count));
}
/**
* Create a tab group using {@code tabs}.
* @param cta The current running activity.
* @param isIncognito Whether the group is in normal model or incognito model.
* @param tabs A list of {@link Tab} to create group.
*/
static void createTabGroup(ChromeTabbedActivity cta, boolean isIncognito, List<Tab> tabs) {
if (tabs.size() == 0) return;
assert cta.getTabModelSelector().getTabModelFilterProvider().getCurrentTabModelFilter()
instanceof TabGroupModelFilter;
TabGroupModelFilter filter = (TabGroupModelFilter) cta.getTabModelSelector()
.getTabModelFilterProvider()
.getTabModelFilter(isIncognito);
Tab rootTab = tabs.get(0);
for (int i = 1; i < tabs.size(); i++) {
Tab tab = tabs.get(i);
assertEquals(isIncognito, tab.isIncognito());
TestThreadUtils.runOnUiThreadBlocking(
() -> filter.mergeTabsToGroup(tab.getId(), rootTab.getId()));
}
}
/**
* Create a {@link OverviewModeBehaviorWatcher} to inspect overview show.
*/
static OverviewModeBehaviorWatcher createOverviewShowWatcher(ChromeTabbedActivity cta) {
return new OverviewModeBehaviorWatcher(cta.getLayoutManager(), true, false);
}
/**
* Create a {@link OverviewModeBehaviorWatcher} to inspect overview hide.
*/
static OverviewModeBehaviorWatcher createOverviewHideWatcher(ChromeTabbedActivity cta) {
return new OverviewModeBehaviorWatcher(cta.getLayoutManager(), false, true);
}
/**
* Implementation of {@link ViewAssertion} to verify the {@link RecyclerView} has correct number
* of children, and children are showing correctly.
*/
public static class CardCountAssertion implements ViewAssertion {
private int mExpectedCount;
public static CardCountAssertion havingTabCount(int tabCount) {
return new CardCountAssertion(tabCount);
}
public CardCountAssertion(int expectedCount) {
mExpectedCount = expectedCount;
}
@Override
public void check(View view, NoMatchingViewException noMatchException) {
if (noMatchException != null) throw noMatchException;
RecyclerView recyclerView = ((RecyclerView) view);
RecyclerView.Adapter adapter = recyclerView.getAdapter();
CriteriaHelper.pollUiThread(
Criteria.equals(mExpectedCount, () -> adapter.getItemCount()));
for (int i = 0; i < mExpectedCount; i++) {
RecyclerView.ViewHolder viewHolder =
recyclerView.findViewHolderForAdapterPosition(i);
if (viewHolder == null) return;
// This is to check if dialog hiding animation plays properly.
assertTrue(1f == viewHolder.itemView.getAlpha());
assertEquals(View.VISIBLE, viewHolder.itemView.getVisibility());
}
}
}
}
\ No newline at end of file
...@@ -25,6 +25,7 @@ import android.content.res.Resources; ...@@ -25,6 +25,7 @@ import android.content.res.Resources;
import android.graphics.Rect; import android.graphics.Rect;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
...@@ -370,6 +371,19 @@ public class TabGridDialogMediatorUnitTest { ...@@ -370,6 +371,19 @@ public class TabGridDialogMediatorUnitTest {
assertThat(mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(TAB1_TITLE)); assertThat(mModel.get(TabGridPanelProperties.HEADER_TITLE), equalTo(TAB1_TITLE));
} }
@Test
public void onTitleTextTouchEvent() {
View.OnTouchListener listener =
mModel.get(TabGridPanelProperties.TITLE_TEXT_ON_TOUCH_LISTENER);
assertThat(mModel.get(TabGridPanelProperties.IS_POPUP_WINDOW_FOCUSABLE), equalTo(false));
listener.onTouch(mTitleTextView, mock(MotionEvent.class));
assertThat(mModel.get(TabGridPanelProperties.IS_POPUP_WINDOW_FOCUSABLE), equalTo(true));
verify(mTitleTextView).performClick();
}
@Test @Test
public void tabAddition() { public void tabAddition() {
Tab newTab = prepareTab(TAB3_ID, TAB3_TITLE); Tab newTab = prepareTab(TAB3_ID, TAB3_TITLE);
......
...@@ -24,6 +24,7 @@ public_tab_management_java_sources += start_surface_public_java_sources ...@@ -24,6 +24,7 @@ public_tab_management_java_sources += start_surface_public_java_sources
tab_management_test_java_sources = [ tab_management_test_java_sources = [
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/AssertsTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/AssertsTest.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogTest.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParentTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParentTest.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridMessageCardViewBinderTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridMessageCardViewBinderTest.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java",
...@@ -31,6 +32,7 @@ tab_management_test_java_sources = [ ...@@ -31,6 +32,7 @@ tab_management_test_java_sources = [
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabListViewHolderTest.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorLayoutBinderTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSelectionEditorLayoutBinderTest.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMultiWindowTest.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMultiWindowTest.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabUiTestHelper.java",
"//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TestRecyclerViewSimpleViewBinder.java", "//chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TestRecyclerViewSimpleViewBinder.java",
] ]
......
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