Merge "Log split button visibility to debug spacing issue" into main
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index dc30a35..5413601 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -20,6 +20,7 @@
 aconfig_declarations {
     name: "com_android_launcher3_flags",
     package: "com.android.launcher3",
+    container: "system",
     srcs: ["**/*.aconfig"],
 }
 
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 82ae4cb..6d899d9 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -1,4 +1,5 @@
 package: "com.android.launcher3"
+container: "system"
 
 flag {
     name: "enable_expanding_pause_work_button"
diff --git a/aconfig/launcher_search.aconfig b/aconfig/launcher_search.aconfig
index 4e16e7f..2f2690e 100644
--- a/aconfig/launcher_search.aconfig
+++ b/aconfig/launcher_search.aconfig
@@ -1,4 +1,5 @@
 package: "com.android.launcher3"
+container: "system"
 
 flag {
     name: "enable_private_space"
diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
index 29b24b7..6e7a82a 100644
--- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
+++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.ShortcutAndWidgetContainer;
+import com.android.launcher3.icons.ClockDrawableWrapper;
 import com.android.launcher3.testing.shared.TestProtocol;
 
 import java.util.ArrayList;
@@ -136,10 +137,12 @@
 
             case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
                 TestProtocol.sDebugTracing = true;
+                ClockDrawableWrapper.sRunningInTest = true;
                 return response;
 
             case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
                 TestProtocol.sDebugTracing = false;
+                ClockDrawableWrapper.sRunningInTest = false;
                 return response;
 
             case TestProtocol.REQUEST_PID: {
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 68bad5c..853ac74 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -32,8 +32,11 @@
     <dimen name="overview_minimum_next_prev_size">50dp</dimen>
 
     <!--  Overview Task Views  -->
-    <!--  The primary task thumbnail uses up to this much of the total screen height/width  -->
+    <!--  The thumbnail uses up to this much of the total screen height/width in Overview -->
     <item name="overview_max_scale" format="float" type="dimen">0.7</item>
+    <!--  The thumbnail should not go smaller than this much of the total screen height/width in
+             tablet app to Overview carousel -->
+    <item name="overview_carousel_min_scale" format="float" type="dimen">0.46</item>
     <!--  A touch target for icons, sometimes slightly larger than the icons themselves  -->
     <dimen name="task_thumbnail_icon_size">48dp</dimen>
     <!--  The icon size for the focused task, placed in center of touch target  -->
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index 436fe3b..68e7824 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -23,6 +23,7 @@
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
+import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ClipData;
 import android.content.ClipDescription;
@@ -50,7 +51,6 @@
 /** An Activity that can host Launcher's widget picker. */
 public class WidgetPickerActivity extends BaseActivity {
     private static final String TAG = "WidgetPickerActivity";
-    private static final boolean DEBUG = false;
 
     /**
      * Name of the extra that indicates that a widget being dragged.
@@ -65,13 +65,13 @@
     private static final String EXTRA_DESIRED_WIDGET_WIDTH = "desired_widget_width";
     private static final String EXTRA_DESIRED_WIDGET_HEIGHT = "desired_widget_height";
 
-
     private SimpleDragLayer<WidgetPickerActivity> mDragLayer;
     private WidgetsModel mModel;
     private final PopupDataProvider mPopupDataProvider = new PopupDataProvider(i -> {});
 
     private int mDesiredWidgetWidth;
     private int mDesiredWidgetHeight;
+    private int mWidgetCategoryFilter;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -104,6 +104,10 @@
         mDesiredWidgetHeight =
                 getIntent().getIntExtra(EXTRA_DESIRED_WIDGET_HEIGHT, 0);
 
+        // Defaults to '0' to indicate that there isn't a category filter.
+        mWidgetCategoryFilter =
+                getIntent().getIntExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER, 0);
+
         refreshAndBindWidgets();
     }
 
@@ -199,6 +203,14 @@
             return rejectWidget(widget, "shortcut");
         }
 
+        if (mWidgetCategoryFilter > 0 && (info.widgetCategory & mWidgetCategoryFilter) == 0) {
+            return rejectWidget(
+                    widget,
+                    "doesn't match category filter [filter=%d, widget=%d]",
+                    mWidgetCategoryFilter,
+                    info.widgetCategory);
+        }
+
         if (mDesiredWidgetWidth == 0 && mDesiredWidgetHeight == 0) {
             // Accept the widget if the desired dimensions are unspecified.
             return acceptWidget(widget);
@@ -210,22 +222,18 @@
             if (info.maxResizeWidth > 0 && info.maxResizeWidth < mDesiredWidgetWidth) {
                 return rejectWidget(
                         widget,
-                        String.format(
-                                Locale.ENGLISH,
-                                "maxResizeWidth[%d] < mDesiredWidgetWidth[%d]",
-                                info.maxResizeWidth,
-                                mDesiredWidgetWidth));
+                        "maxResizeWidth[%d] < mDesiredWidgetWidth[%d]",
+                        info.maxResizeWidth,
+                        mDesiredWidgetWidth);
             }
 
             final int minWidth = info.minResizeWidth > 0 ? info.minResizeWidth : info.minWidth;
             if (minWidth > mDesiredWidgetWidth) {
                 return rejectWidget(
                         widget,
-                        String.format(
-                                Locale.ENGLISH,
-                                "minWidth[%d] > mDesiredWidgetWidth[%d]",
-                                minWidth,
-                                mDesiredWidgetWidth));
+                        "minWidth[%d] > mDesiredWidgetWidth[%d]",
+                        minWidth,
+                        mDesiredWidgetWidth);
             }
         }
 
@@ -235,22 +243,18 @@
             if (info.maxResizeHeight > 0 && info.maxResizeHeight < mDesiredWidgetHeight) {
                 return rejectWidget(
                         widget,
-                        String.format(
-                                Locale.ENGLISH,
-                                "maxResizeHeight[%d] < mDesiredWidgetHeight[%d]",
-                                info.maxResizeHeight,
-                                mDesiredWidgetHeight));
+                        "maxResizeHeight[%d] < mDesiredWidgetHeight[%d]",
+                        info.maxResizeHeight,
+                        mDesiredWidgetHeight);
             }
 
             final int minHeight = info.minResizeHeight > 0 ? info.minResizeHeight : info.minHeight;
             if (minHeight > mDesiredWidgetHeight) {
                 return rejectWidget(
                         widget,
-                        String.format(
-                                Locale.ENGLISH,
-                                "minHeight[%d] > mDesiredWidgetHeight[%d]",
-                                minHeight,
-                                mDesiredWidgetHeight));
+                        "minHeight[%d] > mDesiredWidgetHeight[%d]",
+                        minHeight,
+                        mDesiredWidgetHeight);
             }
         }
 
@@ -264,8 +268,11 @@
     }
 
     private static WidgetAcceptabilityVerdict rejectWidget(
-            WidgetItem widget, String rejectionReason) {
-        return new WidgetAcceptabilityVerdict(false, widget.label, rejectionReason);
+            WidgetItem widget, String rejectionReason, Object... args) {
+        return new WidgetAcceptabilityVerdict(
+                false,
+                widget.label,
+                String.format(Locale.ENGLISH, rejectionReason, args));
     }
 
     private static WidgetAcceptabilityVerdict acceptWidget(WidgetItem widget) {
@@ -276,7 +283,7 @@
             boolean isAcceptable, String widgetLabel, String reason) {
         void maybeLogVerdict() {
             // Only log a verdict if a reason is specified.
-            if (DEBUG && !reason.isEmpty()) {
+            if (Log.isLoggable(TAG, Log.DEBUG) && !reason.isEmpty()) {
                 Log.i(TAG, String.format(
                         Locale.ENGLISH,
                         "%s: %s because %s",
diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
index 037f7a8..694475a 100644
--- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -77,19 +77,15 @@
     public AppsDividerView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
 
-        boolean isMainColorDark = Themes.getAttrBoolean(context, R.attr.isMainColorDark);
         mDividerSize = new int[]{
                 getResources().getDimensionPixelSize(R.dimen.all_apps_divider_width),
                 getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height)
         };
 
-        mStrokeColor = ContextCompat.getColor(context, isMainColorDark
-                ? R.color.all_apps_prediction_row_separator_dark
-                : R.color.all_apps_prediction_row_separator);
+        mStrokeColor = ContextCompat.getColor(context, R.color.material_color_outline_variant);
 
-        mAllAppsLabelTextColor = ContextCompat.getColor(context, isMainColorDark
-                ? R.color.all_apps_label_text_dark
-                : R.color.all_apps_label_text);
+        mAllAppsLabelTextColor = ContextCompat.getColor(context,
+                R.color.material_color_on_surface_variant);
 
         mShowAllAppsLabel = !ALL_APPS_VISITED_COUNT.hasReachedMax(context);
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 55deca8..b69f657 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -36,12 +36,14 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
+import static com.android.launcher3.taskbar.TaskbarDragLayerController.TASKBAR_REAPPEAR_DELAY_MS;
 import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
 import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
 
 import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.app.ActivityOptions;
 import android.content.ActivityNotFoundException;
@@ -77,6 +79,7 @@
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.config.FeatureFlags;
@@ -1377,6 +1380,23 @@
         });
     }
 
+    public void hideTaskbarWhenFolding() {
+        AnimatedFloat alphaAnim = mControllers.taskbarDragLayerController.getTaskbarAlpha();
+        alphaAnim.cancelAnimation();
+        alphaAnim.updateValue(0);
+        ObjectAnimator animator = alphaAnim.animateToValue(1).setDuration(0);
+        animator.setStartDelay(TASKBAR_REAPPEAR_DELAY_MS);
+        animator.start();
+    }
+
+    public void cancelHideTaskbarWhenFolding() {
+        mControllers.taskbarDragLayerController.getTaskbarAlpha().cancelAnimation();
+    }
+
+    public void resetHideTaskbarWhenUnfolding() {
+        mControllers.taskbarDragLayerController.getTaskbarAlpha().updateValue(1);
+    }
+
     protected boolean isUserSetupComplete() {
         return mIsUserSetupComplete;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 3f5402f..74eda24 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -44,6 +44,12 @@
     private static final boolean DEBUG = SystemProperties.getBoolean(
             "persist.debug.draw_taskbar_debug_ui", false);
 
+    // Delay to reset the task bar alpha back to 1 after fading it for transition from unfold to
+    // fold. Normally this is not needed since the new task bar is recreated after fading, but in
+    // case something goes wrong this provides a fallback mechanism to make sure the task bar is
+    // visible after the transition finishes.
+    public static final long TASKBAR_REAPPEAR_DELAY_MS = 2000;
+
     private final TaskbarActivityContext mActivity;
     private final TaskbarDragLayer mTaskbarDragLayer;
     private final int mFolderMargin;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 7c7c426..4dd2f44 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -30,6 +30,7 @@
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING;
 import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
 import static com.android.quickstep.util.SystemActionConstants.ACTION_SHOW_TASKBAR;
@@ -43,6 +44,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.display.DisplayManager;
 import android.net.Uri;
 import android.os.Handler;
@@ -109,6 +111,7 @@
 
     private final Context mContext;
     private final @Nullable Context mNavigationBarPanelContext;
+    private final DeviceStateManager mDeviceStateManager;
     private WindowManager mWindowManager;
     private FrameLayout mTaskbarRootLayout;
     private boolean mAddedWindow;
@@ -175,7 +178,8 @@
         }
     };
 
-    UnfoldTransitionProgressProvider.TransitionProgressListener mUnfoldTransitionProgressListener =
+    private final UnfoldTransitionProgressProvider.TransitionProgressListener
+            mUnfoldTransitionProgressListener =
             new UnfoldTransitionProgressProvider.TransitionProgressListener() {
                 @Override
                 public void onTransitionStarted() {
@@ -204,6 +208,9 @@
                 }
             };
 
+    private final DeviceStateManager.FoldStateListener mFoldStateListener;
+    private Boolean mFolded;
+
     @SuppressLint("WrongConstant")
     public TaskbarManager(TouchInteractionService service) {
         Display display =
@@ -229,6 +236,29 @@
                 }
             };
         }
+        // Temporary solution to mitigate the visual jump from folding the device. Currently, the
+        // screen turns on much earlier than we receive the onConfigurationChanged callback or
+        // receiving the correct device profile. While the ideal the solution is to align turning
+        // the screen on after onConfigurationChanged (by either delaying turning on the screen or
+        // figuring out what is causing the delay in getting onConfigurationChanged callback), one
+        // easy temporary mitigation is to dimming the bar so that the visual jump isn't as glaring.
+        mFoldStateListener = new DeviceStateManager.FoldStateListener(mContext, folded -> {
+            boolean firstTime = mFolded == null;
+            if (mTaskbarActivityContext == null) {
+                return;
+            }
+            if (!firstTime && mFolded.booleanValue() != folded) {
+                mTaskbarActivityContext.cancelHideTaskbarWhenFolding();
+            }
+            mFolded = folded;
+            if (folded && !firstTime) {
+                mTaskbarActivityContext.hideTaskbarWhenFolding();
+            } else {
+                mTaskbarActivityContext.resetHideTaskbarWhenUnfolding();
+            }
+        });
+        mDeviceStateManager = mContext.getSystemService(DeviceStateManager.class);
+        mDeviceStateManager.registerCallback(MAIN_EXECUTOR, mFoldStateListener);
         mNavButtonController = new TaskbarNavButtonController(service,
                 SystemUiProxy.INSTANCE.get(mContext), new Handler(),
                 AssistUtils.newInstance(mContext));
@@ -588,6 +618,7 @@
         Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy().");
         mContext.unregisterComponentCallbacks(mComponentCallbacks);
         mContext.unregisterReceiver(mShutdownReceiver);
+        mDeviceStateManager.unregisterCallback(mFoldStateListener);
     }
 
     public @Nullable TaskbarActivityContext getCurrentActivityContext() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index ca598c8..fc3eeba 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -38,6 +38,7 @@
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 
+import com.android.internal.jank.Cuj;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.Utilities;
@@ -53,6 +54,7 @@
 import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.OverviewToHomeAnim;
 import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 
 import java.util.function.Consumer;
 
@@ -148,6 +150,8 @@
         mMotionPauseDetector.clear();
 
         if (handlingOverviewAnim()) {
+            InteractionJankMonitorWrapper.begin(mRecentsView, Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
+                    "Home");
             mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseDetected);
         }
 
@@ -182,6 +186,7 @@
         if (mStartedOverview) {
             goToOverviewOrHomeOnDragEnd(velocity);
         } else {
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
             super.onDragEnd(velocity);
         }
 
@@ -237,6 +242,7 @@
 
     private void maybeSwipeInteractionToOverviewComplete() {
         if (mReachedOverview && !mDetector.isDraggingState()) {
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
             onSwipeInteractionCompleted(OVERVIEW);
         }
     }
@@ -280,6 +286,7 @@
         if (goToHomeInsteadOfOverview) {
             new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(NORMAL), null)
                     .animateWithVelocity(velocity);
+            InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
         }
         if (mReachedOverview) {
             float distanceDp = dpiFromPx(Math.max(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 6d3b60a..b7a907f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -193,6 +193,8 @@
         mMotionPauseDetector.clear();
         if (start) {
             InteractionJankMonitorWrapper.begin(mRecentsView, Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
+            InteractionJankMonitorWrapper.begin(mRecentsView, Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
+                    "Home");
 
             mStartState = mLauncher.getStateManager().getState();
 
@@ -350,6 +352,7 @@
                     .dispatchOnStart();
             return;
         }
+        InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
 
         final LauncherState targetState;
         if (horizontalFling && verticalFling) {
@@ -471,6 +474,8 @@
 
         if (targetState == QUICK_SWITCH_FROM_HOME) {
             InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
+        } else if (targetState == OVERVIEW) {
+            InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
         }
 
         mLauncher.getStateManager().goToState(targetState, false, forEndCallback(this::clearState));
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 6698600..4752225 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -30,6 +30,7 @@
 import static com.android.launcher3.BaseActivity.EVENT_STARTED;
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
 import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
 import static com.android.launcher3.PagedView.INVALID_PAGE;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -2561,9 +2562,11 @@
         }
 
         float scrollOffset = Math.abs(mRecentsView.getScrollOffset(mRecentsView.getCurrentPage()));
+        Rect carouselTaskSize = enableGridOnlyOverview()
+                ? mRecentsView.getLastComputedCarouselTaskSize()
+                : mRecentsView.getLastComputedTaskSize();
         int maxScrollOffset = mRecentsView.getPagedOrientationHandler().getPrimaryValue(
-                mRecentsView.getLastComputedTaskSize().width(),
-                mRecentsView.getLastComputedTaskSize().height());
+                carouselTaskSize.width(), carouselTaskSize.height());
         maxScrollOffset += mRecentsView.getPageSpacing();
 
         float maxScaleProgress =
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index b89d20c..879312d 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -261,6 +261,23 @@
         }
     }
 
+    /**
+     * Calculates the taskView size for carousel during app to overview animation on tablets.
+     */
+    public final void calculateCarouselTaskSize(Context context, DeviceProfile dp, Rect outRect,
+            PagedOrientationHandler orientedState) {
+        if (dp.isTablet && dp.isGestureMode) {
+            Resources res = context.getResources();
+            float minScale = res.getFloat(R.dimen.overview_carousel_min_scale);
+            Rect gridRect = new Rect();
+            calculateGridSize(dp, context, gridRect);
+            calculateTaskSizeInternal(context, dp, gridRect, minScale, Gravity.CENTER | Gravity.TOP,
+                    outRect);
+        } else {
+            calculateTaskSize(context, dp, outRect, orientedState);
+        }
+    }
+
     private void calculateFocusTaskSize(Context context, DeviceProfile dp, Rect outRect) {
         Resources res = context.getResources();
         float maxScale = res.getFloat(R.dimen.overview_max_scale);
@@ -286,13 +303,13 @@
     }
 
     private void calculateTaskSizeInternal(Context context, DeviceProfile dp,
-            Rect potentialTaskRect, float maxScale, int gravity, Rect outRect) {
+            Rect potentialTaskRect, float targetScale, int gravity, Rect outRect) {
         PointF taskDimension = getTaskDimension(context, dp);
 
         float scale = Math.min(
                 potentialTaskRect.width() / taskDimension.x,
                 potentialTaskRect.height() / taskDimension.y);
-        scale = Math.min(scale, maxScale);
+        scale = Math.min(scale, targetScale);
         int outWidth = Math.round(scale * taskDimension.x);
         int outHeight = Math.round(scale * taskDimension.y);
 
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
index 278ca56..1e05a69 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
@@ -67,15 +67,15 @@
     /**
      * Adds a log to be printed at log-dump-time.
      */
-    public void addLog(String event) {
+    public void addLog(@NonNull String event) {
         addLog(event, null);
     }
 
-    public void addLog(String event, int extras) {
+    public void addLog(@NonNull String event, int extras) {
         addLog(event, extras, null);
     }
 
-    public void addLog(String event, boolean extras) {
+    public void addLog(@NonNull String event, boolean extras) {
         addLog(event, extras, null);
     }
 
@@ -85,30 +85,30 @@
      * @param gestureEvent GestureEvent representing the event being logged.
      */
     public void addLog(
-            String event, @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
+            @NonNull String event, @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
         addLog(new CompoundString(event), gestureEvent);
     }
 
     public void addLog(
-            String event,
+            @NonNull String event,
             int extras,
             @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
         addLog(new CompoundString(event).append(": ").append(extras), gestureEvent);
     }
 
     public void addLog(
-            String event,
+            @NonNull String event,
             boolean extras,
             @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
         addLog(new CompoundString(event).append(": ").append(extras), gestureEvent);
     }
 
-    public void addLog(CompoundString compoundString) {
+    public void addLog(@NonNull CompoundString compoundString) {
         addLog(compoundString, null);
     }
 
     public void addLog(
-            CompoundString compoundString,
+            @NonNull CompoundString compoundString,
             @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
         EventLog lastEventLog = logs[(nextIndex + logs.length - 1) % logs.length];
         if (lastEventLog == null || mCurrentLogId != lastEventLog.logId) {
@@ -259,21 +259,20 @@
 
         public CompoundString(String substring) {
             mIsNoOp = substring == null;
-            if (mIsNoOp) {
-                mSubstrings = null;
-                mArgs = null;
-                return;
+            mSubstrings = mIsNoOp ? null : new ArrayList<>();
+            mArgs = mIsNoOp ? null : new ArrayList<>();
+
+            if (!mIsNoOp) {
+                mSubstrings.add(substring);
             }
-            mSubstrings = new ArrayList<>();
-            mSubstrings.add(substring);
-            mArgs = new ArrayList<>();
         }
 
         public CompoundString append(CompoundString substring) {
-            if (mIsNoOp) {
+            if (mIsNoOp || substring.mIsNoOp) {
                 return this;
             }
             mSubstrings.addAll(substring.mSubstrings);
+            mArgs.addAll(substring.mArgs);
 
             return this;
         }
@@ -288,30 +287,53 @@
         }
 
         public CompoundString append(int num) {
+            if (mIsNoOp) {
+                return this;
+            }
+            mArgs.add(num);
+
+            return append("%d");
+        }
+
+        public CompoundString append(long num) {
+            if (mIsNoOp) {
+                return this;
+            }
             mArgs.add(num);
 
             return append("%d");
         }
 
         public CompoundString append(float num) {
+            if (mIsNoOp) {
+                return this;
+            }
             mArgs.add(num);
 
             return append("%.2f");
         }
 
         public CompoundString append(double num) {
+            if (mIsNoOp) {
+                return this;
+            }
             mArgs.add(num);
 
             return append("%.2f");
         }
 
         public CompoundString append(boolean bool) {
+            if (mIsNoOp) {
+                return this;
+            }
             mArgs.add(bool);
 
             return append("%b");
         }
 
-        public Object[] getArgs() {
+        private Object[] getArgs() {
+            Preconditions.assertTrue(!mIsNoOp);
+
             return mArgs.toArray();
         }
 
@@ -320,7 +342,7 @@
             return String.format(toUnformattedString(), getArgs());
         }
 
-        public String toUnformattedString() {
+        private String toUnformattedString() {
             Preconditions.assertTrue(!mIsNoOp);
 
             StringBuilder sb = new StringBuilder();
@@ -333,7 +355,7 @@
 
         @Override
         public int hashCode() {
-            return Objects.hash(mIsNoOp, mSubstrings);
+            return Objects.hash(mIsNoOp, mSubstrings, mArgs);
         }
 
         @Override
@@ -342,7 +364,9 @@
                 return false;
             }
             CompoundString other = (CompoundString) obj;
-            return (mIsNoOp == other.mIsNoOp) && Objects.equals(mSubstrings, other.mSubstrings);
+            return (mIsNoOp == other.mIsNoOp)
+                    && Objects.equals(mSubstrings, other.mSubstrings)
+                    && Objects.equals(mArgs, other.mArgs);
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index bc8b571..16f2065 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -17,6 +17,7 @@
 
 import static com.android.app.animation.Interpolators.DECELERATE;
 import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
 import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
@@ -58,6 +59,7 @@
         FROM_APP(0.75f, 0.5f, 1f, false),
         FROM_APP_TO_ALL_APPS(1f, 0.6f, 0.8f, false),
         FROM_APP_TABLET(1f, 0.7f, 1f, true),
+        FROM_APP_TABLET_GRID_ONLY(1f, 1f, 1f, true),
         FROM_APP_TO_ALL_APPS_TABLET(1f, 0.5f, 0.5f, false),
         FROM_OVERVIEW(1f, 0.75f, 0.5f, false);
 
@@ -239,10 +241,10 @@
         float stopResist =
                 params.resistanceParams.stopScalingAtTop ? 1f - startRect.top / endRectF.top : 1f;
         final TimeInterpolator scaleInterpolator = t -> {
-            if (t < startResist) {
+            if (t <= startResist) {
                 return t;
             }
-            if (t > stopResist) {
+            if (t >= stopResist) {
                 return maxResist;
             }
             float resistProgress = Utilities.getProgress(t, startResist, stopResist);
@@ -304,7 +306,9 @@
                 resistanceParams =
                         recentsOrientedState.getActivityInterface().allowAllAppsFromOverview()
                                 ? RecentsResistanceParams.FROM_APP_TO_ALL_APPS_TABLET
-                                : RecentsResistanceParams.FROM_APP_TABLET;
+                                : enableGridOnlyOverview()
+                                        ? RecentsResistanceParams.FROM_APP_TABLET_GRID_ONLY
+                                        : RecentsResistanceParams.FROM_APP_TABLET;
             } else {
                 resistanceParams =
                         recentsOrientedState.getActivityInterface().allowAllAppsFromOverview()
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index a8a96ce..b8bc828 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -96,8 +96,14 @@
         mSpeedSomewhatFast = res.getDimension(R.dimen.motion_pause_detector_speed_somewhat_fast);
         mSpeedFast = res.getDimension(R.dimen.motion_pause_detector_speed_fast);
         mForcePauseTimeout = new Alarm();
-        mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */,
-                "Force pause timeout after " +  alarm.getLastSetTimeout() + "ms" /* reason */));
+        mForcePauseTimeout.setOnAlarmListener(alarm -> {
+            ActiveGestureLog.CompoundString log =
+                    new ActiveGestureLog.CompoundString("Force pause timeout after ")
+                            .append(alarm.getLastSetTimeout())
+                            .append("ms");
+            addLogs(log);
+            updatePaused(true /* isPaused */, log);
+        });
         mMakePauseHarderToTrigger = makePauseHarderToTrigger;
         mVelocityProvider = new SystemVelocityProvider(axis);
     }
@@ -113,8 +119,14 @@
      * @param disallowPause If true, we will not detect any pauses until this is set to false again.
      */
     public void setDisallowPause(boolean disallowPause) {
+        ActiveGestureLog.CompoundString log =
+                new ActiveGestureLog.CompoundString("Set disallowPause=")
+                        .append(disallowPause);
+        if (mDisallowPause != disallowPause) {
+            addLogs(log);
+        }
         mDisallowPause = disallowPause;
-        updatePaused(mIsPaused, "Set disallowPause=" + disallowPause);
+        updatePaused(mIsPaused, log);
     }
 
     /**
@@ -148,27 +160,30 @@
         float speed = Math.abs(velocity);
         float previousSpeed = Math.abs(prevVelocity);
         boolean isPaused;
-        String isPausedReason = "";
+        ActiveGestureLog.CompoundString isPausedReason;
         if (mIsPaused) {
             // Continue to be paused until moving at a fast speed.
             isPaused = speed < mSpeedFast || previousSpeed < mSpeedFast;
-            isPausedReason = "Was paused, but started moving at a fast speed";
+            isPausedReason = new ActiveGestureLog.CompoundString(
+                    "Was paused, but started moving at a fast speed");
         } else {
             if (velocity < 0 != prevVelocity < 0) {
                 // We're just changing directions, not necessarily stopping.
                 isPaused = false;
-                isPausedReason = "Velocity changed directions";
+                isPausedReason = new ActiveGestureLog.CompoundString("Velocity changed directions");
             } else {
                 isPaused = speed < mSpeedVerySlow && previousSpeed < mSpeedVerySlow;
-                isPausedReason = "Pause requires back to back slow speeds";
+                isPausedReason = new ActiveGestureLog.CompoundString(
+                        "Pause requires back to back slow speeds");
                 if (!isPaused && !mHasEverBeenPaused) {
                     // We want to be more aggressive about detecting the first pause to ensure it
                     // feels as responsive as possible; getting two very slow speeds back to back
                     // takes too long, so also check for a rapid deceleration.
                     boolean isRapidDeceleration = speed < previousSpeed * RAPID_DECELERATION_FACTOR;
                     isPaused = isRapidDeceleration && speed < mSpeedSomewhatFast;
-                    isPausedReason = "Didn't have back to back slow speeds, checking for rapid"
-                            + " deceleration on first pause only";
+                    isPausedReason = new ActiveGestureLog.CompoundString(
+                            "Didn't have back to back slow speeds, checking for rapid ")
+                            .append(" deceleration on first pause only");
                 }
                 if (mMakePauseHarderToTrigger) {
                     if (speed < mSpeedSlow) {
@@ -176,12 +191,14 @@
                             mSlowStartTime = time;
                         }
                         isPaused = time - mSlowStartTime >= HARDER_TRIGGER_TIMEOUT;
-                        isPausedReason = "Maintained slow speed for sufficient duration when making"
-                                + " pause harder to trigger";
+                        isPausedReason = new ActiveGestureLog.CompoundString(
+                                "Maintained slow speed for sufficient duration when making")
+                                .append(" pause harder to trigger");
                     } else {
                         mSlowStartTime = 0;
                         isPaused = false;
-                        isPausedReason = "Intentionally making pause harder to trigger";
+                        isPausedReason = new ActiveGestureLog.CompoundString(
+                                "Intentionally making pause harder to trigger");
                     }
                 }
             }
@@ -189,18 +206,21 @@
         updatePaused(isPaused, isPausedReason);
     }
 
-    private void updatePaused(boolean isPaused, String reason) {
+    private void updatePaused(boolean isPaused, ActiveGestureLog.CompoundString reason) {
         if (mDisallowPause) {
-            reason = "Disallow pause; otherwise, would have been " + isPaused + " due to " + reason;
+            reason = new ActiveGestureLog.CompoundString(
+                    "Disallow pause; otherwise, would have been ")
+                    .append(isPaused)
+                    .append(" due to reason:")
+                    .append(reason);
             isPaused = false;
         }
         if (mIsPaused != isPaused) {
             mIsPaused = isPaused;
-            String logString = "onMotionPauseChanged, paused=" + mIsPaused + " reason=" + reason;
-            if (Utilities.isRunningInTestHarness()) {
-                Log.d(TAG, logString);
-            }
-            ActiveGestureLog.INSTANCE.addLog(logString);
+            addLogs(new ActiveGestureLog.CompoundString("onMotionPauseChanged triggered; paused=")
+                    .append(mIsPaused)
+                    .append(", reason=")
+                    .append(reason));
             boolean isFirstDetectedPause = !mHasEverBeenPaused && mIsPaused;
             if (mIsPaused) {
                 AccessibilityManagerCompat.sendTestProtocolEventToTest(mContext,
@@ -219,6 +239,16 @@
         }
     }
 
+    private void addLogs(ActiveGestureLog.CompoundString compoundString) {
+        ActiveGestureLog.CompoundString logString =
+                new ActiveGestureLog.CompoundString("MotionPauseDetector: ")
+                        .append(compoundString);
+        if (Utilities.isRunningInTestHarness()) {
+            Log.d(TAG, logString.toString());
+        }
+        ActiveGestureLog.INSTANCE.addLog(logString);
+    }
+
     public void clear() {
         mVelocityProvider.clear();
         mPreviousVelocity = null;
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 0bb6b23..1152de2 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -38,10 +38,12 @@
 import android.graphics.RectF;
 import android.util.Log;
 import android.view.RemoteAnimationTarget;
+import android.view.animation.Interpolator;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.app.animation.Interpolators;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatedFloat;
@@ -76,6 +78,8 @@
 
     private final Rect mTaskRect = new Rect();
     private final Rect mFullTaskSize = new Rect();
+    private final Rect mCarouselTaskSize = new Rect();
+    private PointF mPivotOverride = null;
     private final PointF mPivot = new PointF();
     private DeviceProfile mDp;
     @StagePosition
@@ -95,6 +99,11 @@
     public final AnimatedFloat taskPrimaryTranslation = new AnimatedFloat();
     public final AnimatedFloat taskSecondaryTranslation = new AnimatedFloat();
 
+    // Carousel properties
+    public final AnimatedFloat carouselScale = new AnimatedFloat();
+    public final AnimatedFloat carouselPrimaryTranslation = new AnimatedFloat();
+    public final AnimatedFloat carouselSecondaryTranslation = new AnimatedFloat();
+
     // RecentsView properties
     public final AnimatedFloat recentsViewScale = new AnimatedFloat();
     public final AnimatedFloat fullScreenProgress = new AnimatedFloat();
@@ -109,9 +118,9 @@
     private Boolean mDrawsBelowRecents = null;
     private boolean mIsGridTask;
     private boolean mIsDesktopTask;
+    private boolean mScaleToCarouselTaskSize = false;
     private int mTaskRectTranslationX;
     private int mTaskRectTranslationY;
-    private int mPivotOffsetX;
 
     public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
         mContext = context;
@@ -124,6 +133,7 @@
         mOrientationStateId = mOrientationState.getStateId();
         Resources resources = context.getResources();
         mIsRecentsRtl = mOrientationState.getOrientationHandler().getRecentsRtlSetting(resources);
+        carouselScale.value = 1f;
     }
 
     /**
@@ -149,6 +159,11 @@
                     mOrientationState.getOrientationHandler());
         }
 
+        if (enableGridOnlyOverview()) {
+            mSizeStrategy.calculateCarouselTaskSize(mContext, mDp, mCarouselTaskSize,
+                    mOrientationState.getOrientationHandler());
+        }
+
         if (mSplitBounds != null) {
             // The task rect changes according to the staged split task sizes, but recents
             // fullscreen scale and pivot remains the same since the task fits into the existing
@@ -193,9 +208,18 @@
         }
         // Copy mFullTaskSize instead of updating it directly so it could be reused next time
         // without recalculating
-        Rect scaleRect = new Rect(mFullTaskSize);
-        scaleRect.offset(mTaskRectTranslationX + mPivotOffsetX, mTaskRectTranslationY);
-        return mOrientationState.getFullScreenScaleAndPivot(scaleRect, mDp, mPivot);
+        Rect scaleRect = new Rect();
+        if (mScaleToCarouselTaskSize) {
+            scaleRect.set(mCarouselTaskSize);
+        } else {
+            scaleRect.set(mFullTaskSize);
+        }
+        scaleRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
+        float scale = mOrientationState.getFullScreenScaleAndPivot(scaleRect, mDp, mPivot);
+        if (mPivotOverride != null) {
+            mPivot.set(mPivotOverride);
+        }
+        return scale;
     }
 
     /**
@@ -278,14 +302,64 @@
     /**
      * Adds animation for all the components corresponding to transition from an app to overview.
      */
-    public void addAppToOverviewAnim(PendingAnimation pa, TimeInterpolator interpolator) {
+    public void addAppToOverviewAnim(PendingAnimation pa, Interpolator interpolator) {
         pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 1, 0, interpolator);
-        if (enableGridOnlyOverview() && mDp.isTablet) {
-            int translationXToMiddle = mDp.widthPx / 2 - mFullTaskSize.centerX();
-            taskPrimaryTranslation.value = translationXToMiddle;
-            mPivotOffsetX = translationXToMiddle;
+        float fullScreenScale;
+        if (enableGridOnlyOverview() && mDp.isTablet && mDp.isGestureMode) {
+            // Move pivot to top right edge of the screen, to avoid task scaling down in opposite
+            // direction of app window movement, otherwise the animation will wiggle left and right.
+            // Also translate the app window to top right edge of the screen to simplify
+            // calculations.
+            taskPrimaryTranslation.value = mIsRecentsRtl
+                    ? mDp.widthPx - mFullTaskSize.right
+                    : -mFullTaskSize.left;
+            taskSecondaryTranslation.value = -mFullTaskSize.top;
+            mPivotOverride = new PointF(mIsRecentsRtl ? mDp.widthPx : 0, 0);
+
+            // Scale down to the carousel and use the carousel Rect to calculate fullScreenScale.
+            mScaleToCarouselTaskSize = true;
+            carouselScale.value = mCarouselTaskSize.width() / (float) mFullTaskSize.width();
+            fullScreenScale = getFullScreenScale();
+
+            float carouselPrimaryTranslationTarget = mIsRecentsRtl
+                    ? mCarouselTaskSize.right - mDp.widthPx
+                    : mCarouselTaskSize.left;
+            float carouselSecondaryTranslationTarget = mCarouselTaskSize.top;
+
+            // Expected carousel position's center is in the middle, and invariant of
+            // recentsViewScale.
+            float exceptedCarouselCenterX = mCarouselTaskSize.centerX();
+            // Animating carousel translations linearly will result in a curved path, therefore
+            // we'll need to calculate the expected translation at each recentsView scale. Luckily
+            // primary and secondary follow the same translation, and primary is used here due to
+            // it being simpler.
+            Interpolator carouselTranslationInterpolator = t -> {
+                // recentsViewScale is calculated rather than using recentsViewScale.value, so that
+                // this interpolator works independently even if recentsViewScale don't animate.
+                float recentsViewScale =
+                        Utilities.mapToRange(t, 0, 1, fullScreenScale, 1, Interpolators.LINEAR);
+                // Without the translation, the app window will animate from fullscreen into top
+                // right corner.
+                float expectedTaskCenterX = mIsRecentsRtl
+                        ? mDp.widthPx - mCarouselTaskSize.width() * recentsViewScale / 2f
+                        : mCarouselTaskSize.width() * recentsViewScale / 2f;
+                // Calculate the expected translation, then work back the animatedFraction that
+                // results in this value.
+                float carouselPrimaryTranslation =
+                        (exceptedCarouselCenterX - expectedTaskCenterX) / recentsViewScale;
+                return carouselPrimaryTranslation / carouselPrimaryTranslationTarget;
+            };
+
+            // Use addAnimatedFloat so this animation can later be canceled and animate to a
+            // different value in RecentsView.onPrepareGestureEndAnimation.
+            pa.addAnimatedFloat(carouselPrimaryTranslation, 0, carouselPrimaryTranslationTarget,
+                    carouselTranslationInterpolator);
+            pa.addAnimatedFloat(carouselSecondaryTranslation, 0, carouselSecondaryTranslationTarget,
+                    carouselTranslationInterpolator);
+        } else {
+            fullScreenScale = getFullScreenScale();
         }
-        pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, getFullScreenScale(), 1, interpolator);
+        pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, fullScreenScale, 1, interpolator);
     }
 
     /**
@@ -382,7 +456,7 @@
 
         float fullScreenProgress = Utilities.boundToRange(this.fullScreenProgress.value, 0, 1);
         mCurrentFullscreenParams.setProgress(fullScreenProgress, recentsViewScale.value,
-                /* taskViewScale= */1f);
+                carouselScale.value);
 
         // Apply thumbnail matrix
         float taskWidth = mTaskRect.width();
@@ -396,6 +470,13 @@
                 taskPrimaryTranslation.value);
         mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
                 taskSecondaryTranslation.value);
+
+        mMatrix.postScale(carouselScale.value, carouselScale.value, mPivot.x, mPivot.y);
+        mOrientationState.getOrientationHandler().setPrimary(mMatrix, MATRIX_POST_TRANSLATE,
+                carouselPrimaryTranslation.value);
+        mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
+                carouselSecondaryTranslation.value);
+
         mOrientationState.getOrientationHandler().setPrimary(
                 mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value);
 
@@ -420,15 +501,18 @@
             return;
         }
         Log.d(TAG, "progress: " + fullScreenProgress
+                + " carouselScale: " + carouselScale.value
                 + " recentsViewScale: " + recentsViewScale.value
                 + " crop: " + mTmpCropRect
                 + " radius: " + getCurrentCornerRadius()
                 + " taskW: " + taskWidth + " H: " + taskHeight
                 + " taskRect: " + mTaskRect
                 + " taskPrimaryT: " + taskPrimaryTranslation.value
+                + " taskSecondaryT: " + taskSecondaryTranslation.value
+                + " carouselPrimaryT: " + carouselPrimaryTranslation.value
+                + " carouselSecondaryT: " + carouselSecondaryTranslation.value
                 + " recentsPrimaryT: " + recentsViewPrimaryTranslation.value
                 + " recentsSecondaryT: " + recentsViewSecondaryTranslation.value
-                + " taskSecondaryT: " + taskSecondaryTranslation.value
                 + " recentsScroll: " + recentsViewScroll.value
                 + " pivot: " + mPivot
         );
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 9884d8d..f6afaf0 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -459,6 +459,7 @@
 
     @Nullable
     protected RemoteTargetHandle[] mRemoteTargetHandles;
+    protected final Rect mLastComputedCarouselTaskSize = new Rect();
     protected final Rect mLastComputedTaskSize = new Rect();
     protected final Rect mLastComputedGridSize = new Rect();
     protected final Rect mLastComputedGridTaskSize = new Rect();
@@ -2108,6 +2109,10 @@
             mSizeStrategy.calculateDesktopTaskSize(mActivity, mActivity.getDeviceProfile(),
                     mLastComputedDesktopTaskSize);
         }
+        if (enableGridOnlyOverview()) {
+            mSizeStrategy.calculateCarouselTaskSize(mActivity, dp, mLastComputedCarouselTaskSize,
+                    getPagedOrientationHandler());
+        }
 
         mTaskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
         mTopBottomRowHeightDiff =
@@ -2137,9 +2142,12 @@
         }
 
         float accumulatedTranslationX = 0;
-        float translateXToMiddle = enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet
-                ? mActivity.getDeviceProfile().widthPx / 2 - mLastComputedGridTaskSize.centerX()
-                : 0;
+        float translateXToMiddle = 0;
+        if (enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet) {
+            translateXToMiddle = mIsRtl
+                    ? mLastComputedCarouselTaskSize.right - mLastComputedTaskSize.right
+                    : mLastComputedCarouselTaskSize.left - mLastComputedTaskSize.left;
+        }
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = requireTaskViewAt(i);
             taskView.updateTaskSize();
@@ -2206,6 +2214,10 @@
         return mLastComputedDesktopTaskSize;
     }
 
+    public Rect getLastComputedCarouselTaskSize() {
+        return mLastComputedCarouselTaskSize;
+    }
+
     /** Gets the task size for modal state. */
     public void getModalTaskSize(Rect outRect) {
         mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
@@ -2675,6 +2687,9 @@
                     tvs.taskSecondaryTranslation.value = runningTaskSecondaryGridTranslation;
                 } else {
                     animatorSet.play(ObjectAnimator.ofFloat(this, RECENTS_GRID_PROGRESS, 1));
+                    animatorSet.play(tvs.carouselScale.animateToValue(1));
+                    animatorSet.play(tvs.carouselPrimaryTranslation.animateToValue(0));
+                    animatorSet.play(tvs.carouselSecondaryTranslation.animateToValue(0));
                     animatorSet.play(tvs.taskPrimaryTranslation.animateToValue(
                             runningTaskPrimaryGridTranslation));
                     animatorSet.play(tvs.taskSecondaryTranslation.animateToValue(
@@ -4411,12 +4426,13 @@
                 mTempPointF.set(mLastComputedTaskSize.centerX(), mLastComputedTaskSize.bottom);
             }
         } else {
-            mTempRect.set(mLastComputedTaskSize);
             // Only update pivot when it is tablet and not in grid yet, so the pivot is correct
             // for non-current tasks when swiping up to overview
             if (enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet
                     && !mOverviewGridEnabled) {
-                mTempRect.offset(mActivity.getDeviceProfile().widthPx / 2 - mTempRect.centerX(), 0);
+                mTempRect.set(mLastComputedCarouselTaskSize);
+            } else {
+                mTempRect.set(mLastComputedTaskSize);
             }
             getPagedViewOrientedState().getFullScreenScaleAndPivot(mTempRect,
                     mActivity.getDeviceProfile(), mTempPointF);
@@ -5117,7 +5133,12 @@
      * Returns the scale up required on the view, so that it coves the screen completely
      */
     public float getMaxScaleForFullScreen() {
-        getTaskSize(mTempRect);
+        if (enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet
+                && !mOverviewGridEnabled) {
+            mTempRect.set(mLastComputedCarouselTaskSize);
+        } else {
+            mTempRect.set(mLastComputedTaskSize);
+        }
         return getPagedViewOrientedState().getFullScreenScaleAndPivot(
                 mTempRect, mActivity.getDeviceProfile(), mTempPointF);
     }
@@ -5545,7 +5566,7 @@
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = requireTaskViewAt(i);
             float scrollDiff = taskView.getScrollAdjustment(showAsGrid);
-            int pageScroll = newPageScrolls[i] + (int) scrollDiff;
+            int pageScroll = newPageScrolls[i] + Math.round(scrollDiff);
             if ((mIsRtl && pageScroll < lastTaskScroll)
                     || (!mIsRtl && pageScroll > lastTaskScroll)) {
                 pageScroll = lastTaskScroll;
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 5057c38..55da160 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -23,6 +23,7 @@
 import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.launcher3.Flags.enableCursorHoverStates;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
 import static com.android.launcher3.Flags.enableOverviewIconMenu;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
@@ -1750,7 +1751,13 @@
             expectedHeight = boxHeight + thumbnailPadding;
 
             // Scale to to fit task Rect.
-            nonGridScale = taskWidth / (float) boxWidth;
+            if (enableGridOnlyOverview()) {
+                final Rect lastComputedCarouselTaskSize =
+                        getRecentsView().getLastComputedCarouselTaskSize();
+                nonGridScale = lastComputedCarouselTaskSize.width() / (float) taskWidth;
+            } else {
+                nonGridScale = taskWidth / (float) boxWidth;
+            }
 
             // Align to top of task Rect.
             boxTranslationY = (expectedHeight - thumbnailPadding - taskHeight) / 2.0f;
diff --git a/res/layout/widgets_two_pane_sheet.xml b/res/layout/widgets_two_pane_sheet.xml
index cd7f2e1..f692e24 100644
--- a/res/layout/widgets_two_pane_sheet.xml
+++ b/res/layout/widgets_two_pane_sheet.xml
@@ -116,6 +116,7 @@
                         android:clipToOutline="true"
                         android:paddingBottom="36dp"
                         android:background="@drawable/widgets_surface_background"
+                        android:importantForAccessibility="yes"
                         android:id="@+id/right_pane">
                         <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
                             android:id="@+id/recommended_widget_table"
diff --git a/res/values-ldrtl/strings.xml b/res/values-ldrtl/strings.xml
new file mode 100644
index 0000000..118b499
--- /dev/null
+++ b/res/values-ldrtl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+* Copyright (C) 2008 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- General -->
+    <skip />
+
+    <!-- accessibilityPaneTitle for the right pane when showing suggested widgets. -->
+    <string name="widget_picker_right_pane_accessibility_title"><xliff:g id="selected_header" example="Calendar">%1$s</xliff:g> widgets on left, search and options on right</string>
+</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5cc4616..a4e7ec4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -77,6 +77,8 @@
     <string name="fitness_widget_recommendation_category_label">Reach Your Fitness Goals</string>
     <string name="weather_widget_recommendation_category_label">Stay Ahead of the Weather</string>
     <string name="others_widget_recommendation_category_label">You Might Also Like</string>
+    <!-- accessibilityPaneTitle for the right pane when showing suggested widgets. -->
+    <string name="widget_picker_right_pane_accessibility_title"><xliff:g id="selected_header" example="Calendar">%1$s</xliff:g> widgets on right, search and options on left</string>
     <!-- Label for showing the number of widgets an app has in the full widgets picker.
          [CHAR_LIMIT=25][ICU SYNTAX] -->
     <string name="widgets_count">
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index 5172999..f6bc1f1 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -178,7 +178,10 @@
         val hadWorkApps = launcher.appsView.shouldShowTabs()
         launcher.appsView.appsStore.setApps(apps, flags, packageUserKeytoUidMap)
         PopupContainerWithArrow.dismissInvalidPopup(launcher)
-        if (hadWorkApps != launcher.appsView.shouldShowTabs()) {
+        if (
+            hadWorkApps != launcher.appsView.shouldShowTabs() &&
+                launcher.stateManager.state == LauncherState.ALL_APPS
+        ) {
             launcher.stateManager.goToState(LauncherState.NORMAL)
         }
     }
diff --git a/src/com/android/launcher3/anim/AnimatedFloat.java b/src/com/android/launcher3/anim/AnimatedFloat.java
index 2f3fa63..b414ab6 100644
--- a/src/com/android/launcher3/anim/AnimatedFloat.java
+++ b/src/com/android/launcher3/anim/AnimatedFloat.java
@@ -109,6 +109,13 @@
     public void cancelAnimation() {
         if (mValueAnimator != null) {
             mValueAnimator.cancel();
+            // Clears the property values, so further ObjectAnimator#setCurrentFraction from e.g.
+            // AnimatorPlaybackController calls would do nothing. The null check is necessary to
+            // avoid mValueAnimator being set to null in onAnimationEnd.
+            if (mValueAnimator != null) {
+                mValueAnimator.setValues();
+                mValueAnimator = null;
+            }
         }
     }
 
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index 586beb2..e58890f 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -83,6 +83,20 @@
         add(anim);
     }
 
+    /**
+     * Add an {@link AnimatedFloat} to the animation.
+     * <p>
+     * Different from {@link #addFloat}, this method use animator provided by
+     * {@link AnimatedFloat#animateToValue}, which tracks the animator inside the AnimatedFloat,
+     * allowing the animation to be canceled and animate again from AnimatedFloat side.
+     */
+    public void addAnimatedFloat(AnimatedFloat target, float from, float to,
+            TimeInterpolator interpolator) {
+        Animator anim = target.animateToValue(from, to);
+        anim.setInterpolator(interpolator);
+        add(anim);
+    }
+
     /** If trace is enabled, add counter to trace animation progress. */
     public void logAnimationProgressToTrace(String counterName) {
         if (Trace.isEnabled()) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 28bae59..4e704fd 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -20,15 +20,16 @@
 import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_DIALOG_SEEN;
+import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
 import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
 
 import android.animation.Animator;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.os.Build;
+import android.os.Parcelable;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -99,7 +100,6 @@
     // resolution or landscape on phone. This ratio defines the max percentage of content area that
     // the table can display.
     private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f;
-
     private final UserCache mUserCache;
     private final UserManagerState mUserManagerState = new UserManagerState();
     private final UserHandle mCurrentUser = Process.myUserHandle();
@@ -522,11 +522,13 @@
     }
 
     @Override
-    public void enterSearchMode() {
+    public void enterSearchMode(boolean shouldLog) {
         if (mIsInSearchMode) return;
         setViewVisibilityBasedOnSearch(/*isInSearchMode= */ true);
         attachScrollbarToRecyclerView(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView);
-        mActivityContext.getStatsLogManager().logger().log(LAUNCHER_WIDGETSTRAY_SEARCHED);
+        if (shouldLog) {
+            mActivityContext.getStatsLogManager().logger().log(LAUNCHER_WIDGETSTRAY_SEARCHED);
+        }
     }
 
     @Override
@@ -789,16 +791,28 @@
                 + marginLayoutParams.topMargin;
     }
 
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
+    private int getCurrentAdapterHolderType() {
         if (mIsInSearchMode) {
-            mSearchBar.reset();
+            return SEARCH;
+        } else if (mViewPager != null) {
+            return mViewPager.getCurrentPage();
+        } else {
+            return AdapterHolder.PRIMARY;
+        }
+    }
+
+    private void restorePreviousAdapterHolderType(int previousAdapterHolderType) {
+        if (previousAdapterHolderType == AdapterHolder.WORK && mViewPager != null) {
+            mViewPager.setCurrentPage(previousAdapterHolderType);
+        } else if (previousAdapterHolderType == AdapterHolder.SEARCH) {
+            enterSearchMode(false);
         }
     }
 
     @Override
     public void onDeviceProfileChanged(DeviceProfile dp) {
+        super.onDeviceProfileChanged(dp);
+
         if (mDeviceProfile.isLandscape != dp.isLandscape && dp.isTablet && !dp.isTwoPanels) {
             handleClose(false);
             show(BaseActivity.fromContext(getContext()), false);
@@ -810,8 +824,12 @@
         // When folding/unfolding the foldables, we need to switch between the regular widget picker
         // and the two pane picker, so we rebuild the picker with the correct layout.
         if (mDeviceProfile.isTwoPanels != dp.isTwoPanels && enableUnfoldedTwoPanePicker()) {
+            SparseArray<Parcelable> widgetsState = new SparseArray<>();
+            saveHierarchyState(widgetsState);
             handleClose(false);
-            show(BaseActivity.fromContext(getContext()), false);
+            WidgetsFullSheet sheet = show(BaseActivity.fromContext(getContext()), false);
+            sheet.restoreHierarchyState(widgetsState);
+            sheet.restorePreviousAdapterHolderType(getCurrentAdapterHolderType());
         }
 
         mDeviceProfile = dp;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index 5a1ec87..744c45b 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -18,7 +18,6 @@
 import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
 
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.Outline;
 import android.graphics.Rect;
 import android.os.Process;
@@ -127,10 +126,6 @@
         mFastScroller.setVisibility(GONE);
     }
 
-    /** Overrides onConfigurationChanged method from WidgetsFullSheet. Needed for b/319150904 */
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {}
-
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
@@ -200,10 +195,14 @@
                 return false;
             }
         };
-        packageItemInfo.title = getContext().getString(R.string.suggested_widgets_header_title);
+        String suggestionsHeaderTitle = getContext().getString(
+                R.string.suggested_widgets_header_title);
+        String suggestionsRightPaneTitle = getContext().getString(
+                R.string.widget_picker_right_pane_accessibility_title, suggestionsHeaderTitle);
+        packageItemInfo.title = suggestionsHeaderTitle;
         WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
                         packageItemInfo,
-                        getContext().getString(R.string.suggested_widgets_header_title),
+                        suggestionsHeaderTitle,
                         mActivityContext.getPopupDataProvider().getRecommendedWidgets())
                 .withWidgetListShown();
 
@@ -216,10 +215,12 @@
             mRightPane.removeAllViews();
             mRightPane.addView(mRecommendedWidgetsTable);
             mRightPaneScrollView.setScrollY(0);
+            mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
             mSuggestedWidgetsPackageUserKey = PackageUserKey.fromPackageItemInfo(packageItemInfo);
             mSelectedHeader = mSuggestedWidgetsPackageUserKey;
         });
         mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader);
