Merge "Fix scaling on widget previews that have width / height set to wrap_content" into sc-v2-dev
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 1febc88..f54070e 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -70,6 +70,8 @@
     <item name="content_scale" format="float" type="dimen">0.97</item>
     <dimen name="closing_window_trans_y">115dp</dimen>
 
+    <dimen name="quick_switch_scaling_scroll_threshold">100dp</dimen>
+
     <dimen name="recents_empty_message_text_size">16sp</dimen>
     <dimen name="recents_empty_message_text_padding">16dp</dimen>
 
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index ebf8fb7..2da8a45 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -40,7 +40,6 @@
 import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
 import static com.android.launcher3.statehandlers.DepthController.DEPTH;
 import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
-import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
 import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
 import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
 import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
@@ -1047,7 +1046,7 @@
             mLauncherOpenTransition = RemoteAnimationAdapterCompat.buildRemoteTransition(
                     new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner,
                             false /* startAtFrontOfQueue */));
-            mLauncherOpenTransition.addHomeOpenCheck();
+            mLauncherOpenTransition.addHomeOpenCheck(mLauncher.getComponentName());
             SystemUiProxy.INSTANCE.getNoCreate().registerRemoteTransition(mLauncherOpenTransition);
         }
     }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 9180bd0..076f28a 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -212,6 +212,8 @@
 
     public static final long RECENTS_ATTACH_DURATION = 300;
 
+    private static final float MAX_QUICK_SWITCH_RECENTS_SCALE_PROGRESS = 0.07f;
+
     /**
      * Used as the page index for logging when we return to the last task at the end of the gesture.
      */
@@ -252,6 +254,9 @@
     private SwipePipToHomeAnimator mSwipePipToHomeAnimator;
     protected boolean mIsSwipingPipToHome;
 
+    // Interpolate RecentsView scale from start of quick switch scroll until this scroll threshold
+    private final float mQuickSwitchScaleScrollThreshold;
+
     public AbsSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
             TaskAnimationManager taskAnimationManager, GestureState gestureState,
             long touchTimeMs, boolean continuingLastGesture,
@@ -267,6 +272,8 @@
         mTaskAnimationManager = taskAnimationManager;
         mTouchTimeMs = touchTimeMs;
         mContinuingLastGesture = continuingLastGesture;
+        mQuickSwitchScaleScrollThreshold = context.getResources().getDimension(
+                R.dimen.quick_switch_scaling_scroll_threshold);
 
         initAfterSubclassConstructor();
         initStateCallbacks();
@@ -539,7 +546,7 @@
             @Override
             public void onMotionPauseDetected() {
                 mHasMotionEverBeenPaused = true;
-                maybeUpdateRecentsAttachedState();
+                maybeUpdateRecentsAttachedState(true/* animate */, true/* moveFocusedTask */);
                 performHapticFeedback();
             }
 
@@ -550,18 +557,24 @@
         };
     }
 
-    public void maybeUpdateRecentsAttachedState() {
+    private void maybeUpdateRecentsAttachedState() {
         maybeUpdateRecentsAttachedState(true /* animate */);
     }
 
+    private void maybeUpdateRecentsAttachedState(boolean animate) {
+        maybeUpdateRecentsAttachedState(animate, false /* moveFocusedTask */);
+    }
+
     /**
      * Determines whether to show or hide RecentsView. The window is always
      * synchronized with its corresponding TaskView in RecentsView, so if
      * RecentsView is shown, it will appear to be attached to the window.
      *
      * 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
      */
-    private void maybeUpdateRecentsAttachedState(boolean animate) {
+    private void maybeUpdateRecentsAttachedState(boolean animate, boolean moveFocusedTask) {
         if (!mDeviceState.isFullyGesturalNavMode() || mRecentsView == null) {
             return;
         }
@@ -580,6 +593,12 @@
         } else {
             recentsAttachedToAppWindow = mHasMotionEverBeenPaused || mIsLikelyToStartNewTask;
         }
+        if (moveFocusedTask && !mAnimationFactory.hasRecentsEverAttachedToAppWindow()
+                && recentsAttachedToAppWindow) {
+            // Only move focused task if RecentsView has never been attached before, to avoid
+            // TaskView jumping to new position as we move the tasks.
+            mRecentsView.moveFocusedTaskToFront();
+        }
         mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
 
         // Reapply window transform throughout the attach animation, as the animation affects how
@@ -669,7 +688,8 @@
                 || !canCreateNewOrUpdateExistingLauncherTransitionController()) {
             return;
         }
-        mLauncherTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
+        mLauncherTransitionController.setProgress(
+                Math.max(mCurrentShift.value, getScaleProgressDueToScroll()), mDragLengthFactor);
     }
 
     /**
@@ -1784,7 +1804,9 @@
      */
     protected void applyWindowTransform() {
         if (mWindowTransitionController != null) {
-            mWindowTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor);
+            mWindowTransitionController.setProgress(
+                    Math.max(mCurrentShift.value, getScaleProgressDueToScroll()),
+                    mDragLengthFactor);
         }
         // No need to apply any transform if there is ongoing swipe-pip-to-home animator since
         // that animator handles the leash solely.
