Merge "Enabling app tracing for Launcher" into udc-qpr-dev
diff --git a/quickstep/res/layout/taskbar_all_apps.xml b/quickstep/res/layout/taskbar_all_apps.xml
index 976cd9e..e234165 100644
--- a/quickstep/res/layout/taskbar_all_apps.xml
+++ b/quickstep/res/layout/taskbar_all_apps.xml
@@ -14,18 +14,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView
+<com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:accessibilityPaneTitle="@string/all_apps_label">
-
-    <com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView
-        android:id="@+id/apps_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:clipChildren="true"
-        android:clipToPadding="false"
-        android:focusable="false"
-        android:saveEnabled="false" />
-</com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView>
+    android:clipChildren="true"
+    android:clipToPadding="false"
+    android:focusable="false"
+    android:saveEnabled="false" />
diff --git a/quickstep/res/layout/taskbar_all_apps_sheet.xml b/quickstep/res/layout/taskbar_all_apps_sheet.xml
new file mode 100644
index 0000000..a1d5fa6
--- /dev/null
+++ b/quickstep/res/layout/taskbar_all_apps_sheet.xml
@@ -0,0 +1,26 @@
+<?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.taskbar.allapps.TaskbarAllAppsSlideInView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:accessibilityPaneTitle="@string/all_apps_label">
+
+    <include
+        android:id="@+id/apps_view"
+        layout="@layout/taskbar_all_apps" />
+</com.android.launcher3.taskbar.allapps.TaskbarAllAppsSlideInView>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index a1c9f05..0541e61 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -449,6 +449,11 @@
         return mControllers.taskbarDragController;
     }
 
+    @Nullable
+    public BubbleControllers getBubbleControllers() {
+        return mControllers.bubbleControllers.orElse(null);
+    }
+
     @Override
     public ViewCache getViewCache() {
         return mViewCache;
@@ -641,8 +646,12 @@
         mControllers.taskbarForceVisibleImmersiveController.updateSysuiFlags(systemUiStateFlags);
         mControllers.voiceInteractionWindowController.setIsVoiceInteractionWindowVisible(
                 (systemUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0, fromInit);
-
         mControllers.uiController.updateStateForSysuiFlags(systemUiStateFlags);
+        mControllers.bubbleControllers.ifPresent(controllers -> {
+            controllers.bubbleBarController.updateStateForSysuiFlags(systemUiStateFlags);
+            controllers.bubbleStashedHandleViewController.setIsHomeButtonDisabled(
+                    mControllers.navbarButtonsViewController.isHomeDisabled());
+        });
     }
 
     /**
@@ -738,7 +747,7 @@
             }
         }
         mWindowLayoutParams.height = height;
-        mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged();
+        mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
         mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
     }
 
@@ -996,10 +1005,19 @@
      * Called when we want to unstash taskbar when user performs swipes up gesture.
      */
     public void onSwipeToUnstashTaskbar() {
-        mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
+        mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false);
         mControllers.taskbarEduTooltipController.hide();
     }
 
