Commit 4c77bb64 authored by Mei Liang's avatar Mei Liang Committed by Commit Bot

Remove PopupWindow usage in TabSelectionEditor

Using PopupWindow as a container has shown some disadvantages, and it
is listed in https://docs.google.com/document/d/1z49-ehX2VzoY_KcMUOSDi3FU7NzqLlrQocD_M-bPZ1A/edit?usp=sharing.

In addition, crrev.com/c/2399314 has also shown the difficulties of
supporting accessibility with the focusable PopupWindow.

This CL removes the PopupWindow usage in TabSelectionEditor by allowing
TabSelectionEditorLayout attaches itself to the parent view when
TabSelectionEditorController#show is called, and removes itself from
the parent view when TabSelectionEditorController#hide is called.

Bug: 1133014, 1124919
Change-Id: Ic53efddd9de1c22d02753c3f40df2769a5603495
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2438769Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Commit-Queue: Mei Liang <meiliang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#812559}
parent 2fa0636a
...@@ -9,4 +9,6 @@ ...@@ -9,4 +9,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/default_bg_color" android:background="@color/default_bg_color"
android:focusable="true"
android:focusableInTouchMode="true"
android:contentDescription="@string/accessibility_tab_selection_editor"/> android:contentDescription="@string/accessibility_tab_selection_editor"/>
\ No newline at end of file
...@@ -107,7 +107,8 @@ public class TabGridDialogCoordinator implements TabGridDialogMediator.DialogCon ...@@ -107,7 +107,8 @@ public class TabGridDialogCoordinator implements TabGridDialogMediator.DialogCon
int mode = SysUtils.isLowEndDevice() ? TabListCoordinator.TabListMode.LIST int mode = SysUtils.isLowEndDevice() ? TabListCoordinator.TabListMode.LIST
: TabListCoordinator.TabListMode.GRID; : TabListCoordinator.TabListMode.GRID;
mTabSelectionEditorCoordinator = new TabSelectionEditorCoordinator(context, mTabSelectionEditorCoordinator = new TabSelectionEditorCoordinator(context,
mContainerView, tabModelSelector, tabContentManager, mDialogView, mode); mDialogView.findViewById(R.id.dialog_container_view), tabModelSelector,
tabContentManager, mode);
controller = mTabSelectionEditorCoordinator.getController(); controller = mTabSelectionEditorCoordinator.getController();
} else { } else {
......
...@@ -27,7 +27,6 @@ import android.widget.RelativeLayout; ...@@ -27,7 +27,6 @@ import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat; import androidx.core.graphics.drawable.DrawableCompat;
...@@ -51,8 +50,7 @@ import java.util.Map; ...@@ -51,8 +50,7 @@ import java.util.Map;
/** /**
* Parent for TabGridDialog component. * Parent for TabGridDialog component.
*/ */
public class TabGridDialogView extends FrameLayout public class TabGridDialogView extends FrameLayout {
implements TabSelectionEditorMediator.TabSelectionEditorPositionProvider {
private static final int DIALOG_ANIMATION_DURATION = 300; private static final int DIALOG_ANIMATION_DURATION = 300;
private static final int DIALOG_ALPHA_ANIMATION_DURATION = 150; private static final int DIALOG_ALPHA_ANIMATION_DURATION = 150;
private static final int CARD_FADE_ANIMATION_DURATION = 50; private static final int CARD_FADE_ANIMATION_DURATION = 50;
...@@ -713,20 +711,6 @@ public class TabGridDialogView extends FrameLayout ...@@ -713,20 +711,6 @@ public class TabGridDialogView extends FrameLayout
mHideDialogAnimation.start(); mHideDialogAnimation.start();
} }
/**
* {@link TabSelectionEditorMediator.TabSelectionEditorPositionProvider} implementation.
* Returns a {@link Rect} that indicates the current position of dialog.
*/
@Override
@NonNull
public Rect getSelectionEditorPositionRect() {
// Get the status bar height as offset.
Rect parentRect = new Rect();
mParent.getGlobalVisibleRect(parentRect);
return new Rect(mSideMargin, mTopMargin + parentRect.top, mParentWidth - mSideMargin,
mParentHeight - mTopMargin + parentRect.top);
}
/** /**
* Update the ungroup bar based on {@code status}. * Update the ungroup bar based on {@code status}.
* *
......
...@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.tasks.tab_management; ...@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.tasks.tab_management;
import static org.chromium.chrome.browser.tasks.tab_management.TabListModel.CardProperties.CARD_TYPE; import static org.chromium.chrome.browser.tasks.tab_management.TabListModel.CardProperties.CARD_TYPE;
import static org.chromium.chrome.browser.tasks.tab_management.TabListModel.CardProperties.ModelType.OTHERS; import static org.chromium.chrome.browser.tasks.tab_management.TabListModel.CardProperties.ModelType.OTHERS;
import static org.chromium.chrome.browser.tasks.tab_management.TabSelectionEditorProperties.IS_VISIBLE;
import android.content.Context; import android.content.Context;
import android.view.LayoutInflater; import android.view.LayoutInflater;
...@@ -20,6 +21,7 @@ import org.chromium.base.metrics.RecordUserAction; ...@@ -20,6 +21,7 @@ import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode;
import org.chromium.chrome.tab_ui.R; import org.chromium.chrome.tab_ui.R;
import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate; import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate;
import org.chromium.ui.modelutil.LayoutViewBuilder; import org.chromium.ui.modelutil.LayoutViewBuilder;
...@@ -109,25 +111,29 @@ class TabSelectionEditorCoordinator { ...@@ -109,25 +111,29 @@ class TabSelectionEditorCoordinator {
private final TabSelectionEditorLayout mTabSelectionEditorLayout; private final TabSelectionEditorLayout mTabSelectionEditorLayout;
private final TabListCoordinator mTabListCoordinator; private final TabListCoordinator mTabListCoordinator;
private final SelectionDelegate<Integer> mSelectionDelegate = new SelectionDelegate<>(); private final SelectionDelegate<Integer> mSelectionDelegate = new SelectionDelegate<>();
private final PropertyModel mModel = new PropertyModel(TabSelectionEditorProperties.ALL_KEYS); private final PropertyModel mModel;
private final PropertyModelChangeProcessor mTabSelectionEditorLayoutChangeProcessor; private final PropertyModelChangeProcessor mTabSelectionEditorLayoutChangeProcessor;
private final TabSelectionEditorMediator mTabSelectionEditorMediator; private final TabSelectionEditorMediator mTabSelectionEditorMediator;
public TabSelectionEditorCoordinator(Context context, ViewGroup parentView, public TabSelectionEditorCoordinator(Context context, ViewGroup parentView,
TabModelSelector tabModelSelector, TabContentManager tabContentManager, TabModelSelector tabModelSelector, TabContentManager tabContentManager,
@Nullable TabSelectionEditorMediator @TabListMode int mode) {
.TabSelectionEditorPositionProvider positionProvider,
@TabListCoordinator.TabListMode int mode) {
mContext = context; mContext = context;
mParentView = parentView; mParentView = parentView;
mTabModelSelector = tabModelSelector; mTabModelSelector = tabModelSelector;
assert mode == TabListCoordinator.TabListMode.GRID assert mode == TabListCoordinator.TabListMode.GRID
|| mode == TabListCoordinator.TabListMode.LIST; || mode == TabListCoordinator.TabListMode.LIST;
mTabSelectionEditorLayout =
LayoutInflater.from(context)
.inflate(R.layout.tab_selection_editor_layout, parentView, false)
.findViewById(R.id.selectable_list);
mTabListCoordinator = new TabListCoordinator(mode, context, mTabModelSelector, mTabListCoordinator = new TabListCoordinator(mode, context, mTabModelSelector,
tabContentManager::getTabThumbnailWithCallback, null, false, null, null, tabContentManager::getTabThumbnailWithCallback, null, false, null, null,
TabProperties.UiType.SELECTABLE, this::getSelectionDelegate, mParentView, false, TabProperties.UiType.SELECTABLE, this::getSelectionDelegate,
COMPONENT_NAME); mTabSelectionEditorLayout, false, COMPONENT_NAME);
// Note: The TabSelectionEditorCoordinator is always created after native is initialized. // Note: The TabSelectionEditorCoordinator is always created after native is initialized.
assert LibraryLoader.getInstance().isInitialized(); assert LibraryLoader.getInstance().isInitialized();
mTabListCoordinator.initWithNative(null); mTabListCoordinator.initWithNative(null);
...@@ -154,18 +160,19 @@ class TabSelectionEditorCoordinator { ...@@ -154,18 +160,19 @@ class TabSelectionEditorCoordinator {
}); });
} }
mTabSelectionEditorLayout = LayoutInflater.from(context)
.inflate(R.layout.tab_selection_editor_layout, null)
.findViewById(R.id.selectable_list);
mTabSelectionEditorLayout.initialize(mParentView, mTabListCoordinator.getContainerView(), mTabSelectionEditorLayout.initialize(mParentView, mTabListCoordinator.getContainerView(),
mTabListCoordinator.getContainerView().getAdapter(), mSelectionDelegate); mTabListCoordinator.getContainerView().getAdapter(), mSelectionDelegate);
mSelectionDelegate.setSelectionModeEnabledForZeroItems(true); mSelectionDelegate.setSelectionModeEnabledForZeroItems(true);
mModel = new PropertyModel.Builder(TabSelectionEditorProperties.ALL_KEYS)
.with(IS_VISIBLE, false)
.build();
mTabSelectionEditorLayoutChangeProcessor = PropertyModelChangeProcessor.create( mTabSelectionEditorLayoutChangeProcessor = PropertyModelChangeProcessor.create(
mModel, mTabSelectionEditorLayout, TabSelectionEditorLayoutBinder::bind); mModel, mTabSelectionEditorLayout, TabSelectionEditorLayoutBinder::bind, false);
mTabSelectionEditorMediator = new TabSelectionEditorMediator(mContext, mTabModelSelector, mTabSelectionEditorMediator = new TabSelectionEditorMediator(
this::resetWithListOfTabs, mModel, mSelectionDelegate, positionProvider); mContext, mTabModelSelector, this::resetWithListOfTabs, mModel, mSelectionDelegate);
} }
/** /**
......
...@@ -5,65 +5,48 @@ ...@@ -5,65 +5,48 @@
package org.chromium.chrome.browser.tasks.tab_management; package org.chromium.chrome.browser.tasks.tab_management;
import android.content.Context; import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import android.widget.PopupWindow; import android.widget.PopupWindow;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import org.chromium.chrome.tab_ui.R; import org.chromium.chrome.tab_ui.R;
import org.chromium.components.browser_ui.widget.selectable_list.SelectableListLayout; import org.chromium.components.browser_ui.widget.selectable_list.SelectableListLayout;
import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate; import org.chromium.components.browser_ui.widget.selectable_list.SelectionDelegate;
import java.util.HashMap;
import java.util.Map;
/** /**
* This class is used to show the {@link SelectableListLayout} in a {@link PopupWindow}. * This class is used to show the {@link SelectableListLayout} in a {@link PopupWindow}.
*/ */
class TabSelectionEditorLayout extends SelectableListLayout<Integer> { class TabSelectionEditorLayout extends SelectableListLayout<Integer> {
private final PopupWindow mWindow;
private TabSelectionEditorToolbar mToolbar; private TabSelectionEditorToolbar mToolbar;
private View mParentView; private ViewGroup mParentView;
private ViewTreeObserver.OnGlobalLayoutListener mParentLayoutListener;
private @Nullable Rect mPositionRect;
private boolean mIsInitialized; private boolean mIsInitialized;
private Runnable mEditorHideController; private boolean mIsShowing;
private Map<View, Integer> mAccessibilityImportanceMap = new HashMap<>();
// TODO(meiliang): inflates R.layout.tab_selection_editor_layout in // TODO(meiliang): inflates R.layout.tab_selection_editor_layout in
// TabSelectionEditorCoordinator. // TabSelectionEditorCoordinator.
public TabSelectionEditorLayout(Context context, AttributeSet attrs) { public TabSelectionEditorLayout(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
mWindow = new PopupWindow(
this, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
if (TabUiFeatureUtilities.isLaunchPolishEnabled()) {
// TODO(crbug.com/1124919): Remove PopupWindow usage, the focusable PopupWindow messes
// up the TalkBack. Focusable PopupWindow always focuses the first item in the content
// view and announces the first item twice under Talkback mode.
mWindow.setFocusable(true);
mWindow.setOnDismissListener(() -> {
if (mEditorHideController != null) mEditorHideController.run();
});
}
} }
/** /**
* Initializes the RecyclerView and the toolbar for the layout. Also initializes the selection * Initializes the RecyclerView and the toolbar for the layout. Also initializes the selection
* editor layout provider if there is one.This must be called before calling show/hide. * editor layout provider if there is one.This must be called before calling show/hide.
* *
* @param parentView The parent view for the {@link PopupWindow}. * @param parentView The parent view to attach the {@link TabSelectionEditorLayout}.
* @param recyclerView The recycler view to be shown. * @param recyclerView The recycler view to be shown.
* @param adapter The adapter that provides views that represent items in the recycler view. * @param adapter The adapter that provides views that represent items in the recycler view.
* @param selectionDelegate The {@link SelectionDelegate} that will inform the toolbar of * @param selectionDelegate The {@link SelectionDelegate} that will inform the toolbar of
* selection changes. * selection changes.
*/ */
void initialize(View parentView, RecyclerView recyclerView, RecyclerView.Adapter adapter, void initialize(ViewGroup parentView, RecyclerView recyclerView, RecyclerView.Adapter adapter,
SelectionDelegate<Integer> selectionDelegate) { SelectionDelegate<Integer> selectionDelegate) {
mIsInitialized = true; mIsInitialized = true;
initializeRecyclerView(adapter, recyclerView); initializeRecyclerView(adapter, recyclerView);
...@@ -74,35 +57,23 @@ class TabSelectionEditorLayout extends SelectableListLayout<Integer> { ...@@ -74,35 +57,23 @@ class TabSelectionEditorLayout extends SelectableListLayout<Integer> {
} }
/** /**
* Shows the layout in a {@link PopupWindow}. * Add and shows the layout in the parent view.
*/ */
public void show() { public void show() {
assert mIsInitialized; assert mIsInitialized;
if (mPositionRect == null) { mIsShowing = true;
mWindow.showAtLocation(mParentView, Gravity.CENTER, 0, 0); clearBackgroundViewAccessibilityImportance();
if (TabUiFeatureUtilities.isLaunchPolishEnabled()) { mParentView.addView(this);
// TODO(crbug.com/1124919): The following line forces Talkback to announce the
// content description of this view. Remove after PopupWindow usage is removed.
sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT);
}
return;
}
mWindow.setWidth(mPositionRect.width());
mWindow.setHeight(mPositionRect.height());
mWindow.showAtLocation(
mParentView, Gravity.NO_GRAVITY, mPositionRect.left, mPositionRect.top);
if (TabUiFeatureUtilities.isLaunchPolishEnabled()) {
// TODO(crbug.com/1124919): Remove after PopupWindow usage is removed.
sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT);
}
} }
/** /**
* Hides the {@link PopupWindow}. * Remove and hides the layout from parent view.
*/ */
public void hide() { public void hide() {
assert mIsInitialized; assert mIsInitialized && mIsShowing;
if (mWindow.isShowing()) mWindow.dismiss(); mIsShowing = false;
mParentView.removeView(this);
restoreBackgroundViewAccessibilityImportance();
} }
/** /**
...@@ -112,51 +83,40 @@ class TabSelectionEditorLayout extends SelectableListLayout<Integer> { ...@@ -112,51 +83,40 @@ class TabSelectionEditorLayout extends SelectableListLayout<Integer> {
return mToolbar; return mToolbar;
} }
/**
* Register a {@link ViewTreeObserver.OnGlobalLayoutListener} handling TabSelectionEditor
* related changes when parent view global layout changed.
*/
public void registerGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener listener) {
if (mParentView == null || listener == null) return;
if (mParentLayoutListener != null) {
mParentView.getViewTreeObserver().removeOnGlobalLayoutListener(mParentLayoutListener);
}
mParentLayoutListener = listener;
mParentView.getViewTreeObserver().addOnGlobalLayoutListener(listener);
}
/**
* Update the {@link Rect} used to show the selection editor. If the editor is currently
* showing, update its positioning.
* @param rect The {@link Rect} to update mPositionRect.
*/
public void updateTabSelectionEditorPositionRect(@NonNull Rect rect) {
assert rect != null;
mPositionRect = rect;
if (mWindow.isShowing()) {
mWindow.update(rect.left, rect.top, rect.width(), rect.height());
}
}
/** /**
* Destroy any members that needs clean up. * Destroy any members that needs clean up.
*/ */
public void destroy() { public void destroy() {
super.onDestroyed(); super.onDestroyed();
}
private void clearBackgroundViewAccessibilityImportance() {
assert mAccessibilityImportanceMap.size() == 0 && mParentView.indexOfChild(this) == -1;
if (mParentView != null && mParentLayoutListener != null) { for (int i = 0; i < mParentView.getChildCount(); i++) {
mParentView.getViewTreeObserver().removeOnGlobalLayoutListener(mParentLayoutListener); View view = mParentView.getChildAt(i);
mAccessibilityImportanceMap.put(view, view.getImportantForAccessibility());
view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
} }
mAccessibilityImportanceMap.put(mParentView, mParentView.getImportantForAccessibility());
mParentView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
} }
@VisibleForTesting private void restoreBackgroundViewAccessibilityImportance() {
Rect getPositionRectForTesting() { assert mParentView.indexOfChild(this) == -1;
return mPositionRect;
}
void setEditorHideController(Runnable hideController) { for (int i = 0; i < mParentView.getChildCount(); i++) {
if (!TabUiFeatureUtilities.isLaunchPolishEnabled()) return; View view = mParentView.getChildAt(i);
mEditorHideController = hideController; assert mAccessibilityImportanceMap.containsKey(view);
Integer importance = mAccessibilityImportanceMap.get(view);
view.setImportantForAccessibility(
importance == null ? IMPORTANT_FOR_ACCESSIBILITY_AUTO : importance);
}
assert mAccessibilityImportanceMap.containsKey(mParentView);
Integer importance = mAccessibilityImportanceMap.get(mParentView);
mParentView.setImportantForAccessibility(
importance == null ? IMPORTANT_FOR_ACCESSIBILITY_AUTO : importance);
mAccessibilityImportanceMap.clear();
} }
} }
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
package org.chromium.chrome.browser.tasks.tab_management; package org.chromium.chrome.browser.tasks.tab_management;
import android.graphics.Rect;
import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
...@@ -51,24 +49,10 @@ public class TabSelectionEditorLayoutBinder { ...@@ -51,24 +49,10 @@ public class TabSelectionEditorLayoutBinder {
== propertyKey) { == propertyKey) {
view.getToolbar().setActionButtonEnablingThreshold(model.get( view.getToolbar().setActionButtonEnablingThreshold(model.get(
TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_ENABLING_THRESHOLD)); TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_ENABLING_THRESHOLD));
} else if (TabSelectionEditorProperties.SELECTION_EDITOR_POSITION_RECT == propertyKey) {
Rect positionRect =
model.get(TabSelectionEditorProperties.SELECTION_EDITOR_POSITION_RECT);
if (positionRect == null) {
return;
}
view.updateTabSelectionEditorPositionRect(positionRect);
} else if (TabSelectionEditorProperties.SELECTION_EDITOR_GLOBAL_LAYOUT_LISTENER
== propertyKey) {
view.registerGlobalLayoutListener(model.get(
TabSelectionEditorProperties.SELECTION_EDITOR_GLOBAL_LAYOUT_LISTENER));
} else if (TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_DESCRIPTION_RESOURCE_ID } else if (TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_DESCRIPTION_RESOURCE_ID
== propertyKey) { == propertyKey) {
view.getToolbar().setActionButtonDescriptionResourceId(model.get( view.getToolbar().setActionButtonDescriptionResourceId(model.get(
TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_DESCRIPTION_RESOURCE_ID)); TabSelectionEditorProperties.TOOLBAR_ACTION_BUTTON_DESCRIPTION_RESOURCE_ID));
} else if (TabUiFeatureUtilities.isLaunchPolishEnabled()
&& TabSelectionEditorProperties.DISMISS_HANDLER == propertyKey) {
view.setEditorHideController(model.get(TabSelectionEditorProperties.DISMISS_HANDLER));
} }
} }
} }
...@@ -6,11 +6,9 @@ package org.chromium.chrome.browser.tasks.tab_management; ...@@ -6,11 +6,9 @@ package org.chromium.chrome.browser.tasks.tab_management;
import android.content.Context; import android.content.Context;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.view.View; import android.view.View;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.content.res.AppCompatResources;
...@@ -53,19 +51,6 @@ class TabSelectionEditorMediator ...@@ -53,19 +51,6 @@ class TabSelectionEditorMediator
void resetWithListOfTabs(@Nullable List<Tab> tabs, int preSelectedCount); void resetWithListOfTabs(@Nullable List<Tab> tabs, int preSelectedCount);
} }
/**
* An interface to provide the {@link Rect} used to position the selection editor on screen.
*/
public interface TabSelectionEditorPositionProvider {
/**
* This method fetches the {@link Rect} used to position the selection editor layout.
* @return The {@link Rect} indicates where to show the selection editor layout. This Rect
* should never be null.
*/
@NonNull
Rect getSelectionEditorPositionRect();
}
private final Context mContext; private final Context mContext;
private final TabModelSelector mTabModelSelector; private final TabModelSelector mTabModelSelector;
private final ResetHandler mResetHandler; private final ResetHandler mResetHandler;
...@@ -73,7 +58,6 @@ class TabSelectionEditorMediator ...@@ -73,7 +58,6 @@ class TabSelectionEditorMediator
private final SelectionDelegate<Integer> mSelectionDelegate; private final SelectionDelegate<Integer> mSelectionDelegate;
private final TabModelSelectorTabModelObserver mTabModelObserver; private final TabModelSelectorTabModelObserver mTabModelObserver;
private final TabModelSelectorObserver mTabModelSelectorObserver; private final TabModelSelectorObserver mTabModelSelectorObserver;
private final TabSelectionEditorPositionProvider mPositionProvider;
private TabSelectionEditorActionProvider mActionProvider; private TabSelectionEditorActionProvider mActionProvider;
private TabSelectionEditorCoordinator.TabSelectionEditorNavigationProvider mNavigationProvider; private TabSelectionEditorCoordinator.TabSelectionEditorNavigationProvider mNavigationProvider;
...@@ -101,15 +85,12 @@ class TabSelectionEditorMediator ...@@ -101,15 +85,12 @@ class TabSelectionEditorMediator
TabSelectionEditorMediator(Context context, TabModelSelector tabModelSelector, TabSelectionEditorMediator(Context context, TabModelSelector tabModelSelector,
ResetHandler resetHandler, PropertyModel model, ResetHandler resetHandler, PropertyModel model,
SelectionDelegate<Integer> selectionDelegate, SelectionDelegate<Integer> selectionDelegate) {
@Nullable TabSelectionEditorMediator
.TabSelectionEditorPositionProvider positionProvider) {
mContext = context; mContext = context;
mTabModelSelector = tabModelSelector; mTabModelSelector = tabModelSelector;
mResetHandler = resetHandler; mResetHandler = resetHandler;
mModel = model; mModel = model;
mSelectionDelegate = selectionDelegate; mSelectionDelegate = selectionDelegate;
mPositionProvider = positionProvider;
mModel.set( mModel.set(
TabSelectionEditorProperties.TOOLBAR_NAVIGATION_LISTENER, mNavigationClickListener); TabSelectionEditorProperties.TOOLBAR_NAVIGATION_LISTENER, mNavigationClickListener);
...@@ -119,6 +100,7 @@ class TabSelectionEditorMediator ...@@ -119,6 +100,7 @@ class TabSelectionEditorMediator
mTabModelObserver = new TabModelSelectorTabModelObserver(mTabModelSelector) { mTabModelObserver = new TabModelSelectorTabModelObserver(mTabModelSelector) {
@Override @Override
public void didAddTab(Tab tab, int type, @TabCreationState int creationState) { public void didAddTab(Tab tab, int type, @TabCreationState int creationState) {
if (!mTabModelSelector.isTabStateInitialized()) return;
// When tab is added due to multi-window close or moving between multiple windows, // When tab is added due to multi-window close or moving between multiple windows,
// force hiding the selection editor. // force hiding the selection editor.
if (type == TabLaunchType.FROM_RESTORE || type == TabLaunchType.FROM_REPARENTING) { if (type == TabLaunchType.FROM_RESTORE || type == TabLaunchType.FROM_REPARENTING) {
...@@ -170,18 +152,6 @@ class TabSelectionEditorMediator ...@@ -170,18 +152,6 @@ class TabSelectionEditorMediator
mNavigationProvider = mNavigationProvider =
new TabSelectionEditorCoordinator.TabSelectionEditorNavigationProvider(this); new TabSelectionEditorCoordinator.TabSelectionEditorNavigationProvider(this);
if (mPositionProvider != null) {
mModel.set(TabSelectionEditorProperties.SELECTION_EDITOR_GLOBAL_LAYOUT_LISTENER,
()
-> mModel.set(
TabSelectionEditorProperties.SELECTION_EDITOR_POSITION_RECT,
mPositionProvider.getSelectionEditorPositionRect()));
}
if (TabUiFeatureUtilities.isLaunchPolishEnabled()) {
mModel.set(TabSelectionEditorProperties.DISMISS_HANDLER, this::hide);
}
} }
private boolean isEditorVisible() { private boolean isEditorVisible() {
...@@ -214,10 +184,6 @@ class TabSelectionEditorMediator ...@@ -214,10 +184,6 @@ class TabSelectionEditorMediator
mResetHandler.resetWithListOfTabs(tabs, preSelectedTabCount); mResetHandler.resetWithListOfTabs(tabs, preSelectedTabCount);
if (mPositionProvider != null) {
mModel.set(TabSelectionEditorProperties.SELECTION_EDITOR_POSITION_RECT,
mPositionProvider.getSelectionEditorPositionRect());
}
mModel.set(TabSelectionEditorProperties.IS_VISIBLE, true); mModel.set(TabSelectionEditorProperties.IS_VISIBLE, true);
} }
......
...@@ -5,10 +5,7 @@ ...@@ -5,10 +5,7 @@
package org.chromium.chrome.browser.tasks.tab_management; package org.chromium.chrome.browser.tasks.tab_management;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.view.View; import android.view.View;
import android.view.ViewTreeObserver;
import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
...@@ -47,25 +44,13 @@ public class TabSelectionEditorProperties { ...@@ -47,25 +44,13 @@ public class TabSelectionEditorProperties {
public static final PropertyModel.WritableIntPropertyKey TOOLBAR_TEXT_APPEARANCE = public static final PropertyModel.WritableIntPropertyKey TOOLBAR_TEXT_APPEARANCE =
new PropertyModel.WritableIntPropertyKey(); new PropertyModel.WritableIntPropertyKey();
public static final PropertyModel
.WritableObjectPropertyKey<Rect> SELECTION_EDITOR_POSITION_RECT =
new PropertyModel.WritableObjectPropertyKey<>();
public static final PropertyModel.WritableObjectPropertyKey<
ViewTreeObserver.OnGlobalLayoutListener> SELECTION_EDITOR_GLOBAL_LAYOUT_LISTENER =
new PropertyModel.WritableObjectPropertyKey<>();
public static final PropertyModel public static final PropertyModel
.WritableIntPropertyKey TOOLBAR_ACTION_BUTTON_DESCRIPTION_RESOURCE_ID = .WritableIntPropertyKey TOOLBAR_ACTION_BUTTON_DESCRIPTION_RESOURCE_ID =
new PropertyModel.WritableIntPropertyKey(); new PropertyModel.WritableIntPropertyKey();
public static final PropertyModel.WritableObjectPropertyKey<Runnable> DISMISS_HANDLER =
new PropertyModel.WritableObjectPropertyKey();
public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {IS_VISIBLE, public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {IS_VISIBLE,
TOOLBAR_ACTION_BUTTON_LISTENER, TOOLBAR_ACTION_BUTTON_TEXT, TOOLBAR_ACTION_BUTTON_LISTENER, TOOLBAR_ACTION_BUTTON_TEXT,
TOOLBAR_ACTION_BUTTON_ENABLING_THRESHOLD, TOOLBAR_NAVIGATION_LISTENER, PRIMARY_COLOR, TOOLBAR_ACTION_BUTTON_ENABLING_THRESHOLD, TOOLBAR_NAVIGATION_LISTENER, PRIMARY_COLOR,
TOOLBAR_BACKGROUND_COLOR, TOOLBAR_GROUP_BUTTON_TINT, TOOLBAR_TEXT_APPEARANCE, TOOLBAR_BACKGROUND_COLOR, TOOLBAR_GROUP_BUTTON_TINT, TOOLBAR_TEXT_APPEARANCE,
SELECTION_EDITOR_POSITION_RECT, SELECTION_EDITOR_GLOBAL_LAYOUT_LISTENER, TOOLBAR_ACTION_BUTTON_DESCRIPTION_RESOURCE_ID};
TOOLBAR_ACTION_BUTTON_DESCRIPTION_RESOURCE_ID, DISMISS_HANDLER};
} }
...@@ -109,6 +109,7 @@ public class TabSwitcherCoordinator ...@@ -109,6 +109,7 @@ public class TabSwitcherCoordinator
private ViewGroup mContainer; private ViewGroup mContainer;
private TabCreatorManager mTabCreatorManager; private TabCreatorManager mTabCreatorManager;
private boolean mIsInitialized; private boolean mIsInitialized;
private final ViewGroup mRootView;
private final MenuOrKeyboardActionController private final MenuOrKeyboardActionController
.MenuOrKeyboardActionHandler mTabSwitcherMenuActionHandler = .MenuOrKeyboardActionHandler mTabSwitcherMenuActionHandler =
...@@ -147,6 +148,7 @@ public class TabSwitcherCoordinator ...@@ -147,6 +148,7 @@ public class TabSwitcherCoordinator
mMode = mode; mMode = mode;
mTabModelSelector = tabModelSelector; mTabModelSelector = tabModelSelector;
mContainer = container; mContainer = container;
mRootView = ((ChromeTabbedActivity) context).findViewById(R.id.coordinator);
mTabCreatorManager = tabCreatorManager; mTabCreatorManager = tabCreatorManager;
mMultiWindowModeStateDispatcher = multiWindowModeStateDispatcher; mMultiWindowModeStateDispatcher = multiWindowModeStateDispatcher;
...@@ -213,9 +215,8 @@ public class TabSwitcherCoordinator ...@@ -213,9 +215,8 @@ public class TabSwitcherCoordinator
if (TabUiFeatureUtilities.isTabGroupsAndroidEnabled()) { if (TabUiFeatureUtilities.isTabGroupsAndroidEnabled()) {
mTabGridDialogCoordinator = new TabGridDialogCoordinator(context, tabModelSelector, mTabGridDialogCoordinator = new TabGridDialogCoordinator(context, tabModelSelector,
tabContentManager, tabCreatorManager, tabContentManager, tabCreatorManager, mRootView, this, mMediator,
((ChromeTabbedActivity) context).findViewById(R.id.coordinator), this, this::getTabGridDialogAnimationSourceView, shareDelegateSupplier,
mMediator, this::getTabGridDialogAnimationSourceView, shareDelegateSupplier,
scrimCoordinator); scrimCoordinator);
mMediator.setTabGridDialogController(mTabGridDialogCoordinator.getDialogController()); mMediator.setTabGridDialogController(mTabGridDialogCoordinator.getDialogController());
} else { } else {
...@@ -314,8 +315,8 @@ public class TabSwitcherCoordinator ...@@ -314,8 +315,8 @@ public class TabSwitcherCoordinator
int selectionEditorMode = mMode == TabListCoordinator.TabListMode.CAROUSEL int selectionEditorMode = mMode == TabListCoordinator.TabListMode.CAROUSEL
? TabListCoordinator.TabListMode.GRID ? TabListCoordinator.TabListMode.GRID
: mMode; : mMode;
mTabSelectionEditorCoordinator = new TabSelectionEditorCoordinator(context, mContainer, mTabSelectionEditorCoordinator = new TabSelectionEditorCoordinator(
mTabModelSelector, tabContentManager, null, selectionEditorMode); context, mRootView, mTabModelSelector, tabContentManager, selectionEditorMode);
mMediator.initWithNative(mTabSelectionEditorCoordinator.getController()); mMediator.initWithNative(mTabSelectionEditorCoordinator.getController());
mTabGroupManualSelectionMode = new TabGroupManualSelectionMode( mTabGroupManualSelectionMode = new TabGroupManualSelectionMode(
......
...@@ -27,7 +27,6 @@ import static androidx.test.espresso.matcher.ViewMatchers.withParent; ...@@ -27,7 +27,6 @@ import static androidx.test.espresso.matcher.ViewMatchers.withParent;
import static androidx.test.espresso.matcher.ViewMatchers.withText; import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
...@@ -108,6 +107,7 @@ import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate; ...@@ -108,6 +107,7 @@ import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.ChromeRenderTestRule; import org.chromium.chrome.test.util.ChromeRenderTestRule;
import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils; import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.KeyboardVisibilityDelegate; import org.chromium.ui.KeyboardVisibilityDelegate;
...@@ -415,8 +415,13 @@ public class TabGridDialogTest { ...@@ -415,8 +415,13 @@ public class TabGridDialogTest {
@Test @Test
@MediumTest @MediumTest
@Features.EnableFeatures(ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID) // clang-format off
@EnableFeatures({ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID,
ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID + "<Study"})
@CommandLineFlags.Add({"force-fieldtrials=Study/Group",
"force-fieldtrial-params=Study.Group:enable_launch_polish/true"})
public void testSelectionEditorShowHide() throws ExecutionException { public void testSelectionEditorShowHide() throws ExecutionException {
// clang-format on
final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
createTabs(cta, false, 2); createTabs(cta, false, 2);
enterTabSwitcher(cta); enterTabSwitcher(cta);
...@@ -532,8 +537,13 @@ public class TabGridDialogTest { ...@@ -532,8 +537,13 @@ public class TabGridDialogTest {
@Test @Test
@MediumTest @MediumTest
@Features.EnableFeatures(ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID) // clang-format off
@EnableFeatures({ChromeFeatureList.TAB_GROUPS_CONTINUATION_ANDROID,
ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID + "<Study"})
@CommandLineFlags.Add({"force-fieldtrials=Study/Group",
"force-fieldtrial-params=Study.Group:enable_launch_polish/true"})
public void testSelectionEditorPosition() { public void testSelectionEditorPosition() {
// clang-format on
final ChromeTabbedActivity cta = mActivityTestRule.getActivity(); final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
View parentView = cta.getCompositorViewHolder(); View parentView = cta.getCompositorViewHolder();
createTabs(cta, false, 3); createTabs(cta, false, 3);
...@@ -546,22 +556,22 @@ public class TabGridDialogTest { ...@@ -546,22 +556,22 @@ public class TabGridDialogTest {
// Verify the size and position of TabGridDialog in portrait mode. // Verify the size and position of TabGridDialog in portrait mode.
openDialogFromTabSwitcherAndVerify(cta, 3, null); openDialogFromTabSwitcherAndVerify(cta, 3, null);
checkPopupPosition(cta, true, true); checkPosition(cta, true, true);
// Verify the size and position of TabSelectionEditor in portrait mode. // Verify the size and position of TabSelectionEditor in portrait mode.
openSelectionEditorAndVerify(cta, 3); openSelectionEditorAndVerify(cta, 3);
checkPopupPosition(cta, false, true); checkPosition(cta, false, true);
// Verify the size and position of TabSelectionEditor in landscape mode. // Verify the size and position of TabSelectionEditor in landscape mode.
rotateDeviceToOrientation(cta, Configuration.ORIENTATION_LANDSCAPE); rotateDeviceToOrientation(cta, Configuration.ORIENTATION_LANDSCAPE);
CriteriaHelper.pollUiThread(() -> parentView.getHeight() < parentView.getWidth()); CriteriaHelper.pollUiThread(() -> parentView.getHeight() < parentView.getWidth());
checkPopupPosition(cta, false, false); checkPosition(cta, false, false);
// Verify the size and position of TabGridDialog in landscape mode. // Verify the size and position of TabGridDialog in landscape mode.
mSelectionEditorRobot.actionRobot.clickToolbarNavigationButton(); mSelectionEditorRobot.actionRobot.clickToolbarNavigationButton();
mSelectionEditorRobot.resultRobot.verifyTabSelectionEditorIsHidden(); mSelectionEditorRobot.resultRobot.verifyTabSelectionEditorIsHidden();
assertTrue(isDialogShowing(cta)); assertTrue(isDialogShowing(cta));
checkPopupPosition(cta, true, false); checkPosition(cta, true, false);
// Verify the positioning in multi-window mode. Adjusting the height of the root view to // Verify the positioning in multi-window mode. Adjusting the height of the root view to
// mock entering/exiting multi-window mode. // mock entering/exiting multi-window mode.
...@@ -574,17 +584,17 @@ public class TabGridDialogTest { ...@@ -574,17 +584,17 @@ public class TabGridDialogTest {
params.height = rootViewHeight / 2; params.height = rootViewHeight / 2;
rootView.setLayoutParams(params); rootView.setLayoutParams(params);
}); });
checkPopupPosition(cta, true, true); checkPosition(cta, true, true);
openSelectionEditorAndVerify(cta, 3); openSelectionEditorAndVerify(cta, 3);
checkPopupPosition(cta, false, true); checkPosition(cta, false, true);
TestThreadUtils.runOnUiThreadBlocking(() -> { TestThreadUtils.runOnUiThreadBlocking(() -> {
ViewGroup.LayoutParams params = rootView.getLayoutParams(); ViewGroup.LayoutParams params = rootView.getLayoutParams();
params.height = rootViewHeight; params.height = rootViewHeight;
rootView.setLayoutParams(params); rootView.setLayoutParams(params);
}); });
checkPopupPosition(cta, false, true); checkPosition(cta, false, true);
checkPopupPosition(cta, true, true); checkPosition(cta, true, true);
} }
@Test @Test
...@@ -1154,8 +1164,7 @@ public class TabGridDialogTest { ...@@ -1154,8 +1164,7 @@ public class TabGridDialogTest {
.verifyAdapterHasItemCount(count); .verifyAdapterHasItemCount(count);
} }
private void checkPopupPosition( private void checkPosition(ChromeTabbedActivity cta, boolean isDialog, boolean isPortrait) {
ChromeTabbedActivity cta, boolean isDialog, boolean isPortrait) {
// If isDialog is true, we are checking the position of TabGridDialog; otherwise we are // If isDialog is true, we are checking the position of TabGridDialog; otherwise we are
// checking the position of TabSelectionEditor. // checking the position of TabSelectionEditor.
int contentViewId = isDialog ? R.id.dialog_container_view : R.id.selectable_list; int contentViewId = isDialog ? R.id.dialog_container_view : R.id.selectable_list;
...@@ -1168,19 +1177,16 @@ public class TabGridDialogTest { ...@@ -1168,19 +1177,16 @@ public class TabGridDialogTest {
Rect parentRect = new Rect(); Rect parentRect = new Rect();
parentView.getGlobalVisibleRect(parentRect); parentView.getGlobalVisibleRect(parentRect);
onView(withId(contentViewId)) onView(isDialog ? withId(contentViewId) : withId(contentViewId)).check((v, e) -> {
.inRoot(isDialog ? withDecorView(is(cta.getWindow().getDecorView())) int[] location = new int[2];
: withDecorView(not(cta.getWindow().getDecorView()))) v.getLocationOnScreen(location);
.check((v, e) -> { // Check the position.
int[] location = new int[2]; assertEquals(sideMargin, location[0]);
v.getLocationOnScreen(location); assertEquals(topMargin + parentRect.top, location[1]);
// Check the position. // Check the size.
assertEquals(sideMargin, location[0]); assertEquals(parentView.getHeight() - 2 * topMargin, v.getHeight());
assertEquals(topMargin + parentRect.top, location[1]); assertEquals(parentView.getWidth() - 2 * sideMargin, v.getWidth());
// Check the size. });
assertEquals(parentView.getHeight() - 2 * topMargin, v.getHeight());
assertEquals(parentView.getWidth() - 2 * sideMargin, v.getWidth());
});
} }
private void editDialogTitle(ChromeTabbedActivity cta, String title) { private void editDialogTitle(ChromeTabbedActivity cta, String title) {
......
...@@ -4,16 +4,13 @@ ...@@ -4,16 +4,13 @@
package org.chromium.chrome.browser.tasks.tab_management; package org.chromium.chrome.browser.tasks.tab_management;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import android.graphics.Rect;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.Button; import android.widget.Button;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
...@@ -132,32 +129,6 @@ public class TabSelectionEditorLayoutBinderTest extends DummyUiActivityTestCase ...@@ -132,32 +129,6 @@ public class TabSelectionEditorLayoutBinderTest extends DummyUiActivityTestCase
assertFalse(button.isEnabled()); assertFalse(button.isEnabled());
} }
@Test
@SmallTest
@UiThreadTest
public void testSetPositionRect() {
assertNull(mEditorLayoutView.getPositionRectForTesting());
Rect rect = new Rect();
mModel.set(TabSelectionEditorProperties.SELECTION_EDITOR_POSITION_RECT, rect);
assertEquals(rect, mModel.get(TabSelectionEditorProperties.SELECTION_EDITOR_POSITION_RECT));
}
@Test
@SmallTest
@UiThreadTest
public void testRegisterGlobalLayoutListener() {
AtomicBoolean globalLayoutChanged = new AtomicBoolean();
globalLayoutChanged.set(false);
ViewTreeObserver.OnGlobalLayoutListener listener = () -> globalLayoutChanged.set(true);
mModel.set(TabSelectionEditorProperties.SELECTION_EDITOR_GLOBAL_LAYOUT_LISTENER, listener);
mParentView.getViewTreeObserver().dispatchOnGlobalLayout();
assertTrue(globalLayoutChanged.get());
}
@Test @Test
@SmallTest @SmallTest
@UiThreadTest @UiThreadTest
......
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
package org.chromium.chrome.browser.tasks.tab_management; package org.chromium.chrome.browser.tasks.tab_management;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
...@@ -42,6 +46,7 @@ import org.chromium.chrome.test.ChromeJUnit4ClassRunner; ...@@ -42,6 +46,7 @@ import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule; import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.ChromeRenderTestRule; import org.chromium.chrome.test.util.ChromeRenderTestRule;
import org.chromium.chrome.test.util.ChromeTabUtils; import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.chrome.test.util.browser.Features.DisableFeatures; import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures; import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.test.util.CriteriaHelper;
...@@ -51,7 +56,9 @@ import org.chromium.ui.test.util.UiRestriction; ...@@ -51,7 +56,9 @@ import org.chromium.ui.test.util.UiRestriction;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* End-to-end test for TabSelectionEditor. * End-to-end test for TabSelectionEditor.
...@@ -78,18 +85,18 @@ public class TabSelectionEditorTest { ...@@ -78,18 +85,18 @@ public class TabSelectionEditorTest {
private TabSelectionEditorCoordinator mTabSelectionEditorCoordinator; private TabSelectionEditorCoordinator mTabSelectionEditorCoordinator;
private WeakReference<TabSelectionEditorLayout> mRef; private WeakReference<TabSelectionEditorLayout> mRef;
private ViewGroup mParentView;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
mActivityTestRule.startMainActivityOnBlankPage(); mActivityTestRule.startMainActivityOnBlankPage();
mTabModelSelector = mActivityTestRule.getActivity().getTabModelSelector(); mTabModelSelector = mActivityTestRule.getActivity().getTabModelSelector();
mParentView = (ViewGroup) mActivityTestRule.getActivity().findViewById(R.id.coordinator);
TestThreadUtils.runOnUiThreadBlocking(() -> { TestThreadUtils.runOnUiThreadBlocking(() -> {
mTabSelectionEditorCoordinator = new TabSelectionEditorCoordinator( mTabSelectionEditorCoordinator = new TabSelectionEditorCoordinator(
mActivityTestRule.getActivity(), mActivityTestRule.getActivity(), mParentView, mTabModelSelector,
(ViewGroup) mActivityTestRule.getActivity().getWindow().getDecorView(), mActivityTestRule.getActivity().getTabContentManager(), getMode());
mTabModelSelector, mActivityTestRule.getActivity().getTabContentManager(), null,
getMode());
mTabSelectionEditorController = mTabSelectionEditorCoordinator.getController(); mTabSelectionEditorController = mTabSelectionEditorCoordinator.getController();
mTabSelectionEditorLayout = mTabSelectionEditorLayout =
...@@ -168,7 +175,12 @@ public class TabSelectionEditorTest { ...@@ -168,7 +175,12 @@ public class TabSelectionEditorTest {
@Test @Test
@MediumTest @MediumTest
// clang-format off
@Features.EnableFeatures({ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID + "<Study"})
@CommandLineFlags.Add({"force-fieldtrials=Study/Group",
"force-fieldtrial-params=Study.Group:enable_launch_polish/true"})
public void testToolbarNavigationButtonHideTabSelectionEditor() { public void testToolbarNavigationButtonHideTabSelectionEditor() {
// clang-format on
prepareBlankTab(2, false); prepareBlankTab(2, false);
List<Tab> tabs = getTabsInCurrentTabModel(); List<Tab> tabs = getTabsInCurrentTabModel();
...@@ -591,6 +603,60 @@ public class TabSelectionEditorTest { ...@@ -591,6 +603,60 @@ public class TabSelectionEditorTest {
mRobot.resultRobot.verifyTabSelectionEditorIsVisible(); mRobot.resultRobot.verifyTabSelectionEditorIsVisible();
} }
@Test
@MediumTest
// clang-format off
@EnableFeatures({ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID + "<Study"})
@CommandLineFlags.Add({"force-fieldtrials=Study/Group",
"force-fieldtrial-params=Study.Group:enable_launch_polish/true"})
public void testBackgroundViewAccessibilityImportance() {
// clang-format on
prepareBlankTab(2, false);
List<Tab> tabs = getTabsInCurrentTabModel();
Map<View, Integer> initialValues = getParentViewAccessibilityImportanceMap();
TestThreadUtils.runOnUiThreadBlocking(() -> { mTabSelectionEditorController.show(tabs); });
mRobot.resultRobot.verifyTabSelectionEditorIsVisible();
ViewGroup parentView = (ViewGroup) mTabSelectionEditorLayout.getParent();
verifyBackgroundViewAccessibilityImportance(parentView, true, initialValues);
mRobot.actionRobot.clickToolbarNavigationButton();
mRobot.resultRobot.verifyTabSelectionEditorIsHidden();
verifyBackgroundViewAccessibilityImportance(parentView, false, initialValues);
}
private Map<View, Integer> getParentViewAccessibilityImportanceMap() {
Map<View, Integer> map = new HashMap<>();
for (int i = 0; i < mParentView.getChildCount(); i++) {
View view = mParentView.getChildAt(i);
map.put(view, view.getImportantForAccessibility());
}
map.put(mParentView, mParentView.getImportantForAccessibility());
return map;
}
private void verifyBackgroundViewAccessibilityImportance(ViewGroup parentView,
boolean isTabSelectionEditorShowing, Map<View, Integer> initialValues) {
assertEquals(isTabSelectionEditorShowing ? IMPORTANT_FOR_ACCESSIBILITY_NO
: initialValues.get(parentView).intValue(),
parentView.getImportantForAccessibility());
for (int i = 0; i < parentView.getChildCount(); i++) {
View view = parentView.getChildAt(i);
int expected = isTabSelectionEditorShowing
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: initialValues.get(view).intValue();
if (view == mTabSelectionEditorLayout) {
expected = IMPORTANT_FOR_ACCESSIBILITY_YES;
}
assertEquals(expected, view.getImportantForAccessibility());
}
}
private List<Tab> getTabsInCurrentTabModel() { private List<Tab> getTabsInCurrentTabModel() {
List<Tab> tabs = new ArrayList<>(); List<Tab> tabs = new ArrayList<>();
......
...@@ -9,19 +9,18 @@ import static androidx.test.espresso.action.ViewActions.click; ...@@ -9,19 +9,18 @@ import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition; import static androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition;
import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition; import static androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition;
import static androidx.test.espresso.matcher.RootMatchers.withDecorView;
import static androidx.test.espresso.matcher.ViewMatchers.isClickable; import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.isEnabled; import static androidx.test.espresso.matcher.ViewMatchers.isEnabled;
import static androidx.test.espresso.matcher.ViewMatchers.isFocusable; import static androidx.test.espresso.matcher.ViewMatchers.isFocusable;
import static androidx.test.espresso.matcher.ViewMatchers.withClassName;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withParent; import static androidx.test.espresso.matcher.ViewMatchers.withParent;
import static androidx.test.espresso.matcher.ViewMatchers.withText; import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.chromium.chrome.browser.tasks.tab_management.RecyclerViewMatcherUtils.atPosition; import static org.chromium.chrome.browser.tasks.tab_management.RecyclerViewMatcherUtils.atPosition;
...@@ -34,7 +33,6 @@ import android.view.View; ...@@ -34,7 +33,6 @@ import android.view.View;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.test.espresso.NoMatchingRootException; import androidx.test.espresso.NoMatchingRootException;
import androidx.test.espresso.NoMatchingViewException; import androidx.test.espresso.NoMatchingViewException;
import androidx.test.espresso.Root;
import androidx.test.espresso.UiController; import androidx.test.espresso.UiController;
import androidx.test.espresso.ViewAction; import androidx.test.espresso.ViewAction;
import androidx.test.espresso.matcher.BoundedMatcher; import androidx.test.espresso.matcher.BoundedMatcher;
...@@ -50,28 +48,12 @@ import org.junit.Assert; ...@@ -50,28 +48,12 @@ import org.junit.Assert;
*/ */
public class TabSelectionEditorTestingRobot { public class TabSelectionEditorTestingRobot {
/** /**
* @return A root matcher that matches the TabSelectionEditor popup decor view. * @param viewMatcher A matcher that matches a view.
* @return A matcher that matches view in the {@link TabSelectionEditorLayout} based on the
* given matcher.
*/ */
public static Matcher<Root> isTabSelectionEditorPopup() { public static Matcher<View> inTabSelectionEditor(Matcher<View> viewMatcher) {
return new TypeSafeMatcher<Root>() { return allOf(isDescendantOfA(instanceOf(TabSelectionEditorLayout.class)), viewMatcher);
@Override
public void describeTo(Description description) {
description.appendText("is TabSelectionEditor Popup");
}
@Override
public boolean matchesSafely(Root root) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
return withDecorView(
withClassName(is(TabSelectionEditorLayout.class.getName())))
.matches(root);
} else {
return withDecorView(
withClassName(is("android.widget.PopupWindow$PopupDecorView")))
.matches(root);
}
}
};
} }
/** /**
...@@ -146,31 +128,30 @@ public class TabSelectionEditorTestingRobot { ...@@ -146,31 +128,30 @@ public class TabSelectionEditorTestingRobot {
*/ */
public static class Action { public static class Action {
public TabSelectionEditorTestingRobot.Action clickItemAtAdapterPosition(int position) { public TabSelectionEditorTestingRobot.Action clickItemAtAdapterPosition(int position) {
onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)) onView(inTabSelectionEditor(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))
.inRoot(isTabSelectionEditorPopup())
.perform(actionOnItemAtPosition(position, click())); .perform(actionOnItemAtPosition(position, click()));
return this; return this;
} }
public TabSelectionEditorTestingRobot.Action clickToolbarActionButton() { public TabSelectionEditorTestingRobot.Action clickToolbarActionButton() {
onView(allOf(withId(org.chromium.chrome.tab_ui.R.id.action_button), onView(inTabSelectionEditor(allOf(withId(org.chromium.chrome.tab_ui.R.id.action_button),
withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))) withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))))
.inRoot(isTabSelectionEditorPopup())
.perform(click()); .perform(click());
return this; return this;
} }
public TabSelectionEditorTestingRobot.Action clickToolbarNavigationButton() { public TabSelectionEditorTestingRobot.Action clickToolbarNavigationButton() {
onView(allOf(withContentDescription(org.chromium.chrome.tab_ui.R.string.close), onView(inTabSelectionEditor(
withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))) allOf(withContentDescription(
.inRoot(isTabSelectionEditorPopup()) org.chromium.chrome.tab_ui.R.string
.accessibility_tab_selection_editor_back_button),
withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))))
.perform(click()); .perform(click());
return this; return this;
} }
public TabSelectionEditorTestingRobot.Action clickEndButtonAtAdapterPosition(int position) { public TabSelectionEditorTestingRobot.Action clickEndButtonAtAdapterPosition(int position) {
onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)) onView(inTabSelectionEditor(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))
.inRoot(isTabSelectionEditorPopup())
.perform(new ViewAction() { .perform(new ViewAction() {
@Override @Override
public Matcher<View> getConstraints() { public Matcher<View> getConstraints() {
...@@ -203,16 +184,16 @@ public class TabSelectionEditorTestingRobot { ...@@ -203,16 +184,16 @@ public class TabSelectionEditorTestingRobot {
*/ */
public static class Result { public static class Result {
public TabSelectionEditorTestingRobot.Result verifyTabSelectionEditorIsVisible() { public TabSelectionEditorTestingRobot.Result verifyTabSelectionEditorIsVisible() {
onView(withId(org.chromium.chrome.tab_ui.R.id.selectable_list)) onView(allOf(instanceOf(TabSelectionEditorLayout.class),
.inRoot(isTabSelectionEditorPopup()) withId(org.chromium.chrome.tab_ui.R.id.selectable_list)))
.check(matches(isDisplayed())); .check(matches(isDisplayed()));
return this; return this;
} }
public TabSelectionEditorTestingRobot.Result verifyTabSelectionEditorIsHidden() { public TabSelectionEditorTestingRobot.Result verifyTabSelectionEditorIsHidden() {
try { try {
onView(withId(org.chromium.chrome.tab_ui.R.id.selectable_list)) onView(allOf(instanceOf(TabSelectionEditorLayout.class),
.inRoot(isTabSelectionEditorPopup()) withId(org.chromium.chrome.tab_ui.R.id.selectable_list)))
.check(matches(isDisplayed())); .check(matches(isDisplayed()));
} catch (NoMatchingRootException | NoMatchingViewException e) { } catch (NoMatchingRootException | NoMatchingViewException e) {
return this; return this;
...@@ -224,56 +205,47 @@ public class TabSelectionEditorTestingRobot { ...@@ -224,56 +205,47 @@ public class TabSelectionEditorTestingRobot {
public TabSelectionEditorTestingRobot.Result verifyToolbarSelectionTextWithResourceId( public TabSelectionEditorTestingRobot.Result verifyToolbarSelectionTextWithResourceId(
int resourceId) { int resourceId) {
onView(withText(resourceId)) onView(inTabSelectionEditor(withText(resourceId))).check(matches(isDisplayed()));
.inRoot(isTabSelectionEditorPopup())
.check(matches(isDisplayed()));
return this; return this;
} }
public TabSelectionEditorTestingRobot.Result verifyToolbarSelectionText(String text) { public TabSelectionEditorTestingRobot.Result verifyToolbarSelectionText(String text) {
onView(withText(text)) onView(inTabSelectionEditor(withText(text))).check(matches(isDisplayed()));
.inRoot(isTabSelectionEditorPopup())
.check(matches(isDisplayed()));
return this; return this;
} }
public TabSelectionEditorTestingRobot.Result verifyToolbarActionButtonWithResourceId( public TabSelectionEditorTestingRobot.Result verifyToolbarActionButtonWithResourceId(
int resourceId) { int resourceId) {
onView(allOf(withId(org.chromium.chrome.tab_ui.R.id.action_button), onView(inTabSelectionEditor(allOf(withId(org.chromium.chrome.tab_ui.R.id.action_button),
withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))) withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))))
.inRoot(isTabSelectionEditorPopup())
.check(matches(withText(resourceId))); .check(matches(withText(resourceId)));
return this; return this;
} }
public TabSelectionEditorTestingRobot.Result verifyToolbarActionButtonWithText( public TabSelectionEditorTestingRobot.Result verifyToolbarActionButtonWithText(
String text) { String text) {
onView(allOf(withId(org.chromium.chrome.tab_ui.R.id.action_button), onView(inTabSelectionEditor(allOf(withId(org.chromium.chrome.tab_ui.R.id.action_button),
withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))) withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))))
.inRoot(isTabSelectionEditorPopup())
.check(matches(withText(text))); .check(matches(withText(text)));
return this; return this;
} }
public TabSelectionEditorTestingRobot.Result verifyToolbarActionButtonDisabled() { public TabSelectionEditorTestingRobot.Result verifyToolbarActionButtonDisabled() {
onView(allOf(withId(org.chromium.chrome.tab_ui.R.id.action_button), onView(inTabSelectionEditor(allOf(withId(org.chromium.chrome.tab_ui.R.id.action_button),
withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))) withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))))
.inRoot(isTabSelectionEditorPopup())
.check(matches(not(isEnabled()))); .check(matches(not(isEnabled())));
return this; return this;
} }
public TabSelectionEditorTestingRobot.Result verifyToolbarActionButtonEnabled() { public TabSelectionEditorTestingRobot.Result verifyToolbarActionButtonEnabled() {
onView(allOf(withId(org.chromium.chrome.tab_ui.R.id.action_button), onView(inTabSelectionEditor(allOf(withId(org.chromium.chrome.tab_ui.R.id.action_button),
withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))) withParent(withId(org.chromium.chrome.tab_ui.R.id.action_bar)))))
.inRoot(isTabSelectionEditorPopup())
.check(matches(isEnabled())); .check(matches(isEnabled()));
return this; return this;
} }
public TabSelectionEditorTestingRobot.Result verifyHasAtLeastNItemVisible(int count) { public TabSelectionEditorTestingRobot.Result verifyHasAtLeastNItemVisible(int count) {
onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)) onView(inTabSelectionEditor(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))
.inRoot(isTabSelectionEditorPopup())
.check((v, noMatchException) -> { .check((v, noMatchException) -> {
if (noMatchException != null) throw noMatchException; if (noMatchException != null) throw noMatchException;
...@@ -284,16 +256,14 @@ public class TabSelectionEditorTestingRobot { ...@@ -284,16 +256,14 @@ public class TabSelectionEditorTestingRobot {
} }
public TabSelectionEditorTestingRobot.Result verifyAdapterHasItemCount(int count) { public TabSelectionEditorTestingRobot.Result verifyAdapterHasItemCount(int count) {
onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)) onView(inTabSelectionEditor(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))
.inRoot(isTabSelectionEditorPopup())
.check(matches(RecyclerViewMatcherUtils.adapterHasItemCount(count))); .check(matches(RecyclerViewMatcherUtils.adapterHasItemCount(count)));
return this; return this;
} }
public TabSelectionEditorTestingRobot.Result verifyItemNotSelectedAtAdapterPosition( public TabSelectionEditorTestingRobot.Result verifyItemNotSelectedAtAdapterPosition(
int position) { int position) {
onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)) onView(inTabSelectionEditor(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))
.inRoot(isTabSelectionEditorPopup())
.check(matches( .check(matches(
not(RecyclerViewMatcherUtils.atPosition(position, itemIsSelected())))); not(RecyclerViewMatcherUtils.atPosition(position, itemIsSelected()))));
return this; return this;
...@@ -301,8 +271,7 @@ public class TabSelectionEditorTestingRobot { ...@@ -301,8 +271,7 @@ public class TabSelectionEditorTestingRobot {
public TabSelectionEditorTestingRobot.Result verifyItemSelectedAtAdapterPosition( public TabSelectionEditorTestingRobot.Result verifyItemSelectedAtAdapterPosition(
int position) { int position) {
onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)) onView(inTabSelectionEditor(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))
.inRoot(isTabSelectionEditorPopup())
.check(matches( .check(matches(
RecyclerViewMatcherUtils.atPosition(position, itemIsSelected()))); RecyclerViewMatcherUtils.atPosition(position, itemIsSelected())));
return this; return this;
...@@ -315,9 +284,8 @@ public class TabSelectionEditorTestingRobot { ...@@ -315,9 +284,8 @@ public class TabSelectionEditorTestingRobot {
} }
public Result verifyDividerAlwaysStartsAtTheEdgeOfScreen() { public Result verifyDividerAlwaysStartsAtTheEdgeOfScreen() {
onView(allOf(isDivider(), onView(inTabSelectionEditor(allOf(isDivider(),
withParent(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))) withParent(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))))
.inRoot(isTabSelectionEditorPopup())
.check(matches(isDisplayed())) .check(matches(isDisplayed()))
.check((v, noMatchException) -> { .check((v, noMatchException) -> {
if (noMatchException != null) throw noMatchException; if (noMatchException != null) throw noMatchException;
...@@ -329,12 +297,10 @@ public class TabSelectionEditorTestingRobot { ...@@ -329,12 +297,10 @@ public class TabSelectionEditorTestingRobot {
} }
public Result verifyDividerAlwaysStartsAtTheEdgeOfScreenAtPosition(int position) { public Result verifyDividerAlwaysStartsAtTheEdgeOfScreenAtPosition(int position) {
onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)) onView(inTabSelectionEditor(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))
.inRoot(isTabSelectionEditorPopup())
.perform(scrollToPosition(position)); .perform(scrollToPosition(position));
onView(atPosition(position, isDivider())) onView(inTabSelectionEditor(atPosition(position, isDivider())))
.inRoot(isTabSelectionEditorPopup())
.check(matches(isDisplayed())) .check(matches(isDisplayed()))
.check((v, noMatchException) -> { .check((v, noMatchException) -> {
if (noMatchException != null) throw noMatchException; if (noMatchException != null) throw noMatchException;
...@@ -347,9 +313,8 @@ public class TabSelectionEditorTestingRobot { ...@@ -347,9 +313,8 @@ public class TabSelectionEditorTestingRobot {
} }
public Result verifyDividerNotClickableNotFocusable() { public Result verifyDividerNotClickableNotFocusable() {
onView(allOf(isDivider(), onView(inTabSelectionEditor(allOf(isDivider(),
withParent(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))) withParent(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))))
.inRoot(isTabSelectionEditorPopup())
.check(matches(not(isClickable()))) .check(matches(not(isClickable())))
.check(matches(not(isFocusable()))); .check(matches(not(isFocusable())));
return this; return this;
...@@ -367,11 +332,10 @@ public class TabSelectionEditorTestingRobot { ...@@ -367,11 +332,10 @@ public class TabSelectionEditorTestingRobot {
* @return {@link Result} to do chain verification. * @return {@link Result} to do chain verification.
*/ */
public Result verifyHasItemViewTypeAtAdapterPosition(int position, int targetItemViewType) { public Result verifyHasItemViewTypeAtAdapterPosition(int position, int targetItemViewType) {
onView(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)) onView(inTabSelectionEditor(withId(org.chromium.chrome.tab_ui.R.id.tab_list_view)))
.inRoot(isTabSelectionEditorPopup())
.perform(scrollToPosition(position)); .perform(scrollToPosition(position));
onView(atPositionWithViewHolder(position, withItemType(targetItemViewType))) onView(inTabSelectionEditor(
.inRoot(isTabSelectionEditorPopup()) atPositionWithViewHolder(position, withItemType(targetItemViewType))))
.check(matches(isDisplayed())); .check(matches(isDisplayed()));
return this; return this;
} }
......
...@@ -46,7 +46,7 @@ import org.chromium.ui.test.util.UiRestriction; ...@@ -46,7 +46,7 @@ import org.chromium.ui.test.util.UiRestriction;
@RunWith(ChromeJUnit4ClassRunner.class) @RunWith(ChromeJUnit4ClassRunner.class)
// clang-format off // clang-format off
@Restriction(UiRestriction.RESTRICTION_TYPE_PHONE) @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
@Features.EnableFeatures({ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, @Features.EnableFeatures({ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID+"<Study",
ChromeFeatureList.TAB_GROUPS_ANDROID, ChromeFeatureList.TAB_GROUPS_ANDROID,
ChromeFeatureList.CLOSE_TAB_SUGGESTIONS+"<Study"}) ChromeFeatureList.CLOSE_TAB_SUGGESTIONS+"<Study"})
// Disable TAB_TO_GTS_ANIMATION to make it less flaky. When animation is enabled, the suggestion // Disable TAB_TO_GTS_ANIMATION to make it less flaky. When animation is enabled, the suggestion
...@@ -57,7 +57,7 @@ import org.chromium.ui.test.util.UiRestriction; ...@@ -57,7 +57,7 @@ import org.chromium.ui.test.util.UiRestriction;
public class TabSuggestionMessageCardTest { public class TabSuggestionMessageCardTest {
// clang-format on // clang-format on
private static final String BASE_PARAMS = "force-fieldtrial-params=" private static final String BASE_PARAMS = "force-fieldtrial-params="
+ "Study.Group:baseline_tab_suggestions/true"; + "Study.Group:baseline_tab_suggestions/true/enable_launch_polish/true";
@Rule @Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
......
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