Merge "Fixing pending tasks being queued on bind after the pending executor is already finalized." into main
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index 4f889c0..f82474a 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -16,8 +16,6 @@
 
 package com.android.launcher3.appprediction;
 
-import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW;
-
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Canvas;
@@ -189,7 +187,7 @@
             LayoutInflater inflater = mActivityContext.getAppsView().getLayoutInflater();
             while (getChildCount() < mNumPredictedAppsPerRow) {
                 BubbleTextView icon = (BubbleTextView) inflater.inflate(
-                        R.layout.all_apps_icon, this, false);
+                        R.layout.all_apps_prediction_row_icon, this, false);
                 icon.setOnClickListener(mActivityContext.getItemOnClickListener());
                 icon.setOnLongClickListener(mActivityContext.getAllAppsItemLongClickListener());
                 icon.setLongPressTimeoutFactor(1f);
@@ -211,7 +209,6 @@
             icon.reset();
             if (predictionCount > i) {
                 icon.setVisibility(View.VISIBLE);
-                icon.setDisplay(DISPLAY_PREDICTION_ROW);
                 icon.applyFromWorkspaceItem(mPredictedApps.get(i));
             } else {
                 icon.setVisibility(predictionCount == 0 ? GONE : INVISIBLE);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index ba2116d..e922c4c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -27,6 +27,8 @@
 import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
+import static com.android.quickstep.util.SystemActionConstants.ACTION_SHOW_TASKBAR;
+import static com.android.quickstep.util.SystemActionConstants.SYSTEM_ACTION_ID_TASKBAR;
 
 import android.annotation.SuppressLint;
 import android.app.Activity;
@@ -141,13 +143,6 @@
 
     private boolean mUserUnlocked = false;
 
-    public static final int SYSTEM_ACTION_ID_TASKBAR = 499;
-
-    /**
-     * For Taskbar broadcast intent filter.
-     */
-    public static final String ACTION_SHOW_TASKBAR = "ACTION_SHOW_TASKBAR";
-
     private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver =
             new SimpleBroadcastReceiver(this::showTaskbarFromBroadcast);
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index ee4db73..f2b60b9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -29,10 +29,10 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_HIDE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_SHOW;
 import static com.android.launcher3.taskbar.TaskbarKeyguardController.MASK_ANY_SYSUI_LOCKED;
-import static com.android.launcher3.taskbar.TaskbarManager.SYSTEM_ACTION_ID_TASKBAR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
 import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
+import static com.android.quickstep.util.SystemActionConstants.SYSTEM_ACTION_ID_TASKBAR;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 1756117..40909d5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -50,9 +50,9 @@
 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
 import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -1260,10 +1260,8 @@
                 /* callback= */ success -> mSplitSelectStateController.resetState(),
                 /* freezeTaskList= */ true,
                 groupTask.mSplitBounds == null
-                        ? DEFAULT_SPLIT_RATIO
-                        : groupTask.mSplitBounds.appsStackedVertically
-                                ? groupTask.mSplitBounds.topTaskPercent
-                                : groupTask.mSplitBounds.leftTaskPercent);
+                        ? SNAP_TO_50_50
+                        : groupTask.mSplitBounds.snapPosition);
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 1c74fbe..0a7344a 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -17,6 +17,7 @@
 package com.android.quickstep;
 
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
 import static com.android.quickstep.views.DesktopTaskView.DESKTOP_MODE_SUPPORTED;
 import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
 
@@ -39,7 +40,6 @@
 import com.android.systemui.shared.recents.model.Task;
 import com.android.wm.shell.recents.IRecentTasksListener;
 import com.android.wm.shell.util.GroupedRecentTaskInfo;
-import com.android.wm.shell.util.SplitBounds;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -293,7 +293,7 @@
                 task2.setLastSnapshotData(taskInfo2);
             }
             final SplitConfigurationOptions.SplitBounds launcherSplitBounds =
-                    convertSplitBounds(rawTask.getSplitBounds());
+                    convertShellSplitBoundsToLauncher(rawTask.getSplitBounds());
             allTasks.add(new GroupTask(task1, task2, launcherSplitBounds));
         }
 
@@ -313,15 +313,6 @@
         return new DesktopTask(tasks);
     }
 