+    /**
+     * Called when we want to open bubblebar when user performs swipes up gesture.
+     */
+    public void onSwipeToOpenBubblebar() {
+        mControllers.bubbleControllers.ifPresent(controllers -> {
+            controllers.bubbleStashController.showBubbleBar(/* expandBubbles= */ true);
+        });
+    }
+
     /** Returns {@code true} if Taskbar All Apps is open. */
     public boolean isTaskbarAllAppsOpen() {
         return mControllers.taskbarAllAppsController.isOpen();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 66c2eb3..3cd151d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -226,6 +226,7 @@
         taskbarPopupController.onDestroy();
         taskbarForceVisibleImmersiveController.onDestroy();
         taskbarOverlayController.onDestroy();
+        taskbarAllAppsController.onDestroy();
         navButtonController.onDestroy();
         taskbarInsetsController.onDestroy();
         voiceInteractionWindowController.onDestroy();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 4f9b1e4..07cd8ff 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -56,13 +56,13 @@
     private val touchableRegion: Region = Region()
     private val insetsOwner: IBinder = Binder()
     private val deviceProfileChangeListener = { _: DeviceProfile ->
-        onTaskbarWindowHeightOrInsetsChanged()
+        onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
     }
     private val gestureNavSettingsObserver =
         GestureNavigationSettingsObserver(
             context.mainThreadHandler,
             context,
-            this::onTaskbarWindowHeightOrInsetsChanged
+            this::onTaskbarOrBubblebarWindowHeightOrInsetsChanged
         )
 
     // Initialized in init.
@@ -72,7 +72,7 @@
     fun init(controllers: TaskbarControllers) {
         this.controllers = controllers
         windowLayoutParams = context.windowLayoutParams
-        onTaskbarWindowHeightOrInsetsChanged()
+        onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
 
         context.addOnDeviceProfileChangeListener(deviceProfileChangeListener)
         gestureNavSettingsObserver.registerForCallingUser()
@@ -83,7 +83,7 @@
         gestureNavSettingsObserver.unregister()
     }
 
-    fun onTaskbarWindowHeightOrInsetsChanged() {
+    fun onTaskbarOrBubblebarWindowHeightOrInsetsChanged() {
         val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
         // We only report tappableElement height for unstashed, persistent taskbar,
         // which is also when we draw the rounded corners above taskbar.
@@ -121,13 +121,33 @@
                 )
         }
 
-        val touchableHeight = controllers.taskbarStashController.touchableHeight
-        touchableRegion.set(
-            0,
-            windowLayoutParams.height - touchableHeight,
-            context.deviceProfile.widthPx,
-            windowLayoutParams.height
-        )
+        val taskbarTouchableHeight = controllers.taskbarStashController.touchableHeight
+        val bubblesTouchableHeight =
+            if (controllers.bubbleControllers.isPresent)
+                controllers.bubbleControllers.get().bubbleStashController.touchableHeight
+            else 0
+        val touchableHeight = Math.max(taskbarTouchableHeight, bubblesTouchableHeight)
+
+        if (
+            controllers.bubbleControllers.isPresent &&
+                controllers.bubbleControllers.get().bubbleStashController.isBubblesShowingOnHome
+        ) {
+            val iconBounds =
+                controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
+            touchableRegion.set(
+                iconBounds.left,
+                iconBounds.top,
+                iconBounds.right,
+                iconBounds.bottom
+            )
+        } else {
+            touchableRegion.set(
+                0,
+                windowLayoutParams.height - touchableHeight,
+                context.deviceProfile.widthPx,
+                windowLayoutParams.height
+            )
+        }
         val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
         val res = context.resources
         for (provider in windowLayoutParams.providedInsets) {
@@ -211,6 +231,9 @@
             context.dragLayer,
             insetsInfo.touchableRegion
         )
+        val bubbleBarVisible =
+            controllers.bubbleControllers.isPresent &&
+                controllers.bubbleControllers.get().bubbleBarViewController.isBubbleBarVisible()
         var insetsIsTouchableRegion = true
         if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
             // Let touches pass through us.
@@ -231,7 +254,9 @@
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME)
             insetsIsTouchableRegion = false
         } else if (
-            controllers.taskbarViewController.areIconsVisible() || context.isNavBarKidsModeActive
+            controllers.taskbarViewController.areIconsVisible() ||
+                context.isNavBarKidsModeActive ||
+                bubbleBarVisible
         ) {
             // Taskbar has some touchable elements, take over the full taskbar area
             if (
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 008f5f6..122745c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -404,6 +404,14 @@
                     + ", mLauncherState: " + mLauncherState
                     + ", toAlignment: " + toAlignment);
         }
+        mControllers.bubbleControllers.ifPresent(controllers -> {
+            // Show the bubble bar when on launcher home or in overview.
+            boolean onHome = isInLauncher && mLauncherState == LauncherState.NORMAL;
+            boolean onOverview = mLauncherState == LauncherState.OVERVIEW;
+            controllers.bubbleStashController.setBubblesShowingOnHome(onHome);
+            controllers.bubbleStashController.setBubblesShowingOnOverview(onOverview);
+        });
+
         AnimatorSet animatorSet = new AnimatorSet();
 
         if (hasAnyFlag(changedFlags, FLAG_LAUNCHER_IN_STATE_TRANSITION)) {
@@ -474,7 +482,8 @@
                     public void onAnimationEnd(Animator animation) {
                         TaskbarStashController stashController =
                                 mControllers.taskbarStashController;
-                        stashController.updateAndAnimateTransientTaskbar(/* stash */ true);
+                        stashController.updateAndAnimateTransientTaskbar(
+                                /* stash */ true, /* bubblesShouldFollow */ true);
                     }
                 });
             } else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 5ea00cf..1c250bf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.launcher3.taskbar.bubbles.BubbleBarController.BUBBLE_BAR_ENABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED;
 
@@ -23,6 +24,7 @@
 import android.view.animation.PathInterpolator;
 
 import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.SystemUiProxy;
 
 import java.io.PrintWriter;
@@ -63,6 +65,10 @@
      * Updates the scrim state based on the flags.
      */
     public void updateStateForSysuiFlags(int stateFlags, boolean skipAnim) {
+        if (BUBBLE_BAR_ENABLED && DisplayController.isTransientTaskbar(mActivity)) {
+            // These scrims aren't used if bubble bar & transient taskbar are active.
+            return;
+        }
         final boolean bubblesExpanded = (stateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0;
         final boolean manageMenuExpanded =
                 (stateFlags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index eb4c136..8f5646a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -255,14 +255,15 @@
     private boolean mEnableBlockingTimeoutDuringTests = false;
 
     // Evaluate whether the handle should be stashed
+    private final IntPredicate mIsStashedPredicate = flags -> {
+        boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP);
+        boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP);
+        boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE);
+        boolean forceStashed = hasAnyFlag(flags, FLAGS_FORCE_STASHED);
+        return (inApp && stashedInApp) || (!inApp && stashedLauncherState) || forceStashed;
+    };
     private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
