Merge "Simplifying IconShape" into main
diff --git a/quickstep/res/layout/split_instructions_view.xml b/quickstep/res/layout/split_instructions_view.xml
index a11974c..b433a59 100644
--- a/quickstep/res/layout/split_instructions_view.xml
+++ b/quickstep/res/layout/split_instructions_view.xml
@@ -29,9 +29,9 @@
         android:id="@+id/split_instructions_text"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
-        android:maxWidth="@dimen/split_instructions_view_max_width"
         android:textColor="?androidprv:attr/textColorOnAccent"
-        android:text="@string/toast_split_select_app" />
+        android:text="@string/toast_split_select_app"
+        android:layout_weight="1" />
 
     <androidx.appcompat.widget.AppCompatTextView
         android:id="@+id/split_instructions_text_cancel"
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
index e24d8fe..37a90a1 100644
--- a/quickstep/res/values-sw600dp/dimens.xml
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -44,9 +44,4 @@
     <dimen name="allset_page_margin_horizontal">120dp</dimen>
     <dimen name="allset_page_allset_text_size">38sp</dimen>
     <dimen name="allset_page_swipe_up_text_size">15sp</dimen>
-
-    <!-- Splitscreen -->
-    <!-- Max width of the split instructions view -->
-    <dimen name="split_instructions_view_max_width">300dp</dimen>
-
 </resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index b404bb5..de0b2c7 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -522,9 +522,4 @@
 
     <!-- Digital Wellbeing -->
     <dimen name="digital_wellbeing_toast_height">48dp</dimen>
-
-    <!-- Splitscreen -->
-    <!-- Max width of the split instructions view -->
-    <dimen name="split_instructions_view_max_width">220dp</dimen>
-
 </resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index df949c3..f126568 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -49,9 +49,6 @@
     <!-- Accessibility title for the list of recent apps [CHAR_LIMIT=none] -->
     <string name="accessibility_recent_apps">Recent apps</string>
 
-    <!-- Accessibility confirmation for task closed -->
-    <string name="task_view_closed">Task Closed</string>
-
     <!-- Accessibility title for an app card in Recents for apps that have time limit set
      [CHAR_LIMIT=none] -->
     <string name="task_contents_description_with_remaining_time"><xliff:g id="task_description" example="GMail">%1$s</xliff:g>, <xliff:g id="remaining_time" example="7 minutes left today">%2$s</xliff:g></string>
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 5685093..84243f5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -481,7 +481,7 @@
 
     /** Whether the bubble bar has bubbles. */
     public boolean hasBubbles() {
-        return mBubbleBarController.getSelectedBubbleKey() != null;
+        return mBarView.getBubbleChildCount() > 0;
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 124be41..e27b607 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -100,6 +100,7 @@
 import android.widget.Toast;
 import android.window.DesktopModeFlags;
 import android.window.PictureInPictureSurfaceTransaction;
+import android.window.TransitionInfo;
 import android.window.WindowAnimationState;
 
 import androidx.annotation.NonNull;
@@ -956,10 +957,10 @@
 
     @Override
     public void onRecentsAnimationStart(RecentsAnimationController controller,
-            RecentsAnimationTargets targets) {
-        super.onRecentsAnimationStart(controller, targets);
+            RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+        super.onRecentsAnimationStart(controller, targets, transitionInfo);
         if (targets.hasDesktopTasks(mContext)) {
-            mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets);
+            mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets, transitionInfo);
         } else {
             int untrimmedAppCount = mRemoteTargetHandles.length;
             mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(targets);
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index cfbcf0a..e0fa77a 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -33,6 +33,7 @@
 import android.os.SystemClock;
 import android.view.MotionEvent;
 import android.view.RemoteAnimationTarget;
+import android.window.TransitionInfo;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -491,7 +492,7 @@
 
     @Override
     public void onRecentsAnimationStart(RecentsAnimationController controller,
-            RecentsAnimationTargets targets) {
+            RecentsAnimationTargets targets, TransitionInfo info) {
         mStateCallback.setState(STATE_RECENTS_ANIMATION_STARTED);
     }
 
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index 089706f..66f307c 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -23,6 +23,7 @@
 import android.os.Trace
 import android.util.Log
 import android.view.View
+import android.window.TransitionInfo
 import androidx.annotation.BinderThread
 import androidx.annotation.UiThread
 import androidx.annotation.VisibleForTesting
@@ -369,6 +370,7 @@
                 override fun onRecentsAnimationStart(
                     controller: RecentsAnimationController,
                     targets: RecentsAnimationTargets,
+                    transitionInfo: TransitionInfo,
                 ) {
                     Log.d(TAG, "recents animation started: $command")
                     updateRecentsViewFocus(command)
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 8fc1a78..87bf81c 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -26,6 +26,7 @@
 import android.os.Bundle;
 import android.util.ArraySet;
 import android.view.RemoteAnimationTarget;
+import android.window.TransitionInfo;
 
 import androidx.annotation.BinderThread;
 import androidx.annotation.NonNull;
@@ -93,7 +94,7 @@
             RemoteAnimationTarget[] appTargets, Rect homeContentInsets,
             Rect minimizedHomeBounds, Bundle extras) {
         onAnimationStart(controller, appTargets, new RemoteAnimationTarget[0],
-                homeContentInsets, minimizedHomeBounds, extras);
+                homeContentInsets, minimizedHomeBounds, extras, /* transitionInfo= */ null);
     }
 
     // Called only in R+ platform
