Merge "Possibly fix the widget restoration bug" into udc-dev
diff --git a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
index b13e8dc..225b4cd 100644
--- a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
@@ -157,6 +157,7 @@
         android:layout_marginVertical="16dp"
         android:text="@string/gesture_tutorial_action_button_label"
         android:background="@drawable/gesture_tutorial_action_button_background"
+        android:backgroundTint="?androidprv:attr/materialColorPrimary"
         android:stateListAnimator="@null"
 
         app:layout_constraintTop_toBottomOf="@id/guideline"
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index 3bd0df0..64ad1f7 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -175,6 +175,7 @@
             android:paddingEnd="26dp"
             android:text="@string/gesture_tutorial_action_button_label"
             android:background="@drawable/gesture_tutorial_action_button_background"
+            android:backgroundTint="?android:attr/colorAccent"
             android:stateListAnimator="@null"
             android:visibility="invisible"
 
diff --git a/quickstep/res/layout/gesture_tutorial_mock_task_view.xml b/quickstep/res/layout/gesture_tutorial_mock_task_view.xml
deleted file mode 100644
index 047fdb1..0000000
--- a/quickstep/res/layout/gesture_tutorial_mock_task_view.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?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.
--->
-<View
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:theme="@style/GestureTutorialActivity"
-    android:id="@+id/overview_gesture_tutorial_shape"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_margin="20dp"
-    android:background="?attr/onSurfaceOverview" />
\ No newline at end of file
diff --git a/quickstep/res/layout/gesture_tutorial_step_menu.xml b/quickstep/res/layout/gesture_tutorial_step_menu.xml
index 7a302f4..cf78b1b 100644
--- a/quickstep/res/layout/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout/gesture_tutorial_step_menu.xml
@@ -156,6 +156,7 @@
         android:layout_marginVertical="16dp"
         android:text="@string/gesture_tutorial_action_button_label"
         android:background="@drawable/gesture_tutorial_action_button_background"
+        android:backgroundTint="?androidprv:attr/materialColorPrimary"
         android:stateListAnimator="@null"
 
         app:layout_constraintTop_toBottomOf="@id/guideline"
diff --git a/quickstep/res/layout/swipe_up_gesture_tutorial_shape.xml b/quickstep/res/layout/swipe_up_gesture_tutorial_shape.xml
deleted file mode 100644
index d60e84f..0000000
--- a/quickstep/res/layout/swipe_up_gesture_tutorial_shape.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?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.
--->
-<View
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:theme="@style/GestureTutorialActivity"
-    android:id="@+id/swipe_up_gesture_tutorial_shape"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="?attr/surfaceHome" />
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 6915417..612682a 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -223,6 +223,8 @@
 
     <style name="OverviewActionButton"
         parent="@android:style/Widget.DeviceDefault.Button.Borderless">
+        <item name="android:paddingTop">4dp</item>
+        <item name="android:paddingBottom">4dp</item>
         <item name="android:textColor">@color/overview_button</item>
         <item name="android:drawableTint">@color/overview_button</item>
         <item name="android:tint">?android:attr/textColorPrimary</item>
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index 7bd8898..3230c66 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -185,8 +185,8 @@
                 return false;
             }
             boolean traverseBackwards = (keyCode == KeyEvent.KEYCODE_TAB && event.isShiftPressed())
-                    || (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && !isRTL)
-                    || (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && isRTL);
+                    || (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT && isRTL)
+                    || (keyCode == KeyEvent.KEYCODE_DPAD_LEFT && !isRTL);
             int taskCount = mControllerCallbacks.getTaskCount();
             int toIndex = mCurrentFocusIndex == -1
                     // Focus the second-most recent app if possible
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
index 163c36f..f5ba8f9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -84,6 +84,8 @@
         }
         activityOptions.options.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
+        activityOptions.options.setPendingIntentBackgroundActivityStartMode(
+                ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
         options = Pair.create(options.first, activityOptions.options);
         if (pendingIntent.isActivity()) {
             logAppLaunch(itemInfo);
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 928910d..3a6566a 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -147,6 +147,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.function.Consumer;
 
@@ -662,6 +663,14 @@
         } else {
             runningTasks = mGestureState.getRunningTask().getPlaceholderTasks();
         }
+
+        // Safeguard against any null tasks being sent to recents view, happens when quickswitching
+        // very quickly w/ split tasks because TopTaskTracker provides stale information compared to
+        // actual running tasks in the recents animation.
+        // TODO(b/236226779), Proper fix (ag/22237143)
+        if (Arrays.stream(runningTasks).anyMatch(Objects::isNull)) {
+            return;
+        }
         mRecentsView.onGestureAnimationStart(runningTasks, mDeviceState.getRotationTouchHelper());
     }
 
@@ -915,7 +924,12 @@
         if (DesktopTaskView.DESKTOP_MODE_SUPPORTED && targets.hasDesktopTasks()) {
             mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets);
         } else {
+            int untrimmedAppCount = mRemoteTargetHandles.length;
             mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(targets);
+            if (mRemoteTargetHandles.length < untrimmedAppCount && mIsSwipeForSplit) {
+                updateIsGestureForSplit(mRemoteTargetHandles.length);
+                setupRecentsViewUi();
+            }
         }
         mRecentsAnimationController = controller;
         mRecentsAnimationTargets = targets;
@@ -2260,6 +2274,7 @@
                                         targetCompat.taskId == mGestureState.getLastStartedTaskId())
                                 .findFirst();
                 if (!taskTargetOptional.isPresent()) {
+                    ActiveGestureLog.INSTANCE.addLog("No appeared task matching started task id");
                     finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */);
                     return;
                 }