-            flags -> {
-                boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP);
-                boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP);
-                boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE);
-                boolean forceStashed = hasAnyFlag(flags, FLAGS_FORCE_STASHED);
-                return (inApp && stashedInApp) || (!inApp && stashedLauncherState) || forceStashed;
-            });
+            mIsStashedPredicate);
 
     private boolean mIsTaskbarSystemActionRegistered = false;
     private TaskbarSharedState mTaskbarSharedState;
@@ -501,9 +502,19 @@
     }
 
     /**
-     * Stash or unstashes the transient taskbar.
+     * Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION.
+     * If bubble bar exists, it will match taskbars stashing behavior.
      */
     public void updateAndAnimateTransientTaskbar(boolean stash) {
+        updateAndAnimateTransientTaskbar(stash, /* shouldBubblesFollow= */ true);
+    }
+
+    /**
+     * Stash or unstashes the transient taskbar.
+     * @param stash whether transient taskbar should be stashed.
+     * @param shouldBubblesFollow whether bubbles should match taskbars behavior.
+     */
+    public void updateAndAnimateTransientTaskbar(boolean stash,  boolean shouldBubblesFollow) {
         if (!DisplayController.isTransientTaskbar(mActivity)) {
             return;
         }
@@ -519,6 +530,34 @@
             updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, stash);
             applyState();
         }
+
+        mControllers.bubbleControllers.ifPresent(controllers -> {
+            if (shouldBubblesFollow) {
+                final boolean willStash = mIsStashedPredicate.test(mState);
+                if (willStash != controllers.bubbleStashController.isStashed()) {
+                    // Typically bubbles gets stashed / unstashed along with Taskbar, however, if
+                    // taskbar is becoming stashed because bubbles is being expanded, we don't want
+                    // to stash bubbles.
+                    if (willStash) {
+                        controllers.bubbleStashController.stashBubbleBar();
+                    } else {
+                        controllers.bubbleStashController.showBubbleBar(false /* expandBubbles */);
+                    }
+                }
+            }
+        });
+    }
+
+    /**
+     * Stashes transient taskbar after it has timed out.
+     */
+    private void updateAndAnimateTransientTaskbarForTimeout() {
+        // If bubbles are expanded we shouldn't stash them when taskbar is hidden
+        // for the timeout.
+        boolean bubbleBarExpanded = mControllers.bubbleControllers.isPresent()
+                && mControllers.bubbleControllers.get().bubbleBarViewController.isExpanded();
+        updateAndAnimateTransientTaskbar(/* stash= */ true,
+                /* shouldBubblesFollow= */ !bubbleBarExpanded);
     }
 
     /**
@@ -886,7 +925,7 @@
     private void onIsStashedChanged(boolean isStashed) {
         mControllers.runAfterInit(() -> {
             mControllers.stashedHandleViewController.onIsStashedChanged(isStashed);
-            mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged();
+            mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
         });
     }
 
@@ -1133,7 +1172,7 @@
         if (mControllers.taskbarAutohideSuspendController.isSuspended()) {
             return;
         }
-        updateAndAnimateTransientTaskbar(true);
+        updateAndAnimateTransientTaskbarForTimeout();
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt
index ec93846..deaf024 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashViaTouchController.kt
@@ -108,7 +108,17 @@
         }
 
     override fun onControllerInterceptTouchEvent(ev: MotionEvent): Boolean {
-        if (!enabled || controllers.taskbarStashController.isStashed) {
+        if (!enabled) {
+            return false
+        }
+        val bubbleControllers = controllers.bubbleControllers.orElse(null)
+        if (bubbleControllers != null && bubbleControllers.bubbleBarViewController.isExpanded) {
+            return false
+        }
+        if (
+            (bubbleControllers == null || bubbleControllers.bubbleStashController.isStashed) &&
+                controllers.taskbarStashController.isStashed
+        ) {
             return false
         }
 
@@ -122,7 +132,12 @@
                 return true
             }
         } else if (ev.action == MotionEvent.ACTION_DOWN) {
-            if (screenCoordinatesEv.y < gestureHeightYThreshold) {
+            val isDownOnBubbleBar =
+                (bubbleControllers != null &&
+                    bubbleControllers.bubbleBarViewController.isEventOverAnyItem(
+                        screenCoordinatesEv
+                    ))
+            if (!isDownOnBubbleBar && screenCoordinatesEv.y < gestureHeightYThreshold) {
                 controllers.taskbarStashController.updateAndAnimateTransientTaskbar(true)
             }
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 2b4e67c..916b1e6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -92,6 +92,10 @@
         mControllers.stashedHandleViewController.setTranslationYForSwipe(transY);
         mControllers.taskbarViewController.setTranslationYForSwipe(transY);
         mControllers.taskbarDragLayerController.setTranslationYForSwipe(transY);
+        mControllers.bubbleControllers.ifPresent(controllers -> {
+            controllers.bubbleBarViewController.setTranslationYForSwipe(transY);
+            controllers.bubbleStashedHandleViewController.setTranslationYForSwipe(transY);
+        });
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index e0a502b..4ac779f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -45,8 +45,10 @@
 public final class TaskbarAllAppsController {
 
     private TaskbarControllers mControllers;
+    private @Nullable TaskbarOverlayContext mOverlayContext;
     private @Nullable TaskbarAllAppsSlideInView mSlideInView;
     private @Nullable TaskbarAllAppsContainerView mAppsView;
+    private @Nullable TaskbarSearchSessionController mSearchSessionController;
 
     // Application data models.
     private AppInfo[] mApps;
@@ -70,6 +72,11 @@
         }
     }
 
+    /** Clean up the controller. */
+    public void onDestroy() {
+        cleanUpOverlay();
+    }
+
     /** Updates the current {@link AppInfo} instances. */
     public void setApps(AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map) {
         mApps = apps;
@@ -96,6 +103,9 @@
                     .findFixedRowByType(PredictionRowView.class)
                     .setPredictedApps(mPredictedApps);
         }