@@ -101,7 +102,8 @@
     public final void onAnimationStart(RecentsAnimationControllerCompat animationController,
             RemoteAnimationTarget[] appTargets,
             RemoteAnimationTarget[] wallpaperTargets,
-            Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras) {
+            Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras,
+            TransitionInfo transitionInfo) {
         long appCount = Arrays.stream(appTargets)
                 .filter(app -> app.mode == MODE_CLOSING)
                 .count();
@@ -141,7 +143,7 @@
             Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
                 ActiveGestureProtoLogProxy.logOnRecentsAnimationStart(targets.apps.length);
                 for (RecentsAnimationListener listener : getListeners()) {
-                    listener.onRecentsAnimationStart(mController, targets);
+                    listener.onRecentsAnimationStart(mController, targets, transitionInfo);
                 }
             });
         }
@@ -205,7 +207,7 @@
      */
     public interface RecentsAnimationListener {
         default void onRecentsAnimationStart(RecentsAnimationController controller,
-                RecentsAnimationTargets targets) {}
+                RecentsAnimationTargets targets, TransitionInfo transitionInfo) {}
 
         /**
          * Callback from the system when the recents animation is canceled. {@param thumbnailData}
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 89337e5..8edbacb 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -24,6 +24,7 @@
 import android.graphics.Rect;
 import android.util.Log;
 import android.view.RemoteAnimationTarget;
+import android.window.TransitionInfo;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -213,7 +214,8 @@
      * Similar to {@link #assignTargets(RemoteAnimationTargets)}, except this creates distinct
      * transform params per app in {@code targets.apps} list.
      */
-    public RemoteTargetHandle[] assignTargetsForDesktop(RemoteAnimationTargets targets) {
+    public RemoteTargetHandle[] assignTargetsForDesktop(
+            RemoteAnimationTargets targets, TransitionInfo transitionInfo) {
         resizeRemoteTargetHandles(targets);
 
         for (int i = 0; i < mRemoteTargetHandles.length; i++) {
@@ -222,6 +224,7 @@
                     .filter(target -> target.taskId != primaryTaskTarget.taskId).toList();
             mRemoteTargetHandles[i].mTransformParams.setTargetSet(
                     createRemoteAnimationTargetsForTarget(targets, excludeTargets));
+            mRemoteTargetHandles[i].mTransformParams.setTransitionInfo(transitionInfo);
             mRemoteTargetHandles[i].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
         }
         return mRemoteTargetHandles;
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.kt b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
index 75694af..a7405a0 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.kt
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.kt
@@ -45,6 +45,7 @@
 import android.window.RemoteTransition
 import android.window.TaskSnapshot
 import android.window.TransitionFilter
+import android.window.TransitionInfo
 import androidx.annotation.MainThread
 import androidx.annotation.VisibleForTesting
 import androidx.annotation.WorkerThread
@@ -1174,6 +1175,7 @@
             homeContentInsets: Rect?,
             minimizedHomeBounds: Rect?,
             extras: Bundle?,
+            transitionInfo: TransitionInfo?,
         ) =
             listener.onAnimationStart(
                 RecentsAnimationControllerCompat(controller),
@@ -1186,6 +1188,7 @@
                     // https://developer.android.com/guide/components/aidl#Bundles
                     classLoader = SplitBounds::class.java.classLoader
                 },
+                transitionInfo,
             )
 
         override fun onAnimationCanceled(taskIds: IntArray?, taskSnapshots: Array<TaskSnapshot>?) =
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index e0d4ddd..cea7931 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -36,6 +36,7 @@
 import android.os.SystemProperties;
 import android.util.Log;
 import android.view.RemoteAnimationTarget;
+import android.window.TransitionInfo;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -69,6 +70,7 @@
     private RecentsAnimationController mController;
     private RecentsAnimationCallbacks mCallbacks;
     private RecentsAnimationTargets mTargets;
+    private TransitionInfo mTransitionInfo;
     private RecentsAnimationDeviceState mDeviceState;
 
     // Temporary until we can hook into gesture state events
@@ -166,7 +168,7 @@
         mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
             @Override
             public void onRecentsAnimationStart(RecentsAnimationController controller,
-                    RecentsAnimationTargets targets) {
+                    RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
                 if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) {
                     ActiveGestureProtoLogProxy.logStartRecentsAnimationCallback(
                             "onRecentsAnimationStart");
@@ -180,6 +182,7 @@
                 }
                 mController = controller;
                 mTargets = targets;
+                mTransitionInfo = transitionInfo;
                 // TODO(b/236226779): We can probably get away w/ setting mLastAppearedTaskTargets
                 //  to all appeared targets directly vs just looking at running ones
                 int[] runningTaskIds = mLastGestureState.getRunningTaskIds(targets.apps.length > 1);
