Merge "Use aconfig flag enable_split_contextual" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 874f862..5f4e1b6 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -41,3 +41,10 @@
     description: "Enable updated overview icon and menu within task."
     bug: "257950105"
 }
+
+flag {
+    name: "enable_taskbar_no_recreate"
+    namespace: "launcher"
+    description: "Enables taskbar with no recreation from lifecycle changes of TaskbarActivityContext."
+    bug: "299193589"
+}
diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml
index ee594c8..2b17b93 100644
--- a/quickstep/res/values-land/dimens.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -84,4 +84,5 @@
 
     <dimen name="keyboard_quick_switch_taskview_width">205dp</dimen>
     <dimen name="keyboard_quick_switch_taskview_height">119dp</dimen>
+
 </resources>
diff --git a/quickstep/res/values-sw600dp-land/dimens.xml b/quickstep/res/values-sw600dp-land/dimens.xml
index 9cb3fec..5e9a177 100644
--- a/quickstep/res/values-sw600dp-land/dimens.xml
+++ b/quickstep/res/values-sw600dp-land/dimens.xml
@@ -27,4 +27,10 @@
     <dimen name="gesture_tutorial_menu_done_button_top_spacing">40dp</dimen>
     <dimen name="gesture_tutorial_menu_back_shape_bottom_margin">49dp</dimen>
 
+    <!-- Grid Only Overview -->
+    <!-- The top margin above the top row of tasks in grid only overview -->
+    <dimen name="overview_top_margin_grid_only">24dp</dimen>
+    <!-- The bottom margin above the bottom row of tasks in grid only overview -->
+    <dimen name="overview_bottom_margin_grid_only">40dp</dimen>
+
 </resources>
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
index daf1f63..f9528b3 100644
--- a/quickstep/res/values-sw600dp/dimens.xml
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -33,6 +33,10 @@
     <dimen name="overview_page_spacing">36dp</dimen>
     <!--  The space to the left and to the right of the "Clear all" button  -->
     <dimen name="overview_grid_side_margin">64dp</dimen>
+    <!-- The top margin above the top row of tasks in grid only overview -->
+    <dimen name="overview_top_margin_grid_only">80dp</dimen>
+    <!-- The bottom margin above the bottom row of tasks in grid only overview -->
+    <dimen name="overview_bottom_margin_grid_only">80dp</dimen>
     <!--  Overview actions  -->
     <dimen name="overview_actions_top_margin">24dp</dimen>
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index d4d6b26..50e2a51 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -29,8 +29,8 @@
 import static com.android.launcher3.Flags.enableCursorHoverStates;
 import static com.android.launcher3.Utilities.calculateTextHeight;
 import static com.android.launcher3.Utilities.isRunningInTestHarness;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NO_RECREATION;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_PINNING;
+import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
 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;
@@ -339,7 +339,7 @@
             mIsDestroyed = false;
         }
 
