Merge "Handle swipe up after quick switch in overview grid" into sc-dev
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index c547d00..aba2af2 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -966,6 +966,9 @@
             if (mRecentsView != null) {
                 int nearestPage = mRecentsView.getDestinationPage();
                 boolean isScrolling = false;
+                // Update page scroll before snapping to page to make sure we snapped to the
+                // position calculated with target gesture in mind.
+                mRecentsView.updateScrollSynchronously();
                 if (mRecentsView.getNextPage() != nearestPage) {
                     // We shouldn't really scroll to the next page when swiping up to recents.
                     // Only allow settling on the next page if it's nearest to the center.
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 854a140..4d4b6e1 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -17,6 +17,7 @@
 
 import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
 import static com.android.quickstep.fallback.RecentsState.DEFAULT;
+import static com.android.quickstep.fallback.RecentsState.HOME;
 import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
 
 import android.annotation.TargetApi;
@@ -98,6 +99,15 @@
     }
 
     @Override
+    public void onGestureAnimationEnd() {
+        if (mCurrentGestureEndTarget == GestureState.GestureEndTarget.HOME) {
+            // Clean-up logic that occurs when recents is no longer in use/visible.
+            reset();
+        }
+        super.onGestureAnimationEnd();
+    }
+
+    @Override
     public void setCurrentTask(int runningTaskId) {
         super.setCurrentTask(runningTaskId);
         if (mHomeTaskInfo != null && mHomeTaskInfo.taskId != runningTaskId) {
@@ -156,11 +166,6 @@
     }
 
     @Override
-    protected boolean isHomeTask(TaskView taskView) {
-        return mHomeTaskInfo != null && taskView.hasTaskId(mHomeTaskInfo.taskId);
-    }
-
-    @Override
     public void setModalStateEnabled(boolean isModalState) {
         super.setModalStateEnabled(isModalState);
         if (isModalState) {
@@ -182,6 +187,10 @@
 
     @Override
     public void onStateTransitionComplete(RecentsState finalState) {
+        if (finalState == HOME) {
+            // Clean-up logic that occurs when recents is no longer in use/visible.
+            reset();
+        }
         setOverlayEnabled(finalState == DEFAULT || finalState == MODAL_TASK);
         setFreezeViewVisibility(false);
     }
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index 4300329..b9a9006 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -97,7 +97,7 @@
         }
     }
 
-    public void onRecentsViewScroll(int scrollFromEdge, boolean gridEnabled) {
+    public void onRecentsViewScroll(int scroll, boolean gridEnabled) {
         RecentsView recentsView = getRecentsView();
         if (recentsView == null) {
             return;
@@ -109,8 +109,8 @@
             return;
         }
 
-        int leftEdgeScroll = recentsView.getLeftMostChildScroll();
-        int adjustedScrollFromEdge = scrollFromEdge - leftEdgeScroll;
+        int clearAllScroll = recentsView.getClearAllScroll();
+        int adjustedScrollFromEdge = Math.abs(scroll - clearAllScroll);
         float shift = Math.min(adjustedScrollFromEdge, orientationSize);
         mNormalTranslationPrimary = mIsRtl ? -shift : shift;
         if (!gridEnabled) {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 87c46bf..5d3e0b8 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -355,7 +355,7 @@
     private float mGridProgress = 0;
 
     // The GestureEndTarget that is still in progress.
-    private GestureState.GestureEndTarget mCurrentGestureEndTarget;
+    protected GestureState.GestureEndTarget mCurrentGestureEndTarget;
 
     IntSet mTopIdSet = new IntSet();
 
@@ -818,9 +818,9 @@
 
     private boolean isTaskViewWithinBounds(TaskView tv, int start, int end) {
         int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
-                mOverviewFullscreenEnabled, showAsGrid());
+                showAsFullscreen(), showAsGrid());
         int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
-                mOverviewFullscreenEnabled));
+                showAsFullscreen()));
         int taskEnd = taskStart + taskSize;
         return (taskStart >= start && taskStart <= end) || (taskEnd >= start
                 && taskEnd <= end);