@@ -2267,6 +2282,7 @@
                 TaskView taskView = mRecentsView == null
                         ? null : mRecentsView.getTaskViewByTaskId(taskTarget.taskId);
                 if (taskView == null || !taskView.getThumbnail().shouldShowSplashView()) {
+                    ActiveGestureLog.INSTANCE.addLog("Invalid task view splash state");
                     finishRecentsAnimationOnTasksAppeared(null /* onFinishComplete */);
                     return;
                 }
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index d9c269a..84b90b9 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -29,12 +29,15 @@
 import com.android.quickstep.views.DesktopTaskView;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 
 /**
  * Glues together the necessary components to animate a remote target using a
  * {@link TaskViewSimulator}
  */
 public class RemoteTargetGluer {
+    private static final int DEFAULT_NUM_HANDLES = 2;
+
     private RemoteTargetHandle[] mRemoteTargetHandles;
     private SplitBounds mSplitBounds;
 
@@ -62,8 +65,9 @@
             }
         }
 
-        int[] splitIds = TopTaskTracker.INSTANCE.get(context).getRunningSplitTaskIds();
-        init(context, sizingStrategy, splitIds.length == 2 ? 2 : 1, false /* forDesktop */);
+        // Assume 2 handles needed for split, scale down as needed later on when we actually
+        // get remote targets
+        init(context, sizingStrategy, DEFAULT_NUM_HANDLES, false /* forDesktop */);
     }
 
     private void init(Context context, BaseActivityInterface sizingStrategy, int numHandles,
@@ -108,6 +112,17 @@
      * the left/top task, index 1 right/bottom.
      */
     public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets) {
+        // Resize the mRemoteTargetHandles array since we started assuming split screen, but
+        // targets.apps is the ultimate source of truth here
+        long appCount = Arrays.stream(targets.apps)
+                .filter(app -> app.mode == targets.targetMode)
+                .count();
+        if (appCount < mRemoteTargetHandles.length) {
+            RemoteTargetHandle[] newHandles = new RemoteTargetHandle[(int) appCount];
+            System.arraycopy(mRemoteTargetHandles, 0/*src*/, newHandles, 0/*dst*/, (int) appCount);
+            mRemoteTargetHandles = newHandles;
+        }
+
         if (mRemoteTargetHandles.length == 1) {
             // If we're not in split screen, the splitIds count doesn't really matter since we
             // should always hit this case.
@@ -233,6 +248,14 @@
                 targets.targetMode);
     }
 
+    /**
+     * The object returned by this is may be modified in
+     * {@link #assignTargetsForSplitScreen(RemoteAnimationTargets)}, specifically the length of the
+     * array may be shortened based on the number of RemoteAnimationTargets present.
+     * <p>
+     * This can be accessed at any time, however the count will be more accurate if accessed after
+     * calling one of the respective assignTargets*() methods
+     */
     public RemoteTargetHandle[] getRemoteTargetHandles() {
         return mRemoteTargetHandles;
     }
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 1b4fdc4..25ac47a 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -82,7 +82,8 @@
         mContext = context;
         mDeviceState = deviceState;
         mGestureState = gestureState;
-        mIsSwipeForSplit = TopTaskTracker.INSTANCE.get(context).getRunningSplitTaskIds().length > 1;
+        updateIsGestureForSplit(TopTaskTracker.INSTANCE.get(context)
+                .getRunningSplitTaskIds().length);
 
         mTargetGluer = new RemoteTargetGluer(mContext, mGestureState.getActivityInterface());
         mRemoteTargetHandles = mTargetGluer.getRemoteTargetHandles();
@@ -280,6 +281,10 @@
         return out;
     }
 
