Merge "Moving flag creation to a separate file" into tm-qpr-dev
diff --git a/quickstep/res/layout/taskbar_all_apps_button.xml b/quickstep/res/layout/taskbar_all_apps_button.xml
index 6b665e5..c50db2e 100644
--- a/quickstep/res/layout/taskbar_all_apps_button.xml
+++ b/quickstep/res/layout/taskbar_all_apps_button.xml
@@ -21,5 +21,4 @@
     android:layout_height="@dimen/taskbar_icon_min_touch_size"
     android:contentDescription="@string/all_apps_button_label"
     android:backgroundTint="@android:color/transparent"
-    android:icon="@drawable/ic_all_apps_button"
     />
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index bd71a9f..126ab7c 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -286,6 +286,8 @@
     <dimen name="taskbar_back_button_left_margin_kids">48dp</dimen>
     <dimen name="taskbar_home_button_left_margin_kids">48dp</dimen>
     <dimen name="taskbar_icon_size_kids">32dp</dimen>
+    <dimen name="taskbar_all_apps_button_translation_x_offset">6dp</dimen>
+
 
     <!-- Transient taskbar -->
     <dimen name="transient_taskbar_size">72dp</dimen>
@@ -295,6 +297,7 @@
     <dimen name="transient_taskbar_shadow_blur">40dp</dimen>
     <dimen name="transient_taskbar_key_shadow_distance">10dp</dimen>
     <dimen name="transient_taskbar_stashed_size">32dp</dimen>
+    <dimen name="transient_taskbar_all_apps_button_translation_x_offset">4dp</dimen>
     <!-- An additional touch slop to prevent x-axis movement during the swipe up to show taskbar -->
     <dimen name="transient_taskbar_clamped_offset_bound">16dp</dimen>
     <!-- Taskbar swipe up thresholds -->
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
index 2bfc7dd..1a54576 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
@@ -41,12 +41,15 @@
     public static final int FLAG_AUTOHIDE_SUSPEND_TOUCHING = 1 << 2;
     // Taskbar EDU overlay is open above the Taskbar. */
     public static final int FLAG_AUTOHIDE_SUSPEND_EDU_OPEN = 1 << 3;
+    // Taskbar in immersive mode in overview
+    public static final int FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER = 1 << 4;
 
     @IntDef(flag = true, value = {
             FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
             FLAG_AUTOHIDE_SUSPEND_DRAGGING,
             FLAG_AUTOHIDE_SUSPEND_TOUCHING,
             FLAG_AUTOHIDE_SUSPEND_EDU_OPEN,
+            FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AutohideSuspendFlag {}
@@ -92,6 +95,10 @@
         return mAutohideSuspendFlags != 0;
     }
 
+    public boolean isSuspendedForTransientTaskbarInOverview() {
+        return (mAutohideSuspendFlags & FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER) != 0;
+    }
+
     @Override
     public void dumpLogs(String prefix, PrintWriter pw) {
         pw.println(prefix + "TaskbarAutohideSuspendController:");
@@ -106,6 +113,8 @@
         appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_DRAGGING, "FLAG_AUTOHIDE_SUSPEND_DRAGGING");
         appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_TOUCHING, "FLAG_AUTOHIDE_SUSPEND_TOUCHING");
         appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_EDU_OPEN, "FLAG_AUTOHIDE_SUSPEND_EDU_OPEN");
+        appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER,
+                "FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER");
         return str.toString();
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 50f5d9e..bbf861b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -460,7 +460,9 @@
             return;
         }
 
-        if (stash && mControllers.taskbarAutohideSuspendController.isSuspended()) {
+        if (stash && mControllers.taskbarAutohideSuspendController.isSuspended()
+                && !mControllers.taskbarAutohideSuspendController
+                .isSuspendedForTransientTaskbarInOverview()) {
             // Avoid stashing if autohide is currently suspended.
             return;
         }
@@ -955,6 +957,8 @@
         if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP | FLAGS_IN_APP)) {
             notifyStashChange(/* visible */ hasAnyFlag(FLAGS_IN_APP),
                             /* stashed */ isStashedInApp());
+            mControllers.taskbarAutohideSuspendController.updateFlag(
+                    TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER, !isInApp());
         }
         if (hasAnyFlag(changedFlags, FLAG_STASHED_IN_APP_MANUAL)) {
             if (hasAnyFlag(FLAG_STASHED_IN_APP_MANUAL)) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index c1e85aa..0b275a8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -89,6 +89,8 @@
 
     private float mTransientTaskbarMinWidth;
 
+    private float mTransientTaskbarAllAppsButtonTranslationXOffset;
+
     public TaskbarView(@NonNull Context context) {
         this(context, null);
     }
@@ -108,9 +110,14 @@
         mActivityContext = ActivityContext.lookupContext(context);
         mIconLayoutBounds = mActivityContext.getTransientTaskbarBounds();
         Resources resources = getResources();
+        boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivityContext);
         mIsRtl = Utilities.isRtl(resources);
         mTransientTaskbarMinWidth = mContext.getResources().getDimension(
                 R.dimen.transient_taskbar_min_width);
+        mTransientTaskbarAllAppsButtonTranslationXOffset =
+                resources.getDimension(isTransientTaskbar
+                        ? R.dimen.transient_taskbar_all_apps_button_translation_x_offset
+                        : R.dimen.taskbar_all_apps_button_translation_x_offset);
 
         int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
         int actualIconSize = mActivityContext.getDeviceProfile().iconSizePx;