@@ -1797,6 +1819,35 @@
         ProtoTracer.INSTANCE.get(mContext).scheduleFrameUpdate();
     }
 
+    // Scaling of RecentsView during quick switch based on amount of recents scroll
+    private float getScaleProgressDueToScroll() {
+        if (mActivity == null || !mActivity.getDeviceProfile().isTablet || mRecentsView == null
+                || !mRecentsViewScrollLinked) {
+            return 0;
+        }
+
+        float scrollOffset = Math.abs(mRecentsView.getScrollOffset(mRecentsView.getCurrentPage()));
+        int maxScrollOffset = mRecentsView.getPagedOrientationHandler().getPrimaryValue(
+                mRecentsView.getLastComputedTaskSize().width(),
+                mRecentsView.getLastComputedTaskSize().height());
+        maxScrollOffset += mRecentsView.getPageSpacing();
+
+        float maxScaleProgress =
+                MAX_QUICK_SWITCH_RECENTS_SCALE_PROGRESS * mRecentsView.getMaxScaleForFullScreen();
+        float scaleProgress = maxScaleProgress;
+
+        if (scrollOffset < mQuickSwitchScaleScrollThreshold) {
+            scaleProgress = Utilities.mapToRange(scrollOffset, 0, mQuickSwitchScaleScrollThreshold,
+                    0, maxScaleProgress, ACCEL_DEACCEL);
+        } else if (scrollOffset > (maxScrollOffset - mQuickSwitchScaleScrollThreshold)) {
+            scaleProgress = Utilities.mapToRange(scrollOffset,
+                    (maxScrollOffset - mQuickSwitchScaleScrollThreshold), maxScrollOffset,
+                    maxScaleProgress, 0, ACCEL_DEACCEL);
+        }
+
+        return scaleProgress;
+    }
+
     /**
      * Used for winscope tracing, see launcher_trace.proto
      * @see com.android.systemui.shared.tracing.ProtoTraceable#writeToProto
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 615a510..11fb1d0 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -400,6 +400,10 @@
         default boolean isRecentsAttachedToAppWindow() {
             return false;
         }
+
+        default boolean hasRecentsEverAttachedToAppWindow() {
+            return false;
+        }
     }
 
     class DefaultAnimationFactory implements AnimationFactory {
@@ -409,6 +413,7 @@
         private final Consumer<AnimatorControllerWithResistance> mCallback;
 
         private boolean mIsAttachedToWindow;
+        private boolean mHasEverAttachedToWindow;
 
         DefaultAnimationFactory(Consumer<AnimatorControllerWithResistance> callback) {
             mCallback = callback;
@@ -462,6 +467,9 @@
             }
             mIsAttachedToWindow = attached;
             RecentsView recentsView = mActivity.getOverviewPanel();
+            if (attached) {
+                mHasEverAttachedToWindow = true;
+            }
             Animator fadeAnim = mActivity.getStateManager()
                     .createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
 
@@ -491,6 +499,11 @@
             return mIsAttachedToWindow;
         }
 
+        @Override
+        public boolean hasRecentsEverAttachedToAppWindow() {
+            return mHasEverAttachedToWindow;
+        }
+
         protected void createBackgroundToOverviewAnim(ACTIVITY_TYPE activity, PendingAnimation pa) {
             //  Scale down recents from being full screen to being in overview.
             RecentsView recentsView = activity.getOverviewPanel();
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index dac6981..11ca4b1 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -358,7 +358,7 @@
             try {
                 mSystemUiProxy.setSplitScreenMinimized(minimized);
             } catch (RemoteException e) {
-                Log.w(TAG, "Failed call stopScreenPinning", e);
+                Log.w(TAG, "Failed call setSplitScreenMinimized", e);
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 7bb0b94..b038c7b 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -67,7 +67,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
-import androidx.annotation.VisibleForTesting;
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.BaseDraggingActivity;
@@ -302,7 +301,6 @@
 
     private static boolean sConnected = false;
     private static boolean sIsInitialized = false;
-    private static TouchInteractionService sInstance;
     private RotationTouchHelper mRotationTouchHelper;
 
     public static boolean isConnected() {
@@ -313,15 +311,6 @@
         return sIsInitialized;
     }
 
-    @VisibleForTesting
-    @Nullable
-    public static TaskbarManager getTaskbarManagerForTesting() {
-        if (sInstance == null) {
-            return null;
-        }
-        return sInstance.mTaskbarManager;
-    }
-
     private final AbsSwipeUpHandler.Factory mLauncherSwipeHandlerFactory =
             this::createLauncherSwipeHandler;
     private final AbsSwipeUpHandler.Factory mFallbackSwipeHandlerFactory =
@@ -365,7 +354,6 @@
         mDeviceState.runOnUserUnlocked(mTaskbarManager::onUserUnlocked);
         ProtoTracer.INSTANCE.get(this).add(this);
         sConnected = true;
-        sInstance = this;
     }
 
     private void disposeEventHandlers() {
@@ -523,7 +511,6 @@
 
         mTaskbarManager.destroy();
         sConnected = false;
-        sInstance = null;
         super.onDestroy();
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
index f67940a..04a7baa 100644
--- a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
+++ b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
@@ -17,13 +17,10 @@
 
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
 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.OVERSHOOT_1_7;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_EDU_SHOWN;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -35,7 +32,7 @@
 import android.graphics.drawable.GradientDrawable;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
-import android.view.ViewGroup;
+import android.view.View;
 
 import androidx.core.graphics.ColorUtils;
 
@@ -44,25 +41,21 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
 import com.android.launcher3.util.Themes;
 import com.android.quickstep.util.MultiValueUpdateListener;
 
 /**
  * View used to educate the user on how to access All Apps when in No Nav Button navigation mode.
- * Consumes all touches until after the animation is completed and the view is removed.
+ * If the user drags on the view, the animation is overridden so the user can swipe to All Apps or
+ * Home.
  */
 public class AllAppsEduView extends AbstractFloatingView {
 
-    private static final float HINT_PROG_SCRIM_THRESHOLD = 0.06f;
-    private static final float HINT_PROG_CONTENT_THRESHOLD = 0.08f;
-
     private Launcher mLauncher;
+    private AllAppsEduTouchController mTouchController;
 
     private AnimatorSet mAnimation;
 
@@ -124,7 +117,34 @@
     }
 
     @Override