-    private SplitConfigurationOptions.SplitBounds convertSplitBounds(
-            SplitBounds shellSplitBounds) {
-        return shellSplitBounds == null ?
-                null :
-                new SplitConfigurationOptions.SplitBounds(
-                        shellSplitBounds.leftTopBounds, shellSplitBounds.rightBottomBounds,
-                        shellSplitBounds.leftTopTaskId, shellSplitBounds.rightBottomTaskId);
-    }
-
     private ArrayList<GroupTask> copyOf(ArrayList<GroupTask> tasks) {
         ArrayList<GroupTask> newTasks = new ArrayList<>();
         for (int i = 0; i < tasks.size(); i++) {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index d300cc5..bbcea6c 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -138,7 +138,8 @@
                 nonAppTargets = new RemoteAnimationTarget[0];
             }
             final RecentsAnimationTargets targets = new RecentsAnimationTargets(appTargets,
-                    wallpaperTargets, nonAppTargets, homeContentInsets, minimizedHomeBounds);
+                    wallpaperTargets, nonAppTargets, homeContentInsets, minimizedHomeBounds,
+                    extras);
 
             Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
                 ActiveGestureLog.INSTANCE.addLog(
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index 15e1365..67c56e3 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -20,6 +20,7 @@
 
 import android.app.WindowConfiguration;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.view.RemoteAnimationTarget;
 
 import com.android.quickstep.views.DesktopTaskView;
@@ -35,8 +36,8 @@
 
     public RecentsAnimationTargets(RemoteAnimationTarget[] apps,
             RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
-            Rect homeContentInsets, Rect minimizedHomeBounds) {
-        super(apps, wallpapers, nonApps, MODE_CLOSING);
+            Rect homeContentInsets, Rect minimizedHomeBounds, Bundle extras) {
+        super(apps, wallpapers, nonApps, MODE_CLOSING, extras);
         this.homeContentInsets = homeContentInsets;
         this.minimizedHomeBounds = minimizedHomeBounds;
     }
diff --git a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
index 80aaad0..e0c7403 100644
--- a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
@@ -19,6 +19,7 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 
+import android.os.Bundle;
 import android.view.RemoteAnimationTarget;
 
 import java.util.ArrayList;
@@ -35,6 +36,7 @@
     public final RemoteAnimationTarget[] apps;
     public final RemoteAnimationTarget[] wallpapers;
     public final RemoteAnimationTarget[] nonApps;
+    public final Bundle extras;
     public final int targetMode;
     public final boolean hasRecents;
 
@@ -42,7 +44,7 @@
 
     public RemoteAnimationTargets(RemoteAnimationTarget[] apps,
             RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
-            int targetMode) {
+            int targetMode, Bundle extras) {
         ArrayList<RemoteAnimationTarget> filteredApps = new ArrayList<>();
         boolean hasRecents = false;
         if (apps != null) {
@@ -61,6 +63,13 @@
         this.targetMode = targetMode;
         this.hasRecents = hasRecents;
         this.nonApps = nonApps;
+        this.extras = extras;
+    }
+
+    public RemoteAnimationTargets(RemoteAnimationTarget[] apps,
+            RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+            int targetMode) {
+        this(apps, wallpapers, nonApps, targetMode, new Bundle());
     }
 
     public RemoteAnimationTarget findTask(int taskId) {
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 84246e9..3af5ab7 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -16,7 +16,9 @@
 
 package com.android.quickstep;
 
-import android.app.WindowConfiguration;
+import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
+import static com.android.wm.shell.util.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
+
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.Log;
@@ -24,11 +26,12 @@
 
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
+import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.util.TransformParams;
 import com.android.quickstep.views.DesktopTaskView;
+import com.android.wm.shell.util.SplitBounds;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -43,7 +46,7 @@
     private static final int DEFAULT_NUM_HANDLES = 2;
 
     private RemoteTargetHandle[] mRemoteTargetHandles;
-    private SplitBounds mSplitBounds;
+    private SplitConfigurationOptions.SplitBounds mSplitBounds;
 
     /**
      * Use this constructor if remote targets are split-screen independent
@@ -111,6 +114,16 @@
     }
 
     /**
+     * Calls {@link #assignTargetsForSplitScreen(RemoteAnimationTargets)} with SplitBounds
+     * information specified.
+     */
+    public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets,
+            SplitConfigurationOptions.SplitBounds splitBounds) {
+        mSplitBounds = splitBounds;
+        return assignTargetsForSplitScreen(targets);
+    }
+
+    /**
      * Similar to {@link #assignTargets(RemoteAnimationTargets)}, except this assigns the
      * apps in {@code targets.apps} to the {@link #mRemoteTargetHandles} with index 0 will being
      * the left/top task, index 1 right/bottom.
@@ -129,10 +142,17 @@
             mRemoteTargetHandles = newHandles;
         }
 
-        boolean containsSplitTargets = Arrays.stream(targets.apps)
-                .anyMatch(remoteAnimationTarget ->
-                        remoteAnimationTarget.windowConfiguration.getWindowingMode()
-                                == WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW);
+        // If we are in a true split screen case (2 apps running on screen), either:
+        //     a) mSplitBounds was already set (from the clicked GroupedTaskView)
+        //     b) A SplitBounds was passed up from shell (via AbsSwipeUpHandler)
+        // If both of these are null, we are in a 1-app or 1-app-plus-assistant case.
+        if (mSplitBounds == null) {
+            SplitBounds shellSplitBounds = targets.extras.getParcelable(KEY_EXTRA_SPLIT_BOUNDS,
+                    SplitBounds.class);
+            mSplitBounds = convertShellSplitBoundsToLauncher(shellSplitBounds);
+        }
+
+        boolean containsSplitTargets = mSplitBounds != null;
         Log.d(TAG, "containsSplitTargets? " + containsSplitTargets + " handleLength: " +
                 mRemoteTargetHandles.length + " appsLength: " + targets.apps.length);
 
@@ -154,40 +174,12 @@
             }
         } else {
             // Split apps (+ maybe assistant)
-            RemoteAnimationTarget topLeftTarget = Arrays.stream(targets.apps)
-                    .filter(remoteAnimationTarget ->
-                            remoteAnimationTarget.windowConfiguration.getWindowingMode()
-                                    == WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW)
-                    .findFirst().get();
-
-            // Fetch the adjacent target for split screen.
-            RemoteAnimationTarget bottomRightTarget = null;
-            for (int i = 0; i < targets.apps.length; i++) {
-                final RemoteAnimationTarget target = targets.apps[i];
-                if (target.windowConfiguration.getWindowingMode() !=
-                        WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW ||
-                        target == topLeftTarget) {
-                    continue;
-                }
-                Rect topLeftBounds = getStartBounds(topLeftTarget);
-                Rect bounds = getStartBounds(target);
-                if (topLeftBounds.left > bounds.right || topLeftBounds.top > bounds.bottom) {
-                    bottomRightTarget = topLeftTarget;
-                    topLeftTarget = target;
-                    break;
-                } else if (topLeftBounds.right < bounds.left || topLeftBounds.bottom < bounds.top) {
-                    bottomRightTarget = target;
-                    break;
-                }
-            }
+            RemoteAnimationTarget topLeftTarget = targets.findTask(mSplitBounds.leftTopTaskId);
+            RemoteAnimationTarget bottomRightTarget = targets.findTask(
+                    mSplitBounds.rightBottomTaskId);
 
             // remoteTargetHandle[0] denotes topLeft task, so we pass in the bottomRight to exclude,
             // vice versa
-            mSplitBounds = new SplitBounds(
-                    getStartBounds(topLeftTarget),
-                    getStartBounds(bottomRightTarget),
-                    topLeftTarget.taskId,
-                    bottomRightTarget.taskId);
             mRemoteTargetHandles[0].mTransformParams.setTargetSet(
                     createRemoteAnimationTargetsForTarget(targets, bottomRightTarget));
             mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(topLeftTarget,
@@ -291,7 +283,7 @@
         return mRemoteTargetHandles;
     }
 
-    public SplitBounds getSplitBounds() {
+    public SplitConfigurationOptions.SplitBounds getSplitBounds() {
         return mSplitBounds;
     }
 
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 1dc777d..170847d 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.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.launcher3.util.SplitConfigurationOptions.StagePosition;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENT_TASKS_MISSING;
 import static com.android.quickstep.util.LogUtils.splitFailureMessage;
 
@@ -63,7 +64,6 @@
 import com.android.internal.view.AppearanceRegion;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.AssistUtils;
 import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -78,6 +78,7 @@
 import com.android.wm.shell.back.IBackAnimation;
 import com.android.wm.shell.bubbles.IBubbles;
 import com.android.wm.shell.bubbles.IBubblesListener;
+import com.android.wm.shell.common.split.SplitScreenConstants.SnapPosition;
 import com.android.wm.shell.desktopmode.IDesktopMode;
 import com.android.wm.shell.desktopmode.IDesktopTaskListener;
 import com.android.wm.shell.draganddrop.IDragAndDrop;
@@ -796,12 +797,12 @@
 
     /** Start multiple tasks in split-screen simultaneously. */
     public void startTasks(int taskId1, Bundle options1, int taskId2, Bundle options2,
-            @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio,
+            @StagePosition int splitPosition, @SnapPosition int snapPosition,
             RemoteTransition remoteTransition, InstanceId instanceId) {
         if (mSystemUiProxy != null) {
             try {
                 mSplitScreen.startTasks(taskId1, options1, taskId2, options2, splitPosition,
-                        splitRatio, remoteTransition, instanceId);
+                        snapPosition, remoteTransition, instanceId);
             } catch (RemoteException e) {
                 Log.w(TAG, splitFailureMessage("startTasks", "RemoteException"), e);
             }
@@ -809,12 +810,13 @@
     }
 
     public void startIntentAndTask(PendingIntent pendingIntent, int userId1, Bundle options1,
-            int taskId, Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
-            float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) {
+            int taskId, Bundle options2, @StagePosition int splitPosition,
+            @SnapPosition int snapPosition, RemoteTransition remoteTransition,
+            InstanceId instanceId) {
         if (mSystemUiProxy != null) {
             try {
                 mSplitScreen.startIntentAndTask(pendingIntent, userId1, options1, taskId, options2,
-                        splitPosition, splitRatio, remoteTransition, instanceId);
+                        splitPosition, snapPosition, remoteTransition, instanceId);
             } catch (RemoteException e) {
                 Log.w(TAG, splitFailureMessage("startIntentAndTask", "RemoteException"), e);
             }
@@ -824,13 +826,13 @@
     public void startIntents(PendingIntent pendingIntent1, int userId1,
             @Nullable ShortcutInfo shortcutInfo1, Bundle options1, PendingIntent pendingIntent2,
             int userId2, @Nullable ShortcutInfo shortcutInfo2, Bundle options2,
-            @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio,
+            @StagePosition int splitPosition, @SnapPosition int snapPosition,
             RemoteTransition remoteTransition, InstanceId instanceId) {
         if (mSystemUiProxy != null) {
             try {
                 mSplitScreen.startIntents(pendingIntent1, userId1, shortcutInfo1, options1,
-                        pendingIntent2, userId2, shortcutInfo2, options2, splitPosition, splitRatio,
-                        remoteTransition, instanceId);
+                        pendingIntent2, userId2, shortcutInfo2, options2, splitPosition,
+                        snapPosition, remoteTransition, instanceId);
             } catch (RemoteException e) {
                 Log.w(TAG, splitFailureMessage("startIntents", "RemoteException"), e);
             }
@@ -838,12 +840,12 @@
     }
 
     public void startShortcutAndTask(ShortcutInfo shortcutInfo, Bundle options1, int taskId,
-            Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
-            float splitRatio, RemoteTransition remoteTransition, InstanceId instanceId) {
+            Bundle options2, @StagePosition int splitPosition, @SnapPosition int snapPosition,
+            RemoteTransition remoteTransition, InstanceId instanceId) {
         if (mSystemUiProxy != null) {
             try {
                 mSplitScreen.startShortcutAndTask(shortcutInfo, options1, taskId, options2,
-                        splitPosition, splitRatio, remoteTransition, instanceId);
+                        splitPosition, snapPosition, remoteTransition, instanceId);
             } catch (RemoteException e) {
                 Log.w(TAG, splitFailureMessage("startShortcutAndTask", "RemoteException"), e);
             }
@@ -854,12 +856,12 @@
      * Start multiple tasks in split-screen simultaneously.
      */
     public void startTasksWithLegacyTransition(int taskId1, Bundle options1, int taskId2,
-            Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
-            float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
+            Bundle options2, @StagePosition int splitPosition, @SnapPosition int snapPosition,
+            RemoteAnimationAdapter adapter, InstanceId instanceId) {
         if (mSystemUiProxy != null) {
             try {
                 mSplitScreen.startTasksWithLegacyTransition(taskId1, options1, taskId2, options2,
-                        splitPosition, splitRatio, adapter, instanceId);
+                        splitPosition, snapPosition, adapter, instanceId);
             } catch (RemoteException e) {
                 Log.w(TAG, splitFailureMessage(
                         "startTasksWithLegacyTransition", "RemoteException"), e);
@@ -868,13 +870,13 @@
     }
 
     public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, int userId1,
-            Bundle options1, int taskId, Bundle options2,
-            @SplitConfigurationOptions.StagePosition int splitPosition, float splitRatio,
-            RemoteAnimationAdapter adapter, InstanceId instanceId) {
+            Bundle options1, int taskId, Bundle options2, @StagePosition int splitPosition,
+            @SnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) {
         if (mSystemUiProxy != null) {
             try {
                 mSplitScreen.startIntentAndTaskWithLegacyTransition(pendingIntent, userId1,
-                        options1, taskId, options2, splitPosition, splitRatio, adapter, instanceId);
+                        options1, taskId, options2, splitPosition, snapPosition, adapter,
+                        instanceId);
             } catch (RemoteException e) {
                 Log.w(TAG, splitFailureMessage(
                         "startIntentAndTaskWithLegacyTransition", "RemoteException"), e);
@@ -883,12 +885,12 @@
     }
 
     public void startShortcutAndTaskWithLegacyTransition(ShortcutInfo shortcutInfo, Bundle options1,
-            int taskId, Bundle options2, @SplitConfigurationOptions.StagePosition int splitPosition,
-            float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
+            int taskId, Bundle options2, @StagePosition int splitPosition,
+            @SnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) {
         if (mSystemUiProxy != null) {
             try {
                 mSplitScreen.startShortcutAndTaskWithLegacyTransition(shortcutInfo, options1,
-                        taskId, options2, splitPosition, splitRatio, adapter, instanceId);
+                        taskId, options2, splitPosition, snapPosition, adapter, instanceId);
             } catch (RemoteException e) {
                 Log.w(TAG, splitFailureMessage(
                         "startShortcutAndTaskWithLegacyTransition", "RemoteException"), e);
@@ -903,13 +905,13 @@
     public void startIntentsWithLegacyTransition(PendingIntent pendingIntent1, int userId1,
             @Nullable ShortcutInfo shortcutInfo1, @Nullable Bundle options1,
             PendingIntent pendingIntent2, int userId2, @Nullable ShortcutInfo shortcutInfo2,
-            @Nullable Bundle options2, @SplitConfigurationOptions.StagePosition int sidePosition,
-            float splitRatio, RemoteAnimationAdapter adapter, InstanceId instanceId) {
+            @Nullable Bundle options2, @StagePosition int sidePosition,
+            @SnapPosition int snapPosition, RemoteAnimationAdapter adapter, InstanceId instanceId) {
         if (mSystemUiProxy != null) {
             try {
                 mSplitScreen.startIntentsWithLegacyTransition(pendingIntent1, userId1,
                         shortcutInfo1, options1, pendingIntent2, userId2, shortcutInfo2, options2,
-                        sidePosition, splitRatio, adapter, instanceId);
+                        sidePosition, snapPosition, adapter, instanceId);
             } catch (RemoteException e) {
                 Log.w(TAG, splitFailureMessage(
                         "startIntentsWithLegacyTransition", "RemoteException"), e);
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 4177ced..2adc790 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -30,6 +30,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.provider.Settings;
 import android.util.Log;
 import android.view.View;
 import android.view.WindowInsets;
@@ -345,7 +346,9 @@
         }
 
         private boolean isAvailable(BaseDraggingActivity activity, int displayId) {
-            return ActivityManagerWrapper.getInstance().supportsFreeformMultiWindow(activity)
+            return Settings.Global.getInt(
+                        activity.getContentResolver(),
+                        Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0
                     && !SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
         }
     };
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 97e484a..34965df 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -191,7 +191,8 @@
             if (forDesktop) {
                 remoteTargetHandles = gluer.assignTargetsForDesktop(targets);
             } else if (v.containsMultipleTasks()) {
-                remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets);
+                remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets,
+                        ((GroupedTaskView) v).getSplitBoundsConfig());
             } else {
                 remoteTargetHandles = gluer.assignTargets(targets);
             }
diff --git a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
new file mode 100644
index 0000000..596bb47
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.wm.shell.util.SplitBounds
+
+class SplitScreenUtils {
+    companion object {
+        // TODO(b/254378592): Remove these methods when the two classes are reunited
+        /** Converts the shell version of SplitBounds to the launcher version */
+        @JvmStatic
+        fun convertShellSplitBoundsToLauncher(
+            shellSplitBounds: SplitBounds?
+        ): SplitConfigurationOptions.SplitBounds? {
+            return if (shellSplitBounds == null) {
+                null
+            } else {
+                SplitConfigurationOptions.SplitBounds(
+                    shellSplitBounds.leftTopBounds, shellSplitBounds.rightBottomBounds,
+                    shellSplitBounds.leftTopTaskId, shellSplitBounds.rightBottomTaskId,
+                    shellSplitBounds.snapPosition
+                )
+            }
+        }
+
+        /** Converts the launcher version of SplitBounds to the shell version */
+        @JvmStatic
+        fun convertLauncherSplitBoundsToShell(
+            launcherSplitBounds: SplitConfigurationOptions.SplitBounds?
+        ): SplitBounds? {
+            return if (launcherSplitBounds == null) {
+                null
+            } else {
+                SplitBounds(
+                    launcherSplitBounds.leftTopBounds,
+                    launcherSplitBounds.rightBottomBounds,
+                    launcherSplitBounds.leftTopTaskId,
+                    launcherSplitBounds.rightBottomTaskId,
+                    launcherSplitBounds.snapPosition
+                )
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 16fe07d..c8831c7 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -22,7 +22,6 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DESKTOP_MODE_SPLIT_RIGHT_BOTTOM;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_PENDINGINTENT_PENDINGINTENT;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_PENDINGINTENT_TASK;
@@ -33,6 +32,7 @@
 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;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -98,6 +98,7 @@
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
+import com.android.wm.shell.common.split.SplitScreenConstants.SnapPosition;
 import com.android.wm.shell.splitscreen.ISplitSelectListener;
 
 import java.io.PrintWriter;
@@ -288,11 +289,11 @@
      * To be called when the both split tasks are ready to be launched. Call after launcher side
      * animations are complete.
      */
-    public void launchSplitTasks(@Nullable Consumer<Boolean> callback) {
+    public void launchSplitTasks(@SnapPosition int snapPosition,
+            @Nullable Consumer<Boolean> callback) {
         Pair<InstanceId, com.android.launcher3.logging.InstanceId> instanceIds =
                 LogUtils.getShellShareableInstanceId();
-        launchTasks(callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO,
-                instanceIds.first);
+        launchTasks(callback, false /* freezeTaskList */, snapPosition, instanceIds.first);
 
         mStatsLogManager.logger()
                 .withItemInfo(mSplitSelectDataHolder.getItemInfo())
@@ -301,11 +302,18 @@
     }
 
     /**
-     * A version of {@link #launchTasks(Consumer, boolean, float, InstanceId)} with no success
-     * callback.
+     * A version of {@link #launchSplitTasks(int, Consumer)} that launches with default split ratio.
+     */
+    public void launchSplitTasks(@Nullable Consumer<Boolean> callback) {
+        launchSplitTasks(SNAP_TO_50_50, callback);
+    }
+
+    /**
+     * A version of {@link #launchSplitTasks(int, Consumer)} that launches with a default split
+     * ratio and no callback.
      */
     public void launchSplitTasks() {
-        launchSplitTasks(null);
+        launchSplitTasks(SNAP_TO_50_50, null);
     }
 
     /**
@@ -342,7 +350,7 @@
      *                   foreground (quickswitch, launching previous pairs from overview)
      */
     public void launchTasks(@Nullable Consumer<Boolean> callback, boolean freezeTaskList,
-            float splitRatio, @Nullable InstanceId shellInstanceId) {
+            @SnapPosition int snapPosition, @Nullable InstanceId shellInstanceId) {
         TestLogging.recordEvent(
                 TestProtocol.SEQUENCE_MAIN, "launchSplitTasks");
         final ActivityOptions options1 = ActivityOptions.makeBasic();
@@ -369,33 +377,33 @@
             switch (launchData.getSplitLaunchType()) {
                 case SPLIT_TASK_TASK ->
                         mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId,
-                                null /* options2 */, initialStagePosition, splitRatio,
+                                null /* options2 */, initialStagePosition, snapPosition,
                                 remoteTransition, shellInstanceId);
 
                 case SPLIT_TASK_PENDINGINTENT ->
                         mSystemUiProxy.startIntentAndTask(secondPI, secondUserId, optionsBundle,
-                                firstTaskId, null /*options2*/, initialStagePosition, splitRatio,
+                                firstTaskId, null /*options2*/, initialStagePosition, snapPosition,
                                 remoteTransition, shellInstanceId);
 
                 case SPLIT_TASK_SHORTCUT ->
                         mSystemUiProxy.startShortcutAndTask(secondShortcut, optionsBundle,
-                                firstTaskId, null /*options2*/, initialStagePosition, splitRatio,
+                                firstTaskId, null /*options2*/, initialStagePosition, snapPosition,
                                 remoteTransition, shellInstanceId);
 
                 case SPLIT_PENDINGINTENT_TASK ->
                         mSystemUiProxy.startIntentAndTask(firstPI, firstUserId, optionsBundle,
-                                secondTaskId, null /*options2*/, initialStagePosition, splitRatio,
+                                secondTaskId, null /*options2*/, initialStagePosition, snapPosition,
                                 remoteTransition, shellInstanceId);
 
                 case SPLIT_PENDINGINTENT_PENDINGINTENT ->
                         mSystemUiProxy.startIntents(firstPI, firstUserId, firstShortcut,
                                 optionsBundle, secondPI, secondUserId, secondShortcut,
-                                null /*options2*/, initialStagePosition, splitRatio,
+                                null /*options2*/, initialStagePosition, snapPosition,
                                 remoteTransition, shellInstanceId);
 
                 case SPLIT_SHORTCUT_TASK ->
                         mSystemUiProxy.startShortcutAndTask(firstShortcut, optionsBundle,
-                                secondTaskId, null /*options2*/, initialStagePosition, splitRatio,
+                                secondTaskId, null /*options2*/, initialStagePosition, snapPosition,
                                 remoteTransition, shellInstanceId);
             }
         } else {
@@ -405,40 +413,40 @@
                 case SPLIT_TASK_TASK ->
                         mSystemUiProxy.startTasksWithLegacyTransition(firstTaskId, optionsBundle,
                                 secondTaskId, null /* options2 */, initialStagePosition,
-                                splitRatio, adapter, shellInstanceId);
+                                snapPosition, adapter, shellInstanceId);
 
                 case SPLIT_TASK_PENDINGINTENT ->
                         mSystemUiProxy.startIntentAndTaskWithLegacyTransition(secondPI,
                                 secondUserId, optionsBundle, firstTaskId, null /*options2*/,
-                                initialStagePosition, splitRatio, adapter, shellInstanceId);
+                                initialStagePosition, snapPosition, adapter, shellInstanceId);
 
                 case SPLIT_TASK_SHORTCUT ->
                         mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(secondShortcut,
                                 optionsBundle, firstTaskId, null /*options2*/, initialStagePosition,
-                                splitRatio, adapter, shellInstanceId);
+                                snapPosition, adapter, shellInstanceId);
 
                 case SPLIT_PENDINGINTENT_TASK ->
                         mSystemUiProxy.startIntentAndTaskWithLegacyTransition(firstPI, firstUserId,
                                 optionsBundle, secondTaskId, null /*options2*/,
-                                initialStagePosition, splitRatio, adapter, shellInstanceId);
+                                initialStagePosition, snapPosition, adapter, shellInstanceId);
 
                 case SPLIT_PENDINGINTENT_PENDINGINTENT ->
                         mSystemUiProxy.startIntentsWithLegacyTransition(firstPI, firstUserId,
                                 firstShortcut, optionsBundle, secondPI, secondUserId,
-                                secondShortcut, null /*options2*/, initialStagePosition, splitRatio,
-                                adapter, shellInstanceId);
+                                secondShortcut, null /*options2*/, initialStagePosition,
+                                snapPosition, adapter, shellInstanceId);
 
                 case SPLIT_SHORTCUT_TASK ->
                         mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(firstShortcut,
                                 optionsBundle, secondTaskId, null /*options2*/,
-                                initialStagePosition, splitRatio, adapter, shellInstanceId);
+                                initialStagePosition, snapPosition, adapter, shellInstanceId);
             }
         }
     }
 
     /**
      * Used to launch split screen from a split pair that already exists (usually accessible through
-     * Overview). This is different than {@link #launchTasks(Consumer, boolean, float, InstanceId)}
+     * Overview). This is different than {@link #launchTasks(Consumer, boolean, int, InstanceId)}
      * in that this only launches split screen that are existing tasks. This doesn't determine which
      * API should be used (i.e. launching split with existing tasks vs intents vs shortcuts, etc).
      *
@@ -447,7 +455,7 @@
      */
     public void launchExistingSplitPair(@Nullable GroupedTaskView groupedTaskView,
             int firstTaskId, int secondTaskId, @StagePosition int stagePosition,
-            Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio) {
+            Consumer<Boolean> callback, boolean freezeTaskList, @SnapPosition int snapPosition) {
         mLaunchingTaskView = groupedTaskView;
         final ActivityOptions options1 = ActivityOptions.makeBasic();
         if (freezeTaskList) {
@@ -458,21 +466,20 @@
         if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
             final RemoteTransition remoteTransition = getShellRemoteTransition(firstTaskId,
                     secondTaskId, callback, "LaunchExistingPair");
-            mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId,
-                    null /* options2 */, stagePosition, splitRatio,
-                    remoteTransition, null /*shellInstanceId*/);
+            mSystemUiProxy.startTasks(firstTaskId, optionsBundle, secondTaskId, null /* options2 */,
+                    stagePosition, snapPosition, remoteTransition, null /*shellInstanceId*/);
         } else {
             final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId,
                     secondTaskId, callback);
-            mSystemUiProxy.startTasksWithLegacyTransition(firstTaskId, optionsBundle,
-                    secondTaskId, null /* options2 */, stagePosition,
-                    splitRatio, adapter, null /*shellInstanceId*/);
+            mSystemUiProxy.startTasksWithLegacyTransition(firstTaskId, optionsBundle, secondTaskId,
+                    null /* options2 */, stagePosition, snapPosition, 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
+     * used as {@link #launchSplitTasks(int, Consumer)} because they are overloaded to launch both
      * split and fullscreen tasks)
      */
     public void launchInitialAppFullscreen(Consumer<Boolean> callback) {
@@ -497,14 +504,13 @@
             switch (launchData.getSplitLaunchType()) {
                 case SPLIT_SINGLE_TASK_FULLSCREEN -> mSystemUiProxy.startTasks(firstTaskId,
                         optionsBundle, secondTaskId, null /* options2 */, initialStagePosition,
-                        DEFAULT_SPLIT_RATIO, remoteTransition, instanceId);
+                        SNAP_TO_50_50, remoteTransition, instanceId);
                 case SPLIT_SINGLE_INTENT_FULLSCREEN -> mSystemUiProxy.startIntentAndTask(firstPI,
                         firstUserId, optionsBundle, secondTaskId, null /*options2*/,
-                        initialStagePosition, DEFAULT_SPLIT_RATIO, remoteTransition,
-                        instanceId);
+                        initialStagePosition, SNAP_TO_50_50, remoteTransition, instanceId);
                 case SPLIT_SINGLE_SHORTCUT_FULLSCREEN -> mSystemUiProxy.startShortcutAndTask(
                         initialShortcut, optionsBundle, firstTaskId, null /* options2 */,
-                        initialStagePosition, DEFAULT_SPLIT_RATIO, remoteTransition, instanceId);
+                        initialStagePosition, SNAP_TO_50_50, remoteTransition, instanceId);
             }
         } else {
             final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(firstTaskId,
@@ -512,16 +518,15 @@
             switch (launchData.getSplitLaunchType()) {
                 case SPLIT_SINGLE_TASK_FULLSCREEN -> mSystemUiProxy.startTasksWithLegacyTransition(
                         firstTaskId, optionsBundle, secondTaskId, null /* options2 */,
-                        initialStagePosition, DEFAULT_SPLIT_RATIO, adapter, instanceId);
+                        initialStagePosition, SNAP_TO_50_50, adapter, instanceId);
                 case SPLIT_SINGLE_INTENT_FULLSCREEN ->
                         mSystemUiProxy.startIntentAndTaskWithLegacyTransition(firstPI, firstUserId,
                                 optionsBundle, secondTaskId, null /*options2*/,
-                                initialStagePosition, DEFAULT_SPLIT_RATIO, adapter,
-                                instanceId);
+                                initialStagePosition, SNAP_TO_50_50, adapter, instanceId);
                 case SPLIT_SINGLE_SHORTCUT_FULLSCREEN ->
                         mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(
                                 initialShortcut, optionsBundle, firstTaskId, null /* options2 */,
-                                initialStagePosition, DEFAULT_SPLIT_RATIO, adapter, instanceId);
+                                initialStagePosition, SNAP_TO_50_50, adapter, instanceId);
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/util/SystemActionConstants.java b/quickstep/src/com/android/quickstep/util/SystemActionConstants.java
new file mode 100644
index 0000000..522930f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SystemActionConstants.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util;
+
+/**
+ * Constants for registering SystemActions.
+ *
+ * Prefer to use AccessibilityService.GLOBAL_ACTION_* if applicable.
+ */
+public final class SystemActionConstants {
+
+    public static final int SYSTEM_ACTION_ID_TASKBAR = 499;
+    public static final int SYSTEM_ACTION_ID_SEARCH_SCREEN = 500;
+
+    /**
+     * For Taskbar broadcast intent filter.
+     */
+    public static final String ACTION_SHOW_TASKBAR = "ACTION_SHOW_TASKBAR";
+
+    /**
+     * For Search Screen broadcast intent filter.
+     */
+    public static final String ACTION_SEARCH_SCREEN = "ACTION_SEARCH_SCREEN";
+
+    private SystemActionConstants() {}
+}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index b9ff272..510044d 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -26,6 +26,7 @@
 import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
 import static com.android.quickstep.util.RecentsOrientedState.preDisplayRotation;
