Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 9080284..af175ce 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -83,3 +83,10 @@
     description: "Enables two pane widget picker for unfolded foldables"
     bug: "313922374"
 }
+
+flag {
+    name: "enable_tablet_two_pane_picker_v2"
+    namespace: "launcher"
+    description: "Enables full width two pane widget picker for tablets in landscape and portrait"
+    bug: "315055849"
+}
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index 5a9e147..8240f11 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -138,7 +138,7 @@
   }
 }
 
-// Next value 54
+// Next value 55
 enum Attribute {
   option allow_alias = true;
 
@@ -200,6 +200,7 @@
   DATA_SOURCE_APPSEARCH_CATEGORY_SRP_PREVIEW = 48;
   DATA_SOURCE_APPSEARCH_ENTITY_SRP_PREVIEW = 49;
   DATA_SOURCE_AIAI_SEARCH_ROOT = 47;
+  DATA_SOURCE_LAUNCHER = 54;
 
   // Web suggestions provided by AGA
   ALL_APPS_SEARCH_RESULT_WEB_SUGGEST = 39;
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 0fda0bf..fe517fa 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -31,7 +31,7 @@
             android:layout_height="1dp"
             android:layout_weight="1" />
 
-        <Button
+        <com.android.quickstep.views.ScreenshotActionButton
             android:id="@+id/action_screenshot"
             style="@style/OverviewActionButton"
             android:layout_width="wrap_content"
@@ -40,17 +40,12 @@
             android:text="@string/action_screenshot"
             android:theme="@style/ThemeControlHighlightWorkspaceColor" />
 
-        <Space
-            android:id="@+id/action_split_space"
-            android:layout_width="@dimen/overview_actions_button_spacing"
-            android:layout_height="1dp"
-            android:visibility="gone" />
-
-        <Button
+        <com.android.quickstep.views.SplitActionButton
             android:id="@+id/action_split"
             style="@style/OverviewActionButton"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/overview_actions_button_spacing"
             android:text="@string/action_split"
             android:theme="@style/ThemeControlHighlightWorkspaceColor"
             android:visibility="gone" />
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index d6ab54e..8db63e3 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -55,6 +55,7 @@
 import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
 import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
+import static com.android.launcher3.testing.shared.TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE;
 import static com.android.launcher3.util.DisplayController.isTransientTaskbar;
 import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
 import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
@@ -120,6 +121,7 @@
 import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.model.data.ItemInfo;
@@ -1651,6 +1653,15 @@
         if (launcherIsForceInvisibleOrOpening) {
             addCujInstrumentation(anim, playFallBackAnimation
                     ? CUJ_APP_CLOSE_TO_HOME_FALLBACK : CUJ_APP_CLOSE_TO_HOME);
+
+            anim.addListener(new AnimationSuccessListener() {
+                @Override
+                public void onAnimationSuccess(Animator animator) {
+                    AccessibilityManagerCompat.sendTestProtocolEventToTest(
+                            mLauncher, WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE);
+                }
+            });
+
             // Only register the content animation for cancellation when state changes
             mLauncher.getStateManager().setCurrentAnimation(anim);
 
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 221ce48..f801b3b 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -106,10 +106,10 @@
                 });
                 return response;
 
-            case TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT: {
+            case TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD: {
                 final Resources resources = mContext.getResources();
                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
-                        resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size));
+                        resources.getDimensionPixelSize(R.dimen.taskbar_from_nav_threshold));
                 return response;
             }
 
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index 20a751b..1b3f598 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -31,7 +31,6 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.SparseArray;
-import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.WorkerThread;
 
@@ -45,6 +44,7 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
 import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.Preconditions;
 import com.android.quickstep.util.CancellableTask;
 import com.android.quickstep.util.TaskKeyLruCache;
@@ -62,7 +62,6 @@
 public class TaskIconCache implements DisplayInfoChangeListener {
 
     private final Executor mBgExecutor;
-    private final AccessibilityManager mAccessibilityManager;
 
     private final Context mContext;
     private final TaskKeyLruCache<TaskCacheEntry> mIconCache;
@@ -79,7 +78,6 @@
     public TaskIconCache(Context context, Executor bgExecutor, IconProvider iconProvider) {
         mContext = context;
         mBgExecutor = bgExecutor;
-        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
         mIconProvider = iconProvider;
 
         Resources res = context.getResources();
@@ -238,14 +236,11 @@
             if ((index = mDefaultIcons.indexOfKey(userId)) >= 0) {
                 return mDefaultIcons.valueAt(index).newIcon(mContext);
             } else {
-                try (BaseIconFactory li = getIconFactory()) {
-                    BitmapInfo info = mDefaultIconBase.withFlags(
-                            li.getBitmapFlagOp(new IconOptions()
-                                    .setUser(UserCache.INSTANCE.get(mContext)
-                                            .getUserInfo(UserHandle.of(userId)))));
-                    mDefaultIcons.put(userId, info);
-                    return info.newIcon(mContext);
-                }
+                BitmapInfo info = mDefaultIconBase.withFlags(
+                        UserCache.INSTANCE.get(mContext).getUserInfo(UserHandle.of(userId))
+                                .applyBitmapInfoFlags(FlagOp.NO_OP));
+                mDefaultIcons.put(userId, info);
+                return info.newIcon(mContext);
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
index 57c05e9..4d47f07 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
@@ -56,5 +56,5 @@
      * Called when nav handle gesture is finished by the user lifting their finger or the system
      * cancelling the touch for some other reason.
      */
-    public void onTouchFinished() {}
+    public void onTouchFinished(String reason) {}
 }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index 0127cc9..0a558e2 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -81,7 +81,7 @@
         if (mDelegate.allowInterceptByParent()) {
             handleMotionEvent(ev);
         } else if (MAIN_EXECUTOR.getHandler().hasCallbacks(mTriggerLongPress)) {
-            cancelLongPress();
+            cancelLongPress("intercept disallowed by child input consumer");
         }
 
         if (mState != STATE_ACTIVE) {
@@ -113,10 +113,11 @@
                 float dy = ev.getY() - mCurrentDownEvent.getY();
                 double distanceSquared = (dx * dx) + (dy * dy);
                 if (distanceSquared > touchSlopSquared) {
-                    cancelLongPress();
+                    cancelLongPress("touch slop passed");
                 }
             }
-            case MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> cancelLongPress();
+            case MotionEvent.ACTION_UP -> cancelLongPress("touch action up");
+            case MotionEvent.ACTION_CANCEL -> cancelLongPress("touch action cancel");
         }
 
         // If the gesture is deep press then trigger long press asap
@@ -158,9 +159,9 @@
         }
     }
 