+    public boolean onControllerTouchEvent(MotionEvent ev) {
+        mTouchController.onControllerTouchEvent(ev);
+        if (mAnimation != null) {
+            updateAnimationOnTouchEvent(ev);
+        }
+        return super.onControllerTouchEvent(ev);
+    }
+
+    private void updateAnimationOnTouchEvent(MotionEvent ev) {
+        switch (ev.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                mAnimation.pause();
+                return;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mAnimation.resume();
+                return;
+        }
+
+        if (mTouchController.isDraggingOrSettling()) {
+            mAnimation = null;
+            handleClose(false);
+        }
+    }
+
+    @Override
     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        mTouchController.onControllerInterceptTouchEvent(ev);
         return true;
     }
 
@@ -145,23 +165,9 @@
         int secondPart = 1200;
         int introDuration = firstPart + secondPart;
 
-        StateAnimationConfig config = new StateAnimationConfig();
-        config.setInterpolator(ANIM_ALL_APPS_FADE, Interpolators.clampToProgress(ACCEL,
-                HINT_PROG_SCRIM_THRESHOLD, HINT_PROG_CONTENT_THRESHOLD));
-        config.setInterpolator(ANIM_SCRIM_FADE,
-                Interpolators.clampToProgress(ACCEL, 0, HINT_PROG_CONTENT_THRESHOLD));
-        config.duration = secondPart;
-        config.userControlled = false;
         AnimatorPlaybackController stateAnimationController =
-                mLauncher.getStateManager().createAnimationToNewWorkspace(ALL_APPS, config);
-        float maxAllAppsProgress = mLauncher.getDeviceProfile().isLandscape ? 0.35f : 0.15f;
-
-        AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
-        PendingAnimation allAppsAlpha = new PendingAnimation(config.duration);
-        allAppsController.setAlphas(ALL_APPS, config, allAppsAlpha);
-        mLauncher.getWorkspace().getStateTransitionAnimation().setScrim(allAppsAlpha, ALL_APPS,
-                config);
-        mAnimation.play(allAppsAlpha.buildAnim());
+                mTouchController.initAllAppsAnimation();
+        float maxAllAppsProgress = 0.75f;
 
         ValueAnimator intro = ValueAnimator.ofFloat(0, 1f);
         intro.setInterpolator(LINEAR);