+    protected void updateIsGestureForSplit(int targetCount) {
+        mIsSwipeForSplit = targetCount > 1;
+    }
+
     private RectFSpringAnim getWindowAnimationToHomeInternal(
             HomeAnimationFactory homeAnimationFactory, RectF targetRect,
             TransformParams transformParams, TaskViewSimulator taskViewSimulator,
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 4c4b9b4..410ba21 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -19,6 +19,7 @@
 
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
 import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
 import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION;
@@ -174,16 +175,21 @@
                 if (nonAppTargets == null) {
                     nonAppTargets = new RemoteAnimationTarget[0];
                 }
-                if (activityInterface.isInLiveTileMode()
+                if ((activityInterface.isInLiveTileMode()
+                            || mLastGestureState.getEndTarget() == RECENTS)
                         && activityInterface.getCreatedActivity() != null) {
                     RecentsView recentsView =
                             activityInterface.getCreatedActivity().getOverviewPanel();
                     if (recentsView != null) {
+                        ActiveGestureLog.INSTANCE.addLog("Launching side task id="
+                                + appearedTaskTarget.taskId);
                         recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId,
                                 appearedTaskTargets,
                                 new RemoteAnimationTarget[0] /* wallpaper */,
                                 nonAppTargets /* nonApps */);
                         return;
+                    } else {
+                        ActiveGestureLog.INSTANCE.addLog("Unable to launch side task (no recents)");
                     }
                 } else if (nonAppTargets.length > 0) {
                     TaskViewUtils.createSplitAuxiliarySurfacesAnimator(nonAppTargets /* nonApps */,
diff --git a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
index 44b3d62..742b0fc 100644
--- a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
+++ b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java
@@ -15,10 +15,6 @@
  */
 package com.android.quickstep.interaction;
 
-import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_NAV_FADE_OUT_DURATION;
-import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_OUT_INTERPOLATOR;
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL;
 
 import android.animation.Animator;
@@ -28,30 +24,19 @@
 import android.animation.ValueAnimator;
 import android.annotation.ColorInt;
 import android.content.Context;
-import android.graphics.Matrix;
 import android.graphics.Outline;
 import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Display;
-import android.view.RoundedCorner;
 import android.view.View;
 import android.view.ViewOutlineProvider;
-import android.view.animation.ScaleAnimation;
-import android.view.animation.TranslateAnimation;
-import android.widget.ViewAnimator;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.constraintlayout.widget.ConstraintLayout;
 
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
-import com.android.quickstep.util.MultiValueUpdateListener;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 
 /**
  * Helper View for the gesture tutorial mock previous app task view.
@@ -61,8 +46,6 @@
  */
 public class AnimatedTaskView extends ConstraintLayout {
 
-    private static final long ANIMATE_TO_FULL_SCREEN_DURATION = 300;
-
     private View mFullTaskView;
     private View mTopTaskView;
     private View mBottomTaskView;
@@ -72,17 +55,16 @@
     private float mTaskViewAnimatedRadius;
 
     public AnimatedTaskView(@NonNull Context context) {
-        super(context);
+        this(context, null);
     }
 
-    public AnimatedTaskView(@NonNull Context context,
-            @Nullable AttributeSet attrs) {
-        super(context, attrs);
+    public AnimatedTaskView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
     }
 
     public AnimatedTaskView(
             @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
+        this(context, attrs, defStyleAttr, 0);
     }
 
     public AnimatedTaskView(
@@ -104,97 +86,6 @@
         setToSingleRowLayout(false);
     }
 
-    void animateToFillScreen(@Nullable Runnable onAnimationEndCallback) {
-        if (mTaskViewOutlineProvider == null) {
-            // This is an illegal state.
-            return;
-        }
-        // calculate start and end corner radius
-        Outline startOutline = new Outline();
-        mTaskViewOutlineProvider.getOutline(this, startOutline);
-        Rect outlineStartRect = new Rect();
-        startOutline.getRect(outlineStartRect);
-        float outlineStartRadius = startOutline.getRadius();
-
-        final Display display = mContext.getDisplay();;
-        RoundedCorner corner = display.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT);
-        float outlineEndRadius = corner.getRadius();
-
-        // create animation
-        AnimatorSet set = new AnimatorSet();
-        ArrayList<Animator> animations = new ArrayList<>();
-
-        // center view
-        animations.add(ObjectAnimator.ofFloat(this, TRANSLATION_X, 0));
-
-        // retrieve start animation matrix to scale off of
-        Matrix matrix = getAnimationMatrix();
-        if (matrix == null) {
-            // This is an illegal state.
-            return;
-        }
-
-        float[] matrixValues = new float[9];
-        matrix.getValues(matrixValues);
-        float[] newValues = matrixValues.clone();
-
-        ValueAnimator transformAnimation = ValueAnimator.ofFloat(0, 1);
-
-        MultiValueUpdateListener listener = new MultiValueUpdateListener() {
-            Matrix currentMatrix = new Matrix();
-
-            FloatProp mOutlineRadius = new FloatProp(outlineStartRadius, outlineEndRadius, 0,
-                    ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
-            FloatProp mTransX = new FloatProp(matrixValues[Matrix.MTRANS_X], 0f, 0,
-                    ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
-            FloatProp mTransY = new FloatProp(matrixValues[Matrix.MTRANS_Y], 0f, 0,
-                    ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
-            FloatProp mScaleX = new FloatProp(matrixValues[Matrix.MSCALE_X], 1f, 0,
-                    ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
-            FloatProp mScaleY = new FloatProp(matrixValues[Matrix.MSCALE_Y], 1f, 0,
-                    ANIMATE_TO_FULL_SCREEN_DURATION, LINEAR);
-
-            @Override
-            public void onUpdate(float percent, boolean initOnly) {
-                // scale corner radius to match display radius
-                mTaskViewAnimatedRadius = mOutlineRadius.value;
-                mFullTaskView.invalidateOutline();
-
-                // translate to center, ends at translation x:0, y:0
-                newValues[Matrix.MTRANS_X] = mTransX.value;
-                newValues[Matrix.MTRANS_Y] = mTransY.value;
-
-                // scale to full size, ends at scale 1
-                newValues[Matrix.MSCALE_X] = mScaleX.value;
-                newValues[Matrix.MSCALE_Y] = mScaleY.value;
-
-                // create and set new animation matrix
-                currentMatrix.setValues(newValues);
-                setAnimationMatrix(currentMatrix);
-            }
-        };
-
-        transformAnimation.addUpdateListener(listener);
-        animations.add(transformAnimation);
-        set.playSequentially(animations);
-        set.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                super.onAnimationStart(animation);
-                addAnimatedOutlineProvider(mFullTaskView, outlineStartRect, outlineStartRadius);
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                if (onAnimationEndCallback != null) {
-                    onAnimationEndCallback.run();
-                }
-            }
-        });
-        set.start();
-    }
-
     AnimatorSet createAnimationToMultiRowLayout() {
         if (mTaskViewOutlineProvider == null) {
             // This is an illegal state.
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 17e57bf..54c441b 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -136,7 +136,7 @@
     }
 
     @Override
-    protected int getSwipeActionColor() {
+    protected int getFakeLauncherColor() {
         return mTutorialFragment.mRootView.mColorSurfaceContainer;
     }
 
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index 0012d47..891f20e 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -104,11 +104,9 @@
 
     @Override
     protected int getMockAppTaskLayoutResId() {
-        return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
-                ? R.layout.swipe_up_gesture_tutorial_shape
-                : mTutorialFragment.isLargeScreen()
-                    ? R.layout.gesture_tutorial_tablet_mock_webpage
-                    : R.layout.gesture_tutorial_mock_webpage;
+        return mTutorialFragment.isLargeScreen()
+                ? R.layout.gesture_tutorial_tablet_mock_webpage
+                : R.layout.gesture_tutorial_mock_webpage;
     }
 
     @Override
@@ -121,7 +119,12 @@
     }
 
     @Override
-    protected int getSwipeActionColor() {
+    protected int getFakeTaskViewColor() {
+        return isGestureCompleted() ? getFakeLauncherColor() : getExitingAppColor();
+    }
+
+    @Override
+    protected int getFakeLauncherColor() {
         return mTutorialFragment.mRootView.mColorSurfaceContainer;
     }
 
@@ -148,7 +151,7 @@
                     case BACK_CANCELLED_FROM_LEFT:
                     case BACK_CANCELLED_FROM_RIGHT:
                     case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
-                        resetTaskView();
+                        resetTaskViews();
                         showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
                         break;
                 }
@@ -178,18 +181,18 @@
                     }
                     case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
                     case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
-                        resetTaskView();
+                        resetTaskViews();
                         showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
                         break;
                     case OVERVIEW_GESTURE_COMPLETED:
-                        fadeOutFakeTaskView(true, true, () -> {
+                        fadeOutFakeTaskView(true, () -> {
                             showFeedback(R.string.home_gesture_feedback_overview_detected);
                             showFakeTaskbar(/* animateFromHotseat= */ false);
                         });
                         break;
                     case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
                     case HOME_OR_OVERVIEW_CANCELLED:
-                        fadeOutFakeTaskView(false, true, null);
+                        fadeOutFakeTaskView(false, null);
                         showFeedback(R.string.home_gesture_feedback_wrong_swipe_direction);
                         break;
                 }
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 593e6d9..667fe4d 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -25,7 +25,9 @@
 import android.graphics.PointF;
 import android.os.Build;
 import android.os.Handler;
-import android.view.View;
+
+import androidx.annotation.ColorInt;
+import androidx.core.graphics.ColorUtils;
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -43,6 +45,8 @@
 @TargetApi(Build.VERSION_CODES.R)
 final class OverviewGestureTutorialController extends SwipeUpGestureTutorialController {
 
+    private static final float LAUNCHER_COLOR_BLENDING_RATIO = 0.4f;
+
     OverviewGestureTutorialController(OverviewGestureTutorialFragment fragment,
             TutorialType tutorialType) {
         super(fragment, tutorialType);
@@ -112,11 +116,9 @@
 
     @Override
     protected int getMockAppTaskLayoutResId() {
-        return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
-                ? R.layout.gesture_tutorial_mock_task_view
-                : mTutorialFragment.isLargeScreen()
-                        ? R.layout.gesture_tutorial_tablet_mock_conversation_list
-                        : R.layout.gesture_tutorial_mock_conversation_list;
+        return mTutorialFragment.isLargeScreen()
+                ? R.layout.gesture_tutorial_tablet_mock_conversation_list
+                : R.layout.gesture_tutorial_mock_conversation_list;
     }
 
     @Override
@@ -128,11 +130,31 @@
                 : R.raw.overview_gesture_tutorial_animation;
     }
 
-    @Override
-    protected int getSwipeActionColor() {
+    @ColorInt
+    private int getFakeTaskViewStartColor() {
         return mTutorialFragment.mRootView.mColorSurfaceOverview;
     }
 
+    @ColorInt
+    private int getFakeTaskViewEndColor() {
+        return getMockPreviousAppTaskThumbnailColor();
+    }
+
+    @Override
+    protected int getFakeTaskViewColor() {
+        return isGestureCompleted()
+                ? getFakeTaskViewEndColor()
+                : getFakeTaskViewStartColor();
+    }
+
+    @Override
+    protected int getFakeLauncherColor() {
+        return ColorUtils.blendARGB(
+                mTutorialFragment.mRootView.mColorSurfaceContainer,
+                mTutorialFragment.mRootView.mColorOnSurfaceOverview,
+                LAUNCHER_COLOR_BLENDING_RATIO);
+    }
+
     @Override
     protected int getHotseatIconColor() {
         return mTutorialFragment.mRootView.mColorOnSurfaceOverview;
@@ -159,7 +181,7 @@
                     case BACK_CANCELLED_FROM_LEFT:
                     case BACK_CANCELLED_FROM_RIGHT:
                     case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
-                        resetTaskView();
+                        resetTaskViews();
                         showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
                         break;
                 }
@@ -190,7 +212,7 @@
                     }
                     case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
                     case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
-                        resetTaskView();
+                        resetTaskViews();
                         showFeedback(R.string.overview_gesture_feedback_swipe_too_far_from_edge);
                         break;
                     case OVERVIEW_GESTURE_COMPLETED:
@@ -204,7 +226,7 @@
                         break;
                     case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
                     case HOME_OR_OVERVIEW_CANCELLED:
-                        fadeOutFakeTaskView(false, true, null);
+                        fadeOutFakeTaskView(false, null);
                         showFeedback(R.string.overview_gesture_feedback_wrong_swipe_direction);
                         break;
                 }
@@ -229,15 +251,21 @@
             anim.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animator) {
-                    new Handler().postDelayed(() -> {
-                        mFakeTaskView.setVisibility(View.INVISIBLE);
-                        if (!mTutorialFragment.isLargeScreen()) {
-                            mFakePreviousTaskView.animateToFillScreen(
-                                    () -> onSuccessAnimationComplete());
-                        } else {
-                            onSuccessAnimationComplete();
-                        }
-                    }, TASK_VIEW_FILL_SCREEN_ANIMATION_DELAY_MILLIS);
+                    new Handler().postDelayed(
+                            () -> fadeOutFakeTaskView(
+                                    /* toOverviewFirst= */ true,
+                                    /* animatePreviousTask= */ false,
+                                    /* resetViews= */ false,
+                                    /* updateListener= */ v -> mFakeTaskView.setBackgroundColor(
+                                            ColorUtils.blendARGB(
+                                                    getFakeTaskViewStartColor(),
+                                                    getFakeTaskViewEndColor(),
+                                                    v.getAnimatedFraction())),
+                                    /* onEndRunnable= */ () -> {
+                                        showSuccessFeedback();
+                                        resetTaskViews();
+                                    }),
+                            TASK_VIEW_FILL_SCREEN_ANIMATION_DELAY_MILLIS);
                 }
             });
         }
@@ -259,9 +287,4 @@
         animset.start();
         mRunningWindowAnim = SwipeUpAnimationLogic.RunningWindowAnim.wrap(animset);
     }