@@ -130,9 +137,12 @@
         if (!mActivityContext.getPackageManager().hasSystemFeature(FEATURE_PC)) {
             mAllAppsButton = (IconButtonView) LayoutInflater.from(context)
                     .inflate(R.layout.taskbar_all_apps_button, this, false);
+            mAllAppsButton.setIconDrawable(resources.getDrawable(isTransientTaskbar
+                    ? R.drawable.ic_transient_taskbar_all_apps_button
+                    : R.drawable.ic_taskbar_all_apps_button));
             mAllAppsButton.setScaleX(mIsRtl ? -1 : 1);
-            mAllAppsButton.setForegroundTint(mActivityContext.getColor(
-                    DisplayController.isTransientTaskbar(mActivityContext)
+            mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+            mAllAppsButton.setForegroundTint(mActivityContext.getColor(isTransientTaskbar
                             ? R.color.all_apps_button_color
                             : R.color.all_apps_button_color_dark));
 
@@ -276,6 +286,8 @@
         }
 
         if (mAllAppsButton != null) {
+            mAllAppsButton.setTranslationXForTaskbarAllAppsIcon(getChildCount() > 0
+                    ? mTransientTaskbarAllAppsButtonTranslationXOffset : 0f);
             addView(mAllAppsButton, mIsRtl ? getChildCount() : 0);
 
             // if only all apps button present, don't include divider view.
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index e8e8328..07fcf48 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -121,8 +121,7 @@
     private void handleSplitSelectionState(@NonNull LauncherState toState,
             @NonNull PendingAnimation builder, boolean animate) {
         if (toState != OVERVIEW_SPLIT_SELECT) {
-            // Not going to split, nothing to do but ensure taskviews are at correct offset
-            mRecentsView.resetSplitPrimaryScrollOffset();
+            // Not going to split
             return;
         }
 
@@ -153,8 +152,6 @@
             as.start();
             as.end();
         }
-
-        mRecentsView.applySplitPrimaryScrollOffset();
     }
 
     private void setAlphas(PropertySetter propertySetter, StateAnimationConfig config,
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 1122e00..e264a7f 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -678,7 +678,7 @@
             @Override
             public void onMotionPauseDetected() {
                 mHasMotionEverBeenPaused = true;
-                maybeUpdateRecentsAttachedState(true/* animate */, true/* moveFocusedTask */);
+                maybeUpdateRecentsAttachedState(true/* animate */, true/* moveRunningTask */);
                 Optional.ofNullable(mActivityInterface.getTaskbarController())
                         .ifPresent(TaskbarUIController::startTranslationSpring);
                 performHapticFeedback();
@@ -696,7 +696,7 @@
     }
 
     private void maybeUpdateRecentsAttachedState(boolean animate) {
-        maybeUpdateRecentsAttachedState(animate, false /* moveFocusedTask */);
+        maybeUpdateRecentsAttachedState(animate, false /* moveRunningTask */);
     }
 
     /**
@@ -706,9 +706,9 @@
      *
      * Note this method has no effect unless the navigation mode is NO_BUTTON.
      * @param animate whether to animate when attaching RecentsView
-     * @param moveFocusedTask whether to move focused task to front when attaching
+     * @param moveRunningTask whether to move running task to front when attaching
      */
-    private void maybeUpdateRecentsAttachedState(boolean animate, boolean moveFocusedTask) {
+    private void maybeUpdateRecentsAttachedState(boolean animate, boolean moveRunningTask) {
         if (!mDeviceState.isFullyGesturalNavMode() || mRecentsView == null) {
             return;
         }
@@ -727,11 +727,11 @@
         } else {
             recentsAttachedToAppWindow = mHasMotionEverBeenPaused || mIsLikelyToStartNewTask;
         }
-        if (moveFocusedTask && !mAnimationFactory.hasRecentsEverAttachedToAppWindow()
+        if (moveRunningTask && !mAnimationFactory.hasRecentsEverAttachedToAppWindow()
                 && recentsAttachedToAppWindow) {
-            // Only move focused task if RecentsView has never been attached before, to avoid
+            // Only move running task if RecentsView has never been attached before, to avoid
             // TaskView jumping to new position as we move the tasks.
-            mRecentsView.moveFocusedTaskToFront();
+            mRecentsView.moveRunningTaskToFront();
         }
         mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
 
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 998439e..d7ff8ab 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -231,17 +231,20 @@
     /**
      * Calculates the taskView size for the provided device configuration.
      */
-    public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect) {
-        Resources res = context.getResources();
-        float maxScale = res.getFloat(R.dimen.overview_max_scale);
+    public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
+            PagedOrientationHandler orientedState) {
         if (dp.isTablet) {
-            Rect gridRect = new Rect();
-            calculateGridSize(dp, gridRect);
-
-            calculateTaskSizeInternal(context, dp, gridRect, maxScale, Gravity.CENTER, outRect);
+            if (FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get()) {
+                calculateGridTaskSize(context, dp, outRect, orientedState);
+            } else {
+                calculateFocusTaskSize(context, dp, outRect);
+            }
         } else {
+            Resources res = context.getResources();
+            float maxScale = res.getFloat(R.dimen.overview_max_scale);
             int taskMargin = dp.overviewTaskMarginPx;
-            calculateTaskSizeInternal(context, dp,
+            calculateTaskSizeInternal(
+                    dp,
                     dp.overviewTaskThumbnailTopMarginPx,
                     dp.getOverviewActionsClaimedSpace(),
                     res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
@@ -251,7 +254,15 @@
         }
     }
 
-    private void calculateTaskSizeInternal(Context context, DeviceProfile dp, int claimedSpaceAbove,
+    private void calculateFocusTaskSize(Context context, DeviceProfile dp, Rect outRect) {
+        Resources res = context.getResources();
+        float maxScale = res.getFloat(R.dimen.overview_max_scale);
+        Rect gridRect = new Rect();
+        calculateGridSize(dp, gridRect);
+        calculateTaskSizeInternal(dp, gridRect, maxScale, Gravity.CENTER, outRect);
+    }
+
+    private void calculateTaskSizeInternal(DeviceProfile dp, int claimedSpaceAbove,
             int claimedSpaceBelow, int minimumHorizontalPadding, float maxScale, int gravity,
             Rect outRect) {
         Rect insets = dp.getInsets();
@@ -264,10 +275,10 @@
                 minimumHorizontalPadding,
                 claimedSpaceBelow);
 
-        calculateTaskSizeInternal(context, dp, potentialTaskRect, maxScale, gravity, outRect);
+        calculateTaskSizeInternal(dp, potentialTaskRect, maxScale, gravity, outRect);
     }
 
-    private void calculateTaskSizeInternal(Context context, DeviceProfile dp,
+    private void calculateTaskSizeInternal(DeviceProfile dp,
             Rect potentialTaskRect, float maxScale, int gravity, Rect outRect) {
         PointF taskDimension = getTaskDimension(dp);
 
@@ -318,12 +329,15 @@
     public final void calculateGridTaskSize(Context context, DeviceProfile dp, Rect outRect,
             PagedOrientationHandler orientedState) {
         Resources res = context.getResources();
-        Rect taskRect = new Rect();
-        calculateTaskSize(context, dp, taskRect);
+        Rect potentialTaskRect = new Rect();
+        if (FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get()) {
+            calculateGridSize(dp, potentialTaskRect);
+        } else {
+            calculateFocusTaskSize(context, dp, potentialTaskRect);
+        }
 
-        float rowHeight =
-                (taskRect.height() + dp.overviewTaskThumbnailTopMarginPx - dp.overviewRowSpacing)
-                        / 2f;
+        float rowHeight = (potentialTaskRect.height() + dp.overviewTaskThumbnailTopMarginPx
+                - dp.overviewRowSpacing) / 2f;
 
         PointF taskDimension = getTaskDimension(dp);
         float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / taskDimension.y;
@@ -332,14 +346,15 @@
 
         int gravity = Gravity.TOP;
         gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
-        Gravity.apply(gravity, outWidth, outHeight, taskRect, outRect);
+        Gravity.apply(gravity, outWidth, outHeight, potentialTaskRect, outRect);
     }
 
     /**
      * Calculates the modal taskView size for the provided device configuration
      */
-    public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
-        calculateTaskSize(context, dp, outRect);
+    public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect,
+            PagedOrientationHandler orientedState) {
+        calculateTaskSize(context, dp, outRect, orientedState);
         boolean isGridOnlyOverview = dp.isTablet && FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW.get();
         int claimedSpaceBelow = isGridOnlyOverview
                 ? dp.overviewActionsTopMarginPx + dp.overviewActionsHeight + dp.stashedTaskbarSize
@@ -351,7 +366,7 @@
                     Math.round((dp.availableWidthPx - outRect.width() * maxScale) / 2);
         }
         calculateTaskSizeInternal(
-                context, dp,
+                dp,
                 dp.overviewTaskMarginPx,
                 claimedSpaceBelow,
                 minimumHorizontalPadding,
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index ae9fb0b..8bb189a 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -61,7 +61,7 @@
     @Override
     public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
             PagedOrientationHandler orientationHandler) {
-        calculateTaskSize(context, dp, outRect);
+        calculateTaskSize(context, dp, outRect, orientationHandler);
         if (dp.isVerticalBarLayout() && DisplayController.getNavigationMode(context) != NO_BUTTON) {
             return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
         } else {
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 7f2886c..ea9f032 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -18,7 +18,6 @@
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.LauncherState.QUICK_SWITCH_FROM_HOME;
 import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -73,7 +72,7 @@
     @Override
     public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
             PagedOrientationHandler orientationHandler) {
-        calculateTaskSize(context, dp, outRect);
+        calculateTaskSize(context, dp, outRect, orientationHandler);
         if (dp.isVerticalBarLayout()
                 && DisplayController.getNavigationMode(context) != NavigationMode.NO_BUTTON) {
             return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index ac5b2f2..5b85249 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -283,7 +283,7 @@
 
         RecentsView<?, ?> visibleRecentsView = activityInterface.getVisibleRecentsView();
         if (visibleRecentsView != null) {
-            visibleRecentsView.moveFocusedTaskToFront();
+            visibleRecentsView.moveRunningTaskToFront();
         }
         if (mTaskAnimationManager.isRecentsAnimationRunning()) {
             cmd.mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(gestureState);
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 54e4a0d..5391f4d 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -59,7 +59,7 @@
                 }
                 Rect focusedTaskRect = new Rect();
                 LauncherActivityInterface.INSTANCE.calculateTaskSize(mContext, mDeviceProfile,
-                        focusedTaskRect);
+                        focusedTaskRect, PagedOrientationHandler.PORTRAIT);
                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, focusedTaskRect.height());
                 return response;
             }
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 062e50e..11b1ab8 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -130,15 +130,9 @@
                 mRecentsView.getPagedOrientationHandler().getSplitSelectTaskOffset(
                         TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
                         mActivity.getDeviceProfile());
+        setter.setFloat(mRecentsView, taskViewsFloat.first, isSplitSelectionState(state)
+                ? mRecentsView.getSplitSelectTranslation() : 0, LINEAR);
         setter.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
-        if (isSplitSelectionState(state)) {
-            mRecentsView.applySplitPrimaryScrollOffset();
-            setter.setFloat(mRecentsView, taskViewsFloat.first,
-                    mRecentsView.getSplitSelectTranslation(), LINEAR);
-        } else {
-            mRecentsView.resetSplitPrimaryScrollOffset();
-            setter.setFloat(mRecentsView, taskViewsFloat.first, 0, LINEAR);
-        }
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index 7c83833..baca76c 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -158,7 +158,8 @@
         Rect startRect = new Rect();
         PagedOrientationHandler orientationHandler = params.recentsOrientedState
                 .getOrientationHandler();
-        LauncherActivityInterface.INSTANCE.calculateTaskSize(params.context, params.dp, startRect);
+        LauncherActivityInterface.INSTANCE.calculateTaskSize(params.context, params.dp, startRect,
+                orientationHandler);
         long distanceToCover = startRect.bottom;
         PendingAnimation resistAnim = params.resistAnim != null
                 ? params.resistAnim
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index f7136a5..79656c2 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -43,7 +43,8 @@
             PagedOrientationHandler orientationHandler) {
         // Track the bottom of the window.
         Rect taskSize = new Rect();
-        LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize);
+        LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
+                orientationHandler);
         return orientationHandler.getDistanceToBottomOfRect(dp, taskSize);
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 69f9ce3..0b83eaf 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -157,7 +157,8 @@
             mSizeStrategy.calculateGridTaskSize(mContext, mDp, mTaskRect,
                     mOrientationState.getOrientationHandler());
         } else {
-            mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect);
+            mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect,
+                    mOrientationState.getOrientationHandler());
         }
 
         Rect fullTaskSize;
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index d098ffc..6813857 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -67,7 +67,6 @@
     private float mGridTranslationPrimary;
     private float mGridScrollOffset;
     private float mScrollOffsetPrimary;
-    private float mSplitSelectScrollOffsetPrimary;
 
     private int mSidePadding;
 
@@ -176,10 +175,6 @@
         mScrollOffsetPrimary = scrollOffsetPrimary;
     }
 
-    public void setSplitSelectScrollOffsetPrimary(float splitSelectScrollOffsetPrimary) {
-        mSplitSelectScrollOffsetPrimary = splitSelectScrollOffsetPrimary;
-    }
-
     public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
         float scrollAdjustment = 0;
         if (fullscreenEnabled) {
@@ -189,7 +184,6 @@
             scrollAdjustment += mGridTranslationPrimary + mGridScrollOffset;
         }
         scrollAdjustment += mScrollOffsetPrimary;
-        scrollAdjustment += mSplitSelectScrollOffsetPrimary;
         return scrollAdjustment;
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index f578b87..1058e99 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -56,7 +56,8 @@
             HIDDEN_NO_RECENTS,
             HIDDEN_SPLIT_SCREEN,
             HIDDEN_SPLIT_SELECT_ACTIVE,
-            HIDDEN_ACTIONS_IN_MENU
+            HIDDEN_ACTIONS_IN_MENU,
+            HIDDEN_DESKTOP
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ActionsHiddenFlags { }
@@ -67,6 +68,7 @@
     public static final int HIDDEN_SPLIT_SCREEN = 1 << 3;
     public static final int HIDDEN_SPLIT_SELECT_ACTIVE = 1 << 4;
     public static final int HIDDEN_ACTIONS_IN_MENU = 1 << 5;
+    public static final int HIDDEN_DESKTOP = 1 << 6;
 
     @IntDef(flag = true, value = {
             DISABLED_SCROLLING,
@@ -322,7 +324,7 @@
 
         requestLayout();
 
-        mSplitButton.setCompoundDrawablesWithIntrinsicBounds(
+        mSplitButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
                 (dp.isLandscape ? R.drawable.ic_split_horizontal : R.drawable.ic_split_vertical),
                 0, 0, 0);
     }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index e529b04..1122e80 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -53,8 +53,6 @@
 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.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
 import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
 import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
@@ -62,6 +60,7 @@
 import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
 import static com.android.quickstep.views.OverviewActionsView.FLAG_SINGLE_TASK;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_ACTIONS_IN_MENU;
+import static com.android.quickstep.views.OverviewActionsView.HIDDEN_DESKTOP;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_RECENTS;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS;
@@ -79,7 +78,6 @@
 import android.annotation.SuppressLint;
 import android.annotation.TargetApi;
 import android.app.WindowConfiguration;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.LocusId;
@@ -517,6 +515,7 @@
     private float mTaskThumbnailSplashAlpha = 0;
     private boolean mShowAsGridLastOnLayout = false;
     private final IntSet mTopRowIdSet = new IntSet();
+    private int mClearAllShortTotalWidthTranslation = 0;
 
     // The GestureEndTarget that is still in progress.
     @Nullable
@@ -1233,21 +1232,9 @@
         return clearAllScroll + (mIsRtl ? distance : -distance);
     }
 
-    private int getSnapToFocusedTaskScrollDiff(boolean isClearAllHidden) {
-        int screenStart = mOrientationHandler.getPrimaryScroll(this);
-        int targetScroll = getScrollForPage(indexOfChild(getFocusedTaskView()));
-        if (!isClearAllHidden) {
-            int clearAllWidth = mOrientationHandler.getPrimarySize(mClearAllButton);
-            int taskGridHorizontalDiff = mLastComputedTaskSize.right - mLastComputedGridSize.right;
-            int clearAllFocusScrollDiff =  taskGridHorizontalDiff - clearAllWidth;
-            targetScroll += mIsRtl ? clearAllFocusScrollDiff : -clearAllFocusScrollDiff;
-        }
-        return screenStart - targetScroll;
-    }
-
     private boolean isTaskViewWithinBounds(TaskView tv, int start, int end) {
         int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
-                showAsFullscreen(), showAsGrid());
+                showAsGrid());
         int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
                 showAsFullscreen()));
         int taskEnd = taskStart + taskSize;