@@ -198,6 +204,7 @@
                 mGradient.setAlpha(0);
             }
         });
+        mLauncher.getAppsView().setVisibility(View.VISIBLE);
         mAnimation.play(intro);
 
         ValueAnimator closeAllApps = ValueAnimator.ofFloat(maxAllAppsProgress, 0f);
@@ -223,6 +230,7 @@
 
     private void init(Launcher launcher) {
         mLauncher = launcher;
+        mTouchController = new AllAppsEduTouchController(mLauncher);
 
         int accentColor = Themes.getColorAccent(launcher);
         mGradient = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM,
@@ -250,9 +258,8 @@
      */
     public static void show(Launcher launcher) {
         final DragLayer dragLayer = launcher.getDragLayer();
-        ViewGroup parent = (ViewGroup) dragLayer.getParent();
-        AllAppsEduView view = launcher.getViewCache().getView(R.layout.all_apps_edu_view,
-                launcher, parent);
+        AllAppsEduView view = (AllAppsEduView) launcher.getLayoutInflater().inflate(
+                R.layout.all_apps_edu_view, dragLayer, false);
         view.init(launcher);
         launcher.getDragLayer().addView(view);
         launcher.getStatsLogManager().logger().log(LAUNCHER_ALL_APPS_EDU_SHOWN);
@@ -260,4 +267,27 @@
         view.requestLayout();
         view.playAnimation();
     }
+
+    private static class AllAppsEduTouchController extends PortraitStatesTouchController {
+
+        private AllAppsEduTouchController(Launcher l) {
+            super(l);
+        }
+
+        @Override
+        protected boolean canInterceptTouch(MotionEvent ev) {
+            return true;
+        }
+
+        private AnimatorPlaybackController initAllAppsAnimation() {
+            mFromState = NORMAL;
+            mToState = ALL_APPS;
+            mProgressMultiplier = initCurrentAnimation();
+            return mCurrentAnimation;
+        }
+
+        private boolean isDraggingOrSettling() {
+            return mDetector.isDraggingOrSettling();
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index e128942..edda439 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -563,6 +563,10 @@
      * removed from recentsView
      */
     private int mSplitHiddenTaskViewIndex;
+    /**
+     * The task to be removed and immediately re-added. Should not be added to task pool.
+     */
+    private TaskView mMovingTaskView;
 
     // Keeps track of the index where the first TaskView should be
     private int mTaskViewStartIndex = 0;
@@ -826,9 +830,12 @@
     public void onViewRemoved(View child) {
         super.onViewRemoved(child);
 
-        // Clear the task data for the removed child if it was visible unless it's the initial
-        // taskview for entering split screen, we only pretend to dismiss the task
-        if (child instanceof TaskView && child != mSplitHiddenTaskView) {
+        // Clear the task data for the removed child if it was visible unless:
+        // - It's the initial taskview for entering split screen, we only pretend to dismiss the
+        // task
+        // - It's the focused task to be moved to the front, we immediately re-add the task
+        if (child instanceof TaskView && child != mSplitHiddenTaskView
+                && child != mMovingTaskView) {
             TaskView taskView = (TaskView) child;
             mHasVisibleTaskData.delete(taskView.getTaskId());
             mTaskViewPool.recycle(taskView);
@@ -1121,6 +1128,42 @@
         }
     }
 
+    /**
+     * Moves the focused task to the front of the carousel in tablets, to minimize animation
+     * required to focus the task in grid.
+     */
+    public void moveFocusedTaskToFront() {
+        if (!(mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get())) {
+            return;
+        }
+
+        TaskView focusedTaskView = getFocusedTaskView();
+        if (focusedTaskView == null) {
+            return;
+        }
+
+        if (indexOfChild(focusedTaskView) != mCurrentPage) {
+            return;
+        }
+
+        if (mCurrentPage == mTaskViewStartIndex) {
+            return;
+        }
+
+        int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+        int currentPageScroll = getScrollForPage(mCurrentPage);
+        mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
+
+        mMovingTaskView = focusedTaskView;
+        removeView(focusedTaskView);
+        mMovingTaskView = null;
+        focusedTaskView.onRecycle();
+        addView(focusedTaskView, mTaskViewStartIndex);
+        setCurrentPage(mTaskViewStartIndex);
+
+        updateGridProperties();
+    }
+
     protected void applyLoadPlan(ArrayList<Task> tasks) {
         if (mPendingAnimation != null) {
             mPendingAnimation.addEndListener(success -> applyLoadPlan(tasks));
@@ -3090,6 +3133,9 @@
                 splitController.getLayoutParamsForActivePosition(getResources(),
                         mActivity.getDeviceProfile()));
         mSplitPlaceholderView.setIcon(taskView.getIconView());
+        if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+            finishRecentsAnimation(true, null);
+        }
     }
 
     public PendingAnimation createSplitSelectInitAnimation() {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 2e154f6..159052a 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -531,6 +531,9 @@
         if (getTask() == null) {
             return;
         }
+        if (confirmSecondSplitSelectApp()) {
+            return;
+        }
         if (ENABLE_QUICKSTEP_LIVE_TILE.get() && isRunningTask()) {
             if (!mIsClickableAsLiveTile) {
                 return;
@@ -549,7 +552,7 @@
             if (targets == null) {
                 // If the recents animation is cancelled somehow between the parent if block and
                 // here, try to launch the task as a non live tile task.
-                launcherNonLiveTileTask();
+                launchTaskAnimated();
                 return;
             }
 
@@ -567,19 +570,22 @@
             });
             anim.start();
         } else {
-            launcherNonLiveTileTask();
+            launchTaskAnimated();
         }
         mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo())
                 .log(LAUNCHER_TASK_LAUNCH_TAP);
     }
 
-    private void launcherNonLiveTileTask() {
-        if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
-            // User tapped to select second split screen app
+    /**
+     * @return {@code true} if user is already in split select mode and this tap was to choose the
+     *         second app. {@code false} otherwise
+     */
+    private boolean confirmSecondSplitSelectApp() {
+        boolean isSelectingSecondSplitApp = mActivity.isInState(OVERVIEW_SPLIT_SELECT);
+        if (isSelectingSecondSplitApp) {
             getRecentsView().confirmSplitSelect(this);
-        } else {
-            launchTaskAnimated();
         }
+        return isSelectingSecondSplitApp;
     }
 
     /**
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index fe1bb2e..f44a812 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -25,12 +25,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.launcher3.Launcher;
-import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.launcher3.taskbar.TaskbarDragLayer;
-import com.android.launcher3.taskbar.TaskbarManager;
-import com.android.launcher3.taskbar.TaskbarView;
 import com.android.launcher3.ui.TaplTestsLauncher3;
-import com.android.launcher3.ui.TestViewHelpers;
 import com.android.launcher3.util.RaceConditionReproducer;
 import com.android.quickstep.NavigationModeSwitchRule.Mode;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
@@ -90,7 +85,7 @@
     public void testStressPressHome() {
         for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
             // Destroy Launcher activity.
-            destroyLauncherActivityAndWaitForTaskbarVisible();
+            closeLauncherActivity();
 
             // The test action.
             mLauncher.pressHome();
@@ -102,41 +97,12 @@
     public void testStressSwipeToOverview() {
         for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
             // Destroy Launcher activity.
-            destroyLauncherActivityAndWaitForTaskbarVisible();
+            closeLauncherActivity();
 
             // The test action.
             mLauncher.getBackground().switchToOverview();
         }
-        destroyLauncherActivityAndWaitForTaskbarVisible();
-        mLauncher.pressHome();
-    }
-
-    private void destroyLauncherActivityAndWaitForTaskbarVisible() {
         closeLauncherActivity();
-
-        // After Launcher is destroyed, calculator app started in setup() will be launched, wait for
-        // taskbar to settle before further interaction if it's a tablet.
-        if (!mLauncher.isTablet()) {
-            return;
-        }
-
-        waitForLauncherCondition(
-                "Taskbar not yet visible", launcher -> {
-                    TaskbarManager taskbarManager =
-                            TouchInteractionService.getTaskbarManagerForTesting();
-                    if (taskbarManager == null) {
-                        return false;
-                    }
-
-                    TaskbarActivityContext taskbarActivityContext =
-                            taskbarManager.getCurrentActivityContext();
-                    if (taskbarActivityContext == null) {
-                        return false;
-                    }
-
-                    TaskbarDragLayer taskbarDragLayer = taskbarActivityContext.getDragLayer();
-                    return TestViewHelpers.findChildView(taskbarDragLayer,
-                            view -> view instanceof TaskbarView && view.isVisibleToUser()) != null;
-                }, DEFAULT_UI_TIMEOUT);
+        mLauncher.pressHome();
     }
 }
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 20f5f9b..74b0d9c 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -709,6 +709,7 @@
         final int scrollOffsetStart = mOrientationHandler.getScrollOffsetStart(this, mInsets);
         final int scrollOffsetEnd = mOrientationHandler.getScrollOffsetEnd(this, mInsets);
         boolean pageScrollChanged = false;
+        int panelCount = getPanelCount();
 
         for (int i = startIndex, childStart = scrollOffsetStart; i != endIndex; i += delta) {
             final View child = getPageAt(i);
@@ -726,11 +727,15 @@
                     pageScrollChanged = true;
                     outPageScrolls[i] = pageScroll;
                 }
-                childStart += primaryDimension + mPageSpacing + getChildGap();
+                childStart += primaryDimension + getChildGap();
+
+                // This makes sure that the space is added after the page, not after each panel
+                if (i % panelCount == panelCount - 1) {
+                    childStart += mPageSpacing;
+                }
             }
         }
 
-        int panelCount = getPanelCount();
         if (panelCount > 1) {
             for (int i = 0; i < childCount; i++) {
                 // In case we have multiple panels, always use left panel's page scroll for all
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a585be6..6c0e893 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -315,9 +315,19 @@
         // Increase our bottom insets so we don't overlap with the taskbar.
         mInsets.bottom += grid.nonOverlappingTaskbarInset;
 
-        if (grid.isTwoPanels) {
-            setPageSpacing(0); // we have two pages and we don't want any spacing
+        if (mWorkspaceFadeInAdjacentScreens) {
+            // In landscape mode the page spacing is set to the default.
+            setPageSpacing(grid.edgeMarginPx);
+        } else {
+            // In portrait, we want the pages spaced such that there is no
+            // overhang of the previous / next page into the current page viewport.
+            // We assume symmetrical padding in portrait mode.
+            int maxInsets = Math.max(insets.left, insets.right);
+            int maxPadding = Math.max(grid.edgeMarginPx, padding.left + 1);
+            setPageSpacing(Math.max(maxInsets, maxPadding));
+        }
 
+        if (grid.isTwoPanels) {
             // Add left widget panel if it isn't already there
             if (!mWorkspaceScreens.containsKey(LEFT_PANEL_ID)) {
                 int newCurrentPage = mCurrentPage + 1;
@@ -325,18 +335,6 @@
                 setCurrentPage(newCurrentPage);
             }
         } else {
-            if (mWorkspaceFadeInAdjacentScreens) {
-                // In landscape mode the page spacing is set to the default.
-                setPageSpacing(grid.edgeMarginPx);
-            } else {
-                // In portrait, we want the pages spaced such that there is no
-                // overhang of the previous / next page into the current page viewport.
-                // We assume symmetrical padding in portrait mode.
-                int maxInsets = Math.max(insets.left, insets.right);
-                int maxPadding = Math.max(grid.edgeMarginPx, padding.left + 1);
-                setPageSpacing(Math.max(maxInsets, maxPadding));
-            }
-
             // Remove left widget panel if it is present
             if (mWorkspaceScreens.containsKey(LEFT_PANEL_ID)) {
                 int newCurrentPage = mCurrentPage - 1;
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 90f37f3..5f8a4d4 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -65,12 +65,12 @@
     protected LauncherState mToState;
     protected AnimatorPlaybackController mCurrentAnimation;
     protected boolean mGoingBetweenStates = true;
+    // Ratio of transition process [0, 1] to drag displacement (px)
+    protected float mProgressMultiplier;
 
     private boolean mNoIntercept;
     private boolean mIsLogContainerSet;
     private float mStartProgress;
-    // Ratio of transition process [0, 1] to drag displacement (px)
-    private float mProgressMultiplier;
     private float mDisplacementShift;
     private boolean mCanBlockFling;
     private boolean mAllAppsOvershootStarted;
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 7f9f1b6..1f64131 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -749,7 +749,7 @@
                             displaySize.x / 2, displaySize.y - 1,
                             displaySize.x / 2, 0,
                             ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, NORMAL_STATE_ORDINAL,
-                            launcherWasVisible
+                            launcherWasVisible || isTablet()
                                     ? GestureScope.INSIDE_TO_OUTSIDE
                                     : GestureScope.OUTSIDE_WITH_PILFER);
                 }