+import static com.android.quickstep.util.SplitScreenUtils.convertLauncherSplitBoundsToShell;
 
 import android.animation.TimeInterpolator;
 import android.content.Context;
@@ -210,7 +211,8 @@
         mStagePosition = mThumbnailPosition.equals(splitInfo.leftTopBounds) ?
                 STAGE_POSITION_TOP_OR_LEFT :
                 STAGE_POSITION_BOTTOM_OR_RIGHT;
-        mPositionHelper.setSplitBounds(convertSplitBounds(mSplitBounds), mStagePosition);
+        mPositionHelper.setSplitBounds(convertLauncherSplitBoundsToShell(mSplitBounds),
+                mStagePosition);
     }
 
     /**
@@ -435,16 +437,4 @@
         // Ideally we should use square-root. This is an optimization as one of the dimension is 0.
         return Math.max(Math.abs(mTempPoint[0]), Math.abs(mTempPoint[1]));
     }
-
-    /**
-     * TODO(b/254378592): Remove this after consolidation of classes
-     */
-    public static com.android.wm.shell.util.SplitBounds convertSplitBounds(SplitBounds bounds) {
-        return new com.android.wm.shell.util.SplitBounds(
-                bounds.leftTopBounds,
-                bounds.rightBottomBounds,
-                bounds.leftTopTaskId,
-                bounds.rightBottomTaskId
-        );
-    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 01f6ae8..7e58763 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -2,8 +2,8 @@
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 
-import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.quickstep.util.SplitScreenUtils.convertLauncherSplitBoundsToShell;
 
 import android.content.Context;
 import android.graphics.PointF;
@@ -28,11 +28,11 @@
 import com.android.quickstep.util.CancellableTask;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.util.SplitSelectStateController;
-import com.android.quickstep.util.TaskViewSimulator;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
+import com.android.wm.shell.common.split.SplitScreenConstants.SnapPosition;
 
 import java.util.HashMap;
 import java.util.function.Consumer;
@@ -114,11 +114,11 @@
         if (mSplitBoundsConfig == null) {
             return;
         }
-        mSnapshotView.getPreviewPositionHelper().setSplitBounds(TaskViewSimulator
-                        .convertSplitBounds(splitBoundsConfig),
+        mSnapshotView.getPreviewPositionHelper().setSplitBounds(
+                convertLauncherSplitBoundsToShell(splitBoundsConfig),
                 PreviewPositionHelper.STAGE_POSITION_TOP_OR_LEFT);
-        mSnapshotView2.getPreviewPositionHelper().setSplitBounds(TaskViewSimulator
-                        .convertSplitBounds(splitBoundsConfig),
+        mSnapshotView2.getPreviewPositionHelper().setSplitBounds(
+                convertLauncherSplitBoundsToShell(splitBoundsConfig),
                 PreviewPositionHelper.STAGE_POSITION_BOTTOM_OR_RIGHT);
     }
 
@@ -180,12 +180,20 @@
         invalidate();
     }
 
-    public float getSplitRatio() {
-        if (mSplitBoundsConfig != null) {
-            return mSplitBoundsConfig.appsStackedVertically
-                    ? mSplitBoundsConfig.topTaskPercent : mSplitBoundsConfig.leftTaskPercent;
+    @Nullable
+    public SplitBounds getSplitBoundsConfig() {
+        return mSplitBoundsConfig;
+    }
+
+    /**
+     * Returns the {@link SnapPosition} of this pair of tasks.
+     */
+    public int getSnapPosition() {
+        if (mSplitBoundsConfig == null) {
+            throw new IllegalStateException("mSplitBoundsConfig is null");
         }
-        return DEFAULT_SPLIT_RATIO;
+
+        return mSplitBoundsConfig.snapPosition;
     }
 
     @Override
@@ -251,7 +259,7 @@
         getRecentsView().getSplitSelectController().launchExistingSplitPair(
                 launchingExistingTaskView ? this : null, mTask.key.id,
                 mSecondaryTask.key.id, SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
-                callback, isQuickswitch, getSplitRatio());
+                callback, isQuickswitch, getSnapPosition());
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index b923bea..892ebf9 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -31,7 +31,6 @@
 import android.os.Build;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
-import android.view.Surface;
 
 import androidx.annotation.Nullable;
 
@@ -128,7 +127,9 @@
     @Override
     public void reset() {
         super.reset();
-        setLayoutRotation(Surface.ROTATION_0, Surface.ROTATION_0);
+
+        int recentsActivityRotation = getPagedViewOrientedState().getRecentsActivityRotation();
+        setLayoutRotation(recentsActivityRotation, recentsActivityRotation);
     }
 
     @Override
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index 4ff2f9c..093c45d 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -151,6 +151,13 @@
                 .dragToSplitscreen(TEST_APP_PACKAGE, CALCULATOR_APP_PACKAGE);
     }
 
+    @Test
+    @PortraitLandscape
+    public void testDismissAllAppsByTappingOutsideSheet() {
+        getTaskbar().openAllApps().dismissByTappingOutsideForTablet(/* tapRight= */ true);
+        getTaskbar().openAllApps().dismissByTappingOutsideForTablet(/* tapRight= */ false);
+    }
+
     private boolean isTaskbarTestModeTransient() {
         return TRANSIENT == mTaskbarMode;
     }
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index 4e7fcf0..f198741 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -20,7 +20,6 @@
 import android.app.ActivityManager
 import android.app.PendingIntent
 import android.content.ComponentName
-import android.content.Context
 import android.content.Intent
 import android.graphics.Rect
 import android.os.Handler
@@ -38,7 +37,7 @@
 import com.android.quickstep.RecentsModel
 import com.android.quickstep.SystemUiProxy
 import com.android.systemui.shared.recents.model.Task
-import java.util.function.Consumer
+import com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertNull
@@ -50,6 +49,7 @@
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
+import java.util.function.Consumer
 
 @RunWith(AndroidJUnit4::class)
 class SplitSelectStateControllerTest {
@@ -560,7 +560,7 @@
         return GroupTask(
             task1,
             task2,
-            SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1)
+            SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1, SNAP_TO_50_50)
         )
     }
 