@@ -1257,7 +1244,7 @@
 
     private boolean isTaskViewFullyWithinBounds(TaskView tv, int start, int end) {
         int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
-                showAsFullscreen(), showAsGrid());
+                showAsGrid());
         int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
                 showAsFullscreen()));
         int taskEnd = taskStart + taskSize;
@@ -1493,20 +1480,20 @@
     }
 
     /**
-     * Moves the focused task to the front of the carousel in tablets, to minimize animation
-     * required to focus the task in grid.
+     * Moves the running task to the front of the carousel in tablets, to minimize animation
+     * required to move the running task in grid.
      */
-    public void moveFocusedTaskToFront() {
+    public void moveRunningTaskToFront() {
         if (!mActivity.getDeviceProfile().isTablet) {
             return;
         }
 
-        TaskView focusedTaskView = getFocusedTaskView();
-        if (focusedTaskView == null) {
+        TaskView runningTaskView = getRunningTaskView();
+        if (runningTaskView == null) {
             return;
         }
 
-        if (indexOfChild(focusedTaskView) != mCurrentPage) {
+        if (indexOfChild(runningTaskView) != mCurrentPage) {
             return;
         }
 
@@ -1518,20 +1505,20 @@
         int currentPageScroll = getScrollForPage(mCurrentPage);
         mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
 
-        mMovingTaskView = focusedTaskView;
-        removeView(focusedTaskView);
+        mMovingTaskView = runningTaskView;
+        removeView(runningTaskView);
         mMovingTaskView = null;
-        focusedTaskView.resetPersistentViewTransforms();
+        runningTaskView.resetPersistentViewTransforms();
         int frontTaskIndex = 0;
-        if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED && !focusedTaskView.isDesktopTask()) {
+        if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED && !runningTaskView.isDesktopTask()) {
             // If desktop mode is enabled, desktop task view is pinned at first position.
-            // Move focused task to position 1
+            // Move running task to position 1
             frontTaskIndex = 1;
         }
-        addView(focusedTaskView, frontTaskIndex);
+        addView(runningTaskView, frontTaskIndex);
         setCurrentPage(frontTaskIndex);
 
-        updateGridProperties();
+        updateTaskSize();
     }
 
     @Override
@@ -1564,7 +1551,7 @@
             return;
         }
 
-        int currentTaskId = -1;
+        int currentTaskId = INVALID_TASK_ID;
         TaskView currentTaskView = getTaskViewAt(mCurrentPage);
         if (currentTaskView != null && currentTaskView.getTask() != null) {
             currentTaskId = currentTaskView.getTask().key.id;
@@ -1574,7 +1561,8 @@
         unloadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
 
         TaskView ignoreResetTaskView =
-                mIgnoreResetTaskId == -1 ? null : getTaskViewByTaskId(mIgnoreResetTaskId);
+                mIgnoreResetTaskId == INVALID_TASK_ID
+                        ? null : getTaskViewByTaskId(mIgnoreResetTaskId);
 
         // Save running task ID if it exists before rebinding all taskViews, otherwise the task from
         // the runningTaskView currently bound could get assigned to another TaskView
@@ -1677,20 +1665,20 @@
                 newFocusedTaskView = getTaskViewAt(1);
             }
         }
-        mFocusedTaskViewId = newFocusedTaskView != null ?
-                newFocusedTaskView.getTaskViewId() : -1;
+        mFocusedTaskViewId = newFocusedTaskView != null && !ENABLE_GRID_ONLY_OVERVIEW.get()
+                ? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID;
         updateTaskSize();
         updateChildTaskOrientations();
 
         TaskView newRunningTaskView = null;