@@ -1194,16 +1194,8 @@
 
         float accumulatedTranslationX = 0;
         float[] fullscreenTranslations = new float[taskCount];
-        int firstNonHomeTaskIndex = 0;
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = getTaskViewAt(i);
-            if (isHomeTask(taskView)) {
-                if (firstNonHomeTaskIndex == i) {
-                    firstNonHomeTaskIndex++;
-                }
-                continue;
-            }
-
             taskView.updateTaskSize();
             fullscreenTranslations[i] += accumulatedTranslationX;
             // Compensate space caused by TaskView scaling.
@@ -1215,16 +1207,12 @@
             accumulatedTranslationX += fullscreenTranslationX;
         }
 
-        // We need to maintain first non-home task's full screen translation at 0, now shift
-        // translation of all the TaskViews to achieve that.
-        for (int i = firstNonHomeTaskIndex; i < taskCount; i++) {
-            getTaskViewAt(i).setFullscreenTranslationX(
-                    fullscreenTranslations[i] - fullscreenTranslations[firstNonHomeTaskIndex]);
+        for (int i = 0; i < taskCount; i++) {
+            getTaskViewAt(i).setFullscreenTranslationX(fullscreenTranslations[i]);
         }
-        mClearAllButton.setFullscreenTranslationPrimary(
-                accumulatedTranslationX - fullscreenTranslations[firstNonHomeTaskIndex]);
+        mClearAllButton.setFullscreenTranslationPrimary(accumulatedTranslationX);
 
-        updateGridProperties(false);
+        updateGridProperties(/*isTaskDismissal=*/false);
     }
 
     public void getTaskSize(Rect outRect) {
@@ -1311,13 +1299,12 @@
             return;
         }
         int scroll = mOrientationHandler.getPrimaryScroll(this);