@@ -592,7 +592,7 @@
         return GroupTask(
             task1,
             task2,
-            SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1)
+            SplitConfigurationOptions.SplitBounds(Rect(), Rect(), -1, -1, SNAP_TO_50_50)
         )
     }
 }
diff --git a/res/layout/all_apps_prediction_row_icon.xml b/res/layout/all_apps_prediction_row_icon.xml
new file mode 100644
index 0000000..c9b3275
--- /dev/null
+++ b/res/layout/all_apps_prediction_row_icon.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+<com.android.launcher3.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    style="@style/BaseIcon.AllApps"
+    android:id="@+id/icon"
+    launcher:iconDisplay="prediction_row"
+    launcher:centerVertically="true" />
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 05eaf88..f046eca 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -86,6 +86,7 @@
             <enum name="search_result_tall" value="6" />
             <enum name="search_result_small" value="7" />
             <enum name="prediction_row" value="8" />
+            <enum name="search_result_app_row" value="9" />
         </attr>
         <attr name="centerVertically" format="boolean" />
     </declare-styleable>
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index ec874b9..55b8fcc 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -1,28 +1,12 @@
 package com.android.launcher3;
 
-import static android.os.Process.myUserHandle;
-
-import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.database.Cursor;
 import android.util.Log;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.WorkerThread;