+        if (mSearchSessionController != null) {
+            mSearchSessionController.setZeroStatePredictedItems(predictedApps);
+        }
     }
 
     /** Updates the current notification dots. */
@@ -127,20 +137,25 @@
         // to catch invalid states.
         mControllers.getSharedState().allAppsVisible = true;
 
-        TaskbarOverlayContext overlayContext =
-                mControllers.taskbarOverlayController.requestWindow();
-        mSlideInView = (TaskbarAllAppsSlideInView) overlayContext.getLayoutInflater().inflate(
-                R.layout.taskbar_all_apps, overlayContext.getDragLayer(), false);
+        mOverlayContext = mControllers.taskbarOverlayController.requestWindow();
+
+        // Initialize search session for All Apps.
+        mSearchSessionController = TaskbarSearchSessionController.newInstance(mOverlayContext);
+        mOverlayContext.setSearchSessionController(mSearchSessionController);
+        mSearchSessionController.setZeroStatePredictedItems(mPredictedApps);
+        mSearchSessionController.startLifecycle();
+
+        mSlideInView = (TaskbarAllAppsSlideInView) mOverlayContext.getLayoutInflater().inflate(
+                R.layout.taskbar_all_apps_sheet, mOverlayContext.getDragLayer(), false);
         mSlideInView.addOnCloseListener(() -> {
             mControllers.getSharedState().allAppsVisible = false;
-            mSlideInView = null;
-            mAppsView = null;
+            cleanUpOverlay();
         });
         TaskbarAllAppsViewController viewController = new TaskbarAllAppsViewController(
-                overlayContext, mSlideInView, mControllers);
+                mOverlayContext, mSlideInView, mControllers);
 
         viewController.show(animate);
-        mAppsView = overlayContext.getAppsView();
+        mAppsView = mOverlayContext.getAppsView();
         mAppsView.getAppsStore().setApps(mApps, mAppsModelFlags, mPackageUserKeytoUidMap);
         mAppsView.getFloatingHeaderView()
                 .findFixedRowByType(PredictionRowView.class)
@@ -149,8 +164,21 @@
         // Create a shared drag layer between taskbar and taskbarAllApps so that when dragging
         // starts and taskbarAllApps can close, but the drag layer that the view is being dragged in
         // doesn't also close