-        if (runningTaskId != -1) {
+        if (runningTaskId != INVALID_TASK_ID) {
             // Update mRunningTaskViewId to be the new TaskView that was assigned by binding
             // the full list of tasks to taskViews
             newRunningTaskView = getTaskViewByTaskId(runningTaskId);
             if (newRunningTaskView != null) {
                 mRunningTaskViewId = newRunningTaskView.getTaskViewId();
             } else {
-                mRunningTaskViewId = -1;
+                mRunningTaskViewId = INVALID_TASK_ID;
             }
         }
 
@@ -1698,7 +1686,7 @@
         if (mNextPage != INVALID_PAGE) {
             // Restore mCurrentPage but don't call setCurrentPage() as that clobbers the scroll.
             mCurrentPage = previousCurrentPage;
-            if (currentTaskId != -1) {
+            if (currentTaskId != INVALID_TASK_ID) {
                 currentTaskView = getTaskViewByTaskId(currentTaskId);
                 if (currentTaskView != null) {
                     targetPage = indexOfChild(currentTaskView);
@@ -1706,7 +1694,7 @@
             }
         } else {
             // Set the current page to the running task, but not if settling on new task.
-            if (runningTaskId != -1) {
+            if (runningTaskId != INVALID_TASK_ID) {
                 targetPage = indexOfChild(newRunningTaskView);
             } else if (getTaskViewCount() > 0) {
                 TaskView taskView = requireTaskViewAt(0);
@@ -1732,12 +1720,12 @@
             });
         }
 
-        if (mIgnoreResetTaskId != -1 &&
+        if (mIgnoreResetTaskId != INVALID_TASK_ID &&
                 getTaskViewByTaskId(mIgnoreResetTaskId) != ignoreResetTaskView) {
             // If the taskView mapping is changing, do not preserve the visuals. Since we are
             // mostly preserving the first task, and new taskViews are added to the end, it should
             // generally map to the same task.
-            mIgnoreResetTaskId = -1;
+            mIgnoreResetTaskId = INVALID_TASK_ID;
         }
         resetTaskVisuals();
         onTaskStackUpdated();
@@ -1793,7 +1781,7 @@
      * Returns the number of tasks in the bottom row of the overview grid.
      */
     public int getBottomRowTaskCountForTablet() {
-        return getTaskViewCount() - mTopRowIdSet.size() - 1;
+        return getTaskViewCount() - mTopRowIdSet.size() - (ENABLE_GRID_ONLY_OVERVIEW.get() ? 0 : 1);
     }
 
     protected void onTaskStackUpdated() {
@@ -1999,7 +1987,8 @@
     }
 
     public void getTaskSize(Rect outRect) {
-        mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
+        mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
+                mOrientationHandler);
         mLastComputedTaskSize.set(outRect);
     }
 
@@ -2044,7 +2033,8 @@
 
     /** Gets the task size for modal state. */
     public void getModalTaskSize(Rect outRect) {
-        mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
+        mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
+                mOrientationHandler);
     }
 
     @Override
@@ -2477,8 +2467,7 @@
             for (TaskViewSimulator tvs : taskViewSimulators) {
                 if (animatorSet == null) {
                     setGridProgress(1);
-                    tvs.taskPrimaryTranslation.value =
-                            runningTaskPrimaryGridTranslation;
+                    tvs.taskPrimaryTranslation.value = runningTaskPrimaryGridTranslation;
                 } else {
                     animatorSet.play(ObjectAnimator.ofFloat(this, RECENTS_GRID_PROGRESS, 1));
                     animatorSet.play(tvs.taskPrimaryTranslation.animateToValue(
@@ -2587,7 +2576,7 @@
 
         boolean runningTaskTileHidden = mRunningTaskTileHidden;
         setCurrentTask(runningTaskViewId);
-        mFocusedTaskViewId = runningTaskViewId;
+        mFocusedTaskViewId = ENABLE_GRID_ONLY_OVERVIEW.get() ? INVALID_TASK_ID : runningTaskViewId;
         runOnPageScrollsInitialized(() -> setCurrentPage(getRunningTaskIndex()));
         setRunningTaskViewShowScreenshot(false);
         setRunningTaskHidden(runningTaskTileHidden);
@@ -2720,7 +2709,8 @@
             return;
         }
 
-        int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        int taskTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
 
         int topRowWidth = 0;
         int bottomRowWidth = 0;
@@ -2862,7 +2852,7 @@
         float snappedTaskGridTranslationX = 0;
         if (snappedTaskView != null) {
             snappedTaskNonGridScrollAdjustment = snappedTaskView.getScrollAdjustment(
-                    /*fullscreenEnabled=*/true, /*gridEnabled=*/false);
+                    /*gridEnabled=*/false);
             snappedTaskGridTranslationX = gridTranslations[snappedPage];
         }
 
@@ -2887,18 +2877,28 @@
 
         // If the total width is shorter than one grid's width, move ClearAllButton further away
         // accordingly. Update longRowWidth if ClearAllButton has been moved.
-        float clearAllShortTotalCompensation = 0;
+        float clearAllShortTotalWidthTranslation = 0;
         int longRowWidth = Math.max(topRowWidth, bottomRowWidth);
         if (longRowWidth < mLastComputedGridSize.width()) {
-            float shortTotalCompensation = mLastComputedGridSize.width() - longRowWidth;
-            clearAllShortTotalCompensation =
-                    mIsRtl ? -shortTotalCompensation : shortTotalCompensation;
-            longRowWidth = mLastComputedGridSize.width();
+            mClearAllShortTotalWidthTranslation =
+                    (mIsRtl
+                            ? mLastComputedTaskSize.right
+                            : deviceProfile.widthPx - mLastComputedTaskSize.left)
+                    - longRowWidth - deviceProfile.overviewGridSideMargin;
+            clearAllShortTotalWidthTranslation = mIsRtl
+                    ? -mClearAllShortTotalWidthTranslation : mClearAllShortTotalWidthTranslation;
+            if (snappedTaskRowWidth == longRowWidth) {
+                // Updated snappedTaskRowWidth as well if it's same as longRowWidth.
+                snappedTaskRowWidth += mClearAllShortTotalWidthTranslation;
+            }
+            longRowWidth += mClearAllShortTotalWidthTranslation;
+        } else {
+            mClearAllShortTotalWidthTranslation = 0;
         }
 
         float clearAllTotalTranslationX =
                 clearAllAccumulatedTranslation + clearAllShorterRowCompensation
-                        + clearAllShortTotalCompensation + snappedTaskNonGridScrollAdjustment;
+                        + clearAllShortTotalWidthTranslation + snappedTaskNonGridScrollAdjustment;
         if (focusedTaskIndex < taskCount) {
             // Shift by focused task's width and spacing if a task is focused.
             clearAllTotalTranslationX +=
@@ -2908,11 +2908,15 @@
         // Make sure there are enough space between snapped page and ClearAllButton, for the case
         // of swiping up after quick switch.
         if (snappedTaskView != null) {
-            int distanceFromClearAll = longRowWidth - snappedTaskRowWidth + mPageSpacing;
+            int distanceFromClearAll = longRowWidth - snappedTaskRowWidth;
             // ClearAllButton should be off screen when snapped task is in its snapped position.
             int minimumDistance =
-                    mTaskWidth - snappedTaskView.getLayoutParams().width
-                            + (mLastComputedGridSize.width() - mTaskWidth) / 2;
+                    (mIsRtl
+                            ? mLastComputedTaskSize.left
+                            : deviceProfile.widthPx - mLastComputedTaskSize.right)
+                    - deviceProfile.overviewGridSideMargin - mPageSpacing
+                    + (mTaskWidth - snappedTaskView.getLayoutParams().width)
+                    - mClearAllShortTotalWidthTranslation;
             if (distanceFromClearAll < minimumDistance) {
                 int distanceDifference = minimumDistance - distanceFromClearAll;
                 snappedTaskGridTranslationX += mIsRtl ? distanceDifference : -distanceDifference;
@@ -3195,6 +3199,7 @@
 
         // Grid specific properties.
         boolean isFocusedTaskDismissed = false;
+        boolean isStagingFocusedTask = false;
         TaskView nextFocusedTaskView = null;
         boolean nextFocusedTaskFromTop = false;
         float dismissedTaskWidth = 0;
@@ -3209,26 +3214,30 @@
         if (showAsGrid) {
             dismissedTaskWidth = dismissedTaskView.getLayoutParams().width + mPageSpacing;
             isFocusedTaskDismissed = dismissedTaskViewId == mFocusedTaskViewId;
-            if (isFocusedTaskDismissed && !isSplitSelectionActive()) {
-                nextFocusedTaskFromTop =
-                        mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
-                // Pick the next focused task from the preferred row.
-                for (int i = 0; i < taskCount; i++) {
-                    TaskView taskView = requireTaskViewAt(i);
-                    if (taskView == dismissedTaskView) {
-                        continue;
+            if (isFocusedTaskDismissed) {
+                if (isSplitSelectionActive()) {
+                    isStagingFocusedTask = true;
+                } else {
+                    nextFocusedTaskFromTop =
+                            mTopRowIdSet.size() > 0 && mTopRowIdSet.size() >= (taskCount - 1) / 2f;
+                    // Pick the next focused task from the preferred row.
+                    for (int i = 0; i < taskCount; i++) {
+                        TaskView taskView = requireTaskViewAt(i);
+                        if (taskView == dismissedTaskView) {
+                            continue;
+                        }
+                        boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
+                        if ((nextFocusedTaskFromTop && isTopRow
+                                || (!nextFocusedTaskFromTop && !isTopRow))) {
+                            nextFocusedTaskView = taskView;
+                            break;
+                        }
                     }
-                    boolean isTopRow = mTopRowIdSet.contains(taskView.getTaskViewId());
-                    if ((nextFocusedTaskFromTop && isTopRow
-                            || (!nextFocusedTaskFromTop && !isTopRow))) {
-                        nextFocusedTaskView = taskView;
-                        break;
+                    if (nextFocusedTaskView != null) {
+                        nextFocusedTaskWidth =
+                                nextFocusedTaskView.getLayoutParams().width + mPageSpacing;
                     }
                 }
-                if (nextFocusedTaskView != null) {
-                    nextFocusedTaskWidth =
-                            nextFocusedTaskView.getLayoutParams().width + mPageSpacing;
-                }
             }
         } else {
             getPageScrolls(oldScroll, false, SIMPLE_SCROLL_LOGIC);
@@ -3245,8 +3254,6 @@
         boolean snapToLastTask = false;
         boolean isLandscapeSplit =
                 mActivity.getDeviceProfile().isLandscape && isSplitSelectionActive();
-        boolean isSplitPlaceholderFirstInGrid = isSplitPlaceholderFirstInGrid();
-        boolean isSplitPlaceholderLastInGrid = isSplitPlaceholderLastInGrid();
         TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null;
         int currentPageScroll = getScrollForPage(mCurrentPage);
         int lastGridTaskScroll = getScrollForPage(indexOfChild(lastGridTaskView));
@@ -3258,42 +3265,69 @@
             float longGridRowWidthDiff = 0;
 
             int topGridRowSize = mTopRowIdSet.size();
-            int bottomGridRowSize = taskCount - mTopRowIdSet.size() - 1;
+            int bottomGridRowSize = taskCount - mTopRowIdSet.size()
+                    - (ENABLE_GRID_ONLY_OVERVIEW.get() ? 0 : 1);
             boolean topRowLonger = topGridRowSize > bottomGridRowSize;
             boolean bottomRowLonger = bottomGridRowSize > topGridRowSize;
             boolean dismissedTaskFromTop = mTopRowIdSet.contains(dismissedTaskViewId);
             boolean dismissedTaskFromBottom = !dismissedTaskFromTop && !isFocusedTaskDismissed;
+            if (dismissedTaskFromTop || (isFocusedTaskDismissed && nextFocusedTaskFromTop)) {
+                topGridRowSize--;
+            }
+            if (dismissedTaskFromBottom || (isFocusedTaskDismissed && !nextFocusedTaskFromTop)) {
+                bottomGridRowSize--;
+            }
+            int longRowWidth = Math.max(topGridRowSize, bottomGridRowSize)
+                    * (mLastComputedGridTaskSize.width() + mPageSpacing);
+            if (!ENABLE_GRID_ONLY_OVERVIEW.get() && !isStagingFocusedTask) {
+                longRowWidth += mLastComputedTaskSize.width() + mPageSpacing;
+            }
+
             float gapWidth = 0;
             if ((topRowLonger && dismissedTaskFromTop)
                     || (bottomRowLonger && dismissedTaskFromBottom)) {
                 gapWidth = dismissedTaskWidth;
-            } else if ((topRowLonger && nextFocusedTaskFromTop)
-                    || (bottomRowLonger && !nextFocusedTaskFromTop)) {
+            } else if (nextFocusedTaskView != null
+                    && ((topRowLonger && nextFocusedTaskFromTop)
+                    || (bottomRowLonger && !nextFocusedTaskFromTop))) {
                 gapWidth = nextFocusedTaskWidth;
             }
             if (gapWidth > 0) {
-                if (taskCount > 2) {
-                    // Compensate the removed gap.
-                    longGridRowWidthDiff += mIsRtl ? -gapWidth : gapWidth;
-                    if (isClearAllHidden) {
-                        // If ClearAllButton isn't fully shown, snap to the last task.
-                        snapToLastTask = true;
+                if (mClearAllShortTotalWidthTranslation == 0) {
+                    // Compensate the removed gap if we don't already have shortTotalCompensation,
+                    // and adjust accordingly to the new shortTotalCompensation after dismiss.
+                    int newClearAllShortTotalWidthTranslation = 0;
+                    if (longRowWidth < mLastComputedGridSize.width()) {
+                        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+                        newClearAllShortTotalWidthTranslation =
+                                (mIsRtl
+                                        ? mLastComputedTaskSize.right
+                                        : deviceProfile.widthPx - mLastComputedTaskSize.left)
+                                        - longRowWidth - deviceProfile.overviewGridSideMargin;
                     }
-                } else {
-                    // If only focused task will be left, snap to focused task instead.
-                    longGridRowWidthDiff += getSnapToFocusedTaskScrollDiff(isClearAllHidden);
+                    float gapCompensation = gapWidth - newClearAllShortTotalWidthTranslation;
+                    longGridRowWidthDiff += mIsRtl ? -gapCompensation : gapCompensation;
+                }
+                if (isClearAllHidden) {
+                    // If ClearAllButton isn't fully shown, snap to the last task.
+                    snapToLastTask = true;
                 }
             }
-            if (mClearAllButton.getAlpha() != 0f && isLandscapeSplit) {
-                // ClearAllButton will not be available in split select, snap to last task instead.
-                snapToLastTask = true;
+            if (isLandscapeSplit && !isStagingFocusedTask) {
+                // LastTask's scroll is the minimum scroll in split select, if current scroll is
+                // beyond that, we'll need to snap to last task instead.
+                TaskView lastTask = getLastGridTaskView();
+                if (lastTask != null) {
+                    int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+                    int lastTaskScroll = getScrollForPage(indexOfChild(lastTask));
+                    if ((mIsRtl && primaryScroll < lastTaskScroll)
+                            || (!mIsRtl && primaryScroll > lastTaskScroll)) {
+                        snapToLastTask = true;
+                    }
+                }
             }
             if (snapToLastTask) {
                 longGridRowWidthDiff += getSnapToLastTaskScrollDiff();
-                if (isSplitPlaceholderLastInGrid) {
-                    // Shift all the tasks to make space for split placeholder.
-                    longGridRowWidthDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
-                }
             } else if (isLandscapeSplit && currentPageSnapsToEndOfGrid) {
                 // Use last task as reference point for scroll diff and snapping calculation as it's
                 // the only invariant point in landscape split screen.
@@ -3451,8 +3485,6 @@
                 // dismissed index or next focused index. Offset successive task dismissal
                 // durations for a staggered effect.
                 distanceFromDismissedTask++;
-                boolean isStagingFocusedTask =
-                        isFocusedTaskDismissed && nextFocusedTaskView == null;
                 int staggerColumn =  isStagingFocusedTask
                         ? (int) Math.ceil(distanceFromDismissedTask / 2f)
                         : distanceFromDismissedTask;
@@ -3508,11 +3540,6 @@
                         int focusedTaskScrollDiff = primaryScroll - focusedTaskScroll;
                         primaryTranslation +=
                                 mIsRtl ? focusedTaskScrollDiff : -focusedTaskScrollDiff;
-                        if (isSplitPlaceholderFirstInGrid) {
-                            // Moves less if split placeholder is at the start.
-                            primaryTranslation +=
-                                    mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
-                        }
                     }
 
                     anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
@@ -3641,14 +3668,6 @@
                                         RecentsView.this);
                                 int currentPageScroll = getScrollForPage(mCurrentPage);
                                 mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
-                                // Compensate for coordinate shift by split placeholder.
-                                if (isSplitPlaceholderFirstInGrid && !finalSnapToLastTask) {
-                                    mCurrentPageScrollDiff +=
-                                            mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
-                                } else if (isSplitPlaceholderLastInGrid && finalSnapToLastTask) {
-                                    mCurrentPageScrollDiff +=
-                                            mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
-                                }
                             }
                         }
                     } else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
@@ -3669,7 +3688,9 @@
                     } else {
                         // Update focus task and its size.
                         if (finalIsFocusedTaskDismissed && finalNextFocusedTaskView != null) {
-                            mFocusedTaskViewId = finalNextFocusedTaskView.getTaskViewId();
+                            mFocusedTaskViewId = ENABLE_GRID_ONLY_OVERVIEW.get()
+                                    ? INVALID_TASK_ID
+                                    : finalNextFocusedTaskView.getTaskViewId();
                             mTopRowIdSet.remove(mFocusedTaskViewId);
                             finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
                         }
@@ -3688,8 +3709,7 @@
                                 int screenStart = mOrientationHandler.getPrimaryScroll(
                                         RecentsView.this);
                                 int taskStart = mOrientationHandler.getChildStart(taskView)
-                                        + (int) taskView.getOffsetAdjustment(/*fullscreenEnabled=*/
-                                        false, /*gridEnabled=*/ true);
+                                        + (int) taskView.getOffsetAdjustment(/*gridEnabled=*/ true);
 
                                 // Rebalance only if there is a maximum gap between the task and the
                                 // screen's edge; this ensures that rebalanced tasks are outside the
@@ -3767,6 +3787,10 @@
                 !mActivity.getDeviceProfile().isTablet);
         mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK,
                 !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get() && getTaskViewCount() <= 1);
+        if (DESKTOP_MODE_SUPPORTED) {
+            boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
+            mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
+        }
     }
 
     /**
@@ -3848,14 +3872,6 @@
                 REMOVE_TASK_WAIT_FOR_APP_STOP_MS);
     }
 
-    /**
-     * Returns {@code true} if one of the task thumbnails would intersect/overlap with the
-     * {@link #mFirstFloatingTaskView}.
-     */
-    public boolean shouldShiftThumbnailsForSplitSelect() {
-        return !mActivity.getDeviceProfile().isTablet || !mActivity.getDeviceProfile().isLandscape;
-    }
-
     protected void onDismissAnimationEnds() {
         AccessibilityManagerCompat.sendDismissAnimationEndsEventToTest(getContext());
     }
@@ -4414,65 +4430,6 @@
     }
 
     /**
-     * Apply scroll offset to children of RecentsView when entering split select.
-     */
-    public void applySplitPrimaryScrollOffset() {
-        float taskSplitScrollOffsetPrimary = 0f;
-        float clearAllSplitScrollOffsetPrimar = 0f;
-        if (isSplitPlaceholderFirstInGrid()) {
-            taskSplitScrollOffsetPrimary = mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
-        } else if (isSplitPlaceholderLastInGrid()) {
-            clearAllSplitScrollOffsetPrimar =
-                    mIsRtl ? -mSplitPlaceholderSize : mSplitPlaceholderSize;
-        }
-
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            requireTaskViewAt(i).setSplitScrollOffsetPrimary(taskSplitScrollOffsetPrimary);
-        }
-        mClearAllButton.setSplitSelectScrollOffsetPrimary(clearAllSplitScrollOffsetPrimar);
-    }
-
-    /**
-     * Returns if split placeholder is at the beginning of RecentsView. Always returns {@code false}
-     * if RecentsView is in portrait or RecentsView isn't shown as grid.
-     */
-    private boolean isSplitPlaceholderFirstInGrid() {
-        if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()
-                || !isSplitSelectionActive()) {
-            return false;
-        }
-        @StagePosition int position = mSplitSelectStateController.getActiveSplitStagePosition();
-        return mIsRtl
-                ? position == STAGE_POSITION_BOTTOM_OR_RIGHT
-                : position == STAGE_POSITION_TOP_OR_LEFT;
-    }
-
-    /**
-     * Returns if split placeholder is at the end of RecentsView. Always returns {@code false} if
-     * RecentsView is in portrait or RecentsView isn't shown as grid.
-     */
-    private boolean isSplitPlaceholderLastInGrid() {
-        if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()
-                || !isSplitSelectionActive()) {
-            return false;
-        }
-        @StagePosition int position = mSplitSelectStateController.getActiveSplitStagePosition();
-        return mIsRtl
-                ? position == STAGE_POSITION_TOP_OR_LEFT
-                : position == STAGE_POSITION_BOTTOM_OR_RIGHT;
-    }
-
-    /**
-     * Reset scroll offset on children of RecentsView when exiting split select.
-     */
-    public void resetSplitPrimaryScrollOffset() {
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            requireTaskViewAt(i).setSplitScrollOffsetPrimary(0);
-        }
-        mClearAllButton.setSplitSelectScrollOffsetPrimary(0);
-    }
-
-    /**
      * Resets the visuals when exit modal state.
      */
     public void resetModalVisuals() {
@@ -4680,14 +4637,29 @@
      * Note that the translation can be its primary or secondary dimension.
      */
     public float getSplitSelectTranslation() {
-        int splitPosition = getSplitSelectController().getActiveSplitStagePosition();
-        if (!shouldShiftThumbnailsForSplitSelect()) {
-            return 0f;
-        }
+        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
         PagedOrientationHandler orientationHandler = getPagedOrientationHandler();
+        int splitPosition = getSplitSelectController().getActiveSplitStagePosition();
+        int splitPlaceholderSize =
+                mActivity.getResources().getDimensionPixelSize(R.dimen.split_placeholder_size);
         int direction = orientationHandler.getSplitTranslationDirectionFactor(
-                splitPosition, mActivity.getDeviceProfile());
-        return mActivity.getResources().getDimension(R.dimen.split_placeholder_size) * direction;
+                splitPosition, deviceProfile);
+
+        if (deviceProfile.isTablet && deviceProfile.isLandscape) {
+            // Only shift TaskViews if there is not enough space on the side of
+            // mLastComputedTaskSize to minimize motion.
+            int sideSpace = mIsRtl
+                    ? deviceProfile.widthPx - mLastComputedTaskSize.right
+                    : mLastComputedTaskSize.left;
+            int extraSpace = splitPlaceholderSize + mPageSpacing - sideSpace;
+            if (extraSpace <= 0f) {
+                return 0f;
+            }
+
+            return extraSpace * direction;
+        }
+
+        return splitPlaceholderSize * direction;
     }
 
     protected void onRotateInSplitSelectionState() {
@@ -4709,8 +4681,6 @@
         if (mSplitInstructionsView != null) {
             mSplitInstructionsView.ensureProperRotation();
         }
-
-        applySplitPrimaryScrollOffset();
     }
 
     private void updateDeadZoneRects() {
@@ -5201,11 +5171,21 @@
     }
 
     private int getLastViewIndex() {
-        return mDisallowScrollToClearAll
-                ? mShowAsGridLastOnLayout
-                    ? indexOfChild(getLastGridTaskView())
-                    : getTaskViewCount() - 1
-                : indexOfChild(mClearAllButton);
+        if (!mDisallowScrollToClearAll) {
+            return indexOfChild(mClearAllButton);
+        }
+
+        if (!mShowAsGridLastOnLayout) {
+            return getTaskViewCount() - 1;
+        }
+
+        TaskView lastGridTaskView = getLastGridTaskView();
+        if (lastGridTaskView != null) {
+            return indexOfChild(lastGridTaskView);
+        }
+
+        // Returns focus task if there are no grid tasks.
+        return indexOfChild(getFocusedTaskView());
     }
 
     /**
@@ -5246,11 +5226,11 @@
         }
 
         final int taskCount = getTaskViewCount();
+        int lastTaskScroll = getLastTaskScroll(clearAllScroll, clearAllWidth);
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = requireTaskViewAt(i);
-            float scrollDiff = taskView.getScrollAdjustment(showAsFullscreen, showAsGrid);
+            float scrollDiff = taskView.getScrollAdjustment(showAsGrid);
             int pageScroll = newPageScrolls[i] + (int) scrollDiff;
-            int lastTaskScroll = getLastTaskScroll(clearAllScroll, clearAllWidth);
             if ((mIsRtl && pageScroll < lastTaskScroll)
                     || (!mIsRtl && pageScroll > lastTaskScroll)) {
                 pageScroll = lastTaskScroll;
@@ -5274,8 +5254,7 @@
         int childOffset = super.getChildOffset(index);
         View child = getChildAt(index);
         if (child instanceof TaskView) {
-            childOffset += ((TaskView) child).getOffsetAdjustment(showAsFullscreen(),
-                    showAsGrid());
+            childOffset += ((TaskView) child).getOffsetAdjustment(showAsGrid());
         } else if (child instanceof ClearAllButton) {
             childOffset += ((ClearAllButton) child).getOffsetAdjustment(mOverviewFullscreenEnabled,
                     showAsGrid());
@@ -5383,17 +5362,19 @@
         int gridTaskSizeAndSpacing = mLastComputedGridTaskSize.width() + mPageSpacing;
         int positionDiff = gridTaskSizeAndSpacing * (lastGridTaskViewPosition - taskViewPosition);
 
-        int lastTaskEnd = (mIsRtl
-                ? mLastComputedGridSize.left
-                : mLastComputedGridSize.right)
-                + (mIsRtl ? mPageSpacing : -mPageSpacing);
-        int taskEnd = lastTaskEnd + (mIsRtl ? positionDiff : -positionDiff);
+        int taskEnd = getLastTaskEnd() + (mIsRtl ? positionDiff : -positionDiff);
         int normalTaskEnd = mIsRtl
                 ? mLastComputedGridTaskSize.left
                 : mLastComputedGridTaskSize.right;
         return taskEnd - normalTaskEnd;
     }
 
+    private int getLastTaskEnd() {
+        return mIsRtl
+                ? mLastComputedGridSize.left + mPageSpacing + mClearAllShortTotalWidthTranslation
+                : mLastComputedGridSize.right - mPageSpacing - mClearAllShortTotalWidthTranslation;
+    }
+
     private int getPositionInRow(
             TaskView taskView, IntArray topRowIdArray, IntArray bottomRowIdArray) {
         int position = topRowIdArray.indexOf(taskView.getTaskViewId());
@@ -5693,14 +5674,10 @@
                 taskView = getTaskViewAt(--targetPage);
             }
             // Target a scroll where targetPage is on left of screen but still fully visible.
-            int lastTaskEnd = (mIsRtl
-                    ? mLastComputedGridSize.left
-                    : mLastComputedGridSize.right)
-                    + (mIsRtl ? mPageSpacing : -mPageSpacing);
             int normalTaskEnd = mIsRtl
                     ? mLastComputedGridTaskSize.left
                     : mLastComputedGridTaskSize.right;
-            int targetScroll = getScrollForPage(targetPage) + normalTaskEnd - lastTaskEnd;
+            int targetScroll = getScrollForPage(targetPage) + normalTaskEnd - getLastTaskEnd();
             // Find a page that is close to targetScroll while not over it.
             while (targetPage - 1 >= 0
                     && (mIsRtl
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index fb85605..b9aaef6 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -375,7 +375,6 @@
     // Used when in SplitScreenSelectState
     private float mSplitSelectTranslationY;
     private float mSplitSelectTranslationX;
-    private float mSplitSelectScrollOffsetPrimary;
 
     @Nullable
     private ObjectAnimator mIconAndDimAnimator;
@@ -1297,10 +1296,6 @@
         applyTranslationY();
     }
 
-    public void setSplitScrollOffsetPrimary(float splitSelectScrollOffsetPrimary) {
-        mSplitSelectScrollOffsetPrimary = splitSelectScrollOffsetPrimary;
-    }
-
     private void setDismissTranslationX(float x) {
         mDismissTranslationX = x;
         applyTranslationX();
@@ -1364,19 +1359,18 @@
         applyTranslationX();
     }
 
-    public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
+    public float getScrollAdjustment(boolean gridEnabled) {
         float scrollAdjustment = 0;
         if (gridEnabled) {
             scrollAdjustment += mGridTranslationX;
         } else {
             scrollAdjustment += getPrimaryNonGridTranslationProperty().get(this);
         }
-        scrollAdjustment += mSplitSelectScrollOffsetPrimary;
         return scrollAdjustment;
     }
 
-    public float getOffsetAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
-        return getScrollAdjustment(fullscreenEnabled, gridEnabled);
+    public float getOffsetAdjustment(boolean gridEnabled) {
+        return getScrollAdjustment(gridEnabled);
     }
 
     public float getSizeAdjustment(boolean fullscreenEnabled) {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index aed26d3..735c5e6 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -92,6 +92,7 @@
     @TaskbarModeSwitch(mode = TRANSIENT)
     public void testTransientLaunchApp() throws Exception {
         getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
+        mLauncher.getLaunchedAppState().assertTaskbarHidden();
     }
 
     @Test
@@ -140,6 +141,7 @@
     public void testTransientLaunchAppInSplitscreen() throws Exception {
         getTaskbar().getAppIcon(TEST_APP_NAME).dragToSplitscreen(
                 TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
+        mLauncher.getLaunchedAppState().assertTaskbarHidden();
     }
 
     @Test
diff --git a/res/drawable-sw600dp/ic_transient_taskbar_all_apps_button.xml b/res/drawable-sw600dp/ic_transient_taskbar_all_apps_button.xml
new file mode 100644
index 0000000..6e740ae
--- /dev/null
+++ b/res/drawable-sw600dp/ic_transient_taskbar_all_apps_button.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48">
+  <path
+      android:pathData="M13.5,17C12.538,17 11.715,16.65 11.033,15.967C10.35,15.285 10,14.462 10,13.5C10,12.538 10.35,11.715 11.033,11.033C11.715,10.35 12.538,10 13.5,10C14.462,10 15.285,10.35 15.967,11.033C16.65,11.715 17,12.538 17,13.5C17,14.462 16.65,15.285 15.967,15.967C15.285,16.65 14.462,17 13.5,17Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M24,17C23.038,17 22.215,16.65 21.532,15.967C20.85,15.285 20.5,14.462 20.5,13.5C20.5,12.538 20.85,11.715 21.532,11.033C22.215,10.35 23.038,10 24,10C24.962,10 25.785,10.35 26.468,11.033C27.15,11.715 27.5,12.538 27.5,13.5C27.5,14.462 27.15,15.285 26.468,15.967C25.785,16.65 24.962,17 24,17Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M34.5,17C33.537,17 32.715,16.65 32.033,15.967C31.35,15.285 31,14.462 31,13.5C31,12.538 31.35,11.715 32.033,11.033C32.715,10.35 33.537,10 34.5,10C35.463,10 36.285,10.35 36.967,11.033C37.65,11.715 38,12.538 38,13.5C38,14.462 37.65,15.285 36.967,15.967C36.285,16.65 35.463,17 34.5,17Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M13.5,27.5C12.538,27.5 11.715,27.15 11.033,26.468C10.35,25.785 10,24.962 10,24C10,23.038 10.35,22.215 11.033,21.532C11.715,20.85 12.538,20.5 13.5,20.5C14.462,20.5 15.285,20.85 15.967,21.532C16.65,22.215 17,23.038 17,24C17,24.962 16.65,25.785 15.967,26.468C15.285,27.15 14.462,27.5 13.5,27.5Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M24,27.5C23.038,27.5 22.215,27.15 21.532,26.468C20.85,25.785 20.5,24.962 20.5,24C20.5,23.038 20.85,22.215 21.532,21.532C22.215,20.85 23.038,20.5 24,20.5C24.962,20.5 25.785,20.85 26.468,21.532C27.15,22.215 27.5,23.038 27.5,24C27.5,24.962 27.15,25.785 26.468,26.468C25.785,27.15 24.962,27.5 24,27.5Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M34.5,27.5C33.537,27.5 32.715,27.15 32.033,26.468C31.35,25.785 31,24.962 31,24C31,23.038 31.35,22.215 32.033,21.532C32.715,20.85 33.537,20.5 34.5,20.5C35.463,20.5 36.285,20.85 36.967,21.532C37.65,22.215 38,23.038 38,24C38,24.962 37.65,25.785 36.967,26.468C36.285,27.15 35.463,27.5 34.5,27.5Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M13.5,38C12.538,38 11.715,37.65 11.033,36.967C10.35,36.285 10,35.463 10,34.5C10,33.537 10.35,32.715 11.033,32.033C11.715,31.35 12.538,31 13.5,31C14.462,31 15.285,31.35 15.967,32.033C16.65,32.715 17,33.537 17,34.5C17,35.463 16.65,36.285 15.967,36.967C15.285,37.65 14.462,38 13.5,38Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M24,38C23.038,38 22.215,37.65 21.532,36.967C20.85,36.285 20.5,35.463 20.5,34.5C20.5,33.537 20.85,32.715 21.532,32.033C22.215,31.35 23.038,31 24,31C24.962,31 25.785,31.35 26.468,32.033C27.15,32.715 27.5,33.537 27.5,34.5C27.5,35.463 27.15,36.285 26.468,36.967C25.785,37.65 24.962,38 24,38Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M34.5,38C33.537,38 32.715,37.65 32.033,36.967C31.35,36.285 31,35.463 31,34.5C31,33.537 31.35,32.715 32.033,32.033C32.715,31.35 33.537,31 34.5,31C35.463,31 36.285,31.35 36.967,32.033C37.65,32.715 38,33.537 38,34.5C38,35.463 37.65,36.285 36.967,36.967C36.285,37.65 35.463,38 34.5,38Z"
+      android:fillColor="#40484B"/>
+</vector>
diff --git a/res/drawable/ic_all_apps_button.xml b/res/drawable-sw720dp/ic_transient_taskbar_all_apps_button.xml
similarity index 100%
rename from res/drawable/ic_all_apps_button.xml
rename to res/drawable-sw720dp/ic_transient_taskbar_all_apps_button.xml
diff --git a/res/drawable/ic_taskbar_all_apps_button.xml b/res/drawable/ic_taskbar_all_apps_button.xml
new file mode 100644
index 0000000..82fbbea
--- /dev/null
+++ b/res/drawable/ic_taskbar_all_apps_button.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="44dp"
+    android:height="44dp"
+    android:viewportWidth="44"
+    android:viewportHeight="44">
+  <path
+      android:pathData="M13,16C12.175,16 11.47,15.7 10.885,15.115C10.3,14.53 10,13.825 10,13C10,12.175 10.3,11.47 10.885,10.885C11.47,10.3 12.175,10 13,10C13.825,10 14.53,10.3 15.115,10.885C15.7,11.47 16,12.175 16,13C16,13.825 15.7,14.53 15.115,15.115C14.53,15.7 13.825,16 13,16Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M22,16C21.175,16 20.47,15.7 19.885,15.115C19.3,14.53 19,13.825 19,13C19,12.175 19.3,11.47 19.885,10.885C20.47,10.3 21.175,10 22,10C22.825,10 23.53,10.3 24.115,10.885C24.7,11.47 25,12.175 25,13C25,13.825 24.7,14.53 24.115,15.115C23.53,15.7 22.825,16 22,16Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M31,16C30.175,16 29.47,15.7 28.885,15.115C28.3,14.53 28,13.825 28,13C28,12.175 28.3,11.47 28.885,10.885C29.47,10.3 30.175,10 31,10C31.825,10 32.53,10.3 33.115,10.885C33.7,11.47 34,12.175 34,13C34,13.825 33.7,14.53 33.115,15.115C32.53,15.7 31.825,16 31,16Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M13,25C12.175,25 11.47,24.7 10.885,24.115C10.3,23.53 10,22.825 10,22C10,21.175 10.3,20.47 10.885,19.885C11.47,19.3 12.175,19 13,19C13.825,19 14.53,19.3 15.115,19.885C15.7,20.47 16,21.175 16,22C16,22.825 15.7,23.53 15.115,24.115C14.53,24.7 13.825,25 13,25Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M22,25C21.175,25 20.47,24.7 19.885,24.115C19.3,23.53 19,22.825 19,22C19,21.175 19.3,20.47 19.885,19.885C20.47,19.3 21.175,19 22,19C22.825,19 23.53,19.3 24.115,19.885C24.7,20.47 25,21.175 25,22C25,22.825 24.7,23.53 24.115,24.115C23.53,24.7 22.825,25 22,25Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M31,25C30.175,25 29.47,24.7 28.885,24.115C28.3,23.53 28,22.825 28,22C28,21.175 28.3,20.47 28.885,19.885C29.47,19.3 30.175,19 31,19C31.825,19 32.53,19.3 33.115,19.885C33.7,20.47 34,21.175 34,22C34,22.825 33.7,23.53 33.115,24.115C32.53,24.7 31.825,25 31,25Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M13,34C12.175,34 11.47,33.7 10.885,33.115C10.3,32.53 10,31.825 10,31C10,30.175 10.3,29.47 10.885,28.885C11.47,28.3 12.175,28 13,28C13.825,28 14.53,28.3 15.115,28.885C15.7,29.47 16,30.175 16,31C16,31.825 15.7,32.53 15.115,33.115C14.53,33.7 13.825,34 13,34Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M22,34C21.175,34 20.47,33.7 19.885,33.115C19.3,32.53 19,31.825 19,31C19,30.175 19.3,29.47 19.885,28.885C20.47,28.3 21.175,28 22,28C22.825,28 23.53,28.3 24.115,28.885C24.7,29.47 25,30.175 25,31C25,31.825 24.7,32.53 24.115,33.115C23.53,33.7 22.825,34 22,34Z"
+      android:fillColor="#40484B"/>
+  <path
+      android:pathData="M31,34C30.175,34 29.47,33.7 28.885,33.115C28.3,32.53 28,31.825 28,31C28,30.175 28.3,29.47 28.885,28.885C29.47,28.3 30.175,28 31,28C31.825,28 32.53,28.3 33.115,28.885C33.7,29.47 34,30.175 34,31C34,31.825 33.7,32.53 33.115,33.115C32.53,33.7 31.825,34 31,34Z"
+      android:fillColor="#40484B"/>
+</vector>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 9e28608..df38c26 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -113,6 +113,8 @@
 
     private float mScaleForReorderBounce = 1f;
 
+    private float mTranslationXForTaskbarAllAppsIcon = 0f;
+
     private static final Property<BubbleTextView, Float> DOT_SCALE_PROPERTY
             = new Property<BubbleTextView, Float>(Float.TYPE, "dotScale") {
         @Override
@@ -961,6 +963,7 @@
     private void updateTranslation() {
         super.setTranslationX(mTranslationForReorderBounce.x
                 + mTranslationForReorderPreview.x
+                + mTranslationXForTaskbarAllAppsIcon
                 + mTranslationForMoveFromCenterAnimation.x
                 + mTranslationXForTaskbarAlignmentAnimation
                 + mTranslationXForTaskbarRevealAnimation
@@ -972,6 +975,14 @@
                 + mTranslationYForTaskbarRevealAnimation);
     }
 
+    /**
+     * Sets translationX for taskbar all apps icon
+     */
+    public void setTranslationXForTaskbarAllAppsIcon(float translationX) {
+        mTranslationXForTaskbarAllAppsIcon = translationX;
+        updateTranslation();
+    }
+
     public void setReorderBounceOffset(float x, float y) {
         mTranslationForReorderBounce.set(x, y);
         updateTranslation();
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 90b2374..8a90d0e 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -1597,6 +1597,8 @@
         writer.println(prefix + pxToDpStr("iconTextSizePx", iconTextSizePx));
         writer.println(prefix + pxToDpStr("iconDrawablePaddingPx", iconDrawablePaddingPx));
 
+        writer.println(prefix + "\tinv.numFolderRows: " + inv.numFolderRows);
+        writer.println(prefix + "\tinv.numFolderColumns: " + inv.numFolderColumns);
         writer.println(prefix + pxToDpStr("folderCellWidthPx", folderCellWidthPx));
         writer.println(prefix + pxToDpStr("folderCellHeightPx", folderCellHeightPx));
         writer.println(prefix + pxToDpStr("folderChildIconSizePx", folderChildIconSizePx));
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 06ea72c..de60d05 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1860,6 +1860,9 @@
     }
 
     private void setWorkspaceLoading(boolean value) {
+        if (TestProtocol.sDebugTracing) {
+            Log.d(TestProtocol.FLAKY_BINDING, "running: setWorkspaceLoading=" + value);
+        }
         mWorkspaceLoading = value;
     }
 
@@ -2306,6 +2309,9 @@
      */
     public void startBinding() {
         Object traceToken = TraceHelper.INSTANCE.beginSection("startBinding");
+        if (TestProtocol.sDebugTracing) {
+            Log.d(TestProtocol.FLAKY_BINDING, "running: startBinding");
+        }
         // Floating panels (except the full widget sheet) are associated with individual icons. If
         // we are starting a fresh bind, close all such panels as all the icons are about
         // to go away.
@@ -2778,6 +2784,9 @@
      */
     public void finishBindingItems(IntSet pagesBoundFirst) {
         Object traceToken = TraceHelper.INSTANCE.beginSection("finishBindingItems");
+        if (TestProtocol.sDebugTracing) {
+            Log.d(TestProtocol.FLAKY_BINDING, "running: finishBindingItems");
+        }
         mWorkspace.restoreInstanceStateForRemainingPages();
 
         setWorkspaceLoading(false);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 67bc7fc..7d01f7b 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -131,10 +131,10 @@
     /**
      * Indicates if the device has a debug build. Should only be used to store additional info or
      * add extra logging and not for changing the app behavior.
+     * @deprecated Use {@link BuildConfig#IS_DEBUG_DEVICE} directly
      */
-    public static final boolean IS_DEBUG_DEVICE =
-            Build.TYPE.toLowerCase(Locale.ROOT).contains("debug") ||
-            Build.TYPE.toLowerCase(Locale.ROOT).equals("eng");
+    @Deprecated
+    public static final boolean IS_DEBUG_DEVICE = BuildConfig.IS_DEBUG_DEVICE;
 
     /**
      * Returns true if theme is dark.
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index de79154..db2b759 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -36,18 +36,22 @@
     private FeatureFlags() { }
 
     public static boolean showFlagTogglerUi(Context context) {
-        return Utilities.IS_DEBUG_DEVICE && Utilities.isDevelopersOptionsEnabled(context);
+        return BuildConfig.IS_DEBUG_DEVICE && Utilities.isDevelopersOptionsEnabled(context);
     }
 
     /**
      * True when the build has come from Android Studio and is being used for local debugging.
+     * @deprecated Use {@link BuildConfig#IS_STUDIO_BUILD} directly
      */
-    public static final boolean IS_STUDIO_BUILD = BuildConfig.DEBUG;
+    @Deprecated
+    public static final boolean IS_STUDIO_BUILD = BuildConfig.IS_STUDIO_BUILD;
 
     /**
      * Enable moving the QSB on the 0th screen of the workspace. This is not a configuration feature
      * and should be modified at a project level.
+     * @deprecated Use {@link BuildConfig#QSB_ON_FIRST_SCREEN} directly
      */
+    @Deprecated
     public static final boolean QSB_ON_FIRST_SCREEN = BuildConfig.QSB_ON_FIRST_SCREEN;
 
     /**
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index 9f8db51..8519a3e 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -246,6 +246,9 @@
             sortWorkspaceItemsSpatially(idp, otherWorkspaceItems);
 
             // Tell the workspace that we're about to start binding items
+            if (TestProtocol.sDebugTracing) {
+                Log.d(TestProtocol.FLAKY_BINDING, "scheduling: startBinding");
+            }
             executeCallbacksTask(c -> {
                 c.clearPendingBinds();
                 c.startBinding();
@@ -264,6 +267,9 @@
             Executor pendingExecutor = pendingTasks::add;
             bindWorkspaceItems(otherWorkspaceItems, pendingExecutor);
             bindAppWidgets(otherAppWidgets, pendingExecutor);
+            if (TestProtocol.sDebugTracing) {
+                Log.d(TestProtocol.FLAKY_BINDING, "scheduling: finishBindingItems");
+            }
             executeCallbacksTask(c -> c.finishBindingItems(currentScreenIds), pendingExecutor);
             pendingExecutor.execute(
                     () -> {
diff --git a/src/com/android/launcher3/views/IconButtonView.java b/src/com/android/launcher3/views/IconButtonView.java
index 64e9327..9969eeb 100644
--- a/src/com/android/launcher3/views/IconButtonView.java
+++ b/src/com/android/launcher3/views/IconButtonView.java
@@ -31,6 +31,7 @@
 import android.util.AttributeSet;
 
 import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.icons.BaseIconFactory;
@@ -70,6 +71,15 @@
         }
     }
 
+    /** Sets given Drawable as icon */
+    public void setIconDrawable(@NonNull Drawable drawable) {
+        ColorStateList tintList = getBackgroundTintList();
+        int tint = tintList == null ? Color.WHITE : tintList.getDefaultColor();
+        try (BaseIconFactory factory = LauncherIcons.obtain(getContext())) {
+            setIcon(new IconDrawable(factory.getWhiteShadowLayer(), tint, drawable));
+        }
+    }
+
     /** Updates the color of the icon's foreground layer. */
     public void setForegroundTint(@ColorInt int tintColor) {
         FastBitmapDrawable icon = getIcon();
diff --git a/src_build_config/com/android/launcher3/BuildConfig.java b/src_build_config/com/android/launcher3/BuildConfig.java
index 9a81d3f..1f2e0e5 100644
--- a/src_build_config/com/android/launcher3/BuildConfig.java
+++ b/src_build_config/com/android/launcher3/BuildConfig.java
@@ -18,10 +18,16 @@
 
 public final class BuildConfig {
     public static final String APPLICATION_ID = "com.android.launcher3";
-    public static final boolean DEBUG = false;
+
+    public static final boolean IS_STUDIO_BUILD = false;
     /**
      * Flag to state if the QSB is on the first screen and placed on the top,
      * this can be overwritten in other launchers with a different value, if needed.
      */
     public static final boolean QSB_ON_FIRST_SCREEN = true;
+
+    /**
+     * Flag to control various developer centric features
+     */
+    public static final boolean IS_DEBUG_DEVICE = false;
 }
diff --git a/tests/Android.bp b/tests/Android.bp
index 7144d65..dfbaf86 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -44,6 +44,7 @@
     srcs: [
       "src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
       "src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
+      "src/com/android/launcher3/ui/TaplTestsLauncher3.java",
       "src/com/android/launcher3/util/TestUtil.java",
       "src/com/android/launcher3/util/Wait.java",
       "src/com/android/launcher3/util/WidgetUtils.java",
@@ -54,7 +55,7 @@
       "src/com/android/launcher3/util/rule/ShellCommandRule.java",
       "src/com/android/launcher3/util/rule/SimpleActivityRule.java",
       "src/com/android/launcher3/util/rule/TestStabilityRule.java",
-      "src/com/android/launcher3/ui/TaplTestsLauncher3.java",
+      "src/com/android/launcher3/util/rule/TISBindRule.java",
       "src/com/android/launcher3/testcomponent/BaseTestingActivity.java",
       "src/com/android/launcher3/testcomponent/OtherBaseTestingActivity.java",
       "src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java",
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 65873f1..cc6fa33 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -154,6 +154,7 @@
     public static final String MISSING_PROMISE_ICON = "b/202985412";
     public static final String TASKBAR_IN_APP_STATE = "b/227657604";
     public static final String NPE_TRANSIENT_TASKBAR = "b/257549303";
+    public static final String FLAKY_BINDING = "b/270216650";
 
     public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
     public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
index 77fca96..c2fe3de 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.celllayout.testcases.SimpleReorderCase;
 import com.android.launcher3.tapl.Widget;
 import com.android.launcher3.tapl.WidgetResizeFrame;
+import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.TaplTestsLauncher3;
 import com.android.launcher3.util.rule.ShellCommandRule;
@@ -118,7 +119,14 @@
         // waitForLauncherCondition to wait for that condition, otherwise the condition would
         // always be true and it wouldn't wait for the changes to be applied.
         resetLoaderState();
-        waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading());
+        Log.d(TestProtocol.FLAKY_BINDING, "waiting for: isWorkspaceLoading=false");
+        waitForLauncherCondition("Workspace didn't finish loading", l -> {
+            boolean isWorkspaceLoading = l.isWorkspaceLoading();
+
+            Log.d(TestProtocol.FLAKY_BINDING, "checking: isWorkspaceLoading=" + isWorkspaceLoading);
+
+            return !isWorkspaceLoading;
+        });
         Widget widget = mLauncher.getWorkspace().getWidgetAtCell(mainWidgetCellPos.getCellX(),
                 mainWidgetCellPos.getCellY());
         assertNotNull(widget);
diff --git a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
index d981267..af31e93 100644
--- a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
@@ -76,6 +76,8 @@
                     "\ticonSizePx: 147.0px (56.0dp)\n" +
                     "\ticonTextSizePx: 38.0px (14.476191dp)\n" +
                     "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tinv.numFolderRows: 4\n" +
+                    "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 195.0px (74.28571dp)\n" +
                     "\tfolderCellHeightPx: 230.0px (87.61905dp)\n" +
                     "\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
@@ -206,6 +208,8 @@
                     "\ticonSizePx: 147.0px (56.0dp)\n" +
                     "\ticonTextSizePx: 38.0px (14.476191dp)\n" +
                     "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tinv.numFolderRows: 4\n" +
+                    "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 195.0px (74.28571dp)\n" +
                     "\tfolderCellHeightPx: 230.0px (87.61905dp)\n" +
                     "\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
@@ -336,6 +340,8 @@
                     "\ticonSizePx: 147.0px (56.0dp)\n" +
                     "\ticonTextSizePx: 0.0px (0.0dp)\n" +
                     "\ticonDrawablePaddingPx: 0.0px (0.0dp)\n" +
+                    "\tinv.numFolderRows: 4\n" +
+                    "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 142.0px (54.095238dp)\n" +
                     "\tfolderCellHeightPx: 168.0px (64.0dp)\n" +
                     "\tfolderChildIconSizePx: 108.0px (41.142857dp)\n" +
@@ -466,6 +472,8 @@
                     "\ticonSizePx: 147.0px (56.0dp)\n" +
                     "\ticonTextSizePx: 0.0px (0.0dp)\n" +
                     "\ticonDrawablePaddingPx: 0.0px (0.0dp)\n" +
+                    "\tinv.numFolderRows: 4\n" +
+                    "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 128.0px (48.761906dp)\n" +
                     "\tfolderCellHeightPx: 152.0px (57.904762dp)\n" +
                     "\tfolderChildIconSizePx: 98.0px (37.333332dp)\n" +
@@ -597,6 +605,8 @@
                     "\ticonSizePx: 120.0px (60.0dp)\n" +
                     "\ticonTextSizePx: 28.0px (14.0dp)\n" +
                     "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tinv.numFolderRows: 3\n" +
+                    "\tinv.numFolderColumns: 3\n" +
                     "\tfolderCellWidthPx: 397.0px (198.5dp)\n" +
                     "\tfolderCellHeightPx: 371.0px (185.5dp)\n" +
                     "\tfolderChildIconSizePx: 99.0px (49.5dp)\n" +
@@ -728,6 +738,8 @@
                     "\ticonSizePx: 120.0px (60.0dp)\n" +
                     "\ticonTextSizePx: 28.0px (14.0dp)\n" +
                     "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tinv.numFolderRows: 3\n" +
+                    "\tinv.numFolderColumns: 3\n" +
                     "\tfolderCellWidthPx: 397.0px (198.5dp)\n" +
                     "\tfolderCellHeightPx: 371.0px (185.5dp)\n" +
                     "\tfolderChildIconSizePx: 99.0px (49.5dp)\n" +
@@ -859,6 +871,8 @@
                     "\ticonSizePx: 120.0px (60.0dp)\n" +
                     "\ticonTextSizePx: 28.0px (14.0dp)\n" +
                     "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tinv.numFolderRows: 3\n" +
+                    "\tinv.numFolderColumns: 3\n" +
                     "\tfolderCellWidthPx: 408.0px (204.0dp)\n" +
                     "\tfolderCellHeightPx: 648.0px (324.0dp)\n" +
                     "\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
@@ -990,6 +1004,8 @@
                     "\ticonSizePx: 120.0px (60.0dp)\n" +
                     "\ticonTextSizePx: 28.0px (14.0dp)\n" +
                     "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tinv.numFolderRows: 3\n" +
+                    "\tinv.numFolderColumns: 3\n" +
                     "\tfolderCellWidthPx: 408.0px (204.0dp)\n" +
                     "\tfolderCellHeightPx: 648.0px (324.0dp)\n" +
                     "\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
@@ -1126,6 +1142,8 @@
                     "\ticonSizePx: 141.0px (53.714287dp)\n" +
                     "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
                     "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tinv.numFolderRows: 3\n" +
+                    "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
                     "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
                     "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
@@ -1261,6 +1279,8 @@
                     "\ticonSizePx: 141.0px (53.714287dp)\n" +
                     "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
                     "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tinv.numFolderRows: 3\n" +
+                    "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
                     "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
                     "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
@@ -1396,6 +1416,8 @@
                     "\ticonSizePx: 141.0px (53.714287dp)\n" +
                     "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
                     "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tinv.numFolderRows: 3\n" +
+                    "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
                     "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
                     "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
@@ -1527,6 +1549,8 @@
                     "\ticonSizePx: 141.0px (53.714287dp)\n" +
                     "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
                     "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tinv.numFolderRows: 3\n" +
+                    "\tinv.numFolderColumns: 4\n" +
                     "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
                     "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
                     "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 401c25a4..19b8b0c 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -51,11 +51,13 @@
 import com.android.launcher3.tapl.Workspace;
 import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.util.rule.TISBindRule;
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
 import com.android.launcher3.widget.picker.WidgetsRecyclerView;
 
 import org.junit.Before;
 import org.junit.Ignore;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -71,6 +73,9 @@
     private static final String STORE_APP_NAME = "Play Store";
     private static final String GMAIL_APP_NAME = "Gmail";
 
+    @Rule
+    public TISBindRule mTISBindRule = new TISBindRule();
+
     @Before
     public void setUp() throws Exception {
         super.setUp();
@@ -214,7 +219,7 @@
                 false /* tapRight */);
     }
 
-    @IwTest(focusArea="launcher")
+    @IwTest(focusArea = "launcher")
     @Test
     @ScreenRecord // b/202433017
     public void testWorkspace() throws Exception {
@@ -341,7 +346,7 @@
         }
     }
 
-    @IwTest(focusArea="launcher")
+    @IwTest(focusArea = "launcher")
     @Test
     @PortraitLandscape
     @ScreenRecord // b/256898879
@@ -610,16 +615,16 @@
 
     /**
      * @return List of workspace grid coordinates. Those are not pixels. See {@link
-     *     Workspace#getIconGridDimensions()}
+     * Workspace#getIconGridDimensions()}
      */
     private Point[] getCornersAndCenterPositions() {
         final Point dimensions = mLauncher.getWorkspace().getIconGridDimensions();
-        return new Point[] {
-            new Point(0, 1),
-            new Point(0, dimensions.y - 2),
-            new Point(dimensions.x - 1, 1),
-            new Point(dimensions.x - 1, dimensions.y - 2),
-            new Point(dimensions.x / 2, dimensions.y / 2)
+        return new Point[]{
+                new Point(0, 1),
+                new Point(0, dimensions.y - 2),
+                new Point(dimensions.x - 1, 1),
+                new Point(dimensions.x - 1, dimensions.y - 2),
+                new Point(dimensions.x / 2, dimensions.y / 2)
         };
     }
 
diff --git a/tests/src/com/android/launcher3/util/rule/TISBindRule.java b/tests/src/com/android/launcher3/util/rule/TISBindRule.java
new file mode 100644
index 0000000..3ec4a29
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/TISBindRule.java
@@ -0,0 +1,81 @@
+/*
+ * 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.rule;
+
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+public class TISBindRule implements TestRule {
+    public static String TAG = "TISBindRule";
+    public static String INTENT_FILTER = "android.intent.action.QUICKSTEP_SERVICE";
+    public static String TIS_PERMISSIONS = "android.permission.STATUS_BAR_SERVICE";
+
+    private String getLauncherPackageName(Context context) {
+        return ComponentName.unflattenFromString(context.getString(
+                com.android.internal.R.string.config_recentsComponentName)).getPackageName();
+    }
+
+    private ServiceConnection createConnection() {
+        return new ServiceConnection() {
+            @Override
+            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+                Log.d(TAG, "Connected to TouchInteractionService");
+            }
+
+            @Override
+            public void onServiceDisconnected(ComponentName componentName) {
+                Log.d(TAG, "Disconnected from TouchInteractionService");
+            }
+        };
+    }
+
+    @NonNull
+    @Override
+    public Statement apply(@NonNull Statement base, @NonNull Description description) {
+        return new Statement() {
+
+            @Override
+            public void evaluate() throws Throwable {
+                Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+                final ServiceConnection connection = createConnection();
+                UiAutomation uiAutomation =
+                        InstrumentationRegistry.getInstrumentation().getUiAutomation();
+                uiAutomation.adoptShellPermissionIdentity(TIS_PERMISSIONS);
+                Intent launchIntent = new Intent(INTENT_FILTER);
+                launchIntent.setPackage(getLauncherPackageName(context));
+                context.bindService(launchIntent, connection, Context.BIND_AUTO_CREATE);
+                uiAutomation.dropShellPermissionIdentity();
+                try {
+                    base.evaluate();
+                } finally {
+                    context.unbindService(connection);
+                }
+            }
+        };
+    }
+}