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<>();
......
...@@ -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