-        overlayContext.getDragController().setDisallowGlobalDrag(mDisallowGlobalDrag);
-        overlayContext.getDragController().setDisallowLongClick(mDisallowLongClick);
+        mOverlayContext.getDragController().setDisallowGlobalDrag(mDisallowGlobalDrag);
+        mOverlayContext.getDragController().setDisallowLongClick(mDisallowLongClick);
+    }
+
+    private void cleanUpOverlay() {
+        if (mSearchSessionController != null) {
+            mSearchSessionController.onDestroy();
+            mSearchSessionController = null;
+        }
+        if (mOverlayContext != null) {
+            mOverlayContext.setSearchSessionController(null);
+            mOverlayContext = null;
+        }
+        mSlideInView = null;
+        mAppsView = null;
     }
 
     @VisibleForTesting
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
new file mode 100644
index 0000000..6a9dda5
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
@@ -0,0 +1,52 @@
+/*
+ * 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.launcher3.taskbar.allapps
+
+import android.content.Context
+import com.android.launcher3.R
+import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.util.ResourceBasedOverride
+import com.android.launcher3.util.ResourceBasedOverride.Overrides
+
+/** Stub for managing the Taskbar search session. */
+open class TaskbarSearchSessionController : ResourceBasedOverride {
+
+    /** Start the search session lifecycle. */
+    open fun startLifecycle() {}
+
+    /** Destroy the search session. */
+    open fun onDestroy() {}
+
+    /** Updates the predicted items shown in the zero-state. */
+    open fun setZeroStatePredictedItems(items: List<ItemInfo>) {}
+
+    companion object {
+        @JvmStatic
+        fun newInstance(context: Context): TaskbarSearchSessionController {
+            if (!FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
+                return TaskbarSearchSessionController()
+            }
+
+            return Overrides.getObject(
+                TaskbarSearchSessionController::class.java,
+                context,
+                R.string.taskbar_search_session_controller_class,
+            )
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 82494c6..3786189 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -28,6 +28,8 @@
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.launcher3.taskbar.TaskbarInsetsController;
+import com.android.launcher3.taskbar.TaskbarStashController;
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.quickstep.SystemUiProxy;
@@ -51,6 +53,8 @@
     // Initialized in init.
     private BubbleStashController mBubbleStashController;
     private BubbleBarController mBubbleBarController;
+    private TaskbarStashController mTaskbarStashController;
+    private TaskbarInsetsController mTaskbarInsetsController;
     private View.OnClickListener mBubbleClickListener;
     private View.OnClickListener mBubbleBarClickListener;
 
@@ -80,6 +84,8 @@
     public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
         mBubbleStashController = bubbleControllers.bubbleStashController;
         mBubbleBarController = bubbleControllers.bubbleBarController;
+        mTaskbarStashController = controllers.taskbarStashController;
+        mTaskbarInsetsController = controllers.taskbarInsetsController;
 
         mActivity.addOnDeviceProfileChangeListener(dp ->
                 mBarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarHeight
@@ -89,7 +95,9 @@
         mBubbleClickListener = v -> onBubbleClicked(v);
         mBubbleBarClickListener = v -> setExpanded(true);
         mBarView.setOnClickListener(mBubbleBarClickListener);
-        // TODO: when barView layout changes tell taskbarInsetsController the insets have changed.
+        mBarView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) ->
+                mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+        );
     }
 
     private void onBubbleClicked(View v) {
@@ -283,7 +291,8 @@
                 } else {
                     Log.w(TAG, "trying to expand bubbles when there isn't one selected");
                 }
-                // TODO: Tell taskbar stash controller to stash without bubbles following
+                mTaskbarStashController.updateAndAnimateTransientTaskbar(true /* stash */,
+                        false /* shouldBubblesFollow */);
             }
         }
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index 0ab53b0..b3c7d41 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -25,6 +25,7 @@
 import com.android.launcher3.taskbar.StashedHandleViewController;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.launcher3.taskbar.TaskbarInsetsController;
 import com.android.launcher3.taskbar.TaskbarStashController;
 import com.android.launcher3.util.MultiPropertyFactory;
 
@@ -50,6 +51,7 @@
 
     // Initialized in init.
     private TaskbarControllers mControllers;
+    private TaskbarInsetsController mTaskbarInsetsController;
     private BubbleBarViewController mBarViewController;
     private BubbleStashedHandleViewController mHandleViewController;
     private TaskbarStashController mTaskbarStashController;
@@ -77,6 +79,7 @@
 
     public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
         mControllers = controllers;
+        mTaskbarInsetsController = controllers.taskbarInsetsController;
         mBarViewController = bubbleControllers.bubbleBarViewController;
         mHandleViewController = bubbleControllers.bubbleStashedHandleViewController;
         mTaskbarStashController = controllers.taskbarStashController;