@@ -448,7 +451,7 @@
     public void notifyRecentsAnimationState(
             RecentsAnimationCallbacks.RecentsAnimationListener listener) {
         if (isRecentsAnimationRunning()) {
-            listener.onRecentsAnimationStart(mController, mTargets);
+            listener.onRecentsAnimationStart(mController, mTargets, mTransitionInfo);
         }
         // TODO: Do we actually need to report canceled/finished?
     }
@@ -488,6 +491,7 @@
         mController = null;
         mCallbacks = null;
         mTargets = null;
+        mTransitionInfo = null;
         mLastGestureState = null;
         mLastAppearedTaskTargets = null;
     }
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index dec36cf..3e90374 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -189,7 +189,8 @@
             RemoteTargetGluer gluer = new RemoteTargetGluer(v.getContext(),
                     recentsView.getSizeStrategy(), targets, forDesktop);
             if (forDesktop) {
-                remoteTargetHandles = gluer.assignTargetsForDesktop(targets);
+                remoteTargetHandles =
+                        gluer.assignTargetsForDesktop(targets, /* transitionInfo=*/ null);
             } else if (v.containsMultipleTasks()) {
                 remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets,
                         ((GroupedTaskView) v).getSplitBoundsConfig());
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
index 12bae53..973fb2f 100644
--- a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
@@ -49,6 +49,7 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
 import android.view.animation.Interpolator;
+import android.window.TransitionInfo;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -124,8 +125,8 @@
 
     @Override
     public void onRecentsAnimationStart(RecentsAnimationController controller,
-            RecentsAnimationTargets targets) {
-        super.onRecentsAnimationStart(controller, targets);
+            RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
+        super.onRecentsAnimationStart(controller, targets, transitionInfo);
         initTransformParams();
     }
 
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
index 390d097..b2e7015 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
@@ -57,6 +57,7 @@
     private final int mTouchSlop;
     private final PointF mDownPos = new PointF();
     private final PointF mLastPos = new PointF();
+    private long mDownTime;
     private final long mTimeForLongPress;
     private int mActivePointerId = INVALID_POINTER_ID;
 
@@ -81,6 +82,7 @@
         final int action = ev.getAction();
         switch (action) {
             case MotionEvent.ACTION_DOWN:
+                mDownTime = System.currentTimeMillis();
                 mActivePointerId = ev.getPointerId(0);
                 mDownPos.set(ev.getX(), ev.getY());
                 mLastPos.set(mDownPos);
@@ -120,13 +122,15 @@
                 }
                 break;
             case MotionEvent.ACTION_UP:
+                long tapTime = System.currentTimeMillis() - mDownTime;
                 boolean swipeUpOnBubbleHandle = mBubbleBarSwipeController != null
                         && mBubbleBarSwipeController.isSwipeGesture();
                 // Anything less than a long-press is a tap
-                boolean isWithinTapTime = ev.getEventTime() - ev.getDownTime() <= mTimeForLongPress;
+                boolean isWithinTapTime = tapTime <= mTimeForLongPress;
                 Log.d(TAG, "ACTION_UP swipeUp=" + swipeUpOnBubbleHandle + " isInTapTime="
-                        + isWithinTapTime + " passedTouchSlop=" + mPassedTouchSlop
-                        + " stashedOrCollapsedOnDown=" + mStashedOrCollapsedOnDown);
+                        + isWithinTapTime + " tapTime=" + tapTime + " passedTouchSlop="
+                        + mPassedTouchSlop + " stashedOrCollapsedOnDown="
+                        + mStashedOrCollapsedOnDown);
                 if (isWithinTapTime && !swipeUpOnBubbleHandle && !mPassedTouchSlop
                         && mStashedOrCollapsedOnDown) {
                     Log.d(TAG, "ACTION_UP showing bubble bar");
@@ -153,6 +157,7 @@
         }
         mPassedTouchSlop = false;
         mPilfered = false;