-        int scrollFromEdge = mIsRtl ? scroll : (mMaxScroll - scroll);
-        mClearAllButton.onRecentsViewScroll(scrollFromEdge, mOverviewGridEnabled);
+        mClearAllButton.onRecentsViewScroll(scroll, mOverviewGridEnabled);
     }
 
     @Override
     protected int getDestinationPage(int scaledScroll) {
-        if (!showAsGrid()) {
+        if (!(mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get())) {
             return super.getDestinationPage(scaledScroll);
         }
 
@@ -1326,8 +1313,8 @@
             return -1;
         }
 
-        // When in grid, return the page which scroll is closest to screenStart instead of page
-        // nearest to center of screen.
+        // When in tablet with variable task width, return the page which scroll is closest to
+        // screenStart instead of page nearest to center of screen.
         int minDistanceFromScreenStart = Integer.MAX_VALUE;
         int minDistanceFromScreenStartIndex = -1;
         for (int i = 0; i < childCount; ++i) {
@@ -1578,10 +1565,12 @@
      */
     public void onGestureEndTargetCalculated(GestureState.GestureEndTarget endTarget) {
         mCurrentGestureEndTarget = endTarget;
-        if (showAsGrid()) {
-            mFocusedTaskId = mRunningTaskId;
-            mFocusedTaskRatio =
-                    mLastComputedTaskSize.width() / (float) mLastComputedTaskSize.height();
+        if (endTarget == GestureState.GestureEndTarget.NEW_TASK
+                || endTarget == GestureState.GestureEndTarget.LAST_TASK) {
+            // When switching to tasks in quick switch, ensures the snapped page's scroll maintain
+            // invariant between quick switch and overview grid, to ensure a smooth animation
+            // transition.
+            updateGridProperties(/*isTaskDismissal=*/false);
         }
     }
 
@@ -1645,7 +1634,11 @@
         }
 
         boolean runningTaskTileHidden = mRunningTaskTileHidden;
-        setCurrentTask(runningTaskInfo == null ? -1 : runningTaskInfo.taskId);
+        int runningTaskId = runningTaskInfo == null ? -1 : runningTaskInfo.taskId;
+        setCurrentTask(runningTaskId);
+        if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+            setFocusedTask(runningTaskId);
+        }
         setCurrentPage(getRunningTaskIndex());
         setRunningTaskViewShowScreenshot(false);
         setRunningTaskHidden(runningTaskTileHidden);
@@ -1658,7 +1651,6 @@
 
     /**
      * Sets the running task id, cleaning up the old running task if necessary.
-     * @param runningTaskId
      */
     public void setCurrentTask(int runningTaskId) {
         if (mRunningTaskId == runningTaskId) {
@@ -1675,6 +1667,15 @@
     }
 
     /**
+     * Sets the focused task id and store the width to height ratio of the focused task.
+     */
+    protected void setFocusedTask(int focusedTaskId) {
+        mFocusedTaskId = focusedTaskId;
+        mFocusedTaskRatio =
+                mLastComputedTaskSize.width() / (float) mLastComputedTaskSize.height();
+    }
+
+    /**
      * Hides the tile associated with {@link #mRunningTaskId}
      */
     public void setRunningTaskHidden(boolean isHidden) {
@@ -1768,74 +1769,115 @@
         IntSet topSet = new IntSet();
         IntSet bottomSet = new IntSet();
         float[] gridTranslations = new float[taskCount];
-        int firstNonHomeTaskIndex = 0;
+
+        int focusedTaskIndex = Integer.MAX_VALUE;
+        int focusedTaskShift = 0;
+        int focusedTaskWidthAndSpacing = 0;
+        int snappedTaskRowWidth = 0;
+        int snappedPage = getNextPage();
+        TaskView snappedTaskView = getTaskViewAtByAbsoluteIndex(snappedPage);
 
         if (!isTaskDismissal) {
             mTopIdSet.clear();
         }
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = getTaskViewAt(i);
-            if (isHomeTask(taskView)) {
-                if (firstNonHomeTaskIndex == i) {
-                    firstNonHomeTaskIndex++;
-                }
-                continue;
-            }
-
+            int taskWidthAndSpacing = taskView.getLayoutParams().width + mPageSpacing;
             // Evenly distribute tasks between rows unless rearranging due to task dismissal, in
             // which case keep tasks in their respective rows. For the running task, don't join
             // the grid.
-            if (taskView.isRunningTask()) {
-                topRowWidth += taskView.getLayoutParams().width + mPageSpacing;
-                bottomRowWidth += taskView.getLayoutParams().width + mPageSpacing;
+            if (taskView.isFocusedTask()) {
+                topRowWidth += taskWidthAndSpacing;
+                bottomRowWidth += taskWidthAndSpacing;
+
+                focusedTaskIndex = i;
+                focusedTaskWidthAndSpacing = taskWidthAndSpacing;
+                gridTranslations[i] += focusedTaskShift;
+                gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
 
                 // Center view vertically in case it's from different orientation.
                 taskView.setGridTranslationY((mLastComputedTaskSize.height() + taskTopMargin
                         - taskView.getLayoutParams().height) / 2f);
-            } else if ((!isTaskDismissal && topRowWidth <= bottomRowWidth) || (isTaskDismissal
-                        && mTopIdSet.contains(taskView.getTask().key.id))) {
-                gridTranslations[i] += topAccumulatedTranslationX;
-                topRowWidth += taskView.getLayoutParams().width + mPageSpacing;
-                topSet.add(i);
-                mTopIdSet.add(taskView.getTask().key.id);
 
-                taskView.setGridTranslationY(taskGridVerticalDiff);
-
-                // Move horizontally into empty space.
-                float widthOffset = 0;
-                for (int j = i - 1; bottomSet.contains(j); j--) {
-                    widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
+                if (taskView == snappedTaskView) {
+                    // If focused task is snapped, the row width is just task width and spacing.
+                    snappedTaskRowWidth = taskWidthAndSpacing;
                 }
-
-                float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
-                gridTranslations[i] += gridTranslationX;
-                topAccumulatedTranslationX += gridTranslationX;
             } else {
-                gridTranslations[i] += bottomAccumulatedTranslationX;
-                bottomRowWidth += taskView.getLayoutParams().width + mPageSpacing;
-                bottomSet.add(i);
-
-                // Move into bottom row.
-                taskView.setGridTranslationY(heightOffset + taskGridVerticalDiff);
-
-                // Move horizontally into empty space.
-                float widthOffset = 0;
-                for (int j = i - 1; topSet.contains(j); j--) {
-                    widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
+                if (i > focusedTaskIndex) {
+                    // For tasks after the focused task, shift by focused task's width and spacing.
+                    gridTranslations[i] +=
+                            mIsRtl ? focusedTaskWidthAndSpacing : -focusedTaskWidthAndSpacing;
+                } else {
+                    // For task before the focused task, accumulate the width and spacing to
+                    // calculate the distance focused task need to shift.
+                    focusedTaskShift += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
                 }
+                boolean isTopRow = isTaskDismissal ? mTopIdSet.contains(taskView.getTask().key.id)
+                        : topRowWidth <= bottomRowWidth;
+                if (isTopRow) {
+                    gridTranslations[i] += topAccumulatedTranslationX;
+                    topRowWidth += taskWidthAndSpacing;
+                    topSet.add(i);
+                    mTopIdSet.add(taskView.getTask().key.id);
 
-                float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
-                gridTranslations[i] += gridTranslationX;
-                bottomAccumulatedTranslationX += gridTranslationX;
+                    taskView.setGridTranslationY(taskGridVerticalDiff);
+
+                    // Move horizontally into empty space.
+                    float widthOffset = 0;
+                    for (int j = i - 1; !topSet.contains(j) && j >= 0; j--) {
+                        if (j == focusedTaskIndex) {
+                            continue;
+                        }
+                        widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
+                    }
+
+                    float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
+                    gridTranslations[i] += gridTranslationX;
+                    topAccumulatedTranslationX += gridTranslationX;
+                } else {
+                    gridTranslations[i] += bottomAccumulatedTranslationX;
+                    bottomRowWidth += taskWidthAndSpacing;
+                    bottomSet.add(i);
+
+                    // Move into bottom row.
+                    taskView.setGridTranslationY(heightOffset + taskGridVerticalDiff);
+
+                    // Move horizontally into empty space.
+                    float widthOffset = 0;
+                    for (int j = i - 1; !bottomSet.contains(j) && j >= 0; j--) {
+                        if (j == focusedTaskIndex) {
+                            continue;
+                        }
+                        widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
+                    }
+
+                    float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
+                    gridTranslations[i] += gridTranslationX;
+                    bottomAccumulatedTranslationX += gridTranslationX;
+                }
+                if (taskView == snappedTaskView) {
+                    snappedTaskRowWidth = isTopRow ? topRowWidth : bottomRowWidth;
+                }
             }
         }
 
-        // We need to maintain first non-home task's grid translation at 0, now shift translation
-        // of all the TaskViews to achieve that.
-        for (int i = firstNonHomeTaskIndex; i < taskCount; i++) {
+        // We need to maintain snapped task's page scroll invariant between quick switch and
+        // overview, so we sure snapped task's grid translation is 0, and add a non-fullscreen
+        // translationX that is the same as snapped task's full scroll adjustment.
+        float snappedTaskFullscreenScrollAdjustment = 0;
+        float snappedTaskGridTranslationX = 0;
+        if (snappedTaskView != null) {
+            snappedTaskFullscreenScrollAdjustment = snappedTaskView.getScrollAdjustment(
+                    /*fullscreenEnabled=*/true, /*gridEnabled=*/false);
+            snappedTaskGridTranslationX = gridTranslations[snappedPage - mTaskViewStartIndex];
+        }
+
+
+        for (int i = 0; i < taskCount; i++) {
             TaskView taskView = getTaskViewAt(i);
-            taskView.setGridTranslationX(
-                    gridTranslations[i] - gridTranslations[firstNonHomeTaskIndex]);
+            taskView.setGridTranslationX(gridTranslations[i] - snappedTaskGridTranslationX);
+            taskView.setNonFullscreenTranslationX(snappedTaskFullscreenScrollAdjustment);
         }
 
         // Use the accumulated translation of the longer row.
@@ -1861,7 +1903,7 @@
         // If the total width is shorter than one grid's width, move ClearAllButton further away
         // accordingly.
         float clearAllShortTotalCompensation = 0;
-        float longRowWidth = Math.max(topRowWidth, bottomRowWidth);
+        int longRowWidth = Math.max(topRowWidth, bottomRowWidth);
         if (longRowWidth < mLastComputedGridSize.width()) {
             float shortTotalCompensation = mLastComputedGridSize.width() - longRowWidth;
             clearAllShortTotalCompensation =
@@ -1870,10 +1912,27 @@
 
         float clearAllTotalTranslationX =
                 clearAllAccumulatedTranslation + clearAllShorterRowCompensation
-                        + clearAllShortTotalCompensation;
+                        + clearAllShortTotalCompensation + snappedTaskFullscreenScrollAdjustment;
+        if (focusedTaskIndex < taskCount) {
+            // Shift by focused task's width and spacing if a task is focused.
+            clearAllTotalTranslationX +=
+                    mIsRtl ? focusedTaskWidthAndSpacing : -focusedTaskWidthAndSpacing;
+        }
+
+        // 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;
+            int minimumDistance =
+                    mLastComputedGridSize.width() - snappedTaskView.getLayoutParams().width;
+            if (distanceFromClearAll < minimumDistance) {
+                int distanceDifference = minimumDistance - distanceFromClearAll;
+                clearAllTotalTranslationX += mIsRtl ? -distanceDifference : distanceDifference;
+            }
+        }
 
         mClearAllButton.setGridTranslationPrimary(
-                clearAllTotalTranslationX - gridTranslations[firstNonHomeTaskIndex]);
+                clearAllTotalTranslationX - snappedTaskGridTranslationX);
         mClearAllButton.setGridScrollOffset(
                 mIsRtl ? mLastComputedTaskSize.left - mLastComputedGridSize.left
                         : mLastComputedTaskSize.right - mLastComputedGridSize.right);
@@ -1881,10 +1940,6 @@
         setGridProgress(mGridProgress);
     }
 
-    protected boolean isHomeTask(TaskView taskView) {
-        return false;
-    }
-
     /**
      * Moves TaskView and ClearAllButton between carousel and 2 row grid.
      *
@@ -2107,7 +2162,7 @@
                     } else {
                         snapToPageImmediately(pageToSnapTo);
                         // Grid got messed up, reapply.
-                        updateGridProperties(true);
+                        updateGridProperties(/*isTaskDismissal=*/true);
                         if (showAsGrid() && getFocusedTaskView() == null) {
                             animateActionsViewOut();
                         }
@@ -2981,44 +3036,62 @@
         }
     }
 
+    /**
+     * Updates page scroll synchronously and layout child views.
+     */
+    public void updateScrollSynchronously() {
+        onLayout(false /*  changed */, getLeft(), getTop(), getRight(), getBottom());
+        updateMinAndMaxScrollX();
+    }
+
     @Override
     protected int computeMinScroll() {
         if (getTaskViewCount() > 0) {
-            if (mIsRtl && mDisallowScrollToClearAll) {
-                // We aren't showing the clear all button,
-                // so use the leftmost task as the min scroll.
-                return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
+            if (mIsRtl) {
+                // If we aren't showing the clear all button, use the rightmost task as the min
+                // scroll.
+                return getScrollForPage(mDisallowScrollToClearAll ? indexOfChild(
+                        getTaskViewAt(getTaskViewCount() - 1)) : indexOfChild(mClearAllButton));
+            } else {
+                TaskView focusedTaskView = showAsGrid() ? getFocusedTaskView() : null;
+                return getScrollForPage(focusedTaskView != null ? indexOfChild(focusedTaskView)
+                        : mTaskViewStartIndex);
             }
-            return getLeftMostChildScroll();
         }
         return super.computeMinScroll();
     }
 
-    /**
-     * Returns page scroll of the left most child.
-     */
-    public int getLeftMostChildScroll() {
-        return getScrollForPage(mIsRtl ? indexOfChild(mClearAllButton) : mTaskViewStartIndex);
-    }
-
     @Override
     protected int computeMaxScroll() {
         if (getTaskViewCount() > 0) {
-            if (!mIsRtl && mDisallowScrollToClearAll) {
-                // We aren't showing the clear all button,
-                // so use the rightmost task as the min scroll.
-                return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
+            if (mIsRtl) {
+                TaskView focusedTaskView = showAsGrid() ? getFocusedTaskView() : null;
+                return getScrollForPage(focusedTaskView != null ? indexOfChild(focusedTaskView)
+                        : mTaskViewStartIndex);
+            } else {
+                // If we aren't showing the clear all button, use the leftmost task as the min
+                // scroll.
+                return getScrollForPage(mDisallowScrollToClearAll ? indexOfChild(
+                        getTaskViewAt(getTaskViewCount() - 1)) : indexOfChild(mClearAllButton));
             }
-            return getScrollForPage(mIsRtl ? mTaskViewStartIndex : indexOfChild(mClearAllButton));
         }
         return super.computeMaxScroll();
     }
 
+    /**
+     * Returns page scroll of ClearAllButton.
+     */
+    public int getClearAllScroll() {
+        return getScrollForPage(indexOfChild(mClearAllButton));
+    }
+
     @Override
     protected boolean getPageScrolls(int[] outPageScrolls, boolean layoutChildren,
             ComputePageScrollsLogic scrollLogic) {
         boolean pageScrollChanged = super.getPageScrolls(outPageScrolls, layoutChildren,
                 scrollLogic);
+        boolean showAsFullscreen = showAsFullscreen();
+        boolean showAsGrid = showAsGrid();
 
         // Align ClearAllButton to the left (RTL) or right (non-RTL), which is different from other
         // TaskViews. This must be called after laying out ClearAllButton.
@@ -3032,11 +3105,10 @@
             View child = getChildAt(i);
             float scrollDiff = 0;
             if (child instanceof TaskView) {
-                scrollDiff = ((TaskView) child).getScrollAdjustment(mOverviewFullscreenEnabled,
-                        showAsGrid());
+                scrollDiff = ((TaskView) child).getScrollAdjustment(showAsFullscreen, showAsGrid);
             } else if (child instanceof ClearAllButton) {
-                scrollDiff = ((ClearAllButton) child).getScrollAdjustment(
-                        mOverviewFullscreenEnabled, showAsGrid());
+                scrollDiff = ((ClearAllButton) child).getScrollAdjustment(showAsFullscreen,
+                        showAsGrid);
             }
 
             if (scrollDiff != 0) {
@@ -3052,7 +3124,7 @@
         int childOffset = super.getChildOffset(index);
         View child = getChildAt(index);
         if (child instanceof TaskView) {
-            childOffset += ((TaskView) child).getOffsetAdjustment(mOverviewFullscreenEnabled,
+            childOffset += ((TaskView) child).getOffsetAdjustment(showAsFullscreen(),
                     showAsGrid());
         } else if (child instanceof ClearAllButton) {
             childOffset += ((ClearAllButton) child).getOffsetAdjustment(mOverviewFullscreenEnabled,
@@ -3068,7 +3140,7 @@
             return super.getChildVisibleSize(index);
         }
         return (int) (super.getChildVisibleSize(index) * taskView.getSizeAdjustment(
-                mOverviewFullscreenEnabled));
+                showAsFullscreen()));
     }
 
     public ClearAllButton getClearAllButton() {
@@ -3268,6 +3340,11 @@
                 mCurrentGestureEndTarget).displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
     }
 
+    private boolean showAsFullscreen() {
+        return mOverviewFullscreenEnabled
+                && mCurrentGestureEndTarget != GestureState.GestureEndTarget.RECENTS;
+    }
+
     public boolean shouldShowOverviewActionsForState(STATE_TYPE state) {
         return !state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())
                 || getFocusedTaskView() != null;
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 8c71ab3..e6143fb 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -29,14 +29,12 @@
 
 import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
-import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
 import static com.android.launcher3.Utilities.comp;
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
 import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
 import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -78,7 +76,6 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -287,6 +284,9 @@
     private float mTaskResistanceTranslationY;
     // The following translation variables should only be used in the same orientation as Launcher.
     private float mFullscreenTranslationX;
+    // Applied as a complement to fullscreenTranslation, for adjusting the carousel overview, or the
+    // in transition carousel before forming the grid on tablets.
+    private float mNonFullscreenTranslationX;
     private float mBoxTranslationY;
     // The following grid translations scales with mGridProgress.
     private float mGridTranslationX;
@@ -784,7 +784,8 @@
 
     @Override
     public void onRecycle() {
-        mFullscreenTranslationX = mGridTranslationX = mGridTranslationY = mBoxTranslationY = 0f;
+        mFullscreenTranslationX = mNonFullscreenTranslationX =
+                mGridTranslationX = mGridTranslationY = mBoxTranslationY = 0f;
         resetViewTransforms();
         // Clear any references to the thumbnail (it will be re-read either from the cache or the
         // system on next bind)
@@ -931,6 +932,11 @@
         applyTranslationX();
     }
 
+    public void setNonFullscreenTranslationX(float nonFullscreenTranslationX) {
+        mNonFullscreenTranslationX = nonFullscreenTranslationX;
+        applyTranslationX();
+    }
+
     public void setGridTranslationX(float gridTranslationX) {
         mGridTranslationX = gridTranslationX;
         applyTranslationX();
@@ -953,6 +959,8 @@
         float scrollAdjustment = 0;
         if (fullscreenEnabled) {
             scrollAdjustment += mFullscreenTranslationX;
+        } else {
+            scrollAdjustment += mNonFullscreenTranslationX;
         }
         if (gridEnabled) {
             scrollAdjustment += mGridTranslationX;
@@ -980,6 +988,7 @@
     private void applyTranslationX() {
         setTranslationX(mDismissTranslationX + mTaskOffsetTranslationX + mTaskResistanceTranslationX
                 + getFullscreenTrans(mFullscreenTranslationX)
+                + getNonFullscreenTrans(mNonFullscreenTranslationX)
                 + getGridTrans(mGridTranslationX));
     }
 
@@ -1201,12 +1210,12 @@
             int boxHeight;
             float thumbnailRatio;
             boolean isFocusedTask = isFocusedTask();
-            if (isFocusedTask || isRunningTask()) {
-                // Task will be focused and should use focused task size. Use runningTaskRatio
-                // that is associated with the original orientation of the focused task if possible.
+            if (isFocusedTask) {
+                // Task will be focused and should use focused task size. Use focusTaskRatio
+                // that is associated with the original orientation of the focused task.
                 boxWidth = taskWidth;
                 boxHeight = taskHeight;
-                thumbnailRatio = isFocusedTask ? getRecentsView().getFocusedTaskRatio() : 0;
+                thumbnailRatio = getRecentsView().getFocusedTaskRatio();
             } else {
                 // Otherwise task is in grid, and should use lastComputedGridTaskSize.
                 Rect lastComputedGridTaskSize = getRecentsView().getLastComputedGridTaskSize();
@@ -1262,6 +1271,10 @@
         return Utilities.mapRange(progress, 0, endTranslation);
     }
 
+    private float getNonFullscreenTrans(float endTranslation) {
+        return endTranslation - getFullscreenTrans(endTranslation);
+    }
+
     public boolean isRunningTask() {
         if (getRecentsView() == null) {
             return false;