-        if (!ENABLE_TASKBAR_NO_RECREATION.get() && !mAddedWindow) {
+        if (!enableTaskbarNoRecreate() && !mAddedWindow) {
             mWindowManager.addView(mDragLayer, mWindowLayoutParams);
             mAddedWindow = true;
         } else {
@@ -695,7 +695,7 @@
         mIsDestroyed = true;
         setUIController(TaskbarUIController.DEFAULT);
         mControllers.onDestroy();
-        if (!ENABLE_TASKBAR_NO_RECREATION.get() && !FLAG_HIDE_NAVBAR_WINDOW) {
+        if (!enableTaskbarNoRecreate() && !FLAG_HIDE_NAVBAR_WINDOW) {
             mWindowManager.removeViewImmediate(mDragLayer);
             mAddedWindow = false;
         }
@@ -1290,7 +1290,7 @@
 
     void notifyUpdateLayoutParams() {
         if (mDragLayer.isAttachedToWindow()) {
-            if (ENABLE_TASKBAR_NO_RECREATION.get()) {
+            if (enableTaskbarNoRecreate()) {
                 mWindowManager.updateViewLayout(mDragLayer.getRootView(), mWindowLayoutParams);
             } else {
                 mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 6dfd243..6f2dee9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -23,7 +23,7 @@
 import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
 import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_KEY;
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NO_RECREATION;
+import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
 import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
@@ -210,7 +210,7 @@
         Display display =
                 service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
         mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
-        if (ENABLE_TASKBAR_NO_RECREATION.get()) {
+        if (enableTaskbarNoRecreate()) {
             mWindowManager = mContext.getSystemService(WindowManager.class);
             mTaskbarRootLayout = new FrameLayout(mContext) {
                 @Override
@@ -308,7 +308,7 @@
             LauncherPrefs.get(mContext).removeListener(mTaskbarPinningPreferenceChangeListener,
                     TASKBAR_PINNING);
             mTaskbarActivityContext.onDestroy();
-            if (!FLAG_HIDE_NAVBAR_WINDOW || ENABLE_TASKBAR_NO_RECREATION.get()) {
+            if (!FLAG_HIDE_NAVBAR_WINDOW || enableTaskbarNoRecreate()) {
                 mTaskbarActivityContext = null;
             }
         }
@@ -448,7 +448,7 @@
                 return;
             }
 
-            if (ENABLE_TASKBAR_NO_RECREATION.get() || mTaskbarActivityContext == null) {
+            if (enableTaskbarNoRecreate() || mTaskbarActivityContext == null) {
                 mTaskbarActivityContext = new TaskbarActivityContext(mContext, dp,
                         mNavButtonController, mUnfoldProgressProvider);
             } else {
@@ -461,7 +461,7 @@
                     createTaskbarUIControllerForActivity(mActivity));
             }
 
-            if (ENABLE_TASKBAR_NO_RECREATION.get()) {
+            if (enableTaskbarNoRecreate()) {
                 addTaskbarRootViewToWindow();
                 mTaskbarRootLayout.removeAllViews();
                 mTaskbarRootLayout.addView(mTaskbarActivityContext.getDragLayer());
@@ -603,8 +603,7 @@
     }
 
     private void addTaskbarRootViewToWindow() {
-        if (ENABLE_TASKBAR_NO_RECREATION.get() && !mAddedWindow
-                && mTaskbarActivityContext != null) {
+        if (enableTaskbarNoRecreate() && !mAddedWindow && mTaskbarActivityContext != null) {
             mWindowManager.addView(mTaskbarRootLayout,
                     mTaskbarActivityContext.getWindowLayoutParams());
             mAddedWindow = true;
@@ -612,7 +611,7 @@
     }
 
     private void removeTaskbarRootViewFromWindow() {
-        if (ENABLE_TASKBAR_NO_RECREATION.get() && mAddedWindow) {
+        if (enableTaskbarNoRecreate() && mAddedWindow) {
             mWindowManager.removeViewImmediate(mTaskbarRootLayout);
             mAddedWindow = false;
         }
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 25389c5..88933f4 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -267,7 +267,7 @@
         Resources res = context.getResources();
         float maxScale = res.getFloat(R.dimen.overview_max_scale);
         Rect gridRect = new Rect();
-        calculateGridSize(dp, gridRect);
+        calculateGridSize(dp, context, gridRect);
         calculateTaskSizeInternal(context, dp, gridRect, maxScale, Gravity.CENTER, outRect);
     }
 
@@ -321,10 +321,16 @@
     /**
      * Calculates the overview grid size for the provided device configuration.
      */
-    public final void calculateGridSize(DeviceProfile dp, Rect outRect) {
+    public final void calculateGridSize(DeviceProfile dp, Context context, Rect outRect) {
         Rect insets = dp.getInsets();
         int topMargin = dp.overviewTaskThumbnailTopMarginPx;
         int bottomMargin = dp.getOverviewActionsClaimedSpace();
+        if (dp.isTaskbarPresent && Flags.enableGridOnlyOverview()) {
+            topMargin += context.getResources().getDimensionPixelSize(
+                    R.dimen.overview_top_margin_grid_only);
+            bottomMargin += context.getResources().getDimensionPixelSize(
+                    R.dimen.overview_bottom_margin_grid_only);
+        }
         int sideMargin = dp.overviewGridSideMargin;
 
         outRect.set(0, 0, dp.widthPx, dp.heightPx);
@@ -340,7 +346,7 @@
         Resources res = context.getResources();
         Rect potentialTaskRect = new Rect();
         if (Flags.enableGridOnlyOverview()) {
-            calculateGridSize(dp, potentialTaskRect);
+            calculateGridSize(dp, context, potentialTaskRect);
         } else {
             calculateFocusTaskSize(context, dp, potentialTaskRect);
         }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 3fdc7ba..8d26fd4 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE;
 import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
@@ -60,6 +61,8 @@
 import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
 
+import com.android.launcher3.LauncherPrefs;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
 import com.android.launcher3.util.DisplayController.Info;
@@ -86,8 +89,8 @@
     static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
 
     // TODO: Move to quickstep contract
-    private static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 9;
-    private static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 2;
+    private static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 3f;
+    private static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 1.414f;
 
     private final Context mContext;
     private final DisplayController mDisplayController;
@@ -546,15 +549,31 @@
 
     /**
      * Returns the touch slop for {@link InputConsumer}s to compare against before pilfering
-     * pointers. Note that this is squared because it expects to be compared against
-     * {@link com.android.launcher3.Utilities#squaredHypot} (to avoid square root on each event).
+     * pointers.
      */
-    public float getSquaredTouchSlop() {
+    public float getTouchSlop() {
         float slopMultiplier = isFullyGesturalNavMode()
                 ? QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL
                 : QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON;
         float touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
-        return slopMultiplier * touchSlop * touchSlop;
+
+        if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
+            float customSlopMultiplier =
+                    LauncherPrefs.get(mContext).get(LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE) / 100f;
+            return customSlopMultiplier * slopMultiplier * touchSlop;
+        } else {
+            return slopMultiplier * touchSlop;
+        }
+    }
+
+    /**
+     * Returns the squared touch slop for {@link InputConsumer}s to compare against before pilfering
+     * pointers. Note that this is squared because it expects to be compared against
+     * {@link com.android.launcher3.Utilities#squaredHypot} (to avoid square root on each event).
+     */
+    public float getSquaredTouchSlop() {
+        float touchSlop = getTouchSlop();
+        return touchSlop * touchSlop;
     }
 
     public String getSystemUiStateString() {
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index cf74b7d..312cdc9 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -190,11 +190,11 @@
          */
         public void endLiveTileMode(@NonNull Runnable callback) {
             RecentsView recentsView = mThumbnailView.getTaskView().getRecentsView();
-            if (recentsView != null) {
-                recentsView.switchToScreenshot(
-                        () -> recentsView.finishRecentsAnimation(true /* toRecents */,
-                                false /* shouldPip */, callback));
-            }
+            // Task has already been dismissed
+            if (recentsView == null) return;
+            recentsView.switchToScreenshot(
+                    () -> recentsView.finishRecentsAnimation(true /* toRecents */,
+                            false /* shouldPip */, callback));
         }
 
         /**
@@ -212,6 +212,8 @@
 
         private void enterSplitSelect() {
             RecentsView overviewPanel = mThumbnailView.getTaskView().getRecentsView();
+            // Task has already been dismissed
+            if (overviewPanel == null) return;
             overviewPanel.initiateSplitSelect(mThumbnailView.getTaskView());
         }
 
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index b2f04b8..98a9938 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -963,7 +963,8 @@
                         .append(SUBSTRING_PREFIX)
                         .append("Long press nav handle enabled, ")
                         .append("using NavHandleLongPressInputConsumer");
-                base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat);
+                base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat,
+                        mDeviceState);
             }
 
             if (mDeviceState.isBubblesExpanded()) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index f11e537..32f7bd5 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -15,7 +15,6 @@
  */
 package com.android.quickstep.inputconsumers;
 
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE;
 import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_TIMEOUT_MS;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
@@ -28,6 +27,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.InputConsumer;
+import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.systemui.shared.system.InputMonitorCompat;
 
 /**
@@ -47,23 +47,18 @@
     private MotionEvent mCurrentDownEvent;
 
     public NavHandleLongPressInputConsumer(Context context, InputConsumer delegate,
-            InputMonitorCompat inputMonitor) {
+            InputMonitorCompat inputMonitor, RecentsAnimationDeviceState deviceState) {
         super(delegate, inputMonitor);
         mViewConfiguration = ViewConfiguration.get(context);
         mNavHandleWidth = context.getResources().getDimensionPixelSize(
                 R.dimen.navigation_home_handle_width);
         mScreenWidth = DisplayController.INSTANCE.get(context).getInfo().currentSize.x;
-        float touchSlop;
         if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
-            float customSlopMultiplier =
-                    LauncherPrefs.get(context).get(LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE) / 100f;
-            touchSlop = mViewConfiguration.getScaledEdgeSlop() * customSlopMultiplier;
             mLongPressTimeout = LauncherPrefs.get(context).get(LONG_PRESS_NAV_HANDLE_TIMEOUT_MS);
         } else {
-            touchSlop = mViewConfiguration.getScaledTouchSlop();
             mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
         }
-        mTouchSlopSquared = touchSlop * touchSlop;
+        mTouchSlopSquared = deviceState.getSquaredTouchSlop();
         mNavHandleLongPressHandler = NavHandleLongPressHandler.newInstance(context);
     }
 
@@ -87,17 +82,14 @@
                 }
             }
             case MotionEvent.ACTION_MOVE -> {
+                if (!MAIN_EXECUTOR.getHandler().hasCallbacks(mTriggerLongPress)) {
+                    break;
+                }
+
                 float touchSlopSquared = mTouchSlopSquared;
                 float dx = ev.getX() - mCurrentDownEvent.getX();
                 float dy = ev.getY() - mCurrentDownEvent.getY();
                 double distanceSquared = (dx * dx) + (dy * dy);
-                // If the gesture is ambiguous then require more movement before classifying this
-                // as a NON long press gesture.
-                if (ev.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE) {
-                    float ambiguousGestureMultiplier =
-                            mViewConfiguration.getScaledAmbiguousGestureMultiplier();
-                    touchSlopSquared *= ambiguousGestureMultiplier * ambiguousGestureMultiplier;
-                }
                 if (distanceSquared > touchSlopSquared) {
                     cancelLongPress();
                 }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 28c00eb..e724547 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -40,7 +40,6 @@
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
-import android.view.ViewConfiguration;
 
 import androidx.annotation.UiThread;
 
@@ -154,7 +153,7 @@
         boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning();
         mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget;
 
-        mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
+        mTouchSlop = mDeviceState.getTouchSlop();
         mSquaredTouchSlop = mDeviceState.getSquaredTouchSlop();
 
         mPassedPilferInputSlop = mPassedWindowMoveSlop = continuingPreviousGesture;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index b27035e..b3d8da7 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2064,7 +2064,7 @@
                 dp.widthPx - mInsets.right - mTempRect.right,
                 dp.heightPx - mInsets.bottom - mTempRect.bottom);
 
-        mSizeStrategy.calculateGridSize(mActivity.getDeviceProfile(),
+        mSizeStrategy.calculateGridSize(mActivity.getDeviceProfile(), mActivity,
                 mLastComputedGridSize);
         mSizeStrategy.calculateGridTaskSize(mActivity, mActivity.getDeviceProfile(),
                 mLastComputedGridTaskSize, mOrientationHandler);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index beb10ef..fec17b4 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -1677,6 +1677,7 @@
         return super.performAccessibilityAction(action, arguments);
     }
 
+    @Nullable
     public RecentsView getRecentsView() {
         return (RecentsView) getParent();
     }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index eba3252..f6368b0 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -82,7 +82,7 @@
         taskMenu.touchOutsideTaskMenuToDismiss();
 
         OverviewTaskMenu splitMenu =
-                mLauncher.getOverview().getCurrentTask().tapSplitTaskMenu();
+                mLauncher.goHome().switchToOverview().getCurrentTask().tapSplitTaskMenu();
         assertTrue("App info item not appearing in expanded split task's menu.",
                 splitMenu.hasMenuItem("App info"));
         splitMenu.touchOutsideTaskMenuToDismiss();
diff --git a/res/values/config.xml b/res/values/config.xml
index cd9c9de..4b15a6b 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -242,6 +242,8 @@
         <item>@dimen/iconSize72dp</item>
     </integer-array>
 
+    <dimen name="minimum_icon_label_size">8sp</dimen>
+
     <!--  Used for custom widgets  -->
     <array name="custom_widget_providers"/>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index e532dad..81c2337 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -412,6 +412,9 @@
     <dimen name="overview_grid_side_margin">0dp</dimen>
     <dimen name="overview_grid_row_spacing">0dp</dimen>
     <dimen name="overview_page_spacing">0dp</dimen>
+    <dimen name="overview_top_margin_grid_only">0dp</dimen>
+    <dimen name="overview_bottom_margin_grid_only">0dp</dimen>
+
     <dimen name="split_placeholder_size">72dp</dimen>
     <dimen name="split_placeholder_inset">16dp</dimen>
     <dimen name="split_placeholder_icon_size">44dp</dimen>
@@ -423,7 +426,7 @@
     <dimen name="split_instructions_drawable_padding">10dp</dimen>
     <dimen name="split_instructions_bottom_margin_phone_landscape">24dp</dimen>
     <dimen name="split_instructions_bottom_margin_phone_portrait">60dp</dimen>
-    
+
     <!-- Workspace grid visualization parameters -->
     <dimen name="grid_visualization_rounding_radius">28dp</dimen>
     <dimen name="grid_visualization_horizontal_cell_spacing">6dp</dimen>
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2ac6098..bdffe46 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -63,6 +63,7 @@
 import com.android.launcher3.responsive.HotseatSpecs;
 import com.android.launcher3.responsive.WorkspaceSpecs;
 import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.CellContentDimensions;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.IconSizeSteps;
@@ -299,6 +300,7 @@
     public final int stashedTaskbarHeight;
     public final int taskbarBottomMargin;
     public final int taskbarIconSize;
+    private final int mTransientTaskbarClaimedSpace;
     // If true, used to layout taskbar in 3 button navigation mode.
     public final boolean startAlignTaskbar;
     public final boolean isTransientTaskbar;
@@ -370,18 +372,23 @@
         }
 
         this.isTransientTaskbar = isTransientTaskbar;
+        int transientTaskbarIconSize = pxFromDp(inv.transientTaskbarIconSize[mTypeIndex], mMetrics);
+        int transientTaskbarBottomMargin =
+                res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin);
+        int transientTaskbarHeight =
+                Math.round((transientTaskbarIconSize * ICON_VISIBLE_AREA_FACTOR)
+                    + (2 * res.getDimensionPixelSize(R.dimen.transient_taskbar_padding)));
+        mTransientTaskbarClaimedSpace = transientTaskbarHeight + 2 * transientTaskbarBottomMargin;
+
         if (!isTaskbarPresent) {
             taskbarIconSize = taskbarHeight = stashedTaskbarHeight = taskbarBottomMargin = 0;
             startAlignTaskbar = false;
         } else if (isTransientTaskbar) {
-            float invTransientIconSizeDp = inv.transientTaskbarIconSize[mTypeIndex];
-            taskbarIconSize = pxFromDp(invTransientIconSizeDp, mMetrics);
-            taskbarHeight = Math.round((taskbarIconSize * ICON_VISIBLE_AREA_FACTOR)
-                    + (2 * res.getDimensionPixelSize(R.dimen.transient_taskbar_padding)));
+            taskbarIconSize = transientTaskbarIconSize;
+            taskbarHeight = transientTaskbarHeight;
             stashedTaskbarHeight =
                     res.getDimensionPixelSize(R.dimen.transient_taskbar_stashed_height);
-            taskbarBottomMargin =
-                    res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin);
+            taskbarBottomMargin = transientTaskbarBottomMargin;
             startAlignTaskbar = false;
         } else {
             taskbarIconSize = pxFromDp(ResourcesCompat.getFloat(res, R.dimen.taskbar_icon_size),
@@ -924,14 +931,11 @@
                 - iconTextHeight;
 
         if (mIsResponsiveGrid) {
-            // Hide text only if doesn't fit inside the cell for responsive grid
-            if (workspaceCellPaddingY < 0) {
-                iconTextSizePx = 0;
-                iconDrawablePaddingPx = 0;
-                int iconSizeWithOverlap = getIconSizeWithOverlap(iconSizePx);
-                cellYPaddingPx = Math.max(0, getCellSize().y - iconSizeWithOverlap) / 2;
-                autoResizeAllAppsCells();
-            }
+            iconTextSizePx = 0;
+            iconDrawablePaddingPx = 0;
+            int iconSizeWithOverlap = getIconSizeWithOverlap(iconSizePx);
+            cellYPaddingPx = Math.max(0, getCellSize().y - iconSizeWithOverlap) / 2;
+            autoResizeAllAppsCells();
 
             return;
         }
@@ -1047,22 +1051,23 @@
                 iconSizePx = mIconSizeSteps.getIconSmallerThan(cellWidthPx);
             }
 
-            // TODO(b/296400197): isVerticalBar shouldn't show labels anymore
             iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
-            int iconTextHeight = Utilities.calculateTextHeight(iconTextSizePx);
-            int cellContentHeight = iconSizePx + iconDrawablePaddingPx + iconTextHeight;
 
-            while (iconSizePx > mIconSizeSteps.minimumIconSize()
-                    && cellContentHeight > cellHeightPx) {
-                iconDrawablePaddingPx -= cellContentHeight - cellHeightPx;
-                if (iconDrawablePaddingPx < 0) {
-                    // get a smaller icon size
-                    iconSizePx = mIconSizeSteps.getNextLowerIconSize(iconSizePx);
-                    iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
+            CellContentDimensions cellContentDimensions = new CellContentDimensions(iconSizePx,
+                    iconDrawablePaddingPx,
+                    iconTextSizePx);
+            if (isVerticalLayout) {
+                if (cellHeightPx < iconSizePx) {
+                    cellContentDimensions.setIconSizePx(
+                            mIconSizeSteps.getIconSmallerThan(cellHeightPx));
                 }
-                // calculate new cellContentHeight
-                cellContentHeight = iconSizePx + iconDrawablePaddingPx + iconTextHeight;
+            } else {
+                cellContentDimensions.resizeToFitCellHeight(cellHeightPx, mIconSizeSteps);
             }
+            iconSizePx = cellContentDimensions.getIconSizePx();
+            iconDrawablePaddingPx = cellContentDimensions.getIconDrawablePaddingPx();
+            iconTextSizePx = cellContentDimensions.getIconTextSizePx();
+            int cellContentHeight = cellContentDimensions.getCellContentHeight();
 
             cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2;
         } else if (mIsScalableGrid) {
@@ -1760,14 +1765,9 @@
         return getHotseatBarBottomPadding() + launcherIconBottomSpace - taskbarIconBottomSpace;
     }
 
-    /**
-     * Returns the number of pixels required below OverviewActions excluding insets.
-     */
+    /** Returns the number of pixels required below OverviewActions. */
     public int getOverviewActionsClaimedSpaceBelow() {
-        if (isTaskbarPresent) {
-            return taskbarHeight + taskbarBottomMargin * 2;
-        }
-        return mInsets.bottom;
+        return isTaskbarPresent ? mTransientTaskbarClaimedSpace : mInsets.bottom;
     }
 
     /** Gets the space that the overview actions will take, including bottom margin. */
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 510b9a6..4d8166c 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -202,9 +202,13 @@
     public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(270395798,
             "ENABLE_TRANSIENT_TASKBAR", ENABLED, "Enables transient taskbar.");
 
+    // Aconfig migration complete for ENABLE_TASKBAR_NO_RECREATION.
     public static final BooleanFlag ENABLE_TASKBAR_NO_RECREATION = getDebugFlag(299193589,
             "ENABLE_TASKBAR_NO_RECREATION", DISABLED,
             "Enables taskbar with no recreation from lifecycle changes of TaskbarActivityContext.");
+    public static boolean enableTaskbarNoRecreate() {
+        return ENABLE_TASKBAR_NO_RECREATION.get() || Flags.enableTaskbarNoRecreate();
+    }
 
     // TODO(Block 16): Clean up flags
     // When enabled the promise icon is visible in all apps while installation an app.
diff --git a/src/com/android/launcher3/util/CellContentDimensions.kt b/src/com/android/launcher3/util/CellContentDimensions.kt
new file mode 100644
index 0000000..3c8e0c4
--- /dev/null
+++ b/src/com/android/launcher3/util/CellContentDimensions.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+package com.android.launcher3.util
+
+import com.android.launcher3.Utilities
+import kotlin.math.max
+
+class CellContentDimensions(
+    var iconSizePx: Int,
+    var iconDrawablePaddingPx: Int,
+    var iconTextSizePx: Int
+) {
+    /**
+     * This method goes through some steps to reduce the padding between icon and label, icon size
+     * and then label size, until it can fit in the [cellHeightPx].
+     *
+     * @return the height of the content after being sized down.
+     */
+    fun resizeToFitCellHeight(cellHeightPx: Int, iconSizeSteps: IconSizeSteps): Int {
+        var cellContentHeight = getCellContentHeight()
+
+        // Step 1. Decrease drawable padding
+        if (cellContentHeight > cellHeightPx) {
+            val diff = cellContentHeight - cellHeightPx
+            iconDrawablePaddingPx = max(0, iconDrawablePaddingPx - diff)
+            cellContentHeight = getCellContentHeight()
+        }
+
+        while (
+            (iconTextSizePx > iconSizeSteps.minimumIconLabelSize ||
+                iconSizePx > iconSizeSteps.minimumIconSize()) && cellContentHeight > cellHeightPx
+        ) {
+            // Step 2. Decrease icon size
+            iconSizePx = iconSizeSteps.getNextLowerIconSize(iconSizePx)
+            cellContentHeight = getCellContentHeight()
+
+            // Step 3. Decrease label size
+            if (cellContentHeight > cellHeightPx) {
+                iconTextSizePx =
+                    max(
+                        iconSizeSteps.minimumIconLabelSize,
+                        iconTextSizePx - IconSizeSteps.TEXT_STEP
+                    )
+                cellContentHeight = getCellContentHeight()
+            }
+        }
+
+        return cellContentHeight
+    }
+
+    /** Calculate new cellContentHeight */
+    fun getCellContentHeight(): Int {
+        val iconTextHeight = Utilities.calculateTextHeight(iconTextSizePx.toFloat())
+        return iconSizePx + iconDrawablePaddingPx + iconTextHeight
+    }
+}
diff --git a/src/com/android/launcher3/util/IconSizeSteps.kt b/src/com/android/launcher3/util/IconSizeSteps.kt
index 2a5afe0..aa644b0 100644
--- a/src/com/android/launcher3/util/IconSizeSteps.kt
+++ b/src/com/android/launcher3/util/IconSizeSteps.kt
@@ -23,12 +23,14 @@
 
 class IconSizeSteps(res: Resources) {
     private val steps: List<Int>
+    val minimumIconLabelSize: Int
 
     init {
         steps =
             res.obtainTypedArray(R.array.icon_size_steps).use {
                 (0 until it.length()).map { step -> it.getDimensionOrThrow(step).toInt() }.sorted()
             }
+        minimumIconLabelSize = res.getDimensionPixelSize(R.dimen.minimum_icon_label_size)
     }
 
     fun minimumIconSize(): Int = steps[0]
@@ -44,4 +46,8 @@
     private fun getIndexForIconSize(iconSizePx: Int): Int {
         return max(0, steps.indexOfFirst { iconSizePx <= it })
     }
+
+    companion object {
+        internal const val TEXT_STEP = 1
+    }
 }
diff --git a/tests/Android.bp b/tests/Android.bp
index a3d05bb..8725b46 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -40,19 +40,14 @@
       "src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
       "src/com/android/launcher3/ui/TestViewHelpers.java",
       "src/com/android/launcher3/util/LauncherLayoutBuilder.java",
+      "src/com/android/launcher3/util/ModelTestExtensions.kt",
       "src/com/android/launcher3/util/TestConstants.java",
       "src/com/android/launcher3/util/TestUtil.java",
       "src/com/android/launcher3/util/Wait.java",
       "src/com/android/launcher3/util/WidgetUtils.java",
-      "src/com/android/launcher3/util/rule/FailureWatcher.java",
-      "src/com/android/launcher3/util/rule/ViewCaptureRule.kt",
+      "src/com/android/launcher3/util/rule/*.java",
+      "src/com/android/launcher3/util/rule/*.kt",
       "src/com/android/launcher3/util/viewcapture_analysis/*.java",
-      "src/com/android/launcher3/util/rule/SamplerRule.java",
-      "src/com/android/launcher3/util/rule/ScreenRecordRule.java",
-      "src/com/android/launcher3/util/rule/ShellCommandRule.java",
-      "src/com/android/launcher3/util/rule/TestIsolationRule.java",
-      "src/com/android/launcher3/util/rule/TestStabilityRule.java",
-      "src/com/android/launcher3/util/ModelTestExtensions.kt",
       "src/com/android/launcher3/testcomponent/*.java",
       "src/com/android/launcher3/testcomponent/*.kt",
     ],
diff --git a/tests/src/com/android/launcher3/util/CellContentDimensionsTest.kt b/tests/src/com/android/launcher3/util/CellContentDimensionsTest.kt
new file mode 100644
index 0000000..4770546
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/CellContentDimensionsTest.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+package com.android.launcher3.util
+
+import android.content.Context
+import android.content.res.Configuration
+import android.util.DisplayMetrics
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CellContentDimensionsTest {
+    private var context: Context? = null
+    private val runningContext: Context = ApplicationProvider.getApplicationContext()
+    private lateinit var iconSizeSteps: IconSizeSteps
+
+    @Before
+    fun setup() {
+        // 160dp makes 1px = 1dp
+        val config =
+            Configuration(runningContext.resources.configuration).apply {
+                this.densityDpi = DisplayMetrics.DENSITY_DEFAULT
+            }
+        context = runningContext.createConfigurationContext(config)
+        iconSizeSteps = IconSizeSteps(context!!.resources)
+    }
+
+    @Test
+    fun dimensionsFitTheCell() {
+        val cellSize = Pair(80, 104)
+        val cellContentDimensions =
+            CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+        val contentHeight =
+            cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+        assertThat(contentHeight).isEqualTo(93)
+        cellContentDimensions.run {
+            assertThat(iconSizePx).isEqualTo(66)
+            assertThat(iconDrawablePaddingPx).isEqualTo(8)
+            assertThat(iconTextSizePx).isEqualTo(14)
+        }
+    }
+
+    @Test
+    fun decreasePadding() {
+        val cellSize = Pair(67, 87)
+        val cellContentDimensions =
+            CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+        val contentHeight =
+            cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+        assertThat(contentHeight).isEqualTo(87)
+        cellContentDimensions.run {
+            assertThat(iconSizePx).isEqualTo(66)
+            assertThat(iconDrawablePaddingPx).isEqualTo(2)
+            assertThat(iconTextSizePx).isEqualTo(14)
+        }
+    }
+
+    @Test
+    fun decreaseIcon() {
+        val cellSize = Pair(65, 84)
+        val cellContentDimensions =
+            CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+        val contentHeight =
+            cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+        assertThat(contentHeight).isEqualTo(82)
+        cellContentDimensions.run {
+            assertThat(iconSizePx).isEqualTo(63)
+            assertThat(iconDrawablePaddingPx).isEqualTo(0)
+            assertThat(iconTextSizePx).isEqualTo(14)
+        }
+    }
+
+    @Test
+    fun decreaseText() {
+        val cellSize = Pair(63, 81)
+        val cellContentDimensions =
+            CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+        val contentHeight =
+            cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+        assertThat(contentHeight).isEqualTo(81)
+        cellContentDimensions.run {
+            assertThat(iconSizePx).isEqualTo(63)
+            assertThat(iconDrawablePaddingPx).isEqualTo(0)
+            assertThat(iconTextSizePx).isEqualTo(13)
+        }
+    }
+
+    @Test
+    fun decreaseIconAndTextTwoSteps() {
+        val cellSize = Pair(60, 78)
+        val cellContentDimensions =
+            CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+        val contentHeight =
+            cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+        assertThat(contentHeight).isEqualTo(77)
+        cellContentDimensions.run {
+            assertThat(iconSizePx).isEqualTo(61)
+            assertThat(iconDrawablePaddingPx).isEqualTo(0)
+            assertThat(iconTextSizePx).isEqualTo(12)
+        }
+    }
+
+    @Test
+    fun decreaseIconAndTextToMinimum() {
+        val cellSize = Pair(52, 63)
+        val cellContentDimensions =
+            CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+        val contentHeight =
+            cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+        assertThat(contentHeight).isEqualTo(63)
+        cellContentDimensions.run {
+            assertThat(iconSizePx).isEqualTo(52)
+            assertThat(iconDrawablePaddingPx).isEqualTo(0)
+            assertThat(iconTextSizePx).isEqualTo(8)
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/SetFlagsRuleExt.kt b/tests/src/com/android/launcher3/util/rule/SetFlagsRuleExt.kt
new file mode 100644
index 0000000..d682456
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/SetFlagsRuleExt.kt
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+package com.android.launcher3.util.rule
+
+import android.platform.test.flag.junit.SetFlagsRule
+
+fun SetFlagsRule.setFlags(enabled: Boolean, vararg flagName: String) {
+    if (enabled) enableFlags(*flagName) else disableFlags(*flagName)
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 25c73de..38cc321 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -16,8 +16,6 @@
 
 package com.android.launcher3.tapl;
 
-import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-
 import androidx.annotation.NonNull;
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.UiObject2;
@@ -61,14 +59,8 @@
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                      "before tapping the app info menu item")) {
-
-            mLauncher.executeAndWaitForLauncherEvent(
-                    () -> mLauncher.clickLauncherObject(
-                            mLauncher.findObjectInContainer(mMenu, By.text("App info"))),
-                    accessibilityEvent ->
-                            accessibilityEvent.getEventType() == TYPE_WINDOW_STATE_CHANGED,
-                    () -> "Unable to start Settings by clicking App Info",
-                    "Tap the app info menu item");
+            mLauncher.clickLauncherObject(
+                    mLauncher.findObjectInContainer(mMenu, By.text("App info")));
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "tapped app info menu item")) {