-    private void cancelLongPress() {
+    private void cancelLongPress(String reason) {
         MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
-        mNavHandleLongPressHandler.onTouchFinished();
+        mNavHandleLongPressHandler.onTouchFinished(reason);
     }
 
     private boolean isInNavBarHorizontalArea(float x) {
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
index 423ba43..c013483 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
@@ -93,6 +93,7 @@
     private var secondTaskId: Int = INVALID_TASK_ID
     private var initialIntent: Intent? = null
     private var secondIntent: Intent? = null
+    private var widgetSecondIntent: Intent? = null
     private var initialUser: UserHandle? = null
     private var secondUser: UserHandle? = null
     private var initialPendingIntent: PendingIntent? = null
@@ -167,6 +168,16 @@
         secondUser = pendingIntent.creatorUserHandle
     }
 
+    /**
+     * Similar to [setSecondTask] except this is to be called for widgets which can pass through
+     * an extra intent from their RemoteResponse.
+     * See [android.widget.RemoteViews.RemoteResponse.getLaunchOptions].first
+     */
+    fun setSecondWidget(pendingIntent: PendingIntent, widgetIntent: Intent?) {
+        setSecondTask(pendingIntent)
+        widgetSecondIntent = widgetIntent
+    }
+
     private fun getShortcutInfo(intent: Intent?, user: UserHandle?): ShortcutInfo? {
         val intentPackage = intent?.getPackage() ?: return null
         val shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID)
@@ -241,6 +252,7 @@
                 secondTaskId,
                 initialPendingIntent,
                 secondPendingIntent,
+                widgetSecondIntent,
                 initialUser?.identifier ?: -1,
                 secondUser?.identifier ?: -1,
                 initialShortcut,
@@ -257,7 +269,8 @@
      * Note that both [initialIntent] and [secondIntent] will be nullified on method return
      *
      * One caveat is that if [secondPendingIntent] is set, we will use that and *not* attempt to
-     * convert [secondIntent]
+     * convert [secondIntent].
+     * This also leaves [widgetSecondIntent] untouched.
      */
     private fun convertIntentsToFinalTypes() {
         initialShortcut = getShortcutInfo(initialIntent, initialUser)
@@ -343,6 +356,7 @@
             var secondTaskId: Int = INVALID_TASK_ID,
             var initialPendingIntent: PendingIntent? = null,
             var secondPendingIntent: PendingIntent? = null,
+            var widgetSecondIntent: Intent? = null,
             var initialUserId: Int = -1,
             var secondUserId: Int = -1,
             var initialShortcut: ShortcutInfo? = null,
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 145707b..8b27a85 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -32,6 +32,7 @@
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_SHORTCUT;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_TASK_TASK;
 import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
+import static com.android.wm.shell.common.split.SplitScreenConstants.KEY_EXTRA_WIDGET_INTENT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
 
 import android.animation.Animator;
@@ -355,6 +356,10 @@
         mSplitSelectDataHolder.setSecondTask(pendingIntent);
     }
 
+    public void setSecondWidget(PendingIntent pendingIntent, Intent widgetIntent) {
+        mSplitSelectDataHolder.setSecondWidget(pendingIntent, widgetIntent);
+    }
+
     /**
      * To be called when we want to launch split pairs from Overview. Split can be initiated from
      * either Overview or home, or all apps. Either both taskIds are set, or a pending intent + a
@@ -380,11 +385,13 @@
         ShortcutInfo secondShortcut = launchData.getSecondShortcut();
         PendingIntent firstPI = launchData.getInitialPendingIntent();
         PendingIntent secondPI = launchData.getSecondPendingIntent();
+        Intent widgetIntent = launchData.getWidgetSecondIntent();
         int firstUserId = launchData.getInitialUserId();
         int secondUserId = launchData.getSecondUserId();
         int initialStagePosition = launchData.getInitialStagePosition();
         Bundle optionsBundle = options1.toBundle();
-
+        Bundle extrasBundle = new Bundle(1);
+        extrasBundle.putParcelable(KEY_EXTRA_WIDGET_INTENT, widgetIntent);
         if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
             final RemoteTransition remoteTransition = getShellRemoteTransition(firstTaskId,
                     secondTaskId, callback, "LaunchSplitPair");
@@ -396,7 +403,7 @@
 
                 case SPLIT_TASK_PENDINGINTENT ->
                         mSystemUiProxy.startIntentAndTask(secondPI, secondUserId, optionsBundle,
-                                firstTaskId, null /*options2*/, initialStagePosition, snapPosition,
+                                firstTaskId, extrasBundle, initialStagePosition, snapPosition,
                                 remoteTransition, shellInstanceId);
 
                 case SPLIT_TASK_SHORTCUT ->