@@ -271,7 +274,7 @@
     private void onIsStashedChanged() {
         mControllers.runAfterInit(() -> {
             mHandleViewController.onIsStashedChanged();
-            // TODO: when stash changes tell taskbarInsetsController the insets have changed.
+            mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
         });
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
index a642693..cfcc1a0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
@@ -18,6 +18,8 @@
 import android.content.Context;
 import android.view.View;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.dot.DotInfo;
@@ -29,6 +31,7 @@
 import com.android.launcher3.taskbar.TaskbarDragController;
 import com.android.launcher3.taskbar.TaskbarUIController;
 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView;
+import com.android.launcher3.taskbar.allapps.TaskbarSearchSessionController;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
 
 /**
@@ -47,6 +50,8 @@
     private final int mStashedTaskbarHeight;
     private final TaskbarUIController mUiController;
 
+    private @Nullable TaskbarSearchSessionController mSearchSessionController;
+
     public TaskbarOverlayContext(
             Context windowContext,
             TaskbarActivityContext taskbarContext,
@@ -62,6 +67,15 @@
         mUiController = controllers.uiController;
     }
 
+    public @Nullable TaskbarSearchSessionController getSearchSessionController() {
+        return mSearchSessionController;
+    }
+
+    public void setSearchSessionController(
+            @Nullable TaskbarSearchSessionController searchSessionController) {
+        mSearchSessionController = searchSessionController;
+    }
+
     int getStashedTaskbarHeight() {
         return mStashedTaskbarHeight;
     }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index fbe7fde..e9a0761 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -37,6 +37,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
+import com.android.launcher3.taskbar.bubbles.BubbleControllers;
 import com.android.launcher3.touch.OverScroll;
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.InputConsumer;
@@ -62,6 +63,7 @@
     private final int mTaskbarNavThresholdY;
     private final boolean mIsTaskbarAllAppsOpen;
     private boolean mHasPassedTaskbarNavThreshold;
+    private boolean mIsInBubbleBarArea;
 
     private final PointF mDownPos = new PointF();
     private final PointF mLastPos = new PointF();
@@ -136,7 +138,7 @@
                         mHasPassedTaskbarNavThreshold = false;
                         mTaskbarActivityContext.setAutohideSuspendFlag(
                                 FLAG_AUTOHIDE_SUSPEND_TOUCHING, true);
-                        if (isInArea(x)) {
+                        if (isInTaskbarArea(x)) {
                             if (!mIsTransientTaskbar) {
                                 mLongPressDownX = x;
                                 mLongPressDownY = y;
@@ -145,10 +147,12 @@
                                 mCanceledUnstashHint = false;
                             }
                         }
-
                         if (mTransitionCallback != null && !mIsTaskbarAllAppsOpen) {
                             mTransitionCallback.onActionDown();
                         }
+                        if (mIsTransientTaskbar && isInBubbleBarArea(x)) {
+                            mIsInBubbleBarArea = true;
+                        }
                         break;
                     case MotionEvent.ACTION_POINTER_UP:
                         int ptrIdx = ev.getActionIndex();
@@ -185,7 +189,11 @@
 
                             if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold) {
                                 mHasPassedTaskbarNavThreshold = true;
-                                mTaskbarActivityContext.onSwipeToUnstashTaskbar();
+                                if (mIsInBubbleBarArea) {
+                                    mTaskbarActivityContext.onSwipeToOpenBubblebar();
+                                } else {
+                                    mTaskbarActivityContext.onSwipeToUnstashTaskbar();
+                                }
                             }
 
                             if (dY < 0) {
@@ -208,21 +216,32 @@
                             mTransitionCallback.onActionEnd();
                         }
                         mHasPassedTaskbarNavThreshold = false;
+                        mIsInBubbleBarArea = false;
                         break;
                 }
             }
         }
     }
 
-    private boolean isInArea(float x) {
+    private boolean isInTaskbarArea(float x) {
         float areaFromMiddle = mUnstashArea / 2.0f;
         float distFromMiddle = Math.abs(mScreenWidth / 2.0f - x);
         return distFromMiddle < areaFromMiddle;
     }
 
+    private boolean isInBubbleBarArea(float x) {
+        if (mTaskbarActivityContext != null && mIsTransientTaskbar) {
+            BubbleControllers controllers = mTaskbarActivityContext.getBubbleControllers();
+            if (controllers == null) return false;
+            Rect bubbleBarBounds = controllers.bubbleBarViewController.getBubbleBarBounds();
+            return x >= bubbleBarBounds.left && x <= bubbleBarBounds.right;
+        }
+        return false;
+    }
+
     private void onLongPressDetected(MotionEvent motionEvent) {
         if (mTaskbarActivityContext != null
-                && isInArea(motionEvent.getRawX())
+                && isInTaskbarArea(motionEvent.getRawX())
                 && !mIsTransientTaskbar) {
             boolean taskBarPressed = mTaskbarActivityContext.onLongPressToUnstashTaskbar();
             if (taskBarPressed) {
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 084f8c1..5ec92a6 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -412,10 +412,12 @@
         }
 
         mFeedbackTitleView.setText(titleResId);
-        mFeedbackSubtitleView.setText(spokenSubtitleResId == NO_ID
-                ? mContext.getText(subtitleResId)
-                : Utilities.wrapForTts(
-                        mContext.getText(subtitleResId), mContext.getString(spokenSubtitleResId)));
+        mFeedbackSubtitleView.setText(
+                ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() || spokenSubtitleResId == NO_ID
+                        ? mContext.getText(subtitleResId)
+                        : Utilities.wrapForTts(
+                                mContext.getText(subtitleResId),
+                                mContext.getString(spokenSubtitleResId)));
         if (isGestureSuccessful) {
             if (mTutorialFragment.isAtFinalStep()) {
                 showActionButton();
diff --git a/res/values/config.xml b/res/values/config.xml
index 5a6698b..233119d 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -84,6 +84,7 @@
     <string name="window_manager_proxy_class" translatable="false"></string>
     <string name="secondary_display_predictions_class" translatable="false"></string>
     <string name="widget_holder_factory_class" translatable="false"></string>
+    <string name="taskbar_search_session_controller_class" translatable="false"></string>
 
     <!-- View ID to use for QSB widget -->
     <item type="id" name="qsb_widget" />
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index d4140d8..898009d 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -70,7 +70,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
-import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider;
+import com.android.launcher3.allapps.search.AllAppsSearchUiDelegate;
 import com.android.launcher3.allapps.search.SearchAdapterProvider;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.keyboard.FocusedItemDecorator;
@@ -132,6 +132,7 @@
     protected final Point mFastScrollerOffset = new Point();
     protected final int mScrimColor;
     protected final float mHeaderThreshold;
+    protected final AllAppsSearchUiDelegate mSearchUiDelegate;
 
     // Used to animate Search results out and A-Z apps in, or vice-versa.
     private final SearchTransitionController mSearchTransitionController;
@@ -217,11 +218,17 @@
                 getActiveRecyclerView().requestFocus();
             }
         });
+        mSearchUiDelegate = createSearchUiDelegate();
         initContent();
 
         mSearchTransitionController = new SearchTransitionController(this);
     }
 
+    /** Creates the delegate for initializing search. */
+    protected AllAppsSearchUiDelegate createSearchUiDelegate() {
+        return new AllAppsSearchUiDelegate(this);
+    }
+
     /**
      * Initializes the view hierarchy and internal variables. Any initialization which actually uses
      * these members should be done in {@link #onFinishInflate()}.
@@ -231,7 +238,7 @@
      *   onFinishInflate -> onPostCreate
      */
     protected void initContent() {
-        mMainAdapterProvider = createMainAdapterProvider();
+        mMainAdapterProvider = mSearchUiDelegate.createMainAdapterProvider();
 
         mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN,
                 new AlphabeticalAppsList<>(mActivityContext, mAllAppsStore, null)));