-
-    private void onSuccessAnimationComplete() {
-        mFakeLauncherView.setBackgroundColor(getMockPreviousAppTaskThumbnailColor());
-        showSuccessFeedback();
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 66c659a..0bbf373 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -78,7 +78,7 @@
     private final AnimatorListenerAdapter mResetTaskView = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
-            resetTaskView();
+            resetTaskViews();
         }
     };
 
@@ -122,7 +122,7 @@
         mRunningWindowAnim = null;
     }
 
-    void resetTaskView() {
+    void resetTaskViews() {
         mFakeHotseatView.setVisibility(View.INVISIBLE);
         mFakeIconView.setVisibility(View.INVISIBLE);
         if (mTutorialFragment.getActivity() != null) {
@@ -141,10 +141,21 @@
         mShowPreviousTasks = false;
         mRunningWindowAnim = null;
     }
+    void fadeOutFakeTaskView(boolean toOverviewFirst, @Nullable Runnable onEndRunnable) {
+        fadeOutFakeTaskView(
+                toOverviewFirst,
+                /* animatePreviousTask= */ true,
+                /* resetViews= */ true,
+                /* updateListener= */ null,
+                onEndRunnable);
+    }
 
     /** Fades the task view, optionally after animating to a fake Overview. */
-    void fadeOutFakeTaskView(boolean toOverviewFirst, boolean reset,
-                             @Nullable Runnable onEndRunnable) {
+    void fadeOutFakeTaskView(boolean toOverviewFirst,
+            boolean animatePreviousTask,
+            boolean resetViews,
+            @Nullable ValueAnimator.AnimatorUpdateListener updateListener,
+            @Nullable Runnable onEndRunnable) {
         cancelRunningAnimation();
         PendingAnimation anim = new PendingAnimation(300);
         if (toOverviewFirst) {
@@ -155,20 +166,20 @@
                 public void onAnimationEnd(Animator animation, boolean isReverse) {
                     PendingAnimation fadeAnim =
                             new PendingAnimation(TASK_VIEW_END_ANIMATION_DURATION_MILLIS);
-                    if (reset) {
-                        fadeAnim.setFloat(mTaskViewSwipeUpAnimation
-                                .getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
+                    fadeAnim.setFloat(mTaskViewSwipeUpAnimation
+                            .getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
+                    if (resetViews) {
                         fadeAnim.addListener(mResetTaskView);
-                    } else {
-                        fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL);
-                        fadeAnim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
                     }
                     if (onEndRunnable != null) {
                         fadeAnim.addListener(AnimatorListeners.forSuccessCallback(onEndRunnable));
                     }
+                    if (updateListener != null) {
+                        fadeAnim.addOnFrameListener(updateListener);
+                    }
                     AnimatorSet animset = fadeAnim.buildAnim();
 
-                    if (reset && mTutorialFragment.isLargeScreen()) {
+                    if (animatePreviousTask && mTutorialFragment.isLargeScreen()) {
                         animset.addListener(new AnimatorListenerAdapter() {
                             @Override
                             public void onAnimationStart(Animator animation) {
@@ -190,13 +201,10 @@
                 }
             });
         } else {
-            if (reset) {
-                anim.setFloat(mTaskViewSwipeUpAnimation
-                        .getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
+            anim.setFloat(mTaskViewSwipeUpAnimation
+                    .getCurrentShift(), AnimatedFloat.VALUE, 0, ACCEL);
+            if (resetViews) {
                 anim.addListener(mResetTaskView);
-            } else {
-                anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
-                anim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
             }
             if (onEndRunnable != null) {
                 anim.addListener(AnimatorListeners.forSuccessCallback(onEndRunnable));
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 36655d2..084f8c1 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -268,7 +268,12 @@
     }
 
     @ColorInt
-    protected abstract int getSwipeActionColor();
+    protected int getFakeTaskViewColor() {
+        return Color.TRANSPARENT;
+    }
+
+    @ColorInt
+    protected abstract int getFakeLauncherColor();
 
     @ColorInt
     protected int getExitingAppColor() {
@@ -445,6 +450,7 @@
     }
 
     private void showSuccessPage() {
+        pauseAndHideLottieAnimation();
         mCheckmarkAnimation.setVisibility(View.VISIBLE);
         mCheckmarkAnimation.playAnimation();
         mFeedbackTitleView.setTextAppearance(mContext, getSuccessTitleTextAppearance());
@@ -591,7 +597,7 @@
 
     protected void resetViewsForBackGesture() {
         mFakeTaskView.setVisibility(View.VISIBLE);
-        mFakeTaskView.setBackgroundColor(getSwipeActionColor());
+        mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
         mExitingAppView.setVisibility(View.VISIBLE);
 
         // reset the exiting app's dimensions
@@ -690,11 +696,10 @@
                     mContext, getMockWallpaperResId()));
             mTutorialFragment.updateFeedbackAnimation();
             mFakeLauncherView.setBackgroundColor(ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
-                    ? getSwipeActionColor()
+                    ? getFakeLauncherColor()
                     : mContext.getColor(R.color.gesture_tutorial_fake_wallpaper_color));
             updateFakeViewLayout(mFakeHotseatView, getMockHotseatResId());
             mHotseatIconView = mFakeHotseatView.findViewById(R.id.hotseat_icon_1);
-            updateFakeViewLayout(mFakeTaskView, getMockAppTaskLayoutResId());
             mFakeTaskView.animate().alpha(1).setListener(
                     AnimatorListeners.forSuccessCallback(() -> mFakeTaskView.animate().cancel()));
             mFakePreviousTaskView.setFakeTaskViewFillColor(getMockPreviousAppTaskThumbnailColor());
@@ -703,12 +708,15 @@
 
             if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) {
                 mExitingAppView.setBackgroundColor(getExitingAppColor());
+                mFakeTaskView.setBackgroundColor(getFakeTaskViewColor());
                 updateHotseatChildViewColor(mFakeIconView);
                 updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_2));
                 updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_3));
                 updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_4));
                 updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_5));
                 updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_search_bar));
+            } else {
+                updateFakeViewLayout(mFakeTaskView, getMockAppTaskLayoutResId());
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 9f15e19..bfad643 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -143,6 +143,7 @@
         return null;
     }
 
+    @NonNull
     abstract TutorialController createController(TutorialType type);
 
     abstract Class<? extends TutorialController> getControllerClass();
@@ -374,9 +375,15 @@
     void changeController(TutorialType tutorialType) {
         if (getControllerClass().isInstance(mTutorialController)) {
             mTutorialController.setTutorialType(tutorialType);
+            if (isGestureComplete()) {
+                mTutorialController.setGestureCompleted();
+            }
             mTutorialController.fadeTaskViewAndRun(mTutorialController::transitToController);
         } else {
             mTutorialController = createController(tutorialType);
+            if (isGestureComplete()) {
+                mTutorialController.setGestureCompleted();
+            }
             mTutorialController.transitToController();
         }
         mEdgeBackGestureHandler.registerBackGestureAttemptCallback(mTutorialController);
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
index 614dfe8..8e6415b 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
@@ -61,7 +61,8 @@
      */
     companion object {
         @IntDef(SPLIT_TASK_TASK, SPLIT_TASK_PENDINGINTENT, SPLIT_TASK_SHORTCUT,
-                SPLIT_PENDINGINTENT_TASK, SPLIT_PENDINGINTENT_PENDINGINTENT, SPLIT_SHORTCUT_TASK)
+                SPLIT_PENDINGINTENT_TASK, SPLIT_PENDINGINTENT_PENDINGINTENT, SPLIT_SHORTCUT_TASK,
+                SPLIT_SINGLE_TASK_FULLSCREEN, SPLIT_SINGLE_INTENT_FULLSCREEN)
         @Retention(AnnotationRetention.SOURCE)
         annotation class SplitLaunchType
 
@@ -71,6 +72,10 @@
         const val SPLIT_PENDINGINTENT_TASK = 3
         const val SPLIT_SHORTCUT_TASK = 4
         const val SPLIT_PENDINGINTENT_PENDINGINTENT = 5
+
+        // Non-split edge case of launching the initial selected task as a fullscreen task
+        const val SPLIT_SINGLE_TASK_FULLSCREEN = 6
+        const val SPLIT_SINGLE_INTENT_FULLSCREEN = 7
     }
 
 
@@ -190,7 +195,7 @@
 
     /**
      * @return [SplitLaunchData] with the necessary fields populated as determined by
-     *   [SplitLaunchData.splitLaunchType]
+     *   [SplitLaunchData.splitLaunchType]. This is to be used for launching splitscreen
      */
     fun getSplitLaunchData() : SplitLaunchData {
         // Convert all intents to shortcut infos to see if determine if we launch shortcut or intent
@@ -201,6 +206,24 @@
             initialStagePosition = getOppositeStagePosition(initialStagePosition)
         }
 
+        return generateSplitLaunchData(splitLaunchType)
+    }
+
+    /**
+     * @return [SplitLaunchData] with the necessary fields populated as determined by
+     *   [SplitLaunchData.splitLaunchType]. This is to be used for launching an initially selected
+     *   split task in fullscreen
+     */
+    fun getFullscreenLaunchData() : SplitLaunchData {
+        // Convert all intents to shortcut infos to see if determine if we launch shortcut or intent
+        convertIntentsToFinalTypes()
+        val splitLaunchType = if (initialTaskId != INVALID_TASK_ID) SPLIT_SINGLE_TASK_FULLSCREEN
+        else SPLIT_SINGLE_INTENT_FULLSCREEN
+
+        return generateSplitLaunchData(splitLaunchType)
+    }
+
+    private fun generateSplitLaunchData(@SplitLaunchType splitLaunchType: Int) : SplitLaunchData {
         return SplitLaunchData(
                 splitLaunchType,
                 initialTaskId,
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index ee51af7..ec8be89 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -27,6 +27,8 @@
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_PENDINGINTENT_PENDINGINTENT;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_PENDINGINTENT_TASK;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_SHORTCUT_TASK;
+import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_SINGLE_INTENT_FULLSCREEN;
+import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_SINGLE_TASK_FULLSCREEN;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_PENDINGINTENT;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_SHORTCUT;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_TASK;
@@ -324,11 +326,8 @@
         }
         boolean hasSecondaryPendingIntent = mSecondPendingIntent != null;
         if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-            final RemoteSplitLaunchTransitionRunner animationRunner =
-                    new RemoteSplitLaunchTransitionRunner(taskId1, taskId2, callback);
-            final RemoteTransition remoteTransition = new RemoteTransition(animationRunner,
-                    ActivityThread.currentActivityThread().getApplicationThread(),
-                    "LaunchSplitPair");
+            final RemoteTransition remoteTransition = getShellRemoteTransition(taskId1, taskId2,
+                    callback);
             if (intent1 == null && (intent2 == null && !hasSecondaryPendingIntent)) {
                 mSystemUiProxy.startTasks(taskId1, options1.toBundle(), taskId2,
                         null /* options2 */, stagePosition, splitRatio, remoteTransition,
@@ -351,11 +350,8 @@
                         shellInstanceId);
             }
         } else {
-            final RemoteSplitLaunchAnimationRunner animationRunner =
-                    new RemoteSplitLaunchAnimationRunner(taskId1, taskId2, callback);
-            final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
-                    animationRunner, 300, 150,
-                    ActivityThread.currentActivityThread().getApplicationThread());
+            final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(taskId1, taskId2,
+                    callback);
 
             if (intent1 == null && (intent2 == null && !hasSecondaryPendingIntent)) {
                 mSystemUiProxy.startTasksWithLegacyTransition(taskId1, options1.toBundle(),
@@ -402,11 +398,8 @@
         Bundle optionsBundle = options1.toBundle();
 
         if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-            final RemoteSplitLaunchTransitionRunner animationRunner =
-                    new RemoteSplitLaunchTransitionRunner(firstTaskId, secondTaskId, callback);
-            final RemoteTransition remoteTransition = new RemoteTransition(animationRunner,
-                    ActivityThread.currentActivityThread().getApplicationThread(),
-                    "LaunchSplitPair");
+            final RemoteTransition remoteTransition = getShellRemoteTransition(firstTaskId,
+                    secondTaskId, callback);
             switch (launchData.getSplitLaunchType()) {
                 case SPLIT_TASK_TASK ->
                         mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId,
@@ -440,11 +433,8 @@
                                 remoteTransition, shellInstanceId);
             }
         } else {
-            final RemoteSplitLaunchAnimationRunner animationRunner =
-                    new RemoteSplitLaunchAnimationRunner(firstTaskId, secondTaskId, callback);
-            final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
-                    animationRunner, 300, 150,
-                    ActivityThread.currentActivityThread().getApplicationThread());
+            final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId, secondTaskId,
+                    callback);
             switch (launchData.getSplitLaunchType()) {
                 case SPLIT_TASK_TASK ->
                         mSystemUiProxy.startTasksWithLegacyTransition(firstTaskId, optionsBundle,
@@ -501,26 +491,90 @@
         Bundle optionsBundle = options1.toBundle();
 
         if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-            final RemoteSplitLaunchTransitionRunner animationRunner =
-                    new RemoteSplitLaunchTransitionRunner(firstTaskId, secondTaskId, callback);
-            final RemoteTransition remoteTransition = new RemoteTransition(animationRunner,
-                    ActivityThread.currentActivityThread().getApplicationThread(),
-                    "LaunchSplitPair");
+            final RemoteTransition remoteTransition = getShellRemoteTransition(firstTaskId,
+                    secondTaskId, callback);
             mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId,
                     null /* options2 */, stagePosition, splitRatio,
                     remoteTransition, null /*shellInstanceId*/);
         } else {
-            final RemoteSplitLaunchAnimationRunner animationRunner =
-                    new RemoteSplitLaunchAnimationRunner(firstTaskId, secondTaskId, callback);
-            final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
-                    animationRunner, 300, 150,
-                    ActivityThread.currentActivityThread().getApplicationThread());
+            final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId,
+                    secondTaskId, callback);
             mSystemUiProxy.startTasksWithLegacyTransition(firstTaskId, optionsBundle,
                     secondTaskId, null /* options2 */, stagePosition,
                     splitRatio, adapter, null /*shellInstanceId*/);
         }
     }
 