@@ -411,9 +418,9 @@
 
                 case SPLIT_PENDINGINTENT_PENDINGINTENT ->
                         mSystemUiProxy.startIntents(firstPI, firstUserId, firstShortcut,
-                                optionsBundle, secondPI, secondUserId, secondShortcut,
-                                null /*options2*/, initialStagePosition, snapPosition,
-                                remoteTransition, shellInstanceId);
+                                optionsBundle, secondPI, secondUserId, secondShortcut, extrasBundle,
+                                initialStagePosition, snapPosition, remoteTransition,
+                                shellInstanceId);
 
                 case SPLIT_SHORTCUT_TASK ->
                         mSystemUiProxy.startShortcutAndTask(firstShortcut, optionsBundle,
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index 9313342..e705285 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -72,7 +72,8 @@
      * @return {@code true} if we can attempt launch the widget into split, {@code false} otherwise
      *         to allow launcher to handle the click
      */
-    public boolean handleSecondWidgetSelectionForSplit(View view, PendingIntent pendingIntent) {
+    public boolean handleSecondWidgetSelectionForSplit(View view, PendingIntent pendingIntent,
+            Intent remoteResponseIntent) {
         if (shouldIgnoreSecondSplitLaunch()) {
             return false;
         }
@@ -86,7 +87,7 @@
             Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
 
             view.post(() -> {
-                mController.setSecondTask(pendingIntent);
+                mController.setSecondWidget(pendingIntent, remoteResponseIntent);
                 // Convert original widgetView into bitmap to use for animation
                 Canvas canvas = new Canvas(bitmap);
                 view.draw(canvas);
diff --git a/quickstep/src/com/android/quickstep/views/ActionButton.kt b/quickstep/src/com/android/quickstep/views/ActionButton.kt
new file mode 100644
index 0000000..5c004cc
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/ActionButton.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.views
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.Button
+
+/**
+ * A button on the Overview Actions Bar. Custom logic for hiding/showing each button type is handled
+ * in the respective subclass.
+ */
+open class ActionButton : Button {
+    private var mHiddenFlags = 0
+
+    constructor(context: Context) : super(context)
+    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+    constructor(
+        context: Context,
+        attrs: AttributeSet?,
+        defStyleAttr: Int
+    ) : super(context, attrs, defStyleAttr)
+
+    /**
+     * Updates the proper flags to indicate whether the button should be hidden.
+     *
+     * @param flag The flag to update.
+     * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
+     */
+    protected fun updateHiddenFlags(flag: Int, enable: Boolean) {
+        if (enable) {
+            mHiddenFlags = mHiddenFlags or flag
+        } else {
+            mHiddenFlags = mHiddenFlags and flag.inv()
+        }
+        val shouldBeVisible = mHiddenFlags == 0
+        this.visibility = if (shouldBeVisible) VISIBLE else GONE
+    }
+
+    /** Show/hide the button when the focused task is a single/pair. */
+    open fun updateForMultipleTasks(hasMultipleTasks: Boolean) {
+        // overridden in subclass, or else don't do anything
+    }
+
+    /** Show/hide the button depending on if the device is a tablet. */
+    open fun updateForTablet(isTablet: Boolean) {
+        // overridden in subclass, or else don't do anything
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index b549058..a5c94c5 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -22,7 +22,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.widget.Button;
 import android.widget.FrameLayout;
 
 import androidx.annotation.IntDef;
@@ -41,6 +40,8 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * View for showing action buttons in Overview
@@ -89,14 +90,11 @@
     private static final int INDEX_SCROLL_ALPHA = 5;
     private static final int NUM_ALPHAS = 6;
 
-    public @interface SplitButtonHiddenFlags { }
-    public static final int FLAG_IS_NOT_TABLET = 1 << 0;
-
-    public @interface SplitButtonDisabledFlags { }
-    public static final int FLAG_SINGLE_TASK = 1 << 0;
-
     private MultiValueAlpha mMultiValueAlpha;
-    private Button mSplitButton;
+
+    protected List<ActionButton> mActionButtons = new ArrayList<>();
+    private ScreenshotActionButton mScreenshotButton;
+    private SplitActionButton mSplitButton;
 
     @ActionsHiddenFlags
     private int mHiddenFlags;
@@ -104,12 +102,6 @@
     @ActionsDisabledFlags
     protected int mDisabledFlags;
 
-    @SplitButtonHiddenFlags
-    private int mSplitButtonHiddenFlags;
-
-    @SplitButtonDisabledFlags
-    private int mSplitButtonDisabledFlags;
-
     @Nullable
     protected T mCallbacks;
 
@@ -135,9 +127,12 @@
         mMultiValueAlpha = new MultiValueAlpha(findViewById(R.id.action_buttons), NUM_ALPHAS);
         mMultiValueAlpha.setUpdateVisibility(true);
 
-        findViewById(R.id.action_screenshot).setOnClickListener(this);
+        mScreenshotButton = findViewById(R.id.action_screenshot);
+        mScreenshotButton.setOnClickListener(this);
+        mActionButtons.add(mScreenshotButton);
         mSplitButton = findViewById(R.id.action_split);
         mSplitButton.setOnClickListener(this);
+        mActionButtons.add(mSplitButton);
     }
 
     /**
@@ -201,40 +196,28 @@
         }
         boolean isEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
         LayoutUtils.setViewEnabled(this, isEnabled);
-        updateSplitButtonEnabledState();
     }
 
     /**
-     * Updates the proper flags to indicate whether the "Split screen" button should be hidden.
-     *
-     * @param flag   The flag to update.
-     * @param enable Whether to enable the hidden flag: True will cause view to be hidden.
+     * Updates flags to hide and show actions buttons when a grouped task (split screen) is focused.
+     * @param isGroupedTask True if the focused task is a grouped task.
      */
-    public void updateSplitButtonHiddenFlags(@SplitButtonHiddenFlags int flag, boolean enable) {
-        if (enable) {
-            mSplitButtonHiddenFlags |= flag;
-        } else {
-            mSplitButtonHiddenFlags &= ~flag;
+    public void updateForGroupedTask(boolean isGroupedTask) {
+        for (ActionButton button : mActionButtons) {
+            // Update flags to show/hide buttons.
+            button.updateForMultipleTasks(isGroupedTask);
         }
-        if (mSplitButton == null) return;
-        boolean shouldBeVisible = mSplitButtonHiddenFlags == 0;
-        mSplitButton.setVisibility(shouldBeVisible ? VISIBLE : GONE);
-        findViewById(R.id.action_split_space).setVisibility(shouldBeVisible ? VISIBLE : GONE);
     }
 
     /**
-     * Updates the proper flags to indicate whether the "Split screen" button should be disabled.
-     *
-     * @param flag   The flag to update.
-     * @param enable Whether to enable the disable flag: True will cause view to be disabled.
+     * Updates flags to hide and show actions buttons depending on if the device is a tablet.
+     * @param isTablet True if the current device is a tablet.
      */
-    public void updateSplitButtonDisabledFlags(@SplitButtonDisabledFlags int flag, boolean enable) {
-        if (enable) {
-            mSplitButtonDisabledFlags |= flag;
-        } else {
-            mSplitButtonDisabledFlags &= ~flag;
+    public void updateForTablet(boolean isTablet) {
+        for (ActionButton button : mActionButtons) {
+            // Update flags to show/hide buttons.
+            button.updateForTablet(isTablet);
         }
-        updateSplitButtonEnabledState();
     }
 
     public MultiProperty getContentAlpha() {
@@ -313,18 +296,4 @@
                 : R.drawable.ic_split_vertical;
         mSplitButton.setCompoundDrawablesRelativeWithIntrinsicBounds(splitIconRes, 0, 0, 0);
     }
-
-    /**
-     * Enables/disables the "Split" button based on the status of mSplitButtonDisabledFlags and
-     * mDisabledFlags.
-     */
-    private void updateSplitButtonEnabledState() {
-        if (mSplitButton == null) {
-            return;
-        }
-        boolean isParentEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
-        boolean shouldBeEnabled = mSplitButtonDisabledFlags == 0 && isParentEnabled;
-        mSplitButton.setEnabled(shouldBeEnabled);
-    }
-
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 7e1034b..c56b5bb 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -20,7 +20,6 @@
 import static android.view.Surface.ROTATION_0;
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.makeMeasureSpec;
-
 import static com.android.app.animation.Interpolators.ACCELERATE;
 import static com.android.app.animation.Interpolators.ACCELERATE_0_75;
 import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
@@ -62,8 +61,6 @@
 import static com.android.quickstep.util.TaskGridNavHelper.DIRECTION_UP;
 import static com.android.quickstep.views.ClearAllButton.DISMISS_ALPHA;
 import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
-import static com.android.quickstep.views.OverviewActionsView.FLAG_IS_NOT_TABLET;
-import static com.android.quickstep.views.OverviewActionsView.FLAG_SINGLE_TASK;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_ACTIONS_IN_MENU;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_DESKTOP;
 import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NON_ZERO_ROTATION;
@@ -3941,18 +3938,23 @@
     }
 
     /**
-     * Hides all overview actions if current page is for split apps, shows otherwise
-     * If actions are showing, we only show split option if
+     * Hides all overview actions if user is halfway through split selection, shows otherwise.
+     * We only show split option if:
+     * * Focused view is a single app
      * * Device is large screen
-     * * There are at least 2 tasks to invoke split
      */
     private void updateCurrentTaskActionsVisibility() {
-        boolean isCurrentSplit = getCurrentPageTaskView() instanceof GroupedTaskView;
-        mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isCurrentSplit);
+        boolean isGroupedTask = getCurrentPageTaskView() != null
+                && getCurrentPageTaskView().containsMultipleTasks();
+        // Update flags to see if entire actions bar should be hidden.
+        mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SCREEN, isGroupedTask);
         mActionsView.updateHiddenFlags(HIDDEN_SPLIT_SELECT_ACTIVE, isSplitSelectionActive());
-        mActionsView.updateSplitButtonHiddenFlags(FLAG_IS_NOT_TABLET,
-                !mActivity.getDeviceProfile().isTablet);
-        mActionsView.updateSplitButtonDisabledFlags(FLAG_SINGLE_TASK, /*enable=*/ false);
+        // Update flags to see if actions bar should show buttons for a single task or a pair of
+        // tasks.
+        mActionsView.updateForGroupedTask(isGroupedTask);
+        // Update flags to see if split button should be hidden.
+        mActionsView.updateForTablet(mActivity.getDeviceProfile().isTablet);
+
         if (isDesktopModeSupported()) {
             boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
             mActionsView.updateHiddenFlags(HIDDEN_DESKTOP, isCurrentDesktop);
diff --git a/quickstep/src/com/android/quickstep/views/ScreenshotActionButton.kt b/quickstep/src/com/android/quickstep/views/ScreenshotActionButton.kt
new file mode 100644
index 0000000..9cb48b8
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/ScreenshotActionButton.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.views
+
+import android.content.Context
+import android.util.AttributeSet
+
+/** A button on the Overview Actions Bar for screenshotting the focused app. */
+class ScreenshotActionButton : ActionButton {
+    companion object {
+        const val FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT = 1 shl 0
+    }
+
+    constructor(context: Context) : super(context)
+    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+    constructor(
+        context: Context,
+        attrs: AttributeSet?,
+        defStyleAttr: Int
+    ) : super(context, attrs, defStyleAttr)
+
+    /** Show/hide the button when the focused task is a single/pair. */
+    override fun updateForMultipleTasks(hasMultipleTasks: Boolean) {
+        // Hidden for multiple tasks
+        updateHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT, hasMultipleTasks)
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/SplitActionButton.kt b/quickstep/src/com/android/quickstep/views/SplitActionButton.kt
new file mode 100644
index 0000000..88d1a77
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/SplitActionButton.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.views
+
+import android.content.Context
+import android.util.AttributeSet
+
+/** A button on the Overview Actions Bar for initiating split screen. */
+class SplitActionButton : ActionButton {
+    companion object {
+        const val FLAG_IS_NOT_TABLET_HIDE_SPLIT = 1 shl 0
+        const val FLAG_MULTIPLE_TASKS_HIDE_SPLIT = 1 shl 1
+    }
+
+    constructor(context: Context) : super(context)
+    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+    constructor(
+        context: Context,
+        attrs: AttributeSet?,
+        defStyleAttr: Int
+    ) : super(context, attrs, defStyleAttr)
+
+    /** Show/hide the button when the focused task is a single/pair. */
+    override fun updateForMultipleTasks(hasMultipleTasks: Boolean) {
+        // Hidden for multiple tasks
+        updateHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SPLIT, hasMultipleTasks)
+    }
+
+    /** Show/hide the button depending on if the device is a tablet. */
+    override fun updateForTablet(isTablet: Boolean) {
+        // Hidden for non-tablets
+        updateHiddenFlags(FLAG_IS_NOT_TABLET_HIDE_SPLIT, !isTablet)
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
index 9a2826d..c9e536a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
@@ -20,9 +20,10 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
 
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -32,17 +33,10 @@
 
     @Test
     @TaskbarModeSwitch(mode = PERSISTENT)
-    public void testHideShowTaskbar() {
-        getTaskbar().hide();
-        mLauncher.getLaunchedAppState().showTaskbar();
-    }
-
-    @Test
-    @TaskbarModeSwitch(mode = PERSISTENT)
-    @Ignore // b/301575789
-    public void testHideTaskbarPersistsOnRecreate() {
-        getTaskbar().hide();
-        mLauncher.recreateTaskbar();
-        mLauncher.getLaunchedAppState().assertTaskbarHidden();
+    @PortraitLandscape
+    @NavigationModeSwitch
+    public void testTaskbarFillsWidth() {
+        // Width check is performed inside TAPL whenever getTaskbar() is called.
+        getTaskbar();
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index b3cc215..0bcdb19 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -18,7 +18,6 @@
 
 import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
 import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-import static com.android.quickstep.TaskbarModeSwitchRule.Mode.PERSISTENT;
 import static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
 
 import static org.junit.Assert.assertEquals;
@@ -295,7 +294,8 @@
     }
 
     @Test
-    @TaskbarModeSwitch(mode = PERSISTENT)
+    @TaskbarModeSwitch
+    @Ignore // b/314873201
     public void testQuickSwitchToPreviousAppForTablet() throws Exception {
         assumeTrue(mLauncher.isTablet());
         startTestActivity(2);
@@ -304,22 +304,33 @@
         // Set ignoreTaskbarVisibility to true to verify the task bar visibility explicitly.
         mLauncher.setIgnoreTaskbarVisibility(true);
 
-        // Expect task bar invisible when the launched app was the IME activity.
-        LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
-        if (isHardwareKeyboard()) {
-            launchedAppState.assertTaskbarVisible();
-        } else {
-            launchedAppState.assertTaskbarHidden();
+
+        try {
+            boolean isTransientTaskbar = mLauncher.isTransientTaskbar();
+            // Expect task bar invisible when the launched app was the IME activity.
+            LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
+            if (!isTransientTaskbar && isHardwareKeyboard()) {
+                launchedAppState.assertTaskbarVisible();
+            } else {
+                launchedAppState.assertTaskbarHidden();
+            }
+
+            // Quick-switch to the test app with swiping to right.
+            quickSwitchToPreviousAppAndAssert(true /* toRight */);
+
+            assertTestActivityIsRunning(2,
+                    "The first app we should have quick switched to is not running");
+            launchedAppState = getAndAssertLaunchedApp();
+            if (isTransientTaskbar) {
+                launchedAppState.assertTaskbarHidden();
+            } else {
+                // Expect taskbar visible when the launched app was the test activity.
+                launchedAppState.assertTaskbarVisible();
+            }
+        } finally {
+            // Reset ignoreTaskbarVisibility to ensure other tests still verify it.
+            mLauncher.setIgnoreTaskbarVisibility(false);
         }
-
-        // Quick-switch to the test app with swiping to right.
-        quickSwitchToPreviousAppAndAssert(true /* toRight */);
-
-        assertTestActivityIsRunning(2,
-                "The first app we should have quick switched to is not running");
-        // Expect task bar visible when the launched app was the test activity.
-        launchedAppState = getAndAssertLaunchedApp();
-        launchedAppState.assertTaskbarVisible();
     }
 
     private boolean isHardwareKeyboard() {
@@ -358,7 +369,7 @@
 
     @Test
     @PortraitLandscape
-    @TaskbarModeSwitch(mode = PERSISTENT)
+    @TaskbarModeSwitch()
     @PlatinumTest(focusArea = "launcher")
     @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/309820115
     @ScreenRecord // b/309820115
@@ -454,6 +465,7 @@
 
     @Test
     @PortraitLandscape
+    @TaskbarModeSwitch
     public void testTaskbarDeadzonesForTablet() throws Exception {
         assumeTrue(mLauncher.isTablet());
 
@@ -466,15 +478,29 @@
                 launcher -> assertTrue("Should have at least 3 tasks",
                         getTaskCount(launcher) >= 3));
 
-        // On persistent taskbar, it should not dismiss when tapping the taskbar
-        overview.touchTaskbarBottomCorner(/* tapRight= */ false);
-        assertTrue("Launcher internal state should be Overview",
-                isInState(() -> LauncherState.OVERVIEW));
+        if (mLauncher.isTransientTaskbar()) {
+            // On transient taskbar, it should dismiss when tapping outside taskbar bounds.
+            overview.touchTaskbarBottomCorner(/* tapRight= */ false);
+            assertTrue("Launcher internal state should be Normal",
+                    isInState(() -> LauncherState.NORMAL));
 
-        // On persistent taskbar, it should not dismiss when tapping the taskbar
-        overview.touchTaskbarBottomCorner(/* tapRight= */ true);
-        assertTrue("Launcher internal state should be Overview",
-                isInState(() -> LauncherState.OVERVIEW));
+            overview = mLauncher.getWorkspace().switchToOverview();
+
+            // On transient taskbar, it should dismiss when tapping outside taskbar bounds.
+            overview.touchTaskbarBottomCorner(/* tapRight= */ true);
+            assertTrue("Launcher internal state should be Normal",
+                    isInState(() -> LauncherState.NORMAL));
+        } else {
+            // On persistent taskbar, it should not dismiss when tapping the taskbar
+            overview.touchTaskbarBottomCorner(/* tapRight= */ false);
+            assertTrue("Launcher internal state should be Overview",
+                    isInState(() -> LauncherState.OVERVIEW));
+
+            // On persistent taskbar, it should not dismiss when tapping the taskbar
+            overview.touchTaskbarBottomCorner(/* tapRight= */ true);
+            assertTrue("Launcher internal state should be Overview",
+                    isInState(() -> LauncherState.OVERVIEW));
+        }
     }
 
     @Test
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
index db23cc0..7109bbf 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
@@ -24,6 +24,7 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
 
 import org.junit.Test;
@@ -64,4 +65,12 @@
         getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
         mLauncher.getLaunchedAppState().clickStashedTaskbarToGoHome();
     }
+
+    @Test
+    @TaskbarModeSwitch(mode = TRANSIENT)
+    @PortraitLandscape
+    public void testSwipeToStashAndUnstash() {
+        getTaskbar().swipeDownToStash();
+        mLauncher.getLaunchedAppState().swipeUpToUnstashTaskbar();
+    }
 }
diff --git a/res/layout/widgets_two_pane_sheet_foldable.xml b/res/layout/widgets_two_pane_sheet_foldable.xml
new file mode 100644
index 0000000..93c0c70
--- /dev/null
+++ b/res/layout/widgets_two_pane_sheet_foldable.xml
@@ -0,0 +1,131 @@
+<?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.widget.picker.WidgetsTwoPaneSheet
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:orientation="vertical"
+    android:theme="?attr/widgetsTheme">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:focusable="true"
+        android:importantForAccessibility="no">
+
+        <View
+            android:id="@+id/collapse_handle"
+            android:gravity="center_horizontal"
+            android:layout_width="@dimen/bottom_sheet_handle_width"
+            android:layout_height="@dimen/bottom_sheet_handle_height"
+            android:layout_marginTop="@dimen/bottom_sheet_handle_margin"
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            android:background="@drawable/widget_picker_collapse_handle"/>
+
+        <TextView
+            android:id="@+id/title"
+            android:gravity="center_horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="24dp"
+            android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
+            android:text="@string/widget_button_text"
+            app:layout_constraintTop_toBottomOf="@id/collapse_handle"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            android:textColor="?attr/widgetPickerTitleColor"
+            android:textSize="24sp" />
+
+        <FrameLayout
+            android:id="@+id/recycler_view_container"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            app:layout_constraintTop_toBottomOf="@id/title"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintWidth_percent="0.33"
+            app:layout_constraintWidth_min="254dp"
+            app:layout_constraintWidth_max="395dp">
+            <TextView
+                android:id="@+id/fast_scroller_popup"
+                style="@style/FastScrollerPopup"
+                android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
+
+            <!-- Fast scroller popup -->
+            <com.android.launcher3.views.RecyclerViewFastScroller
+                android:id="@+id/fast_scroller"
+                android:layout_width="@dimen/fastscroll_width"
+                android:layout_height="match_parent"
+                android:layout_marginEnd="@dimen/fastscroll_end_margin" />
+
+            <com.android.launcher3.widget.picker.WidgetsRecyclerView
+                android:id="@+id/search_widgets_list_view"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:clipToPadding="false"
+                android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
+                android:visibility="gone" />
+        </FrameLayout>
+
+        <FrameLayout
+            android:id="@+id/right_pane_container"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginEnd="@dimen/widget_list_horizontal_margin_two_pane"
+            android:paddingTop="@dimen/widget_list_horizontal_margin_two_pane"
+            app:layout_constraintTop_toBottomOf="@id/title"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toEndOf="@id/recycler_view_container"
+            app:layout_constraintEnd_toEndOf="parent">
+            <TextView
+                android:id="@+id/no_widgets_text"
+                style="@style/PrimaryHeadline"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:gravity="center"
+                android:textSize="18sp"
+                android:visibility="gone"
+                tools:text="No widgets available" />
+            <ScrollView
+                android:id="@+id/right_pane_scroll_view"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:fillViewport="true">
+                <LinearLayout
+                    android:orientation="vertical"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_vertical"
+                    android:clipToOutline="true"
+                    android:paddingBottom="36dp"
+                    android:background="@drawable/widgets_surface_background"
+                    android:id="@+id/right_pane">
+                    <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
+                        android:id="@+id/recommended_widget_table"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:paddingHorizontal=
+                            "@dimen/widget_list_horizontal_margin_two_pane"
+                        android:visibility="gone" />
+                </LinearLayout>
+            </ScrollView>
+        </FrameLayout>
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</com.android.launcher3.widget.picker.WidgetsTwoPaneSheet>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 025003b..242c439 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -176,6 +176,7 @@
     <dimen name="widget_tabs_horizontal_padding">16dp</dimen>
     <dimen name="widget_apps_tabs_vertical_padding">6dp</dimen>
     <dimen name="widget_picker_landscape_tablet_left_right_margin">117dp</dimen>
+    <dimen name="widget_picker_two_panels_left_right_margin">0dp</dimen>
 
     <dimen name="recommended_widgets_table_vertical_padding">8dp</dimen>
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0278e4f..126efbb 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -22,7 +22,6 @@
 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
 import static com.android.launcher3.AbstractFloatingView.TYPE_FOLDER;
 import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE;
 import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
@@ -351,14 +350,9 @@
     // UI and state for the overview panel
     private View mOverviewPanel;
 
-    @Thunk
-    boolean mWorkspaceLoading = true;
-
     // Used to notify when an activity launch has been deferred because launcher is not yet resumed
     // TODO: See if we can remove this later
     private Runnable mOnDeferredActivityLaunchCallback;
-
-    private ViewOnDrawExecutor mPendingExecutor;
     private OnPreDrawListener mOnInitialBindListener;
 
     private LauncherModel mModel;
@@ -1075,7 +1069,7 @@
     }
 
     private void logStopAndResume(boolean isResume) {
-        if (mPendingExecutor != null) return;
+        if (mModelCallbacks.getPendingExecutor() != null) return;
         int pageIndex = mWorkspace.isOverlayShown() ? -1 : mWorkspace.getCurrentPage();
         int statsLogOrdinal = mStateManager.getState().statsLogOrdinal;
 
@@ -1715,7 +1709,7 @@
         mAppWidgetHolder.destroy();
 
         TextKeyListener.getInstance().release();
-        clearPendingBinds();
+        mModelCallbacks.clearPendingBinds();
         LauncherAppState.getIDP(this).removeOnChangeListener(this);
 
         mOverlayManager.onActivityDestroyed();
@@ -2077,48 +2071,9 @@
         return mModelCallbacks.getPagesToBindSynchronously(orderedScreenIds);
     }
 
-    /**
-     * Clear any pending bind callbacks. This is called when is loader is planning to
-     * perform a full rebind from scratch.
-     */
-    @Override
-    public void clearPendingBinds() {
-        if (mPendingExecutor != null) {
-            mPendingExecutor.cancel();
-            mPendingExecutor = null;
-
-            // We might have set this flag previously and forgot to clear it.
-            mAppsView.getAppsStore()
-                    .disableDeferUpdatesSilently(AllAppsStore.DEFER_UPDATES_NEXT_DRAW);
-        }
-    }
-
-    /**
-     * Refreshes the shortcuts shown on the workspace.
-     * <p>
-     * Implementation of the method from LauncherModel.Callbacks.
-     */
     @Override
     public void startBinding() {
-        TraceHelper.INSTANCE.beginSection("startBinding");
-        // Floating panels (except the full widget sheet) are associated with individual icons. If
-        // we are starting a fresh bind, close all such panels as all the icons are about
-        // to go away.
-        AbstractFloatingView.closeOpenViews(this, true, TYPE_ALL & ~TYPE_REBIND_SAFE);
-
-        setWorkspaceLoading(true);
-
-        // Clear the workspace because it's going to be rebound
-        mDragController.cancelDrag();
-
-        mWorkspace.clearDropTargets();
-        mWorkspace.removeAllWorkspaceScreens();
-        mAppWidgetHolder.clearViews();
-
-        if (mHotseat != null) {
-            mHotseat.resetLayout(getDeviceProfile().isVerticalBarLayout());
-        }
-        TraceHelper.INSTANCE.endSection();
+        mModelCallbacks.startBinding();
     }
 
     @Override
@@ -2500,8 +2455,8 @@
     }
 
     public void clearPendingExecutor(ViewOnDrawExecutor executor) {
-        if (mPendingExecutor == executor) {
-            mPendingExecutor = null;
+        if (mModelCallbacks.getPendingExecutor() == executor) {
+            mModelCallbacks.setPendingExecutor(null);
         }
     }
 
@@ -2512,9 +2467,9 @@
         mModelCallbacks.setSynchronouslyBoundPages(boundPages);
         mModelCallbacks.setPagesToBindSynchronously(new IntSet());
 
-        clearPendingBinds();
+        mModelCallbacks.clearPendingBinds();
         ViewOnDrawExecutor executor = new ViewOnDrawExecutor(pendingTasks);
-        mPendingExecutor = executor;
+        mModelCallbacks.setPendingExecutor(executor);
         if (!isInState(ALL_APPS)) {
             mAppsView.getAppsStore().enableDeferUpdates(AllAppsStore.DEFER_UPDATES_NEXT_DRAW);
             pendingTasks.add(() -> mAppsView.getAppsStore().disableDeferUpdates(
@@ -2568,7 +2523,7 @@
         TraceHelper.INSTANCE.beginSection("finishBindingItems");
         mWorkspace.restoreInstanceStateForRemainingPages();
 
-        setWorkspaceLoading(false);
+        mModelCallbacks.setWorkspaceLoading(false);
 
         if (mPendingActivityResult != null) {
             handleActivityResult(mPendingActivityResult.requestCode,
@@ -2851,7 +2806,7 @@
 
         writer.println(prefix + "Misc:");
         dumpMisc(prefix + "\t", writer);
-        writer.println(prefix + "\tmWorkspaceLoading=" + mWorkspaceLoading);
+        writer.println(prefix + "\tmWorkspaceLoading=" + mModelCallbacks.getWorkspaceLoading());
         writer.println(prefix + "\tmPendingRequestArgs=" + mPendingRequestArgs
                 + " mPendingActivityResult=" + mPendingActivityResult);
         writer.println(prefix + "\tmRotationHelper: " + mRotationHelper);
@@ -3079,21 +3034,17 @@
 
     // Getters and Setters
 
-    private void setWorkspaceLoading(boolean value) {
-        mWorkspaceLoading = value;
-    }
-
     public boolean isWorkspaceLocked() {
-        return mWorkspaceLoading || mPendingRequestArgs != null;
+        return isWorkspaceLoading() || mPendingRequestArgs != null;
     }
 
     public boolean isWorkspaceLoading() {
-        return mWorkspaceLoading;
+        return mModelCallbacks.getWorkspaceLoading();
     }
 
     @Override
     public boolean isBindingItems() {
-        return mWorkspaceLoading;
+        return isWorkspaceLoading();
     }
 
     /**
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index bcd30d3..51d7690 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -2,6 +2,7 @@
 
 import androidx.annotation.UiThread
 import com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID
+import com.android.launcher3.allapps.AllAppsStore
 import com.android.launcher3.config.FeatureFlags
 import com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget
 import com.android.launcher3.model.BgDataModel
@@ -18,6 +19,8 @@
 import com.android.launcher3.util.IntSet
 import com.android.launcher3.util.PackageUserKey
 import com.android.launcher3.util.Preconditions
+import com.android.launcher3.util.TraceHelper
+import com.android.launcher3.util.ViewOnDrawExecutor
 import com.android.launcher3.widget.PendingAddWidgetInfo
 import com.android.launcher3.widget.model.WidgetsListBaseEntry
 import java.util.function.Predicate
@@ -27,11 +30,55 @@
     var synchronouslyBoundPages = LIntSet()
     var pagesToBindSynchronously = LIntSet()
 
-    var isFirstPagePinnedItemEnabled =
+    private var isFirstPagePinnedItemEnabled =
         (BuildConfig.QSB_ON_FIRST_SCREEN && !FeatureFlags.ENABLE_SMARTSPACE_REMOVAL.get())
 
     var stringCache: StringCache? = null
 
+    var pendingExecutor: ViewOnDrawExecutor? = null
+
+    var workspaceLoading = true
+
+    /**
+     * Refreshes the shortcuts shown on the workspace.
+     *
+     * Implementation of the method from LauncherModel.Callbacks.
+     */
+    override fun startBinding() {
+        TraceHelper.INSTANCE.beginSection("startBinding")
+        // Floating panels (except the full widget sheet) are associated with individual icons. If
+        // we are starting a fresh bind, close all such panels as all the icons are about
+        // to go away.
+        AbstractFloatingView.closeOpenViews(
+            launcher,
+            true,
+            AbstractFloatingView.TYPE_ALL and AbstractFloatingView.TYPE_REBIND_SAFE.inv()
+        )
+        workspaceLoading = true
+
+        // Clear the workspace because it's going to be rebound
+        launcher.dragController.cancelDrag()
+        launcher.workspace.clearDropTargets()
+        launcher.workspace.removeAllWorkspaceScreens()
+        launcher.appWidgetHolder.clearViews()
+        launcher.hotseat?.resetLayout(launcher.deviceProfile.isVerticalBarLayout)
+        TraceHelper.INSTANCE.endSection()
+    }
+
+    /**
+     * Clear any pending bind callbacks. This is called when is loader is planning to perform a full
+     * rebind from scratch.
+     */
+    override fun clearPendingBinds() {
+        pendingExecutor?.cancel() ?: return
+        pendingExecutor = null
+
+        // We might have set this flag previously and forgot to clear it.
+        launcher.appsView.appsStore.disableDeferUpdatesSilently(
+            AllAppsStore.DEFER_UPDATES_NEXT_DRAW
+        )
+    }
+
     override fun preAddApps() {
         // If there's an undo snackbar, force it to complete to ensure empty screens are removed
         // before trying to add new items.
@@ -119,7 +166,7 @@
         val visibleIds =
             when {
                 !pagesToBindSynchronously.isEmpty -> pagesToBindSynchronously
-                !launcher.isWorkspaceLoading -> launcher.workspace.currentPageScreenIds
+                !workspaceLoading -> launcher.workspace.currentPageScreenIds
                 else -> synchronouslyBoundPages
             }
         // Launcher IntArray has the same name as Kotlin IntArray
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index b74699a..e0f6101 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -79,7 +79,6 @@
 
 import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
 import com.android.launcher3.graphics.TintedDrawableSpan;
-import com.android.launcher3.icons.BaseIconFactory;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.icons.ShortcutCachingLogic;
@@ -91,6 +90,7 @@
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.launcher3.testing.shared.ResourceUtils;
+import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.Themes;
@@ -676,12 +676,11 @@
         }
 
         if (badge == null) {
-            try (LauncherIcons li = LauncherIcons.obtain(context)) {
-                badge = BitmapInfo.LOW_RES_INFO.withFlags(
-                                li.getBitmapFlagOp(new BaseIconFactory.IconOptions().setUser(
-                                        UserCache.INSTANCE.get(context).getUserInfo(info.user))))
-                        .getBadgeDrawable(context, useTheme);
-            }
+            badge = BitmapInfo.LOW_RES_INFO.withFlags(
+                            UserCache.INSTANCE.get(context)
+                                    .getUserInfo(info.user)
+                                    .applyBitmapInfoFlags(FlagOp.NO_OP))
+                    .getBadgeDrawable(context, useTheme);
             if (badge == null) {
                 badge = new ColorDrawable(Color.TRANSPARENT);
             }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index bed6efb..746f1cf 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -270,10 +270,6 @@
     public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693,
             "IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps");
 
-    public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(270391653,
-            "ENABLE_PEOPLE_TILE_PREVIEW", DISABLED,
-            "Experimental: Shows conversation shortcuts on home screen as search results");
-
     public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag(270391638,
             "FOLDER_NAME_MAJORITY_RANKING", ENABLED,
             "Suggests folder names based on majority based ranking.");
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 1b1d347..2c834bd 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -47,6 +47,7 @@
 import com.android.launcher3.testing.shared.HotseatCellCenterRequest;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.testing.shared.WorkspaceCellCenterRequest;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.ResourceBasedOverride;
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
 
@@ -179,6 +180,11 @@
                         mDeviceProfile.numShownAllAppsColumns);
                 return response;
 
+            case TestProtocol.REQUEST_IS_TRANSIENT_TASKBAR:
+                response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        DisplayController.isTransientTaskbar(mContext));
+                return response;
+
             case TestProtocol.REQUEST_IS_TWO_PANELS:
                 response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
                         FOLDABLE_SINGLE_PAGE.get() ? false : mDeviceProfile.isTwoPanels);
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 4c83668..045ca79 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -71,7 +71,7 @@
 
     private static final String TAG = "DisplayController";
     private static final boolean DEBUG = false;
-    private static boolean sTransientTaskbarStatusForTests;
+    private static boolean sTransientTaskbarStatusForTests = true;
 
     // TODO(b/254119092) remove all logs with this tag
     public static final String TASKBAR_NOT_DESTROYED_TAG = "b/254119092";
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index e4df413..a1cd697 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -41,6 +41,7 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.testing.shared.ResourceUtils;
 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.TouchController;
@@ -559,7 +560,8 @@
             DeviceProfile dp = mActivity.getDeviceProfile();
             if (dp.isTaskbarPresent) {
                 // Ignore taskbar gesture insets to avoid interfering with TouchControllers.
-                gestureInsetBottom = Math.max(0, gestureInsetBottom - dp.taskbarHeight);
+                gestureInsetBottom = ResourceUtils.getNavbarSize(
+                        ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources());
             }
             mSystemGestureRegion.set(
                     Math.max(gestureInsets.left, imeInset.left),
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index cbc85b6..5cdad03 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -166,12 +166,16 @@
         return show(activityContext, targetRect, items, shouldAddArrow, 0 /* width */);
     }
 
-    public static <T extends Context & ActivityContext> OptionsPopupView<T> show(
-            ActivityContext activityContext,
+    @Nullable
+    private static <T extends Context & ActivityContext> OptionsPopupView<T> show(
+            @Nullable ActivityContext activityContext,
             RectF targetRect,
             List<OptionItem> items,
             boolean shouldAddArrow,
             int width) {
+        if (activityContext == null) {
+            return null;
+        }
         OptionsPopupView<T> popup = (OptionsPopupView<T>) activityContext.getLayoutInflater()
                 .inflate(R.layout.longpress_options_menu, activityContext.getDragLayer(), false);
         popup.mTargetRect = targetRect;
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 9855b20..9adc2ee 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.widget;
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
 import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_TIP_SEEN;
 
 import android.content.Context;
@@ -182,12 +183,8 @@
         DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         int widthUsed;
         if (deviceProfile.isTablet) {
-            int margin = deviceProfile.allAppsLeftRightMargin;
-            if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
-                margin = getResources().getDimensionPixelSize(
-                        R.dimen.widget_picker_landscape_tablet_left_right_margin);
-            }
-            widthUsed = Math.max(2 * margin, 2 * (mInsets.left + mInsets.right));
+            widthUsed = Math.max(2 * getTabletMargin(deviceProfile),
+                    2 * (mInsets.left + mInsets.right));
         } else if (mInsets.bottom > 0) {
             widthUsed = mInsets.left + mInsets.right;
         } else {
@@ -202,6 +199,18 @@
                 MeasureSpec.getSize(heightMeasureSpec));
     }
 
+    private int getTabletMargin(DeviceProfile deviceProfile) {
+        if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
+            return getResources().getDimensionPixelSize(
+                    R.dimen.widget_picker_landscape_tablet_left_right_margin);
+        }
+        if (deviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
+            return getResources().getDimensionPixelSize(
+                    R.dimen.widget_picker_two_panels_left_right_margin);
+        }
+        return deviceProfile.allAppsLeftRightMargin;
+    }
+
     @Override
     protected Interpolator getIdleInterpolator() {
         return mActivityContext.getDeviceProfile().isTablet
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index da90f17..583ef1a 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -17,6 +17,7 @@
 
 import static android.view.View.MeasureSpec.makeMeasureSpec;
 
+import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_DIALOG_SEEN;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
@@ -62,7 +63,6 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.UserManagerState;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.pm.UserCache;
@@ -163,9 +163,7 @@
     private boolean mIsInSearchMode;
     private boolean mIsNoWidgetsViewNeeded;
     @Px private int mMaxSpanPerRow;
-    private final DeviceProfile mDeviceProfile;
-
-    private int mOrientation;
+    private DeviceProfile mDeviceProfile;
 
     protected TextView mNoWidgetsView;
     protected StickyHeaderLayout mSearchScrollView;
@@ -179,7 +177,6 @@
     public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mDeviceProfile = mActivityContext.getDeviceProfile();
-        mOrientation = context.getResources().getConfiguration().orientation;
         mUserCache = UserCache.INSTANCE.get(context);
         mHasWorkProfile = mUserCache.getUserProfiles()
                 .stream()
@@ -676,30 +673,31 @@
 
     /** Shows the {@link WidgetsFullSheet} on the launcher. */
     public static WidgetsFullSheet show(BaseActivity activity, boolean animate) {
-        boolean isTwoPane = activity.getDeviceProfile().isTablet
-                && activity.getDeviceProfile().isLandscape
-                && (!activity.getDeviceProfile().isTwoPanels
-                    || FeatureFlags.UNFOLDED_WIDGET_PICKER.get());
-
-        WidgetsFullSheet sheet;
-        if (isTwoPane) {
-            sheet = (WidgetsTwoPaneSheet) activity.getLayoutInflater().inflate(
-                    R.layout.widgets_two_pane_sheet,
-                    activity.getDragLayer(),
-                    false);
-        } else {
-            sheet = (WidgetsFullSheet) activity.getLayoutInflater().inflate(
-                    R.layout.widgets_full_sheet,
-                    activity.getDragLayer(),
-                    false);
-        }
-
+        WidgetsFullSheet sheet = (WidgetsFullSheet) activity.getLayoutInflater().inflate(
+                getWidgetSheetId(activity),
+                activity.getDragLayer(),
+                false);
         sheet.attachToContainer();
         sheet.mIsOpen = true;
         sheet.open(animate);
         return sheet;
     }
 
+    private static int getWidgetSheetId(BaseActivity activity) {
+        boolean isTwoPane = (activity.getDeviceProfile().isTablet
+                && activity.getDeviceProfile().isLandscape
+                && !activity.getDeviceProfile().isTwoPanels)
+                // Enables two pane picker for unfolded foldables if the flag is on.
+                || (activity.getDeviceProfile().isTwoPanels && enableUnfoldedTwoPanePicker());
+
+        if (isTwoPane && activity.getDeviceProfile().isTwoPanels) {
+            return R.layout.widgets_two_pane_sheet_foldable;
+        } else if (isTwoPane) {
+            return R.layout.widgets_two_pane_sheet;
+        }
+        return R.layout.widgets_full_sheet;
+    }
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         return isTouchOnScrollbar(ev) || super.onInterceptTouchEvent(ev);
@@ -790,17 +788,25 @@
         if (mIsInSearchMode) {
             mSearchBar.reset();
         }
+    }
 
-        // Checks the orientation of the screen
-        if (mOrientation != newConfig.orientation) {
-            mOrientation = newConfig.orientation;
-            if (mDeviceProfile.isTablet && !mDeviceProfile.isTwoPanels) {
-                handleClose(false);
-                show(BaseActivity.fromContext(getContext()), false);
-            } else {
-                reset();
-            }
+    @Override
+    public void onDeviceProfileChanged(DeviceProfile dp) {
+        if (mDeviceProfile.isLandscape != dp.isLandscape && dp.isTablet && !dp.isTwoPanels) {
+            handleClose(false);
+            show(BaseActivity.fromContext(getContext()), false);
+        } else {
+            reset();
         }
+
+        // When folding/unfolding the foldables, we need to switch between the regular widget picker
+        // and the two pane picker, so we rebuild the picker with the correct layout.
+        if (mDeviceProfile.isTwoPanels != dp.isTwoPanels && enableUnfoldedTwoPanePicker()) {
+            handleClose(false);
+            show(BaseActivity.fromContext(getContext()), false);
+        }
+
+        mDeviceProfile = dp;
     }
 
     @Override
diff --git a/tests/assets/ReorderWidgets/full_reorder_case b/tests/assets/ReorderWidgets/full_reorder_case
index 33ebaae..850e4fd 100644
--- a/tests/assets/ReorderWidgets/full_reorder_case
+++ b/tests/assets/ReorderWidgets/full_reorder_case
@@ -20,7 +20,7 @@
 bbmm
 iimm
 iiaa
-arguments: 0 3
+arguments: 0 2
 board: 4x4
 xxxx
 bbii
diff --git a/tests/assets/ReorderWidgets/simple_reorder_case b/tests/assets/ReorderWidgets/simple_reorder_case
index f5eb7b6..2c50ce4 100644
--- a/tests/assets/ReorderWidgets/simple_reorder_case
+++ b/tests/assets/ReorderWidgets/simple_reorder_case
@@ -34,7 +34,7 @@
 --mm
 --mm
 ----
-arguments: 3 3
+arguments: 2 2
 board: 4x4
 xxxx
 ----
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index d5a645e..e19905f 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -30,6 +30,8 @@
     public static final String FOLDER_OPENED_MESSAGE = "TAPL_FOLDER_OPENED";
     public static final String SEARCH_RESULT_COMPLETE = "SEARCH_RESULT_COMPLETE";
     public static final String LAUNCHER_ACTIVITY_STOPPED_MESSAGE = "TAPL_LAUNCHER_ACTIVITY_STOPPED";
+    public static final String WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE =
+            "TAPL_WALLPAPER_OPEN_ANIMATION_FINISHED";
     public static final int NORMAL_STATE_ORDINAL = 0;
     public static final int SPRING_LOADED_STATE_ORDINAL = 1;
     public static final int OVERVIEW_STATE_ORDINAL = 2;
@@ -96,8 +98,9 @@
     public static final String REQUEST_DISABLE_BLOCK_TIMEOUT = "disable-block-timeout";
     public static final String REQUEST_ENABLE_TRANSIENT_TASKBAR = "enable-transient-taskbar";
     public static final String REQUEST_DISABLE_TRANSIENT_TASKBAR = "disable-transient-taskbar";
+    public static final String REQUEST_IS_TRANSIENT_TASKBAR = "is-transient-taskbar";
     public static final String REQUEST_UNSTASH_TASKBAR_IF_STASHED = "unstash-taskbar-if-stashed";
-    public static final String REQUEST_STASHED_TASKBAR_HEIGHT = "stashed-taskbar-height";
+    public static final String REQUEST_TASKBAR_FROM_NAV_THRESHOLD = "taskbar-from-nav-threshold";
     public static final String REQUEST_STASHED_TASKBAR_SCALE = "taskbar-stash-handle-scale";
     public static final String REQUEST_RECREATE_TASKBAR = "recreate-taskbar";
     public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index b2ce400..9fdd21a 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -82,7 +82,6 @@
         runTest(false);
     }
 
-
     /**
      * @param acceptConfig accept the config activity
      */
@@ -101,7 +100,7 @@
         // Verify that the widget id is valid and bound
         assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
 
-        setResult(acceptConfig);
+        setResultAndWaitForAnimation(acceptConfig);
         if (acceptConfig) {
             Wait.atMost("", new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT, mLauncher);
             assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
@@ -112,12 +111,22 @@
         }
     }
 
-    private void setResult(boolean success) {
+    private static void setResult(boolean success) {
         getInstrumentation().getTargetContext().sendBroadcast(
                 WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class,
                         success ? "clickOK" : "clickCancel"));
     }
 
+    private void setResultAndWaitForAnimation(boolean success) {
+        if (mLauncher.isLauncher3()) {
+            setResult(success);
+        } else {
+            mLauncher.executeAndWaitForWallpaperAnimation(
+                    () -> setResult(success),
+                    "setting widget coinfig result");
+        }
+    }
+
     /**
      * Condition for searching widget id
      */
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 7d25121..0e78565 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -54,6 +54,7 @@
     private static final int MAX_SCROLL_ATTEMPTS = 40;
 
     private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background";
+    private static final String FAST_SCROLLER_RES_ID = "fast_scroller";
 
     private static final Pattern EVENT_ALT_ESC_DOWN = Pattern.compile(
             "Key event: KeyEvent.*?action=ACTION_DOWN.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
@@ -369,9 +370,12 @@
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                      "want to tap outside AllApps bottom sheet on the "
                              + (tapRight ? "right" : "left"))) {
-            final UiObject2 allAppsBottomSheet =
+
+            final UiObject2 container = (tapRight)
+                    ? mLauncher.waitForLauncherObject(FAST_SCROLLER_RES_ID) :
                     mLauncher.waitForLauncherObject(BOTTOM_SHEET_RES_ID);
-            mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight);
+
+            mLauncher.touchOutsideContainer(container, tapRight, false);
             try (LauncherInstrumentation.Closable tapped = mLauncher.addContextLayer(
                     "tapped outside AllApps bottom sheet")) {
                 verifyVisibleContainerOnDismiss();
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 44869be..b6b4a47 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -186,7 +186,14 @@
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             Taskbar taskbar = new Taskbar(mLauncher);
             taskbar.touchBottomCorner(tapRight);
-            verifyActiveContainer();
+            if (mLauncher.isTransientTaskbar()) {
+                // Tapping outside Transient Taskbar returns to Workspace, wait for that state.
+                new Workspace(mLauncher);
+            } else {
+                // Should stay in Overview.
+                verifyActiveContainer();
+                verifyActionsViewVisibility();
+            }
         }
     }
 
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index efeb5f6..6d58a35 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -20,12 +20,11 @@
 import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
 import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_SHELL_DRAG_READY;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_SCALE;
+import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
 
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -84,8 +83,6 @@
     public Taskbar getTaskbar() {
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to get the taskbar")) {
-            mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
-
             return new Taskbar(mLauncher);
         }
     }
@@ -113,37 +110,32 @@
     /**
      * Returns the Taskbar in a visible state.
      *
-     * The taskbar must already be hidden when calling this method.
+     * The taskbar must already be hidden and in transient mode when calling this method.
      */
-    public Taskbar showTaskbar() {
-        mLauncher.getTestInfo(REQUEST_ENABLE_MANUAL_TASKBAR_STASHING);
+    public Taskbar swipeUpToUnstashTaskbar() {
+        mLauncher.assertTrue("Taskbar is not transient, swipe up not supported",
+                mLauncher.isTransientTaskbar());
+
         mLauncher.getTestInfo(REQUEST_ENABLE_BLOCK_TIMEOUT);
 
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
-                     "want to show the taskbar")) {
+                     "want to swipe up to unstash the taskbar")) {
             mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
 
-            final long downTime = SystemClock.uptimeMillis();
-            final int unstashTargetY = mLauncher.getRealDisplaySize().y
-                    - (mLauncher.getTestInfo(REQUEST_STASHED_TASKBAR_HEIGHT)
-                            .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD) / 2);
-            final Point unstashTarget = new Point(
-                    mLauncher.getRealDisplaySize().x / 2, unstashTargetY);
+            int taskbarFromNavThreshold = mLauncher.getTestInfo(REQUEST_TASKBAR_FROM_NAV_THRESHOLD)
+                    .getInt(TEST_INFO_RESPONSE_FIELD);
+            int startX = mLauncher.getRealDisplaySize().x / 2;
+            int startY = mLauncher.getRealDisplaySize().y - 1;
+            int endX = startX;
+            int endY = startY - taskbarFromNavThreshold;
 
-            mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, unstashTarget,
+            mLauncher.linearGesture(startX, startY, endX, endY, 10, /* slowDown= */ true,
                     LauncherInstrumentation.GestureScope.EXPECT_PILFER);
-            LauncherInstrumentation.log("showTaskbar: sent down");
+            LauncherInstrumentation.log("swipeUpToUnstashTaskbar: sent linear swipe up gesture");
 
-            try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
-                mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
-                mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, unstashTarget,
-                        LauncherInstrumentation.GestureScope.EXPECT_PILFER);
-
-                return new Taskbar(mLauncher);
-            }
+            return new Taskbar(mLauncher);
         } finally {
-            mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING);
             mLauncher.getTestInfo(REQUEST_DISABLE_BLOCK_TIMEOUT);
         }
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index fb81700..cbf1952 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -824,12 +824,7 @@
                     waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
                     waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
                     waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
-
-                    if (is3PLauncher() && isTablet()) {
-                        waitForSystemLauncherObject(TASKBAR_RES_ID);
-                    } else {
-                        waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
-                    }
+                    waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
 
                     return waitForLauncherObject(WORKSPACE_RES_ID);
                 }
@@ -839,12 +834,7 @@
                     waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
                     waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
                     waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
-
-                    if (is3PLauncher() && isTablet()) {
-                        waitForSystemLauncherObject(TASKBAR_RES_ID);
-                    } else {
-                        waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
-                    }
+                    waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
 
                     return waitForLauncherObject(WIDGETS_RES_ID);
                 }