@@ -252,6 +259,7 @@
         mSearchContainer = inflateSearchBox();
         addView(mSearchContainer);
         mSearchUiManager = (SearchUiManager) mSearchContainer;
+        mSearchUiDelegate.onInitializeSearchBox();
     }
 
     @Override
@@ -341,6 +349,7 @@
      */
     public void setSearchResults(ArrayList<AdapterItem> results, int searchResultCode) {
         setSearchResults(results);
+        mSearchUiDelegate.onSearchResultsChanged(results, searchResultCode);
     }
 
     private void animateToSearchState(boolean goingToSearch) {
@@ -788,12 +797,7 @@
      * Inflates the search box
      */
     protected View inflateSearchBox() {
-        return getLayoutInflater().inflate(R.layout.search_container_all_apps, this, false);
-    }
-
-    /** Creates the adapter provider for the main section. */
-    protected SearchAdapterProvider<?> createMainAdapterProvider() {
-        return new DefaultSearchAdapterProvider(mActivityContext);
+        return mSearchUiDelegate.inflateSearchBox();
     }
 
     /** The adapter provider for the main section. */
@@ -998,7 +1002,7 @@
     }
 
     public LayoutInflater getLayoutInflater() {
-        return LayoutInflater.from(getContext());
+        return mSearchUiDelegate.getLayoutInflater();
     }
 
     @Override