+    /**
+     * Launches the initially selected task/intent in fullscreen (note the same SystemUi APIs are
+     * used as {@link #launchSplitTasks(Consumer)} because they are overloaded to launch both
+     * split and fullscreen tasks)
+     */
+    public void launchInitialAppFullscreen(Consumer<Boolean> callback) {
+        if (!FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
+            launchSplitTasks(callback);
+            return;
+        }
+
+        final ActivityOptions options1 = ActivityOptions.makeBasic();
+        SplitSelectDataHolder.SplitLaunchData launchData =
+                mSplitSelectDataHolder.getFullscreenLaunchData();
+        int firstTaskId = launchData.getInitialTaskId();
+        int secondTaskId = launchData.getSecondTaskId();
+        PendingIntent firstPI = launchData.getInitialPendingIntent();
+        int firstUserId = launchData.getInitialUserId();
+        int initialStagePosition = launchData.getInitialStagePosition();
+        Bundle optionsBundle = options1.toBundle();
+
+        final RemoteSplitLaunchTransitionRunner animationRunner =
+                new RemoteSplitLaunchTransitionRunner(firstTaskId, secondTaskId, callback);
+        final RemoteTransition remoteTransition = new RemoteTransition(animationRunner,
+                ActivityThread.currentActivityThread().getApplicationThread(),
+                "LaunchSplitPair");
+        Pair<InstanceId, com.android.launcher3.logging.InstanceId> instanceIds =
+                LogUtils.getShellShareableInstanceId();
+        if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+            switch (launchData.getSplitLaunchType()) {
+                case SPLIT_SINGLE_TASK_FULLSCREEN -> mSystemUiProxy.startTasks(firstTaskId,
+                        optionsBundle, secondTaskId, null /* options2 */, initialStagePosition,
+                        DEFAULT_SPLIT_RATIO, remoteTransition, instanceIds.first);
+                case SPLIT_SINGLE_INTENT_FULLSCREEN -> mSystemUiProxy.startIntentAndTask(firstPI,
+                        firstUserId, optionsBundle, secondTaskId, null /*options2*/,
+                        initialStagePosition, DEFAULT_SPLIT_RATIO, remoteTransition,
+                        instanceIds.first);
+            }
+        } else {
+            final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId,
+                    secondTaskId, callback);
+            switch (launchData.getSplitLaunchType()) {
+                case SPLIT_SINGLE_TASK_FULLSCREEN -> mSystemUiProxy.startTasksWithLegacyTransition(
+                        firstTaskId, optionsBundle, secondTaskId, null /* options2 */,
+                        initialStagePosition, DEFAULT_SPLIT_RATIO, adapter, instanceIds.first);
+                case SPLIT_SINGLE_INTENT_FULLSCREEN ->
+                        mSystemUiProxy.startIntentAndTaskWithLegacyTransition(firstPI, firstUserId,
+                                optionsBundle, secondTaskId, null /*options2*/,
+                                initialStagePosition, DEFAULT_SPLIT_RATIO, adapter,
+                                instanceIds.first);
+            }
+        }
+    }
+
+    private RemoteTransition getShellRemoteTransition(int firstTaskId, int secondTaskId,
+            Consumer<Boolean> callback) {
+        final RemoteSplitLaunchTransitionRunner animationRunner =
+                new RemoteSplitLaunchTransitionRunner(firstTaskId, secondTaskId, callback);
+        return new RemoteTransition(animationRunner,
+                ActivityThread.currentActivityThread().getApplicationThread(), "LaunchSplitPair");
+    }
+
+    private RemoteAnimationAdapter getLegacyRemoteAdapter(int firstTaskId, int secondTaskId,
+            Consumer<Boolean> callback) {
+        final RemoteSplitLaunchAnimationRunner animationRunner =
+                new RemoteSplitLaunchAnimationRunner(firstTaskId, secondTaskId, callback);
+        return new RemoteAnimationAdapter(animationRunner, 300, 150,
+                ActivityThread.currentActivityThread().getApplicationThread());
+    }
+
     private void launchIntentOrShortcut(Intent intent, UserHandle user, ActivityOptions options1,
             int taskId, @StagePosition int stagePosition, float splitRatio,
             RemoteTransition remoteTransition, @Nullable InstanceId shellInstanceId) {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index d8fe32d..f740d9c 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -3260,7 +3260,7 @@
                 true /* isStagedTask */);
 
         pendingAnimation.addEndListener(animationSuccess ->
-                mSplitSelectStateController.launchSplitTasks(launchSuccess ->
+                mSplitSelectStateController.launchInitialAppFullscreen(launchSuccess ->
                         resetFromSplitSelectionState()));
 
         pendingAnimation.buildAnim().start();
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 617afcb..c20494d 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -20,6 +20,8 @@
 
 import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
 import static com.android.launcher3.config.FeatureFlags.IS_STUDIO_BUILD;
+import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
@@ -560,6 +562,7 @@
             synchronized (mLock) {
                 // Everything loaded bind the data.
                 mModelLoaded = true;
+                testLogD(WORK_TAB_MISSING, "launcher model loaded");
             }
         }
 
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 2ce6c78..dd82ecf 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -273,6 +273,8 @@
         // {@link #onAnimationEnd} before B reads new UI state from {@link #onAnimationStart}.
         a.addListener(new AnimatorListenerAdapter() {
             private CellLayout mCellLayout;
+
+            private boolean mFolderClipChildren;
             private boolean mFolderClipToPadding;
             private boolean mContentClipChildren;
             private boolean mContentClipToPadding;
@@ -283,12 +285,14 @@
             public void onAnimationStart(Animator animator) {
                 super.onAnimationStart(animator);
                 mCellLayout = mContent.getCurrentCellLayout();
+                mFolderClipChildren = mFolder.getClipChildren();
                 mFolderClipToPadding = mFolder.getClipToPadding();
                 mContentClipChildren = mContent.getClipChildren();
                 mContentClipToPadding = mContent.getClipToPadding();
                 mCellLayoutClipChildren = mCellLayout.getClipChildren();
                 mCellLayoutClipPadding = mCellLayout.getClipToPadding();
 
+                mFolder.setClipChildren(false);
                 mFolder.setClipToPadding(false);
                 mContent.setClipChildren(false);
                 mContent.setClipToPadding(false);
@@ -309,6 +313,7 @@
                 mFolder.mFooter.setTranslationX(0f);
                 mFolder.mFolderName.setAlpha(1f);
 
+                mFolder.setClipChildren(mFolderClipChildren);
                 mFolder.setClipToPadding(mFolderClipToPadding);
                 mContent.setClipChildren(mContentClipChildren);
                 mContent.setClipToPadding(mContentClipToPadding);
diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java
index 70c9802..44d32d9 100644
--- a/src/com/android/launcher3/model/BaseModelUpdateTask.java
+++ b/src/com/android/launcher3/model/BaseModelUpdateTask.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.model;
 
 import static com.android.launcher3.testing.shared.TestProtocol.WORK_TAB_MISSING;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
 
 import android.util.Log;
 
@@ -72,7 +73,9 @@
 
     @Override
     public final void run() {
-        if (!Objects.requireNonNull(mModel).isModelLoaded()) {
+        boolean isModelLoaded = Objects.requireNonNull(mModel).isModelLoaded();
+        testLogD(WORK_TAB_MISSING, "modelLoaded: " + isModelLoaded + " forTask: " + this);
+        if (!isModelLoaded) {
             if (DEBUG_TASKS) {
                 Log.d(TAG, "Ignoring model task since loader is pending=" + this);
             }
diff --git a/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
index 2742882..580b4f1 100644
--- a/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
@@ -105,6 +105,7 @@
                 mEnforcedRectangle);
         setOutlineProvider(mCornerRadiusEnforcementOutline);
         setClipToOutline(true);
+        invalidateOutline();
     }
 
     /** Returns the corner radius currently enforced, in pixels. */
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index 723ea17..8dd1de4 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -42,7 +42,6 @@
 import androidx.recyclerview.widget.RecyclerView.ViewHolder;
 
 import com.android.launcher3.R;
-import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.recyclerview.ViewHolderBinder;
 import com.android.launcher3.util.LabelComparator;
 import com.android.launcher3.util.PackageUserKey;
@@ -58,7 +57,6 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
-import java.util.Map;
 import java.util.OptionalInt;
 import java.util.function.IntSupplier;
 import java.util.function.Predicate;
@@ -174,9 +172,6 @@
         mAllEntries.clear();
         mAllEntries.add(new WidgetListSpaceEntry());
         tempEntries.stream().sorted(mRowComparator).forEach(mAllEntries::add);
-        if (shouldClearVisibleEntries()) {
-            mVisibleEntries.clear();
-        }
         updateVisibleEntries();
     }
 
@@ -426,29 +421,6 @@
         updateVisibleEntries();
     }
 
-    /**
-     * Returns {@code true} if there is a change in {@link #mAllEntries} that results in an
-     * invalidation of {@link #mVisibleEntries}. e.g. there is change in the device language.
-     */
-    private boolean shouldClearVisibleEntries() {
-        Map<PackageUserKey, PackageItemInfo> packagesInfo =
-                mAllEntries.stream()
-                        .filter(entry -> entry instanceof WidgetsListHeaderEntry)
-                        .map(entry -> entry.mPkgItem)
-                        .collect(Collectors.toMap(
-                                entry -> PackageUserKey.fromPackageItemInfo(entry),
-                                entry -> entry));
-        for (WidgetsListBaseEntry visibleEntry: mVisibleEntries) {
-            PackageUserKey key = PackageUserKey.fromPackageItemInfo(visibleEntry.mPkgItem);
-            PackageItemInfo packageItemInfo = packagesInfo.get(key);
-            if (packageItemInfo != null
-                    && !visibleEntry.mPkgItem.title.equals(packageItemInfo.title)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     /** Comparator for sorting WidgetListRowEntry based on package title. */
     public static class WidgetListBaseRowEntryComparator implements
             Comparator<WidgetsListBaseEntry> {
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 8def7e8..b7c3aca 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.testing.shared;
 
+import android.util.Log;
+
 /**
  * Protocol for custom accessibility events for communication with UI Automation tests.
  */
@@ -161,4 +163,12 @@
     public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
     public static final String REQUEST_IS_EMULATE_DISPLAY_RUNNING = "is-emulate-display-running";
     public static final String REQUEST_EMULATE_PRINT_DEVICE = "emulate-print-device";
+
+    /** Logs {@link Log#d(String, String)} if {@link #sDebugTracing} is true. */
+    public static void testLogD(String tag, String message) {
+        if (!sDebugTracing) {
+            return;
+        }
+        Log.d(tag, message);
+    }
 }