+        mDownTime = 0;
     }
 
     private boolean isCollapsed() {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 01f5522..503b900 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -37,6 +37,7 @@
 import android.view.MotionEvent;
 import android.view.RemoteAnimationTarget;
 import android.view.VelocityTracker;
+import android.window.TransitionInfo;
 
 import com.android.app.animation.Interpolators;
 import com.android.launcher3.R;
@@ -249,7 +250,7 @@
 
     @Override
     public void onRecentsAnimationStart(RecentsAnimationController controller,
-            RecentsAnimationTargets targets) {
+            RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
         mRecentsAnimationController = controller;
         mTransformParams.setTargetSet(targets);
         applyTransform();
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
index 6dcb7bc..c91bebe 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
@@ -28,6 +28,7 @@
 import android.content.Intent;
 import android.graphics.Point;
 import android.view.MotionEvent;
+import android.window.TransitionInfo;
 
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorListeners;
@@ -172,7 +173,7 @@
 
     @Override
     public void onRecentsAnimationStart(RecentsAnimationController controller,
-            RecentsAnimationTargets targets) {
+            RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
         mRecentsAnimationController = controller;
         mStateCallback.setState(STATE_TARGET_RECEIVED);
     }
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index c524286..202574b 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -678,7 +678,7 @@
         }
 
         @Override
-        public void startAnimation(IBinder transition, TransitionInfo info,
+        public void startAnimation(IBinder transition, TransitionInfo transitionInfo,
                 SurfaceControl.Transaction t,
                 IRemoteTransitionFinishedCallback finishedCallback) {
             final Runnable finishAdapter = () ->  {
@@ -708,7 +708,7 @@
                         null /* nonApps */,
                         mStateManager,
                         mDepthController,
-                        info, t, () -> {
+                        transitionInfo, t, () -> {
                             finishAdapter.run();
                             cleanup(true /*success*/);
                         },
@@ -920,7 +920,7 @@
 
             @Override
             public void onRecentsAnimationStart(RecentsAnimationController controller,
-                    RecentsAnimationTargets targets) {
+                    RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
                 StatsLogManager.LauncherEvent launcherDesktopSplitEvent =
                         mSplitPosition == STAGE_POSITION_BOTTOM_OR_RIGHT ?
                         LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM :
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index 425c4fe..32c4b90 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -30,6 +30,7 @@
 import android.app.ActivityOptions;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.window.TransitionInfo;
 
 import androidx.annotation.BinderThread;
 
@@ -114,7 +115,7 @@
 
         @Override
         public void onRecentsAnimationStart(RecentsAnimationController controller,
-                RecentsAnimationTargets targets) {
+                RecentsAnimationTargets targets, TransitionInfo transitionInfo) {
             mController.setInitialTaskSelect(mRunningTaskInfo,
                     mLeftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT,
                     null /* itemInfo */,
diff --git a/quickstep/src/com/android/quickstep/util/TransformParams.java b/quickstep/src/com/android/quickstep/util/TransformParams.java
index 401eccc..bb88818 100644
--- a/quickstep/src/com/android/quickstep/util/TransformParams.java
+++ b/quickstep/src/com/android/quickstep/util/TransformParams.java
@@ -19,9 +19,12 @@
 
 import android.util.FloatProperty;
 import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
 
 import com.android.quickstep.RemoteAnimationTargets;
 import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
+import com.android.window.flags.Flags;
 
 public class TransformParams {
 
@@ -56,6 +59,7 @@
     private float mTargetAlpha;
     private float mCornerRadius;
     private RemoteAnimationTargets mTargetSet;
+    private TransitionInfo mTransitionInfo;
     private SurfaceTransactionApplier mSyncTransactionApplier;
 
     private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
@@ -107,6 +111,14 @@
     }
 
     /**
+     * Provides the {@code TransitionInfo} of the transition that this transformation stems from.
+     */
+    public TransformParams setTransitionInfo(TransitionInfo transitionInfo) {
+        mTransitionInfo = transitionInfo;
+        return this;
+    }
+
+    /**
      * Sets the SyncRtSurfaceTransactionApplierCompat that will apply the SurfaceParams that
      * are computed based on these TransformParams.
      */
@@ -152,6 +164,9 @@
                 builder.setAlpha(getTargetAlpha());
             }
             targetProxy.onBuildTargetParams(builder, app, this);
+            // Override the corner radius for {@code app} with the leash used by Shell, so that it
+            // doesn't interfere with the window clip and corner radius applied here.
+            overrideChangeLeashCornerRadiusToZero(app, transaction.getTransaction());
         }
 
         // always put wallpaper layer to bottom.
@@ -163,6 +178,28 @@
         return transaction;
     }
 
+    private void overrideChangeLeashCornerRadiusToZero(
+            RemoteAnimationTarget app, SurfaceControl.Transaction transaction) {
+        if (!Flags.enableDesktopRecentsTransitionsCornersBugfix()) {
+            return;
+        }
+        SurfaceControl changeLeash = getChangeLeashForApp(app);
+        if (changeLeash != null) {
+            transaction.setCornerRadius(changeLeash, 0);
+        }
+    }
+
+    private SurfaceControl getChangeLeashForApp(RemoteAnimationTarget app) {
+        if (mTransitionInfo == null) return null;
+        for (TransitionInfo.Change change : mTransitionInfo.getChanges()) {
+            if (change.getTaskInfo() == null) continue;
+            if (change.getTaskInfo().taskId == app.taskId) {
+                return change.getLeash();
+            }
+        }
+        return null;
+    }
+
     // Pubic getters so outside packages can read the values.
 
     public float getProgress() {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 892b89d..9a4933a 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -849,6 +849,8 @@
 
     private final Matrix mTmpMatrix = new Matrix();
 
+    private int mTaskViewCount = 0;
+
     @Nullable
     public TaskView getFirstTaskView() {
         return mUtils.getFirstTaskView();
@@ -925,8 +927,11 @@
         mEmptyMessagePaint.setColor(Themes.getAttrColor(context, android.R.attr.textColorPrimary));
         mEmptyMessagePaint.setTextSize(getResources()
                 .getDimension(R.dimen.recents_empty_message_text_size));
-        mEmptyMessagePaint.setTypeface(Typeface.create(Themes.getDefaultBodyFont(context),
-                Typeface.NORMAL));
+        Typeface typeface = Typeface.create(
+                Typeface.create(Themes.getDefaultBodyFont(context), Typeface.NORMAL),
+                getFontWeight(),
+                false);
+        mEmptyMessagePaint.setTypeface(typeface);
         mEmptyMessagePaint.setAntiAlias(true);
         mEmptyMessagePadding = getResources()
                 .getDimensionPixelSize(R.dimen.recents_empty_message_text_padding);
@@ -1258,9 +1263,11 @@
         // - 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) {
-            clearAndRecycleTaskView((TaskView) child);
+        if (child instanceof TaskView) {
+            mTaskViewCount = Math.max(0, --mTaskViewCount);
+            if (child != mSplitHiddenTaskView && child != mMovingTaskView) {
+                clearAndRecycleTaskView((TaskView) child);
+            }
         }
     }
 
@@ -1281,6 +1288,9 @@
     @Override
     public void onViewAdded(View child) {
         super.onViewAdded(child);
+        if (child instanceof TaskView) {
+            mTaskViewCount++;
+        }
         child.setAlpha(mContentAlpha);
         // RecentsView is set to RTL in the constructor when system is using LTR. Here we set the
         // child direction back to match system settings.
@@ -2095,11 +2105,7 @@
     }
 
     public int getTaskViewCount() {
-        int taskViewCount = getChildCount();
-        if (indexOfChild(mClearAllButton) != -1) {
-            taskViewCount--;
-        }
-        return taskViewCount;
+        return mTaskViewCount;
     }
 
     /**
@@ -4051,8 +4057,6 @@
                         } else {
                             removeTaskInternal(dismissedTaskView);
                         }
-                        announceForAccessibility(
-                                getResources().getString(R.string.task_view_closed));
                         mContainer.getStatsLogManager().logger()
                                 .withItemInfo(dismissedTaskView.getFirstItemInfo())
                                 .log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
@@ -5866,7 +5870,8 @@
         if (recentsAnimationTargets.hasDesktopTasks(mContext)) {
             gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
                     true /* forDesktop */);
-            mRemoteTargetHandles = gluer.assignTargetsForDesktop(recentsAnimationTargets);
+            mRemoteTargetHandles = gluer.assignTargetsForDesktop(
+                    recentsAnimationTargets, /* transitionInfo= */ null);
         } else {
             gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
                     false);
@@ -6856,6 +6861,14 @@
         }
     }
 
+    private int getFontWeight() {
+        int fontWeightAdjustment = getResources().getConfiguration().fontWeightAdjustment;
+        if (fontWeightAdjustment != Configuration.FONT_WEIGHT_ADJUSTMENT_UNDEFINED) {
+            return Typeface.Builder.NORMAL_WEIGHT + fontWeightAdjustment;
+        }
+        return Typeface.Builder.NORMAL_WEIGHT;
+    }
+
     public interface TaskLaunchListener {
         void onTaskLaunched();
     }
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 0dbad70..5b99286 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -633,7 +633,11 @@
         with(info) {
             // Only make actions available if the app icon menu is visible to the user.
             // When modalness is >0, the user is in select mode and the icon menu is hidden.
-            if (modalness == 0f) {
+            // When split selection is active, they should only be able to select the app and not
+            // take any other action.
+            val shouldPopulateAccessibilityMenu =
+                modalness == 0f && recentsView?.isSplitSelectionActive == false
+            if (shouldPopulateAccessibilityMenu) {
                 addAction(
                     AccessibilityAction(
                         R.id.action_close,
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
index f16e193..542eb64 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -364,7 +364,7 @@
 
     private void onRecentsAnimationStart(SWIPE_HANDLER absSwipeUpHandler) {
         runOnMainSync(() -> absSwipeUpHandler.onRecentsAnimationStart(
-                mRecentsAnimationController, mRecentsAnimationTargets));
+                mRecentsAnimationController, mRecentsAnimationTargets, /* transitionInfo= */null));
     }
 
     protected static void runOnMainSync(Runnable runnable) {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
index f58c84e..b744039 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
@@ -57,16 +57,25 @@
             .switchToOverview()
             .apply { flingForward() }
             .also { moveTaskToDesktop(TEST_ACTIVITY_1) }
-
         TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
 
-        // Launch static DesktopTaskView
-        val desktop =
+        // Launch static DesktopTaskView without live tile in Overview
+        val desktopTask =
             mLauncher.goHome().switchToOverview().getTestActivityTask(TEST_ACTIVITIES).open()
         TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
 
         // Launch live-tile DesktopTaskView
-        desktop.switchToOverview().getTestActivityTask(TEST_ACTIVITIES).open()
+        desktopTask.switchToOverview().getTestActivityTask(TEST_ACTIVITIES).open()
+        TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
+
+        // Launch static DesktopTaskView with live tile in Overview
+        mLauncher.goHome()
+        startTestActivity(TEST_ACTIVITY_EXTRA)
+        mLauncher.launchedAppState
+            .switchToOverview()
+            .apply { flingBackward() }
+            .getTestActivityTask(TEST_ACTIVITIES)
+            .open()
         TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
     }
 
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 0ec3b79..5072e37 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -718,12 +718,14 @@
     }
 
     /**
-     * Queues the given callback to be run once {@code mPageScrolls} has been initialized.
+     * Run the given `callback` immediately once {@code mPageScrolls} has been initialized,
+     * otherwise queue the callback to `mOnPageScrollsInitializedCallbacks`.
      */
     public void runOnPageScrollsInitialized(Runnable callback) {
-        mOnPageScrollsInitializedCallbacks.add(callback);
         if (isPageScrollsInitialized()) {
-            onPageScrollsInitialized();
+            callback.run();
+        } else {
+            mOnPageScrollsInitializedCallbacks.add(callback);
         }
     }
 
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 42556ca..b76e098 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -697,15 +697,23 @@
             }
         }
 
+        Log.d("b/383526431", "animateOpen: content child count before: "
+                + mContent.getTotalChildCount());
+
         mContent.completePendingPageChanges();
         mContent.setCurrentPage(pageNo);
 
+        Log.d("b/383526431", "animateOpen: content child count after pending page"
+                + " changes: " + mContent.getTotalChildCount());
+
         // This is set to true in close(), but isn't reset to false until onDropCompleted(). This
         // leads to an inconsistent state if you drag out of the folder and drag back in without
         // dropping. One resulting issue is that replaceFolderWithFinalItem() can be called twice.
         mDeleteFolderOnDropCompleted = false;
 
         cancelRunningAnimations();
+        Log.d("b/383526431", "animateOpen: content child count after cancelling"
+                + " animation: " + mContent.getTotalChildCount());
         FolderAnimationManager fam = new FolderAnimationManager(this, true /* isOpening */);
         AnimatorSet anim = fam.getAnimator();
         anim.addListener(new AnimatorListenerAdapter() {
diff --git a/src/com/android/launcher3/folder/FolderGridOrganizer.java b/src/com/android/launcher3/folder/FolderGridOrganizer.java
index a7ab7b9..06286d6 100644
--- a/src/com/android/launcher3/folder/FolderGridOrganizer.java
+++ b/src/com/android/launcher3/folder/FolderGridOrganizer.java
@@ -19,6 +19,7 @@
 import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
 
 import android.graphics.Point;
+import android.util.Log;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.model.data.FolderInfo;
@@ -178,6 +179,14 @@
                 break;
             }
         }
+
+        if (result.isEmpty()) {
+            // Log specifics since we are getting empty result
+            Log.d("b/383526431", "previewItemsForPage: "
+                    + "mCountX = " + mCountX
+                    + ", mCountY = " + mCountY
+                    + ", content size = " + contents.size());
+        }
         return result;
     }
 
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 22f1164..bebe1a4 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -58,6 +58,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.ToIntFunction;
 import java.util.stream.Collectors;
 
@@ -531,6 +532,16 @@
         verifyVisibleHighResIcons(getCurrentPage() + 1);
     }
 