@@ -1306,6 +1310,7 @@
 
     protected void onInitializeRecyclerView(RecyclerView rv) {
         rv.addOnScrollListener(mScrollListener);
+        mSearchUiDelegate.onInitializeRecyclerView(rv);
     }
 
     /** Returns the instance of @{code SearchTransitionController}. */
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchUiDelegate.java b/src/com/android/launcher3/allapps/search/AllAppsSearchUiDelegate.java
new file mode 100644
index 0000000..abec16e
--- /dev/null
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchUiDelegate.java
@@ -0,0 +1,71 @@
+/*
+ * 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.launcher3.allapps.search;
+
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
+import com.android.launcher3.views.ActivityContext;
+
+import java.util.List;
+
+/** Initializes the search box and its interactions with All Apps. */
+public class AllAppsSearchUiDelegate {
+
+    protected final ActivityAllAppsContainerView<?> mAppsView;
+    protected final ActivityContext mActivityContext;
+
+    public AllAppsSearchUiDelegate(ActivityAllAppsContainerView<?> appsView) {
+        mAppsView = appsView;
+        mActivityContext = ActivityContext.lookupContext(mAppsView.getContext());
+    }
+
+    /** Invoked when an All Apps {@link RecyclerView} is initialized. */
+    public void onInitializeRecyclerView(RecyclerView rv) {
+        // Do nothing.
+    }
+
+    /** Invoked when search results are updated in All Apps. */
+    public void onSearchResultsChanged(List<AdapterItem> results, int searchResultCode) {
+        // Do nothing.
+    }
+
+    /** Invoked when the search box has been added to All Apps. */
+    public void onInitializeSearchBox() {
+        // Do nothing.
+    }
+
+    /** The layout inflater for All Apps and search UI. */
+    public LayoutInflater getLayoutInflater() {
+        return LayoutInflater.from(mAppsView.getContext());
+    }
+
+    /** Inflate the search box for All Apps. */
+    public View inflateSearchBox() {
+        return getLayoutInflater().inflate(R.layout.search_container_all_apps, mAppsView, false);
+    }
+
+    /** Creates the adapter provider for the main section. */
+    public SearchAdapterProvider<?> createMainAdapterProvider() {
+        return new DefaultSearchAdapterProvider(mActivityContext);
+    }
+}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 66ed779..7e065a9 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -831,6 +831,10 @@
      */
     public interface StatsLatencyLogger {
 
+        /**
+         * Should be in sync with:
+         * google3/wireless/android/sysui/aster/asterstats/launcher_event_processed.proto
+         */
         enum LatencyType {
             UNKNOWN(0),
             // example: launcher restart that happens via daily backup and restore
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index dcd61a8..6935353 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -36,7 +36,6 @@
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.LooperExecutor;
@@ -282,33 +281,18 @@
             sortWorkspaceItemsSpatially(idp, currentWorkspaceItems);
             sortWorkspaceItemsSpatially(idp, otherWorkspaceItems);
 
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.WORKSPACE_LOADS_FOREVER, "Before posting startBinding");
-            }
             // Tell the workspace that we're about to start binding items
             executeCallbacksTask(c -> {
                 c.clearPendingBinds();
                 c.startBinding();
             }, mUiExecutor);
 
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.WORKSPACE_LOADS_FOREVER, "1");
-            }
             // Bind workspace screens
             executeCallbacksTask(c -> c.bindScreens(mOrderedScreenIds), mUiExecutor);
 
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.WORKSPACE_LOADS_FOREVER, "2");
-            }
             // Load items on the current page.
             bindWorkspaceItems(currentWorkspaceItems, mUiExecutor);
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.WORKSPACE_LOADS_FOREVER, "3");
-            }
             bindAppWidgets(currentAppWidgets, mUiExecutor);
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.WORKSPACE_LOADS_FOREVER, "4");
-            }
             if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
                 mExtraItems.forEach(item ->
                         executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor));
@@ -317,18 +301,8 @@
             RunnableList pendingTasks = new RunnableList();
             Executor pendingExecutor = pendingTasks::add;
             bindWorkspaceItems(otherWorkspaceItems, pendingExecutor);
-
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.WORKSPACE_LOADS_FOREVER, "5");
-            }
             bindAppWidgets(otherAppWidgets, pendingExecutor);
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.WORKSPACE_LOADS_FOREVER, "6");
-            }
             executeCallbacksTask(c -> c.finishBindingItems(currentScreenIds), pendingExecutor);
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.WORKSPACE_LOADS_FOREVER, "After posting finishBindingItems");
-            }
             pendingExecutor.execute(
                     () -> {
                         MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index d3a237c..623b557 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -249,6 +249,8 @@
                         bottomPadding + insets.getSystemWindowInsetBottom());
                 return insets.consumeSystemWindowInsets();
             });
+            // Overriding Text Direction in the Androidx preference library to support RTL
+            view.setTextDirection(View.TEXT_DIRECTION_LOCALE);
         }
 
         @Override
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index dbaf19b..7f2d4a0 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -155,7 +155,6 @@
     public static final String PERMANENT_DIAG_TAG = "TaplTarget";
     public static final String WORK_TAB_MISSING = "b/243688989";
     public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
-    public static final String WORKSPACE_LOADS_FOREVER = "b/267200150";
 
     public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
     public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
index c4aa42b..243edc3 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
@@ -28,7 +28,6 @@
 import com.android.launcher3.celllayout.testcases.MultipleCellLayoutsSimpleReorder;
 import com.android.launcher3.tapl.Widget;
 import com.android.launcher3.tapl.WidgetResizeFrame;
-import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.TaplTestsLauncher3;
 import com.android.launcher3.util.rule.ShellCommandRule;
@@ -115,11 +114,8 @@
         // resetLoaderState triggers the launcher to start loading the workspace which allows
         // waitForLauncherCondition to wait for that condition, otherwise the condition would
         // always be true and it wouldn't wait for the changes to be applied.
-        Log.d(TestProtocol.WORKSPACE_LOADS_FOREVER, "before resetLoaderState");
         resetLoaderState();
-        Log.d(TestProtocol.WORKSPACE_LOADS_FOREVER, "after resetLoaderState");
         waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading());
-        Log.d(TestProtocol.WORKSPACE_LOADS_FOREVER, "after waitForLauncherCondition");
         Widget widget = mLauncher.getWorkspace().getWidgetAtCell(mainWidgetCellPos.getCellX(),
                 mainWidgetCellPos.getCellY());
         assertNotNull(widget);