+        mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
     }
 
     @Override
@@ -322,6 +323,10 @@
                 mRightPane.removeAllViews();
                 mRightPane.addView(widgetsRowViewHolder.itemView);
                 mRightPaneScrollView.setScrollY(0);
+                mRightPane.setAccessibilityPaneTitle(
+                        getContext().getString(
+                                R.string.widget_picker_right_pane_accessibility_title,
+                                contentEntry.mPkgItem.title));
             }
         };
     }
diff --git a/src/com/android/launcher3/widget/picker/search/SearchModeListener.java b/src/com/android/launcher3/widget/picker/search/SearchModeListener.java
index cee7d67..b2620d0 100644
--- a/src/com/android/launcher3/widget/picker/search/SearchModeListener.java
+++ b/src/com/android/launcher3/widget/picker/search/SearchModeListener.java
@@ -26,7 +26,7 @@
     /**
      * Notifies the subscriber when user enters widget picker search mode.
      */
-    void enterSearchMode();
+    void enterSearchMode(boolean shouldLog);
 
     /**
      * Notifies the subscriber when user exits widget picker search mode.
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
index a15508a..2d96cbd 100644
--- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
+++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
@@ -70,7 +70,7 @@
             mCancelButton.setVisibility(GONE);
         } else {
             mSearchAlgorithm.cancel(/* interruptActiveRequests= */ false);
-            mSearchModeListener.enterSearchMode();
+            mSearchModeListener.enterSearchMode(true);
             mSearchAlgorithm.doSearch(mQuery, this);
             mCancelButton.setVisibility(VISIBLE);
         }
diff --git a/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java b/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
index 583d37f..8457ac6 100644
--- a/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
@@ -78,7 +78,7 @@
     public void afterTextChanged_shouldInformSearchModeListenerToEnterSearch() {
         mEditText.setText("abc");
 
-        verify(mSearchModeListener).enterSearchMode();
+        verify(mSearchModeListener).enterSearchMode(true);
         verifyNoMoreInteractions(mSearchModeListener);
     }