Commit e4e9e9b5 authored by Yue Zhang's avatar Yue Zhang Committed by Commit Bot

Fix TabGridDialog animation in StartSurface

Instead of getting location of the animation source card relative to
recyclerView, this CL gets its global position to make the animation
more robust to different layouts.

Bug: 995423
Change-Id: I349e219356cabc1e5704ba1a1cc62b92791a7ce3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1896297Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Commit-Queue: Yue Zhang <yuezhanggg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#715500}
parent 6eb23e48
...@@ -138,6 +138,11 @@ public class StartSurfaceCoordinator implements StartSurface { ...@@ -138,6 +138,11 @@ public class StartSurfaceCoordinator implements StartSurface {
return mTabSwitcher.getTabListDelegate(); return mTabSwitcher.getTabListDelegate();
} }
@Override
public TabSwitcher.TabDialogDelegation getTabDialogDelegate() {
return mTabSwitcher.getTabGridDialogDelegation();
}
private @SurfaceMode int computeSurfaceMode() { private @SurfaceMode int computeSurfaceMode() {
// Check the cached flag before getting the parameter to be consistent with the other // Check the cached flag before getting the parameter to be consistent with the other
// places. Note that the cached flag may have been set before native initialization. // places. Note that the cached flag may have been set before native initialization.
......
...@@ -388,7 +388,7 @@ public class StartSurfaceLayout extends Layout implements StartSurface.OverviewM ...@@ -388,7 +388,7 @@ public class StartSurfaceLayout extends Layout implements StartSurface.OverviewM
} }
@VisibleForTesting @VisibleForTesting
StartSurface getStartSurfaceForTesting() { public StartSurface getStartSurfaceForTesting() {
return mStartSurface; return mStartSurface;
} }
......
...@@ -111,4 +111,9 @@ public interface StartSurface { ...@@ -111,4 +111,9 @@ public interface StartSurface {
* @return TabListDelegate implementation that can be used to access the Tab List. * @return TabListDelegate implementation that can be used to access the Tab List.
*/ */
TabSwitcher.TabListDelegate getTabListDelegate(); TabSwitcher.TabListDelegate getTabListDelegate();
/**
* @return TabDialogDelegation implementation that can be used to access the Tab Dialog.
*/
TabSwitcher.TabDialogDelegation getTabDialogDelegate();
} }
\ No newline at end of file
...@@ -39,10 +39,10 @@ public class TabGridDialogCoordinator implements TabGridDialogMediator.DialogCon ...@@ -39,10 +39,10 @@ public class TabGridDialogCoordinator implements TabGridDialogMediator.DialogCon
TabContentManager tabContentManager, TabCreatorManager tabCreatorManager, TabContentManager tabContentManager, TabCreatorManager tabCreatorManager,
ViewGroup containerView, TabSwitcherMediator.ResetHandler resetHandler, ViewGroup containerView, TabSwitcherMediator.ResetHandler resetHandler,
TabListMediator.GridCardOnClickListenerProvider gridCardOnClickListenerProvider, TabListMediator.GridCardOnClickListenerProvider gridCardOnClickListenerProvider,
TabGridDialogMediator.AnimationParamsProvider animationParamsProvider, TabGridDialogMediator.AnimationSourceViewProvider animationSourceViewProvider,
TabGroupTitleEditor tabGroupTitleEditor) { TabGroupTitleEditor tabGroupTitleEditor) {
mComponentName = animationParamsProvider == null ? "TabGridDialogFromStrip" mComponentName = animationSourceViewProvider == null ? "TabGridDialogFromStrip"
: "TabGridDialogInSwitcher"; : "TabGridDialogInSwitcher";
mToolbarPropertyModel = new PropertyModel(TabGridPanelProperties.ALL_KEYS); mToolbarPropertyModel = new PropertyModel(TabGridPanelProperties.ALL_KEYS);
...@@ -59,7 +59,7 @@ public class TabGridDialogCoordinator implements TabGridDialogMediator.DialogCon ...@@ -59,7 +59,7 @@ public class TabGridDialogCoordinator implements TabGridDialogMediator.DialogCon
} }
mMediator = new TabGridDialogMediator(context, this, mToolbarPropertyModel, mMediator = new TabGridDialogMediator(context, this, mToolbarPropertyModel,
tabModelSelector, tabCreatorManager, resetHandler, animationParamsProvider, tabModelSelector, tabCreatorManager, resetHandler, animationSourceViewProvider,
controller, tabGroupTitleEditor, mComponentName); controller, tabGroupTitleEditor, mComponentName);
mTabListCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context, mTabListCoordinator = new TabListCoordinator(TabListCoordinator.TabListMode.GRID, context,
......
...@@ -71,17 +71,17 @@ public class TabGridDialogMediator { ...@@ -71,17 +71,17 @@ public class TabGridDialogMediator {
} }
/** /**
* Defines an interface for a {@link TabGridDialogMediator} to get the {@link * Defines an interface for a {@link TabGridDialogMediator} to get the source {@link View}
* TabGridDialogParent.AnimationParams} in order to prepare show/hide animation. * in order to prepare show/hide animation.
*/ */
interface AnimationParamsProvider { interface AnimationSourceViewProvider {
/** /**
* Provide a {@link TabGridDialogParent.AnimationParams} to setup the animation. * Provide {@link View} of the source item to setup the animation.
* *
* @param tabId The id of the tab whose position is requested. * @param tabId The id of the tab whose position is requested.
* @return A {@link TabGridDialogParent.AnimationParams} used to setup the animation. * @return The source {@link View} used to setup the animation.
*/ */
TabGridDialogParent.AnimationParams getAnimationParamsForTab(int tabId); View getAnimationSourceViewForTab(int tabId);
} }
private final Context mContext; private final Context mContext;
...@@ -92,7 +92,7 @@ public class TabGridDialogMediator { ...@@ -92,7 +92,7 @@ public class TabGridDialogMediator {
private final TabCreatorManager mTabCreatorManager; private final TabCreatorManager mTabCreatorManager;
private final DialogController mDialogController; private final DialogController mDialogController;
private final TabSwitcherMediator.ResetHandler mTabSwitcherResetHandler; private final TabSwitcherMediator.ResetHandler mTabSwitcherResetHandler;
private final AnimationParamsProvider mAnimationParamsProvider; private final AnimationSourceViewProvider mAnimationSourceViewProvider;
private final TabGroupTitleEditor mTabGroupTitleEditor; private final TabGroupTitleEditor mTabGroupTitleEditor;
private final DialogHandler mTabGridDialogHandler; private final DialogHandler mTabGridDialogHandler;
private final TabSelectionEditorCoordinator private final TabSelectionEditorCoordinator
...@@ -107,7 +107,7 @@ public class TabGridDialogMediator { ...@@ -107,7 +107,7 @@ public class TabGridDialogMediator {
TabGridDialogMediator(Context context, DialogController dialogController, PropertyModel model, TabGridDialogMediator(Context context, DialogController dialogController, PropertyModel model,
TabModelSelector tabModelSelector, TabCreatorManager tabCreatorManager, TabModelSelector tabModelSelector, TabCreatorManager tabCreatorManager,
TabSwitcherMediator.ResetHandler tabSwitcherResetHandler, TabSwitcherMediator.ResetHandler tabSwitcherResetHandler,
AnimationParamsProvider animationParamsProvider, AnimationSourceViewProvider animationSourceViewProvider,
@Nullable TabSelectionEditorCoordinator @Nullable TabSelectionEditorCoordinator
.TabSelectionEditorController tabSelectionEditorController, .TabSelectionEditorController tabSelectionEditorController,
TabGroupTitleEditor tabGroupTitleEditor, String componentName) { TabGroupTitleEditor tabGroupTitleEditor, String componentName) {
...@@ -117,7 +117,7 @@ public class TabGridDialogMediator { ...@@ -117,7 +117,7 @@ public class TabGridDialogMediator {
mTabCreatorManager = tabCreatorManager; mTabCreatorManager = tabCreatorManager;
mDialogController = dialogController; mDialogController = dialogController;
mTabSwitcherResetHandler = tabSwitcherResetHandler; mTabSwitcherResetHandler = tabSwitcherResetHandler;
mAnimationParamsProvider = animationParamsProvider; mAnimationSourceViewProvider = animationSourceViewProvider;
mTabGroupTitleEditor = tabGroupTitleEditor; mTabGroupTitleEditor = tabGroupTitleEditor;
mTabGridDialogHandler = new DialogHandler(); mTabGridDialogHandler = new DialogHandler();
mTabSelectionEditorController = tabSelectionEditorController; mTabSelectionEditorController = tabSelectionEditorController;
...@@ -225,11 +225,11 @@ public class TabGridDialogMediator { ...@@ -225,11 +225,11 @@ public class TabGridDialogMediator {
void hideDialog(boolean showAnimation) { void hideDialog(boolean showAnimation) {
if (!showAnimation) { if (!showAnimation) {
mModel.set(TabGridPanelProperties.ANIMATION_PARAMS, null); mModel.set(TabGridPanelProperties.ANIMATION_SOURCE_VIEW, null);
} else { } else {
if (mAnimationParamsProvider != null && mCurrentTabId != Tab.INVALID_TAB_ID) { if (mAnimationSourceViewProvider != null && mCurrentTabId != Tab.INVALID_TAB_ID) {
mModel.set(TabGridPanelProperties.ANIMATION_PARAMS, mModel.set(TabGridPanelProperties.ANIMATION_SOURCE_VIEW,
mAnimationParamsProvider.getAnimationParamsForTab(mCurrentTabId)); mAnimationSourceViewProvider.getAnimationSourceViewForTab(mCurrentTabId));
} }
} }
if (mTabSelectionEditorController != null) { if (mTabSelectionEditorController != null) {
...@@ -249,10 +249,9 @@ public class TabGridDialogMediator { ...@@ -249,10 +249,9 @@ public class TabGridDialogMediator {
} }
if (mCurrentTabId != Tab.INVALID_TAB_ID) { if (mCurrentTabId != Tab.INVALID_TAB_ID) {
if (mAnimationParamsProvider != null) { if (mAnimationSourceViewProvider != null) {
TabGridDialogParent.AnimationParams params = mModel.set(TabGridPanelProperties.ANIMATION_SOURCE_VIEW,
mAnimationParamsProvider.getAnimationParamsForTab(mCurrentTabId); mAnimationSourceViewProvider.getAnimationSourceViewForTab(mCurrentTabId));
mModel.set(TabGridPanelProperties.ANIMATION_PARAMS, params);
} }
updateDialog(); updateDialog();
updateDialogScrollPosition(); updateDialogScrollPosition();
......
...@@ -12,6 +12,7 @@ import android.content.ComponentCallbacks; ...@@ -12,6 +12,7 @@ import android.content.ComponentCallbacks;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
...@@ -35,6 +36,7 @@ import androidx.annotation.NonNull; ...@@ -35,6 +36,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.Callback;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.ui.widget.animation.Interpolators; import org.chromium.chrome.browser.ui.widget.animation.Interpolators;
import org.chromium.chrome.browser.widget.ScrimView; import org.chromium.chrome.browser.widget.ScrimView;
...@@ -52,6 +54,7 @@ public class TabGridDialogParent ...@@ -52,6 +54,7 @@ public class TabGridDialogParent
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;
private static Callback<RectF> sSourceRectCallbackForTesting;
@IntDef({UngroupBarStatus.SHOW, UngroupBarStatus.HIDE, UngroupBarStatus.HOVERED}) @IntDef({UngroupBarStatus.SHOW, UngroupBarStatus.HIDE, UngroupBarStatus.HOVERED})
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface UngroupBarStatus { public @interface UngroupBarStatus {
...@@ -274,11 +277,11 @@ public class TabGridDialogParent ...@@ -274,11 +277,11 @@ public class TabGridDialogParent
}); });
} }
void setupDialogAnimation(AnimationParams animationParams) { void setupDialogAnimation(View sourceView) {
// In case where user jumps to a new page from dialog, clean existing animations in // In case where user jumps to a new page from dialog, clean existing animations in
// mHideDialogAnimation and play basic fade out instead of zooming back to corresponding tab // mHideDialogAnimation and play basic fade out instead of zooming back to corresponding tab
// grid card. // grid card.
if (animationParams == null) { if (sourceView == null) {
mShowDialogAnimation = new AnimatorSet(); mShowDialogAnimation = new AnimatorSet();
mShowDialogAnimation.play(mBasicFadeInAnimation); mShowDialogAnimation.play(mBasicFadeInAnimation);
mShowDialogAnimation.removeAllListeners(); mShowDialogAnimation.removeAllListeners();
...@@ -291,8 +294,13 @@ public class TabGridDialogParent ...@@ -291,8 +294,13 @@ public class TabGridDialogParent
return; return;
} }
Rect rect = animationParams.sourceRect; mItemView = sourceView;
mItemView = animationParams.sourceView; Rect rect = new Rect();
mItemView.getGlobalVisibleRect(rect);
// Offset by CompositeViewHolder top offset.
Rect parentRect = new Rect();
mParent.getGlobalVisibleRect(parentRect);
rect.offset(0, -parentRect.top);
// Setup a dummy animation card that looks the same as the original tab grid card for // Setup a dummy animation card that looks the same as the original tab grid card for
// animation. // animation.
updateAnimationCardView(mItemView); updateAnimationCardView(mItemView);
...@@ -304,9 +312,13 @@ public class TabGridDialogParent ...@@ -304,9 +312,13 @@ public class TabGridDialogParent
// Calculate position and size info about the original tab grid card. // Calculate position and size info about the original tab grid card.
float sourceLeft = rect.left + mTabGridCardPadding; float sourceLeft = rect.left + mTabGridCardPadding;
float sourceTop = rect.top + mToolbarHeight + mTabGridCardPadding; float sourceTop = rect.top + mTabGridCardPadding;
float sourceHeight = rect.height() - 2 * mTabGridCardPadding; float sourceHeight = rect.height() - 2 * mTabGridCardPadding;
float sourceWidth = rect.width() - 2 * mTabGridCardPadding; float sourceWidth = rect.width() - 2 * mTabGridCardPadding;
if (sSourceRectCallbackForTesting != null) {
sSourceRectCallbackForTesting.onResult(new RectF(
sourceLeft, sourceTop, sourceLeft + sourceWidth, sourceTop + sourceHeight));
}
// Setup animation position info and scale ratio of the background frame. // Setup animation position info and scale ratio of the background frame.
float frameInitYPosition = -(dialogHeight / 2 + mTopMargin - sourceHeight / 2 - sourceTop); float frameInitYPosition = -(dialogHeight / 2 + mTopMargin - sourceHeight / 2 - sourceTop);
...@@ -820,4 +832,9 @@ public class TabGridDialogParent ...@@ -820,4 +832,9 @@ public class TabGridDialogParent
int getUngroupBarTextAppearanceForTesting() { int getUngroupBarTextAppearanceForTesting() {
return mUngroupBarTextAppearance; return mUngroupBarTextAppearance;
} }
@VisibleForTesting
static void setSourceRectCallbackForTesting(Callback<RectF> callback) {
sSourceRectCallbackForTesting = callback;
}
} }
\ No newline at end of file
...@@ -36,9 +36,8 @@ class TabGridPanelProperties { ...@@ -36,9 +36,8 @@ class TabGridPanelProperties {
public static final PropertyModel public static final PropertyModel
.WritableObjectPropertyKey<ScrimView.ScrimObserver> SCRIMVIEW_OBSERVER = .WritableObjectPropertyKey<ScrimView.ScrimObserver> SCRIMVIEW_OBSERVER =
new PropertyModel.WritableObjectPropertyKey<>(); new PropertyModel.WritableObjectPropertyKey<>();
public static final PropertyModel public static final PropertyModel.WritableObjectPropertyKey<View> ANIMATION_SOURCE_VIEW =
.WritableObjectPropertyKey<TabGridDialogParent.AnimationParams> ANIMATION_PARAMS = new PropertyModel.WritableObjectPropertyKey<>(true);
new PropertyModel.WritableObjectPropertyKey<>();
public static final PropertyModel.WritableIntPropertyKey UNGROUP_BAR_STATUS = public static final PropertyModel.WritableIntPropertyKey UNGROUP_BAR_STATUS =
new PropertyModel.WritableIntPropertyKey(); new PropertyModel.WritableIntPropertyKey();
public static final PropertyModel.WritableIntPropertyKey DIALOG_BACKGROUND_RESOUCE_ID = public static final PropertyModel.WritableIntPropertyKey DIALOG_BACKGROUND_RESOUCE_ID =
...@@ -78,7 +77,7 @@ class TabGridPanelProperties { ...@@ -78,7 +77,7 @@ class TabGridPanelProperties {
new PropertyModel.WritableObjectPropertyKey<View.OnTouchListener>(); new PropertyModel.WritableObjectPropertyKey<View.OnTouchListener>();
public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {COLLAPSE_CLICK_LISTENER, public static final PropertyKey[] ALL_KEYS = new PropertyKey[] {COLLAPSE_CLICK_LISTENER,
ADD_CLICK_LISTENER, HEADER_TITLE, CONTENT_TOP_MARGIN, PRIMARY_COLOR, TINT, ADD_CLICK_LISTENER, HEADER_TITLE, CONTENT_TOP_MARGIN, PRIMARY_COLOR, TINT,
IS_DIALOG_VISIBLE, SCRIMVIEW_OBSERVER, ANIMATION_PARAMS, UNGROUP_BAR_STATUS, IS_DIALOG_VISIBLE, SCRIMVIEW_OBSERVER, ANIMATION_SOURCE_VIEW, UNGROUP_BAR_STATUS,
DIALOG_BACKGROUND_RESOUCE_ID, DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID, DIALOG_BACKGROUND_RESOUCE_ID, DIALOG_UNGROUP_BAR_BACKGROUND_COLOR_ID,
DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID, DIALOG_UNGROUP_BAR_TEXT_APPEARANCE, DIALOG_UNGROUP_BAR_HOVERED_BACKGROUND_COLOR_ID, DIALOG_UNGROUP_BAR_TEXT_APPEARANCE,
INITIAL_SCROLL_INDEX, IS_MAIN_CONTENT_VISIBLE, MENU_CLICK_LISTENER, TITLE_TEXT_WATCHER, INITIAL_SCROLL_INDEX, IS_MAIN_CONTENT_VISIBLE, MENU_CLICK_LISTENER, TITLE_TEXT_WATCHER,
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
package org.chromium.chrome.browser.tasks.tab_management; package org.chromium.chrome.browser.tasks.tab_management;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.ADD_CLICK_LISTENER; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.ADD_CLICK_LISTENER;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.ANIMATION_PARAMS; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.ANIMATION_SOURCE_VIEW;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.COLLAPSE_CLICK_LISTENER; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.COLLAPSE_CLICK_LISTENER;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.CONTENT_TOP_MARGIN; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.CONTENT_TOP_MARGIN;
import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.DIALOG_BACKGROUND_RESOUCE_ID; import static org.chromium.chrome.browser.tasks.tab_management.TabGridPanelProperties.DIALOG_BACKGROUND_RESOUCE_ID;
...@@ -90,8 +90,8 @@ class TabGridPanelViewBinder { ...@@ -90,8 +90,8 @@ class TabGridPanelViewBinder {
} else { } else {
viewHolder.dialogView.hideDialog(); viewHolder.dialogView.hideDialog();
} }
} else if (ANIMATION_PARAMS == propertyKey) { } else if (ANIMATION_SOURCE_VIEW == propertyKey) {
viewHolder.dialogView.setupDialogAnimation(model.get(ANIMATION_PARAMS)); viewHolder.dialogView.setupDialogAnimation(model.get(ANIMATION_SOURCE_VIEW));
} else if (UNGROUP_BAR_STATUS == propertyKey) { } else if (UNGROUP_BAR_STATUS == propertyKey) {
viewHolder.dialogView.updateUngroupBar(model.get(UNGROUP_BAR_STATUS)); viewHolder.dialogView.updateUngroupBar(model.get(UNGROUP_BAR_STATUS));
} else if (DIALOG_BACKGROUND_RESOUCE_ID == propertyKey) { } else if (DIALOG_BACKGROUND_RESOUCE_ID == propertyKey) {
......
...@@ -448,18 +448,6 @@ class TabListRecyclerView extends RecyclerView { ...@@ -448,18 +448,6 @@ class TabListRecyclerView extends RecyclerView {
return getRectOfComponent(root.fastFindViewById(R.id.tab_thumbnail)); return getRectOfComponent(root.fastFindViewById(R.id.tab_thumbnail));
} }
/**
* @param currentTabIndex The the current tab's index in the model.
* @return The {@link Rect} of the tab grid card of the current tab, relative to the
* {@link TabListRecyclerView} coordinates.
*/
@Nullable
Rect getRectOfCurrentTabGridCard(int currentTabIndex) {
ViewHolder holder = findViewHolderForAdapterPosition(currentTabIndex);
if (holder == null) return null;
return getRectOfComponent(holder.itemView);
}
private Rect getRectOfComponent(View v) { private Rect getRectOfComponent(View v) {
Rect recyclerViewRect = new Rect(); Rect recyclerViewRect = new Rect();
Rect componentRect = new Rect(); Rect componentRect = new Rect();
......
...@@ -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 android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
...@@ -174,8 +175,26 @@ public interface TabSwitcher { ...@@ -174,8 +175,26 @@ public interface TabSwitcher {
int getCleanupDelayForTesting(); int getCleanupDelayForTesting();
} }
/**
* Interface to access the Tab Dialog.
*/
interface TabDialogDelegation {
/**
* Set a hook to receive {@link RectF} with position information about source tab card used
* to setup Tab Dialog animation.
* @param callback The callback to send rect through.
*/
@VisibleForTesting
void setSourceRectCallbackForTesting(Callback<RectF> callback);
}
/** /**
* @return The {@link TabListDelegate}. * @return The {@link TabListDelegate}.
*/ */
TabListDelegate getTabListDelegate(); TabListDelegate getTabListDelegate();
/**
* @return The {@link TabDialogDelegation}.
*/
TabDialogDelegation getTabGridDialogDelegation();
} }
...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.tasks.tab_management; ...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.tasks.tab_management;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF;
import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater; import android.view.LayoutInflater;
...@@ -20,6 +21,7 @@ import androidx.annotation.VisibleForTesting; ...@@ -20,6 +21,7 @@ import androidx.annotation.VisibleForTesting;
import org.chromium.base.Callback; import org.chromium.base.Callback;
import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.MenuOrKeyboardActionController; import org.chromium.chrome.browser.MenuOrKeyboardActionController;
import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
import org.chromium.chrome.browser.flags.FeatureUtilities; import org.chromium.chrome.browser.flags.FeatureUtilities;
...@@ -43,9 +45,9 @@ import java.util.List; ...@@ -43,9 +45,9 @@ import java.util.List;
* Parent coordinator that is responsible for showing a grid or carousel of tabs for the main * Parent coordinator that is responsible for showing a grid or carousel of tabs for the main
* TabSwitcher UI. * TabSwitcher UI.
*/ */
public class TabSwitcherCoordinator implements Destroyable, TabSwitcher, public class TabSwitcherCoordinator
TabSwitcher.TabListDelegate, implements Destroyable, TabSwitcher, TabSwitcher.TabListDelegate,
TabSwitcherMediator.ResetHandler { TabSwitcher.TabDialogDelegation, TabSwitcherMediator.ResetHandler {
// TODO(crbug.com/982018): Rename 'COMPONENT_NAME' so as to add different metrics for carousel // TODO(crbug.com/982018): Rename 'COMPONENT_NAME' so as to add different metrics for carousel
// tab switcher. // tab switcher.
static final String COMPONENT_NAME = "GridTabSwitcher"; static final String COMPONENT_NAME = "GridTabSwitcher";
...@@ -118,8 +120,9 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher, ...@@ -118,8 +120,9 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher,
if (FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled()) { if (FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled()) {
mTabGridDialogCoordinator = new TabGridDialogCoordinator(context, tabModelSelector, mTabGridDialogCoordinator = new TabGridDialogCoordinator(context, tabModelSelector,
tabContentManager, tabCreatorManager, container, this, mMediator, tabContentManager, tabCreatorManager,
this::getTabGridDialogAnimationParams, ((ChromeTabbedActivity) context).getCompositorViewHolder(), this, mMediator,
this::getTabGridDialogAnimationSourceView,
mTabListCoordinator.getTabGroupTitleEditor()); mTabListCoordinator.getTabGroupTitleEditor());
mUndoGroupSnackbarController = mUndoGroupSnackbarController =
...@@ -189,6 +192,11 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher, ...@@ -189,6 +192,11 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher,
return this; return this;
} }
@Override
public TabDialogDelegation getTabGridDialogDelegation() {
return this;
}
@Override @Override
public boolean prepareOverview() { public boolean prepareOverview() {
boolean quick = mMediator.prepareOverview(); boolean quick = mMediator.prepareOverview();
...@@ -217,6 +225,7 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher, ...@@ -217,6 +225,7 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher,
return mTabListCoordinator.getThumbnailLocationOfCurrentTab(); return mTabListCoordinator.getThumbnailLocationOfCurrentTab();
} }
// TabListDelegate implementation.
@Override @Override
public int getResourceId() { public int getResourceId() {
return mTabListCoordinator.getResourceId(); return mTabListCoordinator.getResourceId();
...@@ -251,6 +260,13 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher, ...@@ -251,6 +260,13 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher,
return mMediator.getCleanupDelayForTesting(); return mMediator.getCleanupDelayForTesting();
} }
// TabDialogDelegation implementation.
@Override
@VisibleForTesting
public void setSourceRectCallbackForTesting(Callback<RectF> callback) {
TabGridDialogParent.setSourceRectCallbackForTesting(callback);
}
// ResetHandler implementation. // ResetHandler implementation.
@Override @Override
public boolean resetWithTabList(@Nullable TabList tabList, boolean quickMode, boolean mruMode) { public boolean resetWithTabList(@Nullable TabList tabList, boolean quickMode, boolean mruMode) {
...@@ -265,7 +281,7 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher, ...@@ -265,7 +281,7 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher,
return mTabListCoordinator.resetWithListOfTabs(tabs, quickMode, mruMode); return mTabListCoordinator.resetWithListOfTabs(tabs, quickMode, mruMode);
} }
private TabGridDialogParent.AnimationParams getTabGridDialogAnimationParams(int tabId) { private View getTabGridDialogAnimationSourceView(int tabId) {
int index = mTabListCoordinator.indexOfTab(tabId); int index = mTabListCoordinator.indexOfTab(tabId);
// TODO(crbug.com/999372): This is band-aid fix that will show basic fade-in/fade-out // TODO(crbug.com/999372): This is band-aid fix that will show basic fade-in/fade-out
// animation when we cannot find the animation source view holder. This is happening due to // animation when we cannot find the animation source view holder. This is happening due to
...@@ -274,9 +290,7 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher, ...@@ -274,9 +290,7 @@ public class TabSwitcherCoordinator implements Destroyable, TabSwitcher,
ViewHolder sourceViewHolder = ViewHolder sourceViewHolder =
mTabListCoordinator.getContainerView().findViewHolderForAdapterPosition(index); mTabListCoordinator.getContainerView().findViewHolderForAdapterPosition(index);
if (sourceViewHolder == null) return null; if (sourceViewHolder == null) return null;
View itemView = sourceViewHolder.itemView; return sourceViewHolder.itemView;
Rect rect = mTabListCoordinator.getContainerView().getRectOfCurrentTabGridCard(index);
return new TabGridDialogParent.AnimationParams(rect, itemView);
} }
@Override @Override
......
...@@ -8,7 +8,6 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.a ...@@ -8,7 +8,6 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.a
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.Rect;
import android.support.test.annotation.UiThreadTest; import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.MediumTest; import android.support.test.filters.MediumTest;
import android.support.test.filters.SmallTest; import android.support.test.filters.SmallTest;
...@@ -264,10 +263,9 @@ public class TabGridDialogParentTest extends DummyUiActivityTestCase { ...@@ -264,10 +263,9 @@ public class TabGridDialogParentTest extends DummyUiActivityTestCase {
@Test @Test
@MediumTest @MediumTest
public void testDialog_ZoomInZoomOut() { public void testDialog_ZoomInZoomOut() {
// Setup the animation with a dummy animation params. // Setup the animation with a dummy animation source view.
TabGridDialogParent.AnimationParams params = new TabGridDialogParent.AnimationParams( View sourceView = new View(getActivity());
new Rect(3, 3, 3, 3), new View(getActivity())); mTabGridDialogParent.setupDialogAnimation(sourceView);
mTabGridDialogParent.setupDialogAnimation(params);
ViewGroup parent = (ViewGroup) mTabGridDialogContainer.getParent(); ViewGroup parent = (ViewGroup) mTabGridDialogContainer.getParent();
// Show the dialog with zoom-out animation. // Show the dialog with zoom-out animation.
...@@ -321,10 +319,9 @@ public class TabGridDialogParentTest extends DummyUiActivityTestCase { ...@@ -321,10 +319,9 @@ public class TabGridDialogParentTest extends DummyUiActivityTestCase {
@Test @Test
@MediumTest @MediumTest
public void testDialog_ZoomInFadeOut() { public void testDialog_ZoomInFadeOut() {
// Setup the animation with a dummy animation params. // Setup the animation with a dummy animation source view.
TabGridDialogParent.AnimationParams params = new TabGridDialogParent.AnimationParams( View sourceView = new View(getActivity());
new Rect(3, 3, 3, 3), new View(getActivity())); mTabGridDialogParent.setupDialogAnimation(sourceView);
mTabGridDialogParent.setupDialogAnimation(params);
// Show the dialog. // Show the dialog.
TestThreadUtils.runOnUiThreadBlocking(() -> mTabGridDialogParent.showDialog()); TestThreadUtils.runOnUiThreadBlocking(() -> mTabGridDialogParent.showDialog());
// Hide the dialog with basic fade-out animation. // Hide the dialog with basic fade-out animation.
......
...@@ -27,10 +27,14 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.c ...@@ -27,10 +27,14 @@ import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.c
import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.enterTabSwitcher; import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.enterTabSwitcher;
import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyTabSwitcherCardCount; import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.verifyTabSwitcherCardCount;
import android.graphics.Rect;
import android.support.test.espresso.Espresso; import android.support.test.espresso.Espresso;
import android.support.test.espresso.NoMatchingRootException; import android.support.test.espresso.NoMatchingRootException;
import android.support.test.espresso.contrib.RecyclerViewActions; import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.test.filters.MediumTest; import android.support.test.filters.MediumTest;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText; import android.widget.EditText;
import org.junit.Assert; import org.junit.Assert;
...@@ -57,6 +61,7 @@ import org.chromium.chrome.test.ChromeTabbedActivityTestRule; ...@@ -57,6 +61,7 @@ import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.OverviewModeBehaviorWatcher; import org.chromium.chrome.test.util.OverviewModeBehaviorWatcher;
import org.chromium.chrome.test.util.browser.Features; import org.chromium.chrome.test.util.browser.Features;
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.ui.test.util.UiRestriction; import org.chromium.ui.test.util.UiRestriction;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -70,6 +75,9 @@ import java.util.List; ...@@ -70,6 +75,9 @@ import java.util.List;
@Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID}) @Features.EnableFeatures({ChromeFeatureList.TAB_GROUPS_UI_IMPROVEMENTS_ANDROID})
public class TabGridDialogTest { public class TabGridDialogTest {
// clang-format on // clang-format on
private boolean mHasReceivedSourceRect;
@Rule @Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule(); public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
...@@ -160,6 +168,56 @@ public class TabGridDialogTest { ...@@ -160,6 +168,56 @@ public class TabGridDialogTest {
verifyTabGroupsContinuation(cta, true); verifyTabGroupsContinuation(cta, true);
} }
@Test
@MediumTest
public void testTabGridDialogAnimation() throws InterruptedException {
final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
createTabs(cta, false, 2);
enterTabSwitcher(cta);
verifyTabSwitcherCardCount(cta, 2);
// Create a tab group.
mergeAllTabsToAGroup(cta);
verifyTabSwitcherCardCount(cta, 1);
// Add 400px top margin to the recyclerView.
RecyclerView recyclerView = cta.findViewById(R.id.tab_list_view);
float tabGridCardPadding = cta.getResources().getDimension(R.dimen.tab_list_card_padding);
int deltaTopMargin = 400;
ViewGroup.MarginLayoutParams params =
(ViewGroup.MarginLayoutParams) recyclerView.getLayoutParams();
params.topMargin += deltaTopMargin;
TestThreadUtils.runOnUiThreadBlocking(() -> { recyclerView.setLayoutParams(params); });
CriteriaHelper.pollUiThread(() -> !recyclerView.isComputingLayout());
// Calculate expected values of animation source rect.
mHasReceivedSourceRect = false;
View parentView = cta.getCompositorViewHolder();
Rect parentRect = new Rect();
parentView.getGlobalVisibleRect(parentRect);
Rect sourceRect = new Rect();
recyclerView.getChildAt(0).getGlobalVisibleRect(sourceRect);
// TODO(yuezhanggg): Figure out why the sourceRect.left is wrong after setting the margin.
float expectedTop = sourceRect.top - parentRect.top + tabGridCardPadding;
float expectedWidth = sourceRect.width() - 2 * tabGridCardPadding;
float expectedHeight = sourceRect.height() - 2 * tabGridCardPadding;
// Setup the callback to verify the animation source Rect.
StartSurfaceLayout layout = (StartSurfaceLayout) cta.getLayoutManager().getOverviewLayout();
TabSwitcher.TabDialogDelegation delegation =
layout.getStartSurfaceForTesting().getTabDialogDelegate();
delegation.setSourceRectCallbackForTesting((result -> {
mHasReceivedSourceRect = true;
assertTrue(expectedTop == result.top);
assertTrue(expectedHeight == result.height());
assertTrue(expectedWidth == result.width());
}));
TabUiTestHelper.clickFirstCardFromTabSwitcher(cta);
CriteriaHelper.pollUiThread(() -> mHasReceivedSourceRect);
CriteriaHelper.pollInstrumentationThread(() -> isDialogShowing(cta));
}
private void mergeAllTabsToAGroup(ChromeTabbedActivity cta) { private void mergeAllTabsToAGroup(ChromeTabbedActivity cta) {
List<Tab> tabGroup = new ArrayList<>(); List<Tab> tabGroup = new ArrayList<>();
TabModel tabModel = cta.getTabModelSelector().getModel(false); TabModel tabModel = cta.getTabModelSelector().getModel(false);
......
...@@ -7,7 +7,6 @@ package org.chromium.chrome.browser.tasks.tab_management; ...@@ -7,7 +7,6 @@ package org.chromium.chrome.browser.tasks.tab_management;
import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.areAnimatorsEnabled; import static org.chromium.chrome.browser.tasks.tab_management.TabUiTestHelper.areAnimatorsEnabled;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.os.Build; import android.os.Build;
import android.os.SystemClock; import android.os.SystemClock;
...@@ -244,29 +243,27 @@ public class TabGridPanelViewBinderTest extends DummyUiActivityTestCase { ...@@ -244,29 +243,27 @@ public class TabGridPanelViewBinderTest extends DummyUiActivityTestCase {
@Test @Test
@SmallTest @SmallTest
@UiThreadTest @UiThreadTest
public void testSetAnimationParams() { public void testSetAnimationSourceView() {
// Initially, the show animation set is empty. // Initially, the show animation set is empty.
Assert.assertEquals(0, Assert.assertEquals(0,
mTabGridDialogParent.getShowDialogAnimationForTesting() mTabGridDialogParent.getShowDialogAnimationForTesting()
.getChildAnimations() .getChildAnimations()
.size()); .size());
// When set with null as animation params, the show animation is set to be basic fade-in // When set animation source view as null, the show animation is set to be basic fade-in
// which contains only one animation in animation set. // which contains only one animation in animation set.
mModel.set(TabGridPanelProperties.ANIMATION_PARAMS, null); mModel.set(TabGridPanelProperties.ANIMATION_SOURCE_VIEW, null);
Assert.assertEquals(1, Assert.assertEquals(1,
mTabGridDialogParent.getShowDialogAnimationForTesting() mTabGridDialogParent.getShowDialogAnimationForTesting()
.getChildAnimations() .getChildAnimations()
.size()); .size());
// Create a dummy animation param to setup the dialog animation. // Create a dummy source view to setup the dialog animation.
Rect rect = new Rect(); View sourceView = new View(getActivity());
View view = new View(getActivity());
TabGridDialogParent.AnimationParams dummyParams =
new TabGridDialogParent.AnimationParams(rect, view);
// When set with a specific animation param, the show animation contains 6 child animations. // When set with a specific animation source view, the show animation contains 6 child
mModel.set(TabGridPanelProperties.ANIMATION_PARAMS, dummyParams); // animations.
mModel.set(TabGridPanelProperties.ANIMATION_SOURCE_VIEW, sourceView);
Assert.assertEquals(6, Assert.assertEquals(6,
mTabGridDialogParent.getShowDialogAnimationForTesting() mTabGridDialogParent.getShowDialogAnimationForTesting()
.getChildAnimations() .getChildAnimations()
......
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