@@ -865,7 +855,7 @@
                     waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
                     waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
 
-                    if (is3PLauncher() && isTablet()) {
+                    if (is3PLauncher() && isTablet() && !isTransientTaskbar()) {
                         waitForSystemLauncherObject(TASKBAR_RES_ID);
                     } else {
                         waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
@@ -878,7 +868,7 @@
                     waitUntilLauncherObjectGone(APPS_RES_ID);
                     waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
                     waitUntilLauncherObjectGone(WIDGETS_RES_ID);
-                    if (isTablet()) {
+                    if (isTablet() && !is3PLauncher()) {
                         waitForSystemLauncherObject(TASKBAR_RES_ID);
                     } else {
                         waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
@@ -915,7 +905,11 @@
                     }
 
                     if (isTablet()) {
-                        waitForSystemLauncherObject(TASKBAR_RES_ID);
+                        // Only check that Persistent Taskbar is visible, since Transient Taskbar
+                        // may or may not be visible by design.
+                        if (!isTransientTaskbar()) {
+                            waitForSystemLauncherObject(TASKBAR_RES_ID);
+                        }
                     } else {
                         waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
                     }
@@ -995,7 +989,7 @@
     /**
      * Using swiping up gesture to dismiss closable floating views, such as Menu or Folder Content.
      */
-    private void swipeUpToCloseFloatingView(boolean gestureStartFromLauncher) {
+    private void swipeUpToCloseFloatingView() {
         final Point displaySize = getRealDisplaySize();
 
         final Optional<String> floatingRes = getFloatingResId();
@@ -1004,16 +998,11 @@
             return;
         }
 
-        GestureScope gestureScope = gestureStartFromLauncher
-                // Without the navigation bar layer, the gesture scope on tablets remains inside the
-                // launcher process.
-                ? (isTablet() ? GestureScope.DONT_EXPECT_PILFER : GestureScope.EXPECT_PILFER)
-                : GestureScope.EXPECT_PILFER;
         linearGesture(
                 displaySize.x / 2, displaySize.y - 1,
                 displaySize.x / 2, 0,
                 ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
-                false, gestureScope);
+                false, GestureScope.EXPECT_PILFER);
 
         try (LauncherInstrumentation.Closable c1 = addContextLayer(
                 String.format("Swiped up from floating view %s to home", floatingRes.get()))) {
@@ -1081,11 +1070,8 @@
 
                 final Point displaySize = getRealDisplaySize();
 
-                boolean gestureStartFromLauncher =
-                        isTablet() ? !isLauncher3() : isLauncherVisible();
-
                 // CLose floating views before going back to home.
-                swipeUpToCloseFloatingView(gestureStartFromLauncher);
+                swipeUpToCloseFloatingView();
 
                 if (hasLauncherObject(WORKSPACE_RES_ID)) {
                     log(action = "already at home");
@@ -2039,6 +2025,7 @@
         }
     }
 
+    /** Returns the bounds of the display as a Point where x is width and y is height. */
     Point getRealDisplaySize() {
         final Rect displayBounds = getContext().getSystemService(WindowManager.class)
                 .getMaximumWindowMetrics()
@@ -2101,6 +2088,11 @@
                 : TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT);
     }
 
+    public boolean isTransientTaskbar() {
+        return getTestInfo(TestProtocol.REQUEST_IS_TRANSIENT_TASKBAR)
+                .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
     /** Enables transient taskbar for testing purposes only. */
     public void enableTransientTaskbar(boolean enable) {
         getTestInfo(enable
@@ -2188,7 +2180,8 @@
         };
     }
 
-    boolean isLauncher3() {
+    /** Returns whether the Launcher is a Launcher3 one */
+    public boolean isLauncher3() {
         if (mIsLauncher3 == null) {
             mIsLauncher3 = "com.android.launcher3".equals(getLauncherPackageName());
         }
@@ -2313,4 +2306,14 @@
         }
         return result;
     }
+
+    /** Executes a runnable and waits for the wallpaper-open animation completion. */
+    public void executeAndWaitForWallpaperAnimation(Runnable r, String actionName) {
+        executeAndWaitForLauncherEvent(
+                () -> r.run(),
+                event -> TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE
+                        .equals(event.getClassName().toString()),
+                () -> "Didn't detect finishing wallpaper-open animation",
+                actionName);
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 38cc321..4a0131b 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -20,6 +20,8 @@
 import androidx.test.uiautomator.By;
 import androidx.test.uiautomator.UiObject2;
 
+import com.android.launcher3.testing.shared.TestProtocol;
+
 /** Represents the menu of an overview task. */
 public class OverviewTaskMenu {
 
@@ -59,8 +61,13 @@
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                      "before tapping the app info menu item")) {
-            mLauncher.clickLauncherObject(
-                    mLauncher.findObjectInContainer(mMenu, By.text("App info")));
+            mLauncher.executeAndWaitForLauncherEvent(
+                    () -> mLauncher.clickLauncherObject(
+                            mLauncher.findObjectInContainer(mMenu, By.text("App info"))),
+                    event -> TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE
+                            .equals(event.getClassName().toString()),
+                    () -> "Launcher activity didn't stop",
+                    "tapped app info menu item");
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "tapped app info menu item")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index da26694..a202c53 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -18,8 +18,6 @@
 import static android.view.KeyEvent.KEYCODE_META_RIGHT;
 
 import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
 
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -33,6 +31,8 @@
 import androidx.test.uiautomator.BySelector;
 import androidx.test.uiautomator.UiObject2;
 
+import org.junit.Assert;
+
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -45,6 +45,15 @@
 
     Taskbar(LauncherInstrumentation launcher) {
         mLauncher = launcher;
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "expect new taskbar to be visible")) {
+            mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
+        }
+
+        if (!mLauncher.isTransientTaskbar()) {
+            Assert.assertEquals("Persistent taskbar should fill screen width",
+                    getVisibleBounds().width(), mLauncher.getRealDisplaySize().x);
+        }
     }
 
     /**
@@ -61,33 +70,32 @@
     }
 
     /**
-     * Hides this taskbar.
-     *
-     * The taskbar must already be visible when calling this method.
+     * Stashes this taskbar.
+     * <p>
+     * The taskbar must already be unstashed and in transient mode when calling this method.
      */
-    public void hide() {
-        mLauncher.getTestInfo(REQUEST_ENABLE_MANUAL_TASKBAR_STASHING);
+    public void swipeDownToStash() {
+        mLauncher.assertTrue("Taskbar is not transient, swipe down not supported",
+                mLauncher.isTransientTaskbar());
 
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to hide the taskbar");
              LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
 
-            final long downTime = SystemClock.uptimeMillis();
-            Point stashTarget = new Point(
-                    mLauncher.getRealDisplaySize().x - 1, mLauncher.getRealDisplaySize().y - 1);
+            Rect taskbarBounds = getVisibleBounds();
+            int startX = taskbarBounds.centerX();
+            int startY = taskbarBounds.centerY();
+            int endX = startX;
+            int endY = mLauncher.getRealDisplaySize().y - 1;
 
-            mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, stashTarget,
+            mLauncher.linearGesture(startX, startY, endX, endY, 10, false,
                     LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
-            LauncherInstrumentation.log("hideTaskbar: sent down");
-
-            try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
+            LauncherInstrumentation.log("swipeDownToStash: sent linear swipe down gesture");
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                    "expect transient taskbar to be hidden after swipe down")) {
                 mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
-                mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, stashTarget,
-                        LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
             }
-        } finally {
-            mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING);
         }
     }