-
-import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.model.LoaderTask;
-import com.android.launcher3.model.ModelDbController;
-import com.android.launcher3.model.WidgetsModel;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.provider.RestoreDbTask;
-import com.android.launcher3.util.ContentWriter;
-import com.android.launcher3.util.IntArray;
 import com.android.launcher3.widget.LauncherWidgetHolder;
 
 public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
@@ -47,131 +31,4 @@
             }
         }
     }
-
-    /**
-     * Updates the app widgets whose id has changed during the restore process.
-     */
-    @WorkerThread
-    public static void restoreAppWidgetIds(Context context, ModelDbController controller,
-            int[] oldWidgetIds, int[] newWidgetIds, @NonNull AppWidgetHost host) {
-        if (WidgetsModel.GO_DISABLE_WIDGETS) {
-            Log.e(TAG, "Skipping widget ID remap as widgets not supported");
-            host.deleteHost();
-            return;
-        }
-        if (!RestoreDbTask.isPending(context)) {
-            // Someone has already gone through our DB once, probably LoaderTask. Skip any further
-            // modifications of the DB.
-            Log.e(TAG, "Skipping widget ID remap as DB already in use");
-            for (int widgetId : newWidgetIds) {
-                Log.d(TAG, "Deleting widgetId: " + widgetId);
-                host.deleteAppWidgetId(widgetId);
-            }
-            return;
-        }
-
-        final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
-
-        Log.d(TAG, "restoreAppWidgetIds: "
-                + "oldWidgetIds=" + IntArray.wrap(oldWidgetIds).toConcatString()
-                + ", newWidgetIds=" + IntArray.wrap(newWidgetIds).toConcatString());
-
-        // TODO(b/234700507): Remove the logs after the bug is fixed
-        logDatabaseWidgetInfo(controller);
-
-        for (int i = 0; i < oldWidgetIds.length; i++) {
-            Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
-
-            final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
-            final int state;
-            if (LoaderTask.isValidProvider(provider)) {
-                // This will ensure that we show 'Click to setup' UI if required.
-                state = LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
-            } else {
-                state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
-            }
-
-            // b/135926478: Work profile widget restore is broken in platform. This forces us to
-            // recreate the widget during loading with the correct host provider.
-            long mainProfileId = UserCache.INSTANCE.get(context)
-                    .getSerialNumberForUser(myUserHandle());
-            long controllerProfileId = controller.getSerialNumberForUser(myUserHandle());
-            String oldWidgetId = Integer.toString(oldWidgetIds[i]);
-            final String where = "appWidgetId=? and (restored & 1) = 1 and profileId=?";
-            String profileId = Long.toString(mainProfileId);
-            final String[] args = new String[] { oldWidgetId, profileId };
-            Log.d(TAG, "restoreAppWidgetIds: querying profile id=" + profileId
-                    + " with controller profile ID=" + controllerProfileId);
-            int result = new ContentWriter(context,
-                            new ContentWriter.CommitParams(controller, where, args))
-                    .put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i])
-                    .put(LauncherSettings.Favorites.RESTORED, state)
-                    .commit();
-            if (result == 0) {
-                // TODO(b/234700507): Remove the logs after the bug is fixed
-                Log.e(TAG, "restoreAppWidgetIds: remapping failed since the widget is not in"
-                        + " the database anymore");
-                try (Cursor cursor = controller.getDb().query(
-                        Favorites.TABLE_NAME,
-                        new String[]{Favorites.APPWIDGET_ID},
-                        "appWidgetId=?", new String[]{oldWidgetId}, null, null, null)) {
-                    if (!cursor.moveToFirst()) {
-                        // The widget no long exists.
-                        Log.d(TAG, "Deleting widgetId: " + newWidgetIds[i] + " with old id: "
-                                + oldWidgetId);
-                        host.deleteAppWidgetId(newWidgetIds[i]);
-                    }
-                }
-            }
-        }
-
-        LauncherAppState app = LauncherAppState.getInstanceNoCreate();
-        if (app != null) {
-            app.getModel().forceReload();
-        }
-    }
-
-    private static void logDatabaseWidgetInfo(ModelDbController controller) {
-        try (Cursor cursor = controller.getDb().query(Favorites.TABLE_NAME,
-                new String[]{Favorites.APPWIDGET_ID, Favorites.RESTORED, Favorites.PROFILE_ID},
-                Favorites.APPWIDGET_ID + "!=" + LauncherAppWidgetInfo.NO_ID, null,
-                null, null, null)) {
-            IntArray widgetIdList = new IntArray();
-            IntArray widgetRestoreList = new IntArray();
-            IntArray widgetProfileIdList = new IntArray();
-
-            if (cursor.moveToFirst()) {
-                final int widgetIdColumnIndex = cursor.getColumnIndex(Favorites.APPWIDGET_ID);
-                final int widgetRestoredColumnIndex = cursor.getColumnIndex(Favorites.RESTORED);
-                final int widgetProfileIdIndex = cursor.getColumnIndex(Favorites.PROFILE_ID);
-                while (!cursor.isAfterLast()) {
-                    int widgetId = cursor.getInt(widgetIdColumnIndex);
-                    int widgetRestoredFlag = cursor.getInt(widgetRestoredColumnIndex);
-                    int widgetProfileId = cursor.getInt(widgetProfileIdIndex);
-
-                    widgetIdList.add(widgetId);
-                    widgetRestoreList.add(widgetRestoredFlag);
-                    widgetProfileIdList.add(widgetProfileId);
-                    cursor.moveToNext();
-                }
-            }
-
-            StringBuilder builder = new StringBuilder();
-            builder.append("[");
-            for (int i = 0; i < widgetIdList.size(); i++) {
-                builder.append("[")
-                        .append(widgetIdList.get(i))
-                        .append(", ")
-                        .append(widgetRestoreList.get(i))
-                        .append(", ")
-                        .append(widgetProfileIdList.get(i))
-                        .append("]");
-            }
-            builder.append("]");
-            Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: "
-                    + builder.toString());
-        } catch (Exception ex) {
-            Log.e(TAG, "Getting widget ids from the database failed", ex);
-        }
-    }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 25ea102..bd004e9 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -99,8 +99,9 @@
     private static final int DISPLAY_FOLDER = 2;
     protected static final int DISPLAY_TASKBAR = 5;
     public static final int DISPLAY_SEARCH_RESULT = 6;