+    int getTotalChildCount() {
+        AtomicInteger count = new AtomicInteger();
+        iterateOverItems((i, v) -> {
+            count.getAndIncrement();
+            return false;
+        });
+
+        return count.get();
+    }
+
     /**
      * Ensures that all the icons on the given page are of high-res
      */
diff --git a/src/com/android/launcher3/model/GridSizeMigrationDBController.java b/src/com/android/launcher3/model/GridSizeMigrationDBController.java
index bfa00bd..211c351 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationDBController.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationDBController.java
@@ -126,33 +126,43 @@
             return true;
         }
 
-        if (isDestNewDb
+        boolean shouldMigrateToStrictlyTallerGrid = isDestNewDb
                 && srcDeviceState.getColumns().equals(destDeviceState.getColumns())
-                && srcDeviceState.getRows() < destDeviceState.getRows()) {
-            // Only use this strategy when comparing the previous grid to the new grid and the
-            // columns are the same and the destination has more rows
+                && srcDeviceState.getRows() < destDeviceState.getRows();
+        if (shouldMigrateToStrictlyTallerGrid) {
             copyTable(source, TABLE_NAME, target.getWritableDatabase(), TABLE_NAME, context);
-
-            if (oneGridSpecs()) {
-                DbReader destReader = new DbReader(
-                        target.getWritableDatabase(), TABLE_NAME, context);
-                boolean shouldShiftCells = shouldShiftCells(destReader, srcDeviceState.getRows());
-                if (shouldShiftCells) {
-                    shiftTableByXCells(
-                            target.getWritableDatabase(),
-                            (destDeviceState.getRows() - srcDeviceState.getRows()),
-                            TABLE_NAME);
-                }
-            }
-
-            // Save current configuration, so that the migration does not run again.
-            destDeviceState.writeToPrefs(context);
-            return true;
+        } else {
+            copyTable(source, TABLE_NAME, target.getWritableDatabase(), TMP_TABLE, context);
         }
-        copyTable(source, TABLE_NAME, target.getWritableDatabase(), TMP_TABLE, context);
 
         long migrationStartTime = System.currentTimeMillis();
         try (SQLiteTransaction t = new SQLiteTransaction(target.getWritableDatabase())) {
+
+            if (shouldMigrateToStrictlyTallerGrid) {
+                // This is a special case where if the grid is the same amount of columns but a
+                // larger amount of rows we simply copy over the source grid to the destination
+                // grid, rather than undergoing the general grid migration. If there are more icons
+                // on the bottom of the first page then we shift the icons down to the bottom of the
+                // grid so that the icons remain bottom-anchored.
+                if (oneGridSpecs()) {
+                    DbReader destReader = new DbReader(
+                            target.getWritableDatabase(), TABLE_NAME, context);
+                    boolean shouldShiftCells =
+                            shouldShiftCells(destReader, srcDeviceState.getRows());
+                    if (shouldShiftCells) {
+                        shiftTableByXCells(
+                                target.getWritableDatabase(),
+                                (destDeviceState.getRows() - srcDeviceState.getRows()),
+                                TABLE_NAME);
+                    }
+                }
+
+                // Save current configuration, so that the migration does not run again.
+                destDeviceState.writeToPrefs(context);
+                t.commit();
+                return true;
+            }
+
             DbReader srcReader = new DbReader(t.getDb(), TMP_TABLE, context);
             DbReader destReader = new DbReader(t.getDb(), TABLE_NAME, context);
 
diff --git a/src/com/android/launcher3/model/GridSizeMigrationLogic.kt b/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
index 6f86ae0..0b12af8 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
+++ b/src/com/android/launcher3/model/GridSizeMigrationLogic.kt
@@ -65,33 +65,42 @@
                 "$srcDeviceState\ndestDeviceState: $destDeviceState\nisDestNewDb: $isDestNewDb",
         )
 
-        // This is a special case where if the grid is the same amount of columns but a larger
-        // amount of rows we simply copy over the source grid to the destination grid, rather
-        // than undergoing the general grid migration.
-        if (shouldMigrateToStrictlyTallerGrid(isDestNewDb, srcDeviceState, destDeviceState)) {
-            Log.d(TAG, "Migrating to strictly taller grid")
+        val shouldMigrateToStrtictlyTallerGrid =
+            shouldMigrateToStrictlyTallerGrid(isDestNewDb, srcDeviceState, destDeviceState)
+        if (shouldMigrateToStrtictlyTallerGrid) {
             copyTable(source, TABLE_NAME, target.writableDatabase, TABLE_NAME, context)
-            if (oneGridSpecs()) {
-                val destReader = DbReader(target.writableDatabase, TABLE_NAME, context)
-                val shouldShiftCells = shouldShiftCells(destReader, srcDeviceState.rows)
-                if (shouldShiftCells) {
-                    shiftTableByXCells(
-                        target.writableDatabase,
-                        (destDeviceState.rows - srcDeviceState.rows),
-                        TABLE_NAME,
-                    )
-                }
-            }
-            // Save current configuration, so that the migration does not run again.
-            destDeviceState.writeToPrefs(context)
-            return
+        } else {
+            copyTable(source, TABLE_NAME, target.writableDatabase, TMP_TABLE, context)
         }
 
-        copyTable(source, TABLE_NAME, target.writableDatabase, TMP_TABLE, context)
-
         val migrationStartTime = System.currentTimeMillis()
         try {
             SQLiteTransaction(target.writableDatabase).use { t ->
+                // This is a special case where if the grid is the same amount of columns but a
+                // larger amount of rows we simply copy over the source grid to the destination
+                // grid, rather than undergoing the general grid migration. If there are more icons
+                // on the bottom of the first page then we shift the icons down to the bottom of the
+                // grid so that the icons remain bottom-anchored.
+                if (shouldMigrateToStrtictlyTallerGrid) {
+                    Log.d(TAG, "Migrating to strictly taller grid")
+                    if (oneGridSpecs()) {
+                        val destReader = DbReader(target.writableDatabase, TABLE_NAME, context)
+                        val shouldShiftCells = shouldShiftCells(destReader, srcDeviceState.rows)
+                        if (shouldShiftCells) {
+                            Log.i("TAGTAG", "should shift cells")
+                            shiftTableByXCells(
+                                target.writableDatabase,
+                                (destDeviceState.rows - srcDeviceState.rows),
+                                TABLE_NAME,
+                            )
+                        }
+                    }
+                    // Save current configuration, so that the migration does not run again.
+                    destDeviceState.writeToPrefs(context)
+                    t.commit()
+                    return
+                }
+
                 val srcReader = DbReader(t.db, TMP_TABLE, context)
                 val destReader = DbReader(t.db, TABLE_NAME, context)
 
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
index a62258c..bf8e8b1 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
@@ -17,9 +17,6 @@
 
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -41,7 +38,6 @@
 import com.android.launcher3.celllayout.testgenerator.RandomMultiBoardGenerator;
 import com.android.launcher3.util.ActivityContextWrapper;
 import com.android.launcher3.util.rule.TestStabilityRule;
-import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 import com.android.launcher3.views.DoubleShadowBubbleTextView;
 
 import org.junit.Rule;
@@ -82,7 +78,6 @@
      * This test reads existing test cases and makes sure the CellLayout produces the same
      * output for each of them for a given input.
      */
-    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     @Test
     public void testAllCases() throws IOException {
         List<ReorderAlgorithmUnitTestCase> testCases = getTestCases(
@@ -125,7 +120,6 @@
     /**
      * Same as above but testing the Multipage CellLayout.
      */
-    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
     @Test
     public void generateValidTests_Multi() {
         Random generator = new Random(SEED);
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index e2f9feb9a..2e02eb0 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -64,6 +64,7 @@
     @Test
     @PortraitLandscape
     @PlatinumTest(focusArea = "launcher")
+    @ScreenRecordRule.ScreenRecord // b/383917141
     public void testDragToFolder() {
         // TODO: add the use case to drag an icon to an existing folder. Currently it either fails
         // on tablets or phones due to difference in resolution.
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index 1816030..20684b3 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -110,6 +110,9 @@
     @PortraitLandscape
     @PlatinumTest(focusArea = "launcher")
     public void testUninstallFromAllApps() throws Exception {
+        // Ensure no existing app icons on the workspace cause scroll to all apps interruptions
+        mLauncher.clearLauncherData();
+
         installDummyAppAndWaitForUIUpdate();
         try {
             Workspace workspace = mLauncher.getWorkspace();
diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index d49168f..124c18f 100644
--- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -76,8 +76,8 @@
                     mTest.mDevice.setOrientationNatural();
                     mTest.executeOnLauncher(launcher ->
                     {
-                        LauncherPrefs.get(launcher).put(FIXED_LANDSCAPE_MODE, false);
                         if (launcher != null) {
+                            LauncherPrefs.get(launcher).put(FIXED_LANDSCAPE_MODE, false);
                             launcher.getRotationHelper().forceAllowRotationForTesting(false);
                         }
                     });
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index 2fb7987..7e8d759 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -51,6 +51,7 @@
 import com.android.launcher3.util.BlockingBroadcastReceiver;
 import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
 import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.rule.ScreenRecordRule;
 import com.android.launcher3.util.rule.ShellCommandRule;
 
 import org.junit.Before;
@@ -74,6 +75,9 @@
     @Rule
     public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
 
+    @Rule
+    public ScreenRecordRule mScreenRecordRule = new ScreenRecordRule();
+
     private String mCallbackAction;
     private String mShortcutId;
     private int mAppWidgetId;
@@ -87,6 +91,7 @@
     @Test
     public void testEmpty() throws Throwable { /* needed while the broken tests are being fixed */ }
 
+    @ScreenRecordRule.ScreenRecord // b/386243192
     @Test
     public void testPinWidgetNoConfig() throws Throwable {
         runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo
@@ -95,6 +100,7 @@
                         .equals(AppWidgetNoConfig.class.getName()));
     }
 
+    @ScreenRecordRule.ScreenRecord // b/386243192
     @Test
     public void testPinWidgetNoConfig_customPreview() throws Throwable {
         // Command to set custom preview
@@ -108,6 +114,7 @@
                         .equals(AppWidgetNoConfig.class.getName()), command);
     }
 
+    @ScreenRecordRule.ScreenRecord // b/386243192
     @Test
     public void testPinWidgetWithConfig() throws Throwable {
         runTest("pinWidgetWithConfig", true,
@@ -117,6 +124,7 @@
                                 .equals(AppWidgetWithConfig.class.getName()));
     }
 
+    @ScreenRecordRule.ScreenRecord // b/386243192
     @Test
     public void testPinShortcut() throws Throwable {
         // Command to set the shortcut id
diff --git a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
index c852729..a123170 100644
--- a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
@@ -61,8 +61,7 @@
         setThemeEnabled(false);
         new FavoriteItemsTransaction(targetContext()).commit();
         loadLauncherSync();
-        goToState(LauncherState.ALL_APPS);
-        freezeAllApps();
+        switchToAllApps();
 
         scrollToAppIcon(APP_NAME);
         BubbleTextView btv = getFromLauncher(
@@ -76,8 +75,7 @@
         setThemeEnabled(false);
         new FavoriteItemsTransaction(targetContext()).commit();
         loadLauncherSync();
-        goToState(LauncherState.ALL_APPS);
-        freezeAllApps();
+        switchToAllApps();
 
         scrollToAppIcon(TEST_APP_NAME);
         BubbleTextView btv = getFromLauncher(l -> findBtv(TEST_APP_NAME, l.getAppsView()));
@@ -95,8 +93,7 @@
         setThemeEnabled(true);
         new FavoriteItemsTransaction(targetContext()).commit();
         loadLauncherSync();
-        goToState(LauncherState.ALL_APPS);
-        freezeAllApps();
+        switchToAllApps();
 
         scrollToAppIcon(APP_NAME);
         BubbleTextView btv = getFromLauncher(l ->
@@ -109,8 +106,7 @@
     public void testShortcutIconWithTheme() throws Exception {
         setThemeEnabled(true);
         loadLauncherSync();
-        goToState(LauncherState.ALL_APPS);
-        freezeAllApps();
+        switchToAllApps();
 
         scrollToAppIcon(TEST_APP_NAME);
         BubbleTextView btv = getFromLauncher(l -> findBtv(TEST_APP_NAME, l.getAppsView()));
@@ -158,6 +154,13 @@
         }
     }
 
+    private void switchToAllApps() {
+        goToState(LauncherState.ALL_APPS);
+        waitForState("Launcher internal state didn't switch to All Apps",
+                () -> LauncherState.ALL_APPS);
+        freezeAllApps();
+    }
+
     private void scrollToAppIcon(String appName) {
         executeOnLauncher(l -> {
             l.hideKeyboard();