-    private static final int DISPLAY_SEARCH_RESULT_SMALL = 7;
+    public static final int DISPLAY_SEARCH_RESULT_SMALL = 7;
     public static final int DISPLAY_PREDICTION_ROW = 8;
+    public static final int DISPLAY_SEARCH_RESULT_APP_ROW = 9;
 
     private static final float MIN_LETTER_SPACING = -0.05f;
     private static final int MAX_SEARCH_LOOP_COUNT = 20;
@@ -214,7 +215,8 @@
             setCompoundDrawablePadding(grid.iconDrawablePaddingPx);
             defaultIconSize = grid.iconSizePx;
             setCenterVertically(grid.iconCenterVertically);
-        } else if (mDisplay == DISPLAY_ALL_APPS || mDisplay == DISPLAY_PREDICTION_ROW) {
+        } else if (mDisplay == DISPLAY_ALL_APPS || mDisplay == DISPLAY_PREDICTION_ROW
+                || mDisplay == DISPLAY_SEARCH_RESULT_APP_ROW) {
             setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx);
             setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx);
             defaultIconSize = grid.allAppsIconSizePx;
@@ -1105,8 +1107,13 @@
     }
 
     public boolean isDisplaySearchResult() {
-        return mDisplay == DISPLAY_SEARCH_RESULT ||
-                mDisplay == DISPLAY_SEARCH_RESULT_SMALL;
+        return mDisplay == DISPLAY_SEARCH_RESULT
+                || mDisplay == DISPLAY_SEARCH_RESULT_SMALL
+                || mDisplay == DISPLAY_SEARCH_RESULT_APP_ROW;
+    }
+
+    public int getIconDisplay() {
+        return mDisplay;
     }
 
     @Override
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index fc36ce6..57e1641 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -645,6 +645,11 @@
      * is played.
      */
     private void animateOpen(List<WorkspaceItemInfo> items, int pageNo) {
+        if (items == null || items.size() <= 1) {
+            Log.d(TAG, "Couldn't animate folder open because items is: " + items);
+            return;
+        }
+
         Folder openFolder = getOpen(mActivityContext);
         if (openFolder != null && openFolder != this) {
             // Close any open folder before opening a folder.
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index b51373c..4208343 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.graphics;
 
+import static com.android.launcher3.BubbleTextView.DISPLAY_SEARCH_RESULT_APP_ROW;
+
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -100,7 +102,8 @@
             height = mView.getHeight();
         }
 
-        if (mView instanceof BubbleTextView) {
+        if (mView instanceof BubbleTextView btv
+                && btv.getIconDisplay() == DISPLAY_SEARCH_RESULT_APP_ROW) {
             FastBitmapDrawable icon = ((BubbleTextView) mView).getIcon();
             Drawable drawable = icon.getConstantState().newDrawable();
             float xInset = (float) blurSizeOutline / (float) (width + blurSizeOutline);
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index 1f908eb..575551b 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -120,6 +120,10 @@
                 deletedShortcuts.add(lc.id);
                 continue;
             }
+            if (TextUtils.isEmpty(lc.getTitle())) {
+                deletedShortcuts.add(lc.id);
+                continue;
+            }
 
             // Make sure the target intent can be launched without any permissions. Otherwise remove
             // the shortcut
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 4725dd1..10005e5 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -28,6 +28,8 @@
 
 import android.app.backup.BackupManager;
 import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
@@ -42,20 +44,26 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
 
-import com.android.launcher3.AppWidgetsRestoredReceiver;
 import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherPrefs;
+import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.DeviceGridState;
+import com.android.launcher3.model.LoaderTask;
 import com.android.launcher3.model.ModelDbController;
+import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
 import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.ContentWriter;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.LogConfig;
 
@@ -377,11 +385,13 @@
                 .putSync(RESTORE_DEVICE.to(new DeviceGridState(context).getDeviceType()));
     }
 
-    private void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller) {
+    @WorkerThread
+    @VisibleForTesting
+    void restoreAppWidgetIdsIfExists(Context context, ModelDbController controller) {
         LauncherPrefs lp = LauncherPrefs.get(context);
         if (lp.has(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS)) {
             AppWidgetHost host = new AppWidgetHost(context, APPWIDGET_HOST_ID);
-            AppWidgetsRestoredReceiver.restoreAppWidgetIds(context, controller,
+            restoreAppWidgetIds(context, controller,
                     IntArray.fromConcatString(lp.get(OLD_APP_WIDGET_IDS)).toArray(),
                     IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(),
                     host);
@@ -392,6 +402,133 @@
         lp.remove(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS);
     }
 
+    /**
+     * Updates the app widgets whose id has changed during the restore process.
+     */
+    @WorkerThread
+    private void restoreAppWidgetIds(Context context, ModelDbController controller,
+            int[] oldWidgetIds, int[] newWidgetIds, @NonNull AppWidgetHost host) {
+        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+            Log.e(TAG, "Skipping widget ID remap as widgets not supported");
+            host.deleteHost();
+            return;
+        }
+        if (!RestoreDbTask.isPending(context)) {
+            // Someone has already gone through our DB once, probably LoaderTask. Skip any further
+            // modifications of the DB.
+            Log.e(TAG, "Skipping widget ID remap as DB already in use");
+            for (int widgetId : newWidgetIds) {
+                Log.d(TAG, "Deleting widgetId: " + widgetId);
+                host.deleteAppWidgetId(widgetId);
+            }
+            return;
+        }
+
+        final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
+
+        Log.d(TAG, "restoreAppWidgetIds: "
+                + "oldWidgetIds=" + IntArray.wrap(oldWidgetIds).toConcatString()
+                + ", newWidgetIds=" + IntArray.wrap(newWidgetIds).toConcatString());
+
+        // TODO(b/234700507): Remove the logs after the bug is fixed
+        logDatabaseWidgetInfo(controller);
+
+        for (int i = 0; i < oldWidgetIds.length; i++) {
+            Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
+
+            final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
+            final int state;
+            if (LoaderTask.isValidProvider(provider)) {
+                // This will ensure that we show 'Click to setup' UI if required.
+                state = LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
+            } else {
+                state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
+            }
+
+            // b/135926478: Work profile widget restore is broken in platform. This forces us to
+            // recreate the widget during loading with the correct host provider.
+            long mainProfileId = UserCache.INSTANCE.get(context)
+                    .getSerialNumberForUser(myUserHandle());
+            long controllerProfileId = controller.getSerialNumberForUser(myUserHandle());
+            String oldWidgetId = Integer.toString(oldWidgetIds[i]);
+            final String where = "appWidgetId=? and (restored & 1) = 1 and profileId=?";
+            String profileId = Long.toString(mainProfileId);
+            final String[] args = new String[] { oldWidgetId, profileId };
+            Log.d(TAG, "restoreAppWidgetIds: querying profile id=" + profileId
+                    + " with controller profile ID=" + controllerProfileId);
+            int result = new ContentWriter(context,
+                    new ContentWriter.CommitParams(controller, where, args))
+                    .put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i])
+                    .put(LauncherSettings.Favorites.RESTORED, state)
+                    .commit();
+            if (result == 0) {
+                // TODO(b/234700507): Remove the logs after the bug is fixed
+                Log.e(TAG, "restoreAppWidgetIds: remapping failed since the widget is not in"
+                        + " the database anymore");
+                try (Cursor cursor = controller.getDb().query(
+                        Favorites.TABLE_NAME,
+                        new String[]{Favorites.APPWIDGET_ID},
+                        "appWidgetId=?", new String[]{oldWidgetId}, null, null, null)) {
+                    if (!cursor.moveToFirst()) {
+                        // The widget no long exists.
+                        Log.d(TAG, "Deleting widgetId: " + newWidgetIds[i] + " with old id: "
+                                + oldWidgetId);
+                        host.deleteAppWidgetId(newWidgetIds[i]);
+                    }
+                }
+            }
+        }
+
+        LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+        if (app != null) {
+            app.getModel().forceReload();
+        }
+    }
+
+    private static void logDatabaseWidgetInfo(ModelDbController controller) {
+        try (Cursor cursor = controller.getDb().query(Favorites.TABLE_NAME,
+                new String[]{Favorites.APPWIDGET_ID, Favorites.RESTORED, Favorites.PROFILE_ID},
+                Favorites.APPWIDGET_ID + "!=" + LauncherAppWidgetInfo.NO_ID, null,
+                null, null, null)) {
+            IntArray widgetIdList = new IntArray();
+            IntArray widgetRestoreList = new IntArray();
+            IntArray widgetProfileIdList = new IntArray();
+
+            if (cursor.moveToFirst()) {
+                final int widgetIdColumnIndex = cursor.getColumnIndex(Favorites.APPWIDGET_ID);
+                final int widgetRestoredColumnIndex = cursor.getColumnIndex(Favorites.RESTORED);
+                final int widgetProfileIdIndex = cursor.getColumnIndex(Favorites.PROFILE_ID);
+                while (!cursor.isAfterLast()) {
+                    int widgetId = cursor.getInt(widgetIdColumnIndex);
+                    int widgetRestoredFlag = cursor.getInt(widgetRestoredColumnIndex);
+                    int widgetProfileId = cursor.getInt(widgetProfileIdIndex);
+
+                    widgetIdList.add(widgetId);
+                    widgetRestoreList.add(widgetRestoredFlag);
+                    widgetProfileIdList.add(widgetProfileId);
+                    cursor.moveToNext();
+                }
+            }
+
+            StringBuilder builder = new StringBuilder();
+            builder.append("[");
+            for (int i = 0; i < widgetIdList.size(); i++) {
+                builder.append("[")
+                        .append(widgetIdList.get(i))
+                        .append(", ")
+                        .append(widgetRestoreList.get(i))
+                        .append(", ")
+                        .append(widgetProfileIdList.get(i))
+                        .append("]");
+            }
+            builder.append("]");
+            Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: "
+                    + builder.toString());
+        } catch (Exception ex) {
+            Log.e(TAG, "Getting widget ids from the database failed", ex);
+        }
+    }
+
     public static void setRestoredAppWidgetIds(Context context, @NonNull int[] oldIds,
             @NonNull int[] newIds) {
         LauncherPrefs.get(context).putSync(
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index 1ae43d0..f4a0225 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -77,11 +77,6 @@
     public @interface StageType {}
     ///////////////////////////////////
 
-    /**
-     * Default split ratio for launching app pair from overview.
-     */
-    public static final float DEFAULT_SPLIT_RATIO = 0.5f;
-
     public static class SplitPositionOption {
         public final int iconResId;
         public final int textResId;
@@ -116,6 +111,8 @@
         public final float leftTaskPercent;
         public final float dividerWidthPercent;
         public final float dividerHeightPercent;
+        public final int snapPosition;
+
         /**
          * If {@code true}, that means at the time of creation of this object, the
          * split-screened apps were vertically stacked. This is useful in scenarios like
@@ -135,11 +132,12 @@
         public final int rightBottomTaskId;
 
         public SplitBounds(Rect leftTopBounds, Rect rightBottomBounds, int leftTopTaskId,
-                int rightBottomTaskId) {
+                int rightBottomTaskId, int snapPosition) {
             this.leftTopBounds = leftTopBounds;
             this.rightBottomBounds = rightBottomBounds;
             this.leftTopTaskId = leftTopTaskId;
             this.rightBottomTaskId = rightBottomTaskId;
+            this.snapPosition = snapPosition;
 
             if (rightBottomBounds.top > leftTopBounds.top) {
                 // vertical apps, horizontal divider
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index 1e28d98..c652b98 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -189,7 +189,6 @@
     @PlatinumTest(focusArea = "launcher")
     @Test
     @PortraitLandscape
-    @ScreenRecord // b/256898879
     public void testDragAppIcon() {
 
         final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index 73bb586..a21c9b9 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -19,17 +19,30 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.launcher3.LauncherPrefs.APP_WIDGET_IDS;
+import static com.android.launcher3.LauncherPrefs.OLD_APP_WIDGET_IDS;
+import static com.android.launcher3.LauncherPrefs.RESTORE_DEVICE;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
 import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
+import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID;
+
+import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
 
 import android.app.backup.BackupManager;
+import android.appwidget.AppWidgetHost;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
@@ -43,6 +56,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.model.ModelDbController;
@@ -52,6 +66,10 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import java.util.Arrays;
+import java.util.stream.IntStream;
 
 /**
  * Tests for {@link RestoreDbTask}
@@ -66,16 +84,27 @@
 
     private LauncherModelHelper mModelHelper;
     private Context mContext;
+    private RestoreDbTask mTask;
+    private ModelDbController mMockController;
+    private SQLiteDatabase mMockDb;
+    private Cursor mMockCursor;
+    private LauncherPrefs mPrefs;
 
     @Before
     public void setup() {
         mModelHelper = new LauncherModelHelper();
         mContext = mModelHelper.sandboxContext;
+        mTask = new RestoreDbTask();
+        mMockController = Mockito.mock(ModelDbController.class);
+        mMockDb = mock(SQLiteDatabase.class);
+        mMockCursor = mock(Cursor.class);
+        mPrefs = new LauncherPrefs(mContext);
     }
 
     @After
     public void teardown() {
         mModelHelper.destroy();
+        LauncherPrefs.get(mContext).removeSync(RESTORE_DEVICE);
     }
 
     @Test
@@ -148,8 +177,7 @@
         assertEquals(10, getItemCountForProfile(db, myProfileId_old));
         assertEquals(6, getItemCountForProfile(db, workProfileId_old));
 
-        RestoreDbTask task = new RestoreDbTask();
-        task.sanitizeDB(mContext, controller, controller.getDb(), bm);
+        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm);
 
         // All the data has been migrated to the new user ids
         assertEquals(0, getItemCountForProfile(db, myProfileId_old));
@@ -178,8 +206,7 @@
         assertEquals(10, getItemCountForProfile(db, myProfileId_old));
         assertEquals(6, getItemCountForProfile(db, workProfileId_old));
 
-        RestoreDbTask task = new RestoreDbTask();
-        task.sanitizeDB(mContext, controller, controller.getDb(), bm);
+        mTask.sanitizeDB(mContext, controller, controller.getDb(), bm);
 
         // All the data has been migrated to the new user ids
         assertEquals(0, getItemCountForProfile(db, myProfileId_old));
@@ -188,6 +215,83 @@
         assertEquals(10, getCount(db, "select * from favorites"));
     }
 
+    @Test
+    public void givenLauncherPrefsHasNoIds_whenRestoreAppWidgetIdsIfExists_thenIdsAreRemoved() {
+        // When
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+        // Then
+        assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse();
+    }
+
+    @Test
+    public void givenNoPendingRestore_WhenRestoreAppWidgetIds_ThenRemoveNewWidgetIds() {
+        // Given
+        AppWidgetHost expectedHost = new AppWidgetHost(mContext, APPWIDGET_HOST_ID);
+        int[] expectedOldIds = generateOldWidgetIds(expectedHost);
+        int[] expectedNewIds = generateNewWidgetIds(expectedHost, expectedOldIds);
+        when(mMockController.getDb()).thenReturn(mMockDb);
+        mPrefs.remove(RESTORE_DEVICE);
+
+        // When
+        RestoreDbTask.setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+
+        // Then
+        assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds);
+        assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse();
+        verifyZeroInteractions(mMockController);
+    }
+
+    @Test
+    public void givenRestoreWithNonExistingWidgets_WhenRestoreAppWidgetIds_ThenRemoveNewIds() {
+        // Given
+        AppWidgetHost expectedHost = new AppWidgetHost(mContext, APPWIDGET_HOST_ID);
+        int[] expectedOldIds = generateOldWidgetIds(expectedHost);
+        int[] expectedNewIds = generateNewWidgetIds(expectedHost, expectedOldIds);
+        when(mMockController.getDb()).thenReturn(mMockDb);
+        when(mMockDb.query(any(), any(), any(), any(), any(), any(), any())).thenReturn(
+                mMockCursor);
+        when(mMockCursor.moveToFirst()).thenReturn(false);
+        RestoreDbTask.setPending(mContext);
+
+        // When
+        RestoreDbTask.setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+
+        // Then
+        assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds);
+        assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse();
+        verify(mMockController, times(expectedOldIds.length)).update(any(), any(), any(), any());
+    }
+
+    @Test
+    public void givenRestore_WhenRestoreAppWidgetIds_ThenAddNewIds() {
+        // Given
+        AppWidgetHost expectedHost = new AppWidgetHost(mContext, APPWIDGET_HOST_ID);
+        int[] expectedOldIds = generateOldWidgetIds(expectedHost);
+        int[] expectedNewIds = generateNewWidgetIds(expectedHost, expectedOldIds);
+        int[] allExpectedIds = IntStream.concat(
+                Arrays.stream(expectedOldIds),
+                Arrays.stream(expectedNewIds)
+        ).toArray();
+
+        when(mMockController.getDb()).thenReturn(mMockDb);
+        when(mMockDb.query(any(), any(), any(), any(), any(), any(), any()))
+                .thenReturn(mMockCursor);
+        when(mMockCursor.moveToFirst()).thenReturn(true);
+        when(mMockCursor.isAfterLast()).thenReturn(true);
+        RestoreDbTask.setPending(mContext);
+
+        // When
+        RestoreDbTask.setRestoredAppWidgetIds(mContext, expectedOldIds, expectedNewIds);
+        mTask.restoreAppWidgetIdsIfExists(mContext, mMockController);
+
+        // Then
+        assertThat(expectedHost.getAppWidgetIds()).isEqualTo(allExpectedIds);
+        assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse();
+        verify(mMockController, times(expectedOldIds.length)).update(any(), any(), any(), any());
+    }
+
     private void addIconsBulk(MyModelDbController controller,
             int count, int screen, long profileId) {
         int columns = LauncherAppState.getIDP(mContext).numColumns;
@@ -270,6 +374,19 @@
         }
     }
 
+    private int[] generateOldWidgetIds(AppWidgetHost host) {
+        // generate some widget ids in case there are none
+        host.allocateAppWidgetId();
+        host.allocateAppWidgetId();
+        return host.getAppWidgetIds();
+    }
+
+    private int[] generateNewWidgetIds(AppWidgetHost host, int[] oldWidgetIds) {
+        // map as many new ids as old ids
+        return Arrays.stream(oldWidgetIds)
+                .map(id -> host.allocateAppWidgetId()).toArray();
+    }
+
     private class MyModelDbController extends ModelDbController {
 
         public final LongSparseArray<UserHandle> users = new LongSparseArray<>();
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index fb08ea4..44875d5 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -48,6 +48,8 @@
 
     private static final int MAX_SCROLL_ATTEMPTS = 40;
 
+    private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background";
+
     private final int mHeight;
     private final int mIconHeight;
 
@@ -338,6 +340,28 @@
     }
 
     /**
+     * Taps outside bottom sheet to dismiss it. Available on tablets only.
+     * @param tapRight Tap on the right of bottom sheet if true, or left otherwise.
+     */
+    public void dismissByTappingOutsideForTablet(boolean tapRight) {
+        mLauncher.assertTrue("Device must be a tablet", mLauncher.isTablet());
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to tap outside AllApps bottom sheet on the "
+                             + (tapRight ? "right" : "left"))) {
+            final UiObject2 allAppsBottomSheet =
+                    mLauncher.waitForLauncherObject(BOTTOM_SHEET_RES_ID);
+            mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight);
+            try (LauncherInstrumentation.Closable tapped = mLauncher.addContextLayer(
+                    "tapped outside AllApps bottom sheet")) {
+                verifyVisibleContainerOnDismiss();
+            }
+        }
+    }
+
+    protected abstract void verifyVisibleContainerOnDismiss();
+
+    /**
      * Return the QSB UI object on the AllApps screen.
      * @return the QSB UI object.
      */
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
index 2951901..8542f91 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
@@ -23,7 +23,6 @@
 import com.android.launcher3.testing.shared.TestProtocol;
 
 public class HomeAllApps extends AllApps {
-    private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background";
 
     HomeAllApps(LauncherInstrumentation launcher) {
         super(launcher);
@@ -98,25 +97,6 @@
                 .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
-    /**
-     * Taps outside bottom sheet to dismiss and return to workspace. Available on tablets only.
-     * @param tapRight Tap on the right of bottom sheet if true, or left otherwise.
-     */
-    public Workspace dismissByTappingOutsideForTablet(boolean tapRight) {
-        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
-             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
-                     "want to tap outside AllApps bottom sheet on the "
-                             + (tapRight ? "right" : "left"))) {
-            final UiObject2 allAppsBottomSheet =
-                    mLauncher.waitForLauncherObject(BOTTOM_SHEET_RES_ID);
-            mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight);
-            try (LauncherInstrumentation.Closable tapped = mLauncher.addContextLayer(
-                    "tapped outside AllApps bottom sheet")) {
-                return mLauncher.getWorkspace();
-            }
-        }
-    }
-
     @NonNull
     @Override
     public Qsb getQsb() {
@@ -128,4 +108,9 @@
         return mLauncher.getTestInfo(TestProtocol.REQUEST_APPS_LIST_SCROLL_Y)
                 .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
+
+    @Override
+    protected void verifyVisibleContainerOnDismiss() {
+        mLauncher.getWorkspace();
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 872fe6f..71ca77f 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -721,6 +721,10 @@
         mExpectedRotationCheckEnabled = expectedRotationCheckEnabled;
     }
 
+    public boolean getExpectedRotationCheckEnabled() {
+        return mExpectedRotationCheckEnabled;
+    }
+
     public String getNavigationModeMismatchError(boolean waitForCorrectState) {
         final int waitTime = waitForCorrectState ? WAIT_TIME_MS : 0;
         final NavigationModel navigationModel = getNavigationModel();
diff --git a/tests/tapl/com/android/launcher3/tapl/TaskbarAllApps.java b/tests/tapl/com/android/launcher3/tapl/TaskbarAllApps.java
index 63185f9..c1234fe 100644
--- a/tests/tapl/com/android/launcher3/tapl/TaskbarAllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/TaskbarAllApps.java
@@ -68,4 +68,9 @@
     public TaskbarAllAppsQsb getQsb() {
         return new TaskbarAllAppsQsb(mLauncher, verifyActiveContainer());
     }
+
+    @Override
+    protected void verifyVisibleContainerOnDismiss() {
+        mLauncher.getLaunchedAppState().assertTaskbarVisible();
+    }
 }