Merge "Fix hotseat border space crash GSI" into udc-qpr-dev
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index f5a8253..638ce27 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -42,5 +42,6 @@
         "tests/src/com/android/quickstep/NavigationModeSwitchRule.java",
         "tests/src/com/android/quickstep/AbstractQuickStepTest.java",
         "tests/src/com/android/quickstep/TaplTestsQuickstep.java",
+        "tests/src/com/android/quickstep/TaplTestsSplitscreen.java",
     ]
 }
diff --git a/quickstep/res/drawable/taskbar_divider_bg.xml b/quickstep/res/drawable/taskbar_divider_bg.xml
deleted file mode 100644
index 52e230d..0000000
--- a/quickstep/res/drawable/taskbar_divider_bg.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle" >
-    <solid android:color="@color/taskbar_divider_background"/>
-    <corners android:radius="1dp" />
-</shape>
diff --git a/quickstep/res/drawable/taskbar_divider_button.xml b/quickstep/res/drawable/taskbar_divider_button.xml
new file mode 100644
index 0000000..cb116cf
--- /dev/null
+++ b/quickstep/res/drawable/taskbar_divider_button.xml
@@ -0,0 +1,30 @@
+<?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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="52dp"
+    android:height="52dp"
+    android:viewportHeight="52"
+    android:viewportWidth="52">
+    <group>
+        <path
+            android:fillColor="@color/taskbar_divider_background"
+            android:pathData="M26,11L26,41"
+            android:strokeColor="@color/taskbar_divider_background"
+            android:strokeLineCap="round"
+            android:strokeWidth="2" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_divider.xml b/quickstep/res/layout/taskbar_divider.xml
index 73f3811..0a92fa9 100644
--- a/quickstep/res/layout/taskbar_divider.xml
+++ b/quickstep/res/layout/taskbar_divider.xml
@@ -13,16 +13,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<FrameLayout
+<com.android.launcher3.views.IconButtonView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="@dimen/taskbar_icon_min_touch_size"
     android:layout_height="@dimen/taskbar_icon_min_touch_size"
     android:contentDescription="@string/taskbar_divider_a11y_title"
-    android:backgroundTint="@android:color/transparent">
-
-    <View
-        android:layout_height="32dp"
-        android:layout_width="2dp"
-        android:layout_gravity="center"
-        android:background="@drawable/taskbar_divider_bg" />
-</FrameLayout>
\ No newline at end of file
+    android:backgroundTint="@android:color/transparent" />
\ No newline at end of file
diff --git a/quickstep/res/layout/taskbar_divider_popup_menu.xml b/quickstep/res/layout/taskbar_divider_popup_menu.xml
index 195443e..00e47c9 100644
--- a/quickstep/res/layout/taskbar_divider_popup_menu.xml
+++ b/quickstep/res/layout/taskbar_divider_popup_menu.xml
@@ -32,7 +32,7 @@
         android:clickable="true"
         android:gravity="center_vertical"
         android:orientation="horizontal"
-        android:background="@drawable/top_rounded_popup_ripple"
+        android:background="@drawable/rounded_popup_ripple"
         android:paddingEnd="10dp"
         android:paddingStart="10dp"
         android:theme="@style/PopupItem">
@@ -59,40 +59,4 @@
             android:text="@string/always_show_taskbar" />
 
     </LinearLayout>
-
-    <LinearLayout
-        android:id="@+id/navigation_mode_switch_option"
-        android:layout_width="match_parent"
-        android:layout_height="52dp"
-        android:layout_gravity="center_vertical"
-        android:elevation="2dp"
-        android:clickable="true"
-        android:focusable="true"
-        android:background="@drawable/bottom_rounded_popup_ripple"
-        android:gravity="center_vertical"
-        android:orientation="horizontal"
-        android:paddingEnd="10dp"
-        android:paddingStart="10dp"
-        android:theme="@style/PopupItem">
-
-        <View
-            android:layout_width="24dp"
-            android:layout_height="24dp"
-            android:layout_margin="4dp"
-            android:background="@drawable/ic_touch"
-            android:backgroundTint="?android:attr/textColorPrimary" />
-
-        <com.android.launcher3.BubbleTextView
-            style="@style/BaseIcon"
-            android:id="@+id/change_navigation_mode_text"
-            android:gravity="start|center_vertical"
-            android:textAlignment="viewStart"
-            android:paddingStart="12dp"
-            android:singleLine="true"
-            android:ellipsize="end"
-            android:textSize="14sp"
-            android:textColor="?android:attr/textColorPrimary"
-            android:text="@string/change_navigation_mode" />
-
-    </LinearLayout>
 </com.android.launcher3.taskbar.TaskbarDividerPopupView>
\ No newline at end of file
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index b48e5d6..828b85f 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -60,12 +60,12 @@
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Wische vom unteren Displayrand nach oben"</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Achte darauf, nicht innezuhalten, bevor du loslässt"</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Wische gerade nach oben"</string>
-    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Du hast den Schritt für die „Startbildschirm“-Geste abgeschlossen. Jetzt lernst du, wie du zurückgehst."</string>
+    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Du hast den Schritt für die „Zum Startbildschirm“-Geste abgeschlossen. Jetzt lernst du, wie du zurückgehst."</string>
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Du hast den Schritt für die „Startbildschirm“-Touch-Geste abgeschlossen"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Den Startbildschirm aufrufen"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Wenn du zum Startbildschirm gehen möchtest, wische einfach vom unteren Displayrand nach oben."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Wische mit zwei Fingern vom unteren Displayrand nach oben. So gelangst du immer zum Startbildschirm."</string>
-    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Zum Startbildschirm"</string>
+    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Zum StartU+00AD­bildschirm"</string>
     <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Wische vom unteren Displayrand nach oben"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Gut gemacht!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Wische vom unteren Displayrand nach oben"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index b737129..cf5d6e9 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -70,7 +70,7 @@
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"¡Bien hecho!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Asegúrate de deslizar hacia arriba desde el borde inferior de la pantalla"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Intenta mantener presionada la ventana más tiempo antes de soltarla"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Asegúrate de deslizar directamente hacia arriba y, luego, detenerte"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Asegúrate de deslizar directamente hacia arriba y detenerte"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Ya sabes cómo usar los gestos. Para desactivarlos, ve a Configuración."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Completaste el gesto para cambiar de app"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Desliza para cambiar de app"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 7a681b1..d40780c 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -65,12 +65,12 @@
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Desliza para ir a la pantalla de inicio"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Desliza hacia arriba desde la parte inferior de la pantalla. Este gesto siempre te lleva a la pantalla de inicio."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Desliza dos dedos hacia arriba desde la parte inferior de la pantalla. Si haces este gesto, siempre irás a la pantalla de inicio."</string>
-    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ir a Inicio"</string>
+    <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ir a inicio"</string>
     <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Desliza hacia arriba desde la parte inferior de la pantalla"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"¡Bien hecho!"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Asegúrate de deslizar hacia arriba desde el borde inferior de la pantalla"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Prueba a mantener pulsada la ventana durante más tiempo antes de soltarla"</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Asegúrate de deslizar directamente hacia arriba y, luego, detenerte"</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Asegúrate de deslizar directamente hacia arriba y luego detenerte"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Ya sabes cómo utilizar gestos. Para desactivarlos, ve a Ajustes."</string>
     <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Has completado el gesto para cambiar de aplicación"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Desliza el dedo para cambiar de aplicación"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 6de4e90..85b4862 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -72,7 +72,7 @@
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"قبل‌از رها کردن پنجره، آن را برای مدت طولانی‌تری نگه دارید"</string>
     <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"دقت کنید که مستقیماً تند به بالا بکشید و سپس توقف کنید"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"با نحوه استفاده از اشاره‌ها آشنا شدید. برای خاموش کردن اشاره‌ها، به «تنظیمات» بروید."</string>
-    <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"اشاره جابه‌جا شدن بین برنامه‌ها را تکمیل کردید"</string>
+    <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"اشاره جابه‌جایی بین برنامه‌ها را تکمیل کردید"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"برای جابه‌جا شدن بین برنامه‌ها، تند به‌بالا بکشید"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"برای جابه‌جا شدن بین برنامه‌ها، از پایین صفحه تند به‌بالا بکشید، نگه دارید، و سپس رها کنید."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"برای جابه‌جایی بین برنامه‌ها، با ۲ انگشت از پایین صفحه تند به‌بالا بکشید، نگه دارید، و سپس رها کنید."</string>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 91b5551..6a7efe5 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -46,7 +46,7 @@
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Voorspelde app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Het apparaat draaien"</string>
     <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Draai het apparaat om de tutorial voor navigatie met gebaren af te ronden"</string>
-    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Swipe helemaal vanaf de rechter- of linkerrand"</string>
+    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Swipe vanaf de rechter- of linkerrand"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Swipe vanaf de rechter- of linkerrand naar het midden van het scherm en laat los"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Je weet nu hoe je vanaf rechts kunt swipen om terug te gaan. Ontdek nu hoe je tussen apps schakelt."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Je weet nu hoe je het gebaar Terug maakt"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 81d69f9..c943da5 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -72,7 +72,7 @@
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Mantenha a janela pressionada por mais tempo antes de soltar"</string>
     <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Deslize para cima e pare"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Você aprendeu. Para desativar os gestos, acesse as Configurações."</string>
-    <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Você concluiu o gesto para trocar de app"</string>
+    <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Você concluiu o gesto para mudar de app"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Deslizar para trocar de app"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Para mudar de app, deslize de baixo para cima, mantenha a tela pressionada por um tempo e solte."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Para mudar de app, deslize de baixo para cima na tela com dois dedos, segure por um tempo e solte."</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index e436ec1..3980b21 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -72,7 +72,7 @@
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"尝试按住窗口较长时间,然后再松开手指"</string>
     <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"确保笔直向上滑动,然后停住"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"您已了解如何使用手势了。如要关闭手势,请前往“设置”。"</string>
-    <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"您完成了“切换应用”手势"</string>
+    <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"您完成了应用切换手势"</string>
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"滑动即可切换应用"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"如需在应用之间切换,请从屏幕底部向上滑动,按住,然后松开。"</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"如需在应用之间切换,请从屏幕底部向上滑动,按住,然后松开。"</string>
diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
index 28bd701..f64b5cf 100644
--- a/quickstep/src/com/android/launcher3/LauncherInitListener.java
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -15,23 +15,16 @@
  */
 package com.android.launcher3;
 
-import android.animation.AnimatorSet;
 import android.annotation.TargetApi;
 import android.os.Build;
-import android.os.CancellationSignal;
-import android.view.RemoteAnimationTarget;
 
-import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.quickstep.util.ActivityInitListener;
-import com.android.quickstep.util.RemoteAnimationProvider;
 
 import java.util.function.BiPredicate;
 
 @TargetApi(Build.VERSION_CODES.P)
 public class LauncherInitListener extends ActivityInitListener<Launcher> {
 
-    private RemoteAnimationProvider mRemoteAnimationProvider;
-
     /**
      * @param onInitListener a callback made when the activity is initialized. The callback should
      *                       return true to continue receiving callbacks (ie. for if the activity is
@@ -43,37 +36,7 @@
 
     @Override
     public boolean handleInit(Launcher launcher, boolean alreadyOnHome) {
-        if (mRemoteAnimationProvider != null) {
-            QuickstepTransitionManager appTransitionManager =
-                    ((QuickstepLauncher) launcher).getAppTransitionManager();
-
-            // Set a one-time animation provider. After the first call, this will get cleared.
-            // TODO: Probably also check the intended target id.
-            CancellationSignal cancellationSignal = new CancellationSignal();
-            appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() {
-                @Override
-                public AnimatorSet createWindowAnimation(RemoteAnimationTarget[] appTargets,
-                        RemoteAnimationTarget[] wallpaperTargets) {
-
-                    // On the first call clear the reference.
-                    cancellationSignal.cancel();
-                    RemoteAnimationProvider provider = mRemoteAnimationProvider;
-                    mRemoteAnimationProvider = null;
-
-                    if (provider != null && launcher.getStateManager().getState().overviewUi) {
-                        return provider.createWindowAnimation(appTargets, wallpaperTargets);
-                    }
-                    return null;
-                }
-            }, cancellationSignal);
-        }
         launcher.deferOverlayCallbacksUntilNextResumeOrStop();
         return super.handleInit(launcher, alreadyOnHome);
     }
-
-    @Override
-    public void unregister() {
-        mRemoteAnimationProvider = null;
-        super.unregister();
-    }
 }
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 110d275..c6c4dde 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -60,6 +60,8 @@
 import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
 import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
+import static com.android.systemui.shared.system.InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME;
+import static com.android.systemui.shared.system.InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME_FALLBACK;
 import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
 import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
 
@@ -82,7 +84,6 @@
 import android.graphics.RectF;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -140,7 +141,6 @@
 import com.android.quickstep.util.RectFSpringAnim;
 import com.android.quickstep.util.RectFSpringAnim.DefaultSpringConfig;
 import com.android.quickstep.util.RectFSpringAnim.TaskbarHotseatSpringConfig;
-import com.android.quickstep.util.RemoteAnimationProvider;
 import com.android.quickstep.util.StaggeredWorkspaceAnim;
 import com.android.quickstep.util.SurfaceTransaction;
 import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
@@ -229,7 +229,6 @@
 
     private DeviceProfile mDeviceProfile;
 
-    private RemoteAnimationProvider mRemoteAnimationProvider;
     // Strong refs to runners which are cleared when the launcher activity is destroyed
     private RemoteAnimationFactory mWallpaperOpenRunner;
     private RemoteAnimationFactory mAppLaunchRunner;
@@ -468,16 +467,6 @@
         return bounds;
     }
 
-    public void setRemoteAnimationProvider(final RemoteAnimationProvider animationProvider,
-            CancellationSignal cancellationSignal) {
-        mRemoteAnimationProvider = animationProvider;
-        cancellationSignal.setOnCancelListener(() -> {
-            if (animationProvider == mRemoteAnimationProvider) {
-                mRemoteAnimationProvider = null;
-            }
-        });
-    }
-
     /** Dump debug logs to bug report. */
     public void dump(@NonNull String prefix, @NonNull PrintWriter printWriter) {}
 
@@ -1234,7 +1223,7 @@
      * ie. pressing home, swiping up from nav bar.
      */
     RemoteAnimationFactory createWallpaperOpenRunner(boolean fromUnlock) {
-        return new WallpaperOpenLauncherAnimationRunner(mHandler, fromUnlock);
+        return new WallpaperOpenLauncherAnimationRunner(fromUnlock);
     }
 
     /**
@@ -1352,7 +1341,7 @@
     /**
      * Closing animator that animates the window into its final location on the workspace.
      */
-    private RectFSpringAnim getClosingWindowAnimators(AnimatorSet animation,
+    protected RectFSpringAnim getClosingWindowAnimators(AnimatorSet animation,
             RemoteAnimationTarget[] targets, View launcherView, PointF velocityPxPerS,
             RectF closingWindowStartRect, float startWindowCornerRadius) {
         FloatingIconView floatingIconView = null;
@@ -1592,89 +1581,80 @@
             RectF startRect,
             float startWindowCornerRadius,
             boolean fromPredictiveBack) {
-        AnimatorSet anim = null;
+        AnimatorSet anim = new AnimatorSet();
         RectFSpringAnim rectFSpringAnim = null;
 
-        RemoteAnimationProvider provider = mRemoteAnimationProvider;
-        if (provider != null) {
-            anim = provider.createWindowAnimation(appTargets, wallpaperTargets);
+        final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
+                || launcherIsATargetWithMode(appTargets, MODE_OPENING);
+
+        View launcherView = findLauncherView(appTargets);
+        boolean playFallBackAnimation = (launcherView == null
+                && launcherIsForceInvisibleOrOpening)
+                || mLauncher.getWorkspace().isOverlayShown()
+                || shouldPlayFallbackClosingAnimation(appTargets);
+
+        boolean playWorkspaceReveal = true;
+        boolean skipAllAppsScale = false;
+        if (fromUnlock) {
+            anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
+        } else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
+                && !playFallBackAnimation) {
+            // Use a fixed velocity to start the animation.
+            float velocityPxPerS = DynamicResource.provider(mLauncher)
+                    .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
+            PointF velocity = new PointF(0, -velocityPxPerS);
+            rectFSpringAnim = getClosingWindowAnimators(
+                    anim, appTargets, launcherView, velocity, startRect,
+                    startWindowCornerRadius);
+            if (mLauncher.isInState(LauncherState.ALL_APPS)) {
+                // Skip scaling all apps, otherwise FloatingIconView will get wrong
+                // layout bounds.
+                skipAllAppsScale = true;
+            } else if (!fromPredictiveBack) {
+                anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
+                        true /* animateOverviewScrim */, launcherView).getAnimators());
+
+                if (!areAllTargetsTranslucent(appTargets)) {
+                    anim.play(ObjectAnimator.ofFloat(mLauncher.getDepthController().stateDepth,
+                            MULTI_PROPERTY_VALUE,
+                            BACKGROUND_APP.getDepth(mLauncher), NORMAL.getDepth(mLauncher)));
+                }
+
+                // We play StaggeredWorkspaceAnim as a part of the closing window animation.
+                playWorkspaceReveal = false;
+            }
+        } else {
+            anim.play(getFallbackClosingWindowAnimators(appTargets));
         }
 
-        if (anim == null) {
-            anim = new AnimatorSet();
+        // Normally, we run the launcher content animation when we are transitioning
+        // home, but if home is already visible, then we don't want to animate the
+        // contents of launcher unless we know that we are animating home as a result
+        // of the home button press with quickstep, which will result in launcher being
+        // started on touch down, prior to the animation home (and won't be in the
+        // targets list because it is already visible). In that case, we force
+        // invisibility on touch down, and only reset it after the animation to home
+        // is initialized.
+        if (launcherIsForceInvisibleOrOpening) {
+            addCujInstrumentation(anim, playFallBackAnimation
+                    ? CUJ_APP_CLOSE_TO_HOME_FALLBACK :  CUJ_APP_CLOSE_TO_HOME);
+            // Only register the content animation for cancellation when state changes
+            mLauncher.getStateManager().setCurrentAnimation(anim);
 
-            final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible()
-                    || launcherIsATargetWithMode(appTargets, MODE_OPENING);
-
-            View launcherView = findLauncherView(appTargets);
-            boolean playFallBackAnimation = (launcherView == null
-                    && launcherIsForceInvisibleOrOpening)
-                    || mLauncher.getWorkspace().isOverlayShown()
-                    || shouldPlayFallbackClosingAnimation(appTargets);
-
-            boolean playWorkspaceReveal = true;
-            boolean skipAllAppsScale = false;
-            if (fromUnlock) {
-                anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
-            } else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
-                    && !playFallBackAnimation) {
-                // Use a fixed velocity to start the animation.
-                float velocityPxPerS = DynamicResource.provider(mLauncher)
-                        .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
-                PointF velocity = new PointF(0, -velocityPxPerS);
-                rectFSpringAnim = getClosingWindowAnimators(
-                        anim, appTargets, launcherView, velocity, startRect,
-                        startWindowCornerRadius);
-                if (mLauncher.isInState(LauncherState.ALL_APPS)) {
-                    // Skip scaling all apps, otherwise FloatingIconView will get wrong
-                    // layout bounds.
-                    skipAllAppsScale = true;
-                } else if (!fromPredictiveBack) {
-                    anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
-                            true /* animateOverviewScrim */, launcherView).getAnimators());
-
-                    if (!areAllTargetsTranslucent(appTargets)) {
-                        anim.play(ObjectAnimator.ofFloat(mLauncher.getDepthController().stateDepth,
-                                MULTI_PROPERTY_VALUE,
-                                BACKGROUND_APP.getDepth(mLauncher), NORMAL.getDepth(mLauncher)));
+            if (mLauncher.isInState(LauncherState.ALL_APPS)) {
+                Pair<AnimatorSet, Runnable> contentAnimator =
+                        getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY,
+                                skipAllAppsScale);
+                anim.play(contentAnimator.first);
+                anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        contentAnimator.second.run();
                     }
-
-                    // We play StaggeredWorkspaceAnim as a part of the closing window animation.
-                    playWorkspaceReveal = false;
-                }
+                });
             } else {
-                anim.play(getFallbackClosingWindowAnimators(appTargets));
-            }
-
-            // Normally, we run the launcher content animation when we are transitioning
-            // home, but if home is already visible, then we don't want to animate the
-            // contents of launcher unless we know that we are animating home as a result
-            // of the home button press with quickstep, which will result in launcher being
-            // started on touch down, prior to the animation home (and won't be in the
-            // targets list because it is already visible). In that case, we force
-            // invisibility on touch down, and only reset it after the animation to home
-            // is initialized.
-            if (launcherIsForceInvisibleOrOpening) {
-                addCujInstrumentation(
-                        anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
-                // Only register the content animation for cancellation when state changes
-                mLauncher.getStateManager().setCurrentAnimation(anim);
-
-                if (mLauncher.isInState(LauncherState.ALL_APPS)) {
-                    Pair<AnimatorSet, Runnable> contentAnimator =
-                            getLauncherContentAnimator(false, LAUNCHER_RESUME_START_DELAY,
-                                    skipAllAppsScale);
-                    anim.play(contentAnimator.first);
-                    anim.addListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            contentAnimator.second.run();
-                        }
-                    });
-                } else {
-                    if (playWorkspaceReveal) {
-                        anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
-                    }
+                if (playWorkspaceReveal) {
+                    anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
                 }
             }
         }
@@ -1687,11 +1667,9 @@
      */
     protected class WallpaperOpenLauncherAnimationRunner implements RemoteAnimationFactory {
 
-        private final Handler mHandler;
         private final boolean mFromUnlock;
 
-        public WallpaperOpenLauncherAnimationRunner(Handler handler, boolean fromUnlock) {
-            mHandler = handler;
+        public WallpaperOpenLauncherAnimationRunner(boolean fromUnlock) {
             mFromUnlock = fromUnlock;
         }
 
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index 85d0ab5..619bef2 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -114,8 +114,7 @@
         WorkspaceItemInfo dragItem = new WorkspaceItemInfo((WorkspaceItemInfo) v.getTag());
         v.setVisibility(View.INVISIBLE);
         mLauncher.getWorkspace().beginDragShared(
-                v, null, this, dragItem, new DragPreviewProvider(v),
-                mLauncher.getDefaultWorkspaceDragOptions());
+                v, null, this, dragItem, new DragPreviewProvider(v), new DragOptions());
         return true;
     };
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 9fe0c00..0b83a88 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -306,6 +306,9 @@
 
         // Initialize controllers after all are constructed.
         mControllers.init(sharedState);
+        // This may not be necessary and can be reverted once we move towards recreating all
+        // controllers without re-creating the window
+        mControllers.rotationButtonController.onNavigationModeChanged(mNavMode.resValue);
         updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
         disableNavBarElements(sharedState.disableNavBarDisplayId, sharedState.disableNavBarState1,
                 sharedState.disableNavBarState2, false /* animate */);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index a347908..b0d2c3c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -17,7 +17,6 @@
 
 import android.annotation.SuppressLint
 import android.content.Context
-import android.content.Intent
 import android.graphics.Rect
 import android.graphics.drawable.GradientDrawable
 import android.util.AttributeSet
@@ -44,9 +43,6 @@
     companion object {
         private const val TAG = "TaskbarDividerPopupView"
         private const val DIVIDER_POPUP_CLOSING_DELAY = 500L
-        private const val SETTINGS_PACKAGE_NAME = "com.android.settings"
-        private const val CHANGE_NAVIGATION_MODE_ACTION =
-            "com.android.settings.NAVIGATION_MODE_SETTINGS"
 
         @JvmStatic
         fun createAndPopulate(
@@ -103,21 +99,12 @@
         super.onFinishInflate()
         val taskbarSwitchOption = findViewById<LinearLayout>(R.id.taskbar_switch_option)
         val alwaysShowTaskbarSwitch = findViewById<Switch>(R.id.taskbar_pinning_switch)
-        val navigationModeChangeOption =
-            findViewById<LinearLayout>(R.id.navigation_mode_switch_option)
         alwaysShowTaskbarSwitch.isChecked = alwaysShowTaskbarOn
         taskbarSwitchOption.setOnClickListener {
             alwaysShowTaskbarSwitch.isClickable = true
             alwaysShowTaskbarSwitch.isChecked = !alwaysShowTaskbarOn
             onClickAlwaysShowTaskbarSwitchOption()
         }
-        navigationModeChangeOption.setOnClickListener {
-            context.startActivity(
-                Intent(CHANGE_NAVIGATION_MODE_ACTION)
-                    .setPackage(SETTINGS_PACKAGE_NAME)
-                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-            )
-        }
     }
 
     /** Orient object as usual and then center object horizontally. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index a935bac..c51a7ec 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.taskbar
 
+import android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR
 import android.graphics.Insets
 import android.graphics.Region
 import android.os.Binder
@@ -43,6 +44,7 @@
 import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
 import com.android.launcher3.util.DisplayController
 import java.io.PrintWriter
+import kotlin.jvm.optionals.getOrNull
 
 /** Handles the insets that Taskbar provides to underlying apps and the IME. */
 class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
@@ -198,16 +200,22 @@
 
         val imeInsetsSize = getInsetsForGravity(taskbarHeightForIme, gravity)
         val imeInsetsSizeOverride =
-                arrayOf(
-                        InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
-                )
+                if (!ENABLE_HIDE_IME_CAPTION_BAR) {
+                    arrayOf(
+                            InsetsFrameProvider.InsetsSizeOverride(
+                                    TYPE_INPUT_METHOD,
+                                    imeInsetsSize
+                            ),
+                    )
+                } else {
+                    arrayOf()
+                }
         // Use 0 tappableElement insets for the VoiceInteractionWindow when gesture nav is enabled.
         val visInsetsSizeForTappableElement =
                 if (context.isGestureNav) getInsetsForGravity(0, gravity)
                 else getInsetsForGravity(tappableHeight, gravity)
         val insetsSizeOverrideForTappableElement =
-                arrayOf(
-                        InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
+                imeInsetsSizeOverride + arrayOf(
                         InsetsFrameProvider.InsetsSizeOverride(
                                 TYPE_VOICE_INTERACTION,
                                 visInsetsSizeForTappableElement
@@ -216,7 +224,7 @@
         if ((context.isGestureNav || TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
                 && provider.type == tappableElement()) {
             provider.insetsSizeOverrides = insetsSizeOverrideForTappableElement
-        } else if (provider.type != systemGestures()) {
+        } else if (provider.type != systemGestures() && imeInsetsSizeOverride.isNotEmpty()) {
             // We only override insets at the bottom of the screen
             provider.insetsSizeOverrides = imeInsetsSizeOverride
         }
@@ -283,9 +291,24 @@
                 controllers.uiController.isInOverview &&
                     DisplayController.isTransientTaskbar(context)
             ) {
-                insetsInfo.touchableRegion.set(
+                val region =
                     controllers.taskbarActivityContext.dragLayer.lastDrawnTransientRect.toRegion()
-                )
+                val bubbleBarBounds =
+                    controllers.bubbleControllers.getOrNull()?.let { bubbleControllers ->
+                        if (!bubbleControllers.bubbleStashController.isBubblesShowingOnOverview) {
+                            return@let null
+                        }
+                        if (!bubbleControllers.bubbleBarViewController.isBubbleBarVisible) {
+                            return@let null
+                        }
+                        bubbleControllers.bubbleBarViewController.bubbleBarBounds
+                    }
+
+                // Include the bounds of the bubble bar in the touchable region if they exist.
+                if (bubbleBarBounds != null) {
+                    region.op(bubbleBarBounds, Region.Op.UNION)
+                }
+                insetsInfo.touchableRegion.set(region)
             } else {
                 insetsInfo.touchableRegion.set(touchableRegion)
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 074cbe1..fa5a1ae 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -88,7 +88,7 @@
     private @Nullable IconButtonView mAllAppsButton;
 
     // Only non-null when device supports having an All Apps button.
-    private @Nullable View mTaskbarDivider;
+    private @Nullable IconButtonView mTaskbarDivider;
 
     private View mQsb;
 
@@ -158,8 +158,12 @@
                     mActivityContext.getColor(R.color.all_apps_button_color));
 
             if (FeatureFlags.ENABLE_TASKBAR_PINNING.get()) {
-                mTaskbarDivider = LayoutInflater.from(context).inflate(R.layout.taskbar_divider,
+                mTaskbarDivider = (IconButtonView) LayoutInflater.from(context).inflate(
+                        R.layout.taskbar_divider,
                         this, false);
+                mTaskbarDivider.setIconDrawable(
+                        resources.getDrawable(R.drawable.taskbar_divider_button));
+                mTaskbarDivider.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
             }
         }
 
@@ -382,11 +386,6 @@
         int count = getChildCount();
         DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         int spaceNeeded = getIconLayoutWidth();
-        // We are removing the margin from taskbar divider item in taskbar,
-        // so remove it from spacing also.
-        if (FeatureFlags.ENABLE_TASKBAR_PINNING.get() && count > 1) {
-            spaceNeeded -= mIconTouchSize;
-        }
         int navSpaceNeeded = deviceProfile.hotseatBarEndOffset;
         boolean layoutRtl = isLayoutRtl();
         int centerAlignIconEnd = right - (right - left - spaceNeeded) / 2;
@@ -507,7 +506,15 @@
         if (deviceProfile.isQsbInline) {
             countExcludingQsb--;
         }
-        return countExcludingQsb * (mItemMarginLeftRight * 2 + mIconTouchSize);
+        int iconLayoutBoundsWidth =
+                countExcludingQsb * (mItemMarginLeftRight * 2 + mIconTouchSize);
+
+        if (FeatureFlags.ENABLE_TASKBAR_PINNING.get() && countExcludingQsb > 1) {
+            // We are removing 4 * mItemMarginLeftRight as there should be no space between
+            // All Apps icon, divider icon, and first app icon in taskbar
+            iconLayoutBoundsWidth -= mItemMarginLeftRight * 4;
+        }
+        return iconLayoutBoundsWidth;
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index 0ff0469..41c3dec 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -17,7 +17,6 @@
 
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 
-import android.os.SystemProperties;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
@@ -43,10 +42,6 @@
 public class BubbleDismissController {
     private static final String TAG = BubbleDismissController.class.getSimpleName();
     private static final float FLING_TO_DISMISS_MIN_VELOCITY = 6000f;
-    // LINT.IfChange
-    private static final boolean ENABLE_FLING_TO_DISMISS_BUBBLE =
-            SystemProperties.getBoolean("persist.wm.debug.fling_to_dismiss_bubble", true);
-    // LINT.ThenChange(com/android/wm/shell/bubbles/BubbleStackView.java)
     private final TaskbarActivityContext mActivity;
     private final TaskbarDragLayer mDragLayer;
     @Nullable
@@ -182,7 +177,6 @@
         };
 
         mMagnetizedObject.setHapticsEnabled(true);
-        mMagnetizedObject.setFlingToTargetEnabled(ENABLE_FLING_TO_DISMISS_BUBBLE);
         mMagnetizedObject.setFlingToTargetMinVelocity(FLING_TO_DISMISS_MIN_VELOCITY);
         if (mMagneticTarget != null) {
             mMagnetizedObject.addTarget(mMagneticTarget);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index 00c2ca1..a5ea5a9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -197,6 +197,11 @@
         }
     }
 
+    /** Whether bubbles are showing on Overview. */
+    public boolean isBubblesShowingOnOverview() {
+        return mBubblesShowingOnOverview;
+    }
+
     /** Called when sysui locked state changes, when locked, bubble bar is stashed. */
     public void onSysuiLockedStateChange(boolean isSysuiLocked) {
         if (isSysuiLocked != mIsSysuiLocked) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index a53dc15..475f465 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -16,13 +16,16 @@
 
 package com.android.launcher3.uioverrides;
 
+import android.app.ActivityOptions;
 import android.app.Person;
 import android.content.Context;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
 import android.content.pm.ShortcutInfo;
+import android.window.RemoteTransition;
 
 import com.android.launcher3.Utilities;
+import com.android.quickstep.util.FadeOutRemoteTransition;
 
 import java.util.Map;
 
@@ -41,4 +44,13 @@
     public static Map<String, LauncherActivityInfo> getActivityOverrides(Context context) {
         return context.getSystemService(LauncherApps.class).getActivityOverrides();
     }
+
+    /**
+     * Creates an ActivityOptions to play fade-out animation on closing targets
+     */
+    public static ActivityOptions createFadeOutAnimOptions(Context context) {
+        ActivityOptions options = ActivityOptions.makeBasic();
+        options.setRemoteTransition(new RemoteTransition(new FadeOutRemoteTransition()));
+        return options;
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 08ce794..b444b49 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -33,9 +33,7 @@
 import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
-import static com.android.launcher3.config.FeatureFlags.RECEIVE_UNFOLD_EVENTS_FROM_SYSUI;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
@@ -59,8 +57,6 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.Intent;
@@ -70,19 +66,15 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.hardware.SensorManager;
-import android.hardware.devicestate.DeviceStateManager;
 import android.hardware.display.DisplayManager;
 import android.media.permission.SafeCloseable;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.CancellationSignal;
 import android.os.IBinder;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.view.Display;
 import android.view.HapticFeedbackConstants;
-import android.view.RemoteAnimationTarget;
 import android.view.View;
 import android.window.BackEvent;
 import android.window.OnBackAnimationCallback;
@@ -110,7 +102,6 @@
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.appprediction.PredictionRowView;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.hybridhotseat.HotseatPredictionController;
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.StatsLogManager;
@@ -162,10 +153,7 @@
 import com.android.quickstep.TouchInteractionService.TISBinder;
 import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.util.LauncherUnfoldAnimationController;
-import com.android.quickstep.util.ProxyScreenStatusProvider;
 import com.android.quickstep.util.QuickstepOnboardingPrefs;
-import com.android.quickstep.util.RemoteAnimationProvider;
-import com.android.quickstep.util.RemoteFadeOutAnimationListener;
 import com.android.quickstep.util.SplitSelectStateController;
 import com.android.quickstep.util.SplitToWorkspaceController;
 import com.android.quickstep.util.SplitWithKeyboardShortcutController;
@@ -178,14 +166,11 @@
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.unfold.RemoteUnfoldSharedComponent;
-import com.android.systemui.unfold.UnfoldSharedComponent;
 import com.android.systemui.unfold.UnfoldTransitionFactory;
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
 import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig;
 import com.android.systemui.unfold.config.UnfoldTransitionConfig;
 import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver;
-import com.android.systemui.unfold.system.ActivityManagerActivityTypeProvider;
-import com.android.systemui.unfold.system.DeviceStateManagerFoldProvider;
 import com.android.systemui.unfold.updates.RotationChangeProvider;
 
 import java.io.FileDescriptor;
@@ -200,9 +185,10 @@
 import java.util.stream.Stream;
 
 public class QuickstepLauncher extends Launcher {
-
-    public static final boolean ENABLE_PIP_KEEP_CLEAR_ALGORITHM =
-            SystemProperties.getBoolean("persist.wm.debug.enable_pip_keep_clear_algorithm", true);
+    private static final boolean TRACE_LAYOUTS =
+            SystemProperties.getBoolean("persist.debug.trace_layouts", false);
+    private static final String TRACE_RELAYOUT_CLASS =
+            SystemProperties.get("persist.debug.trace_request_layout_class", null);
 
     public static final boolean GO_LOW_RAM_RECENTS_ENABLED = false;
 
@@ -217,7 +203,6 @@
     private TISBindHelper mTISBindHelper;
     private @Nullable LauncherTaskbarUIController mTaskbarUIController;
     // Will be updated when dragging from taskbar.
-    private @Nullable DragOptions mNextWorkspaceDragOptions = null;
     private @Nullable UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider;
     private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController;
 
@@ -439,12 +424,8 @@
             boolean visible = (state == NORMAL || state == OVERVIEW)
                     && (willUserBeActive || isUserActive())
                     && !profile.isVerticalBarLayout();
-            if (ENABLE_PIP_KEEP_CLEAR_ALGORITHM)  {
-                SystemUiProxy.INSTANCE.get(this)
-                        .setLauncherKeepClearAreaHeight(visible, profile.hotseatBarSizePx);
-            } else {
-                SystemUiProxy.INSTANCE.get(this).setShelfHeight(visible, profile.hotseatBarSizePx);
-            }
+            SystemUiProxy.INSTANCE.get(this)
+                    .setLauncherKeepClearAreaHeight(visible, profile.hotseatBarSizePx);
         }
         if (state == NORMAL && !inTransition) {
             ((RecentsView) getOverviewPanel()).setSwipeDownShouldLaunchApp(false);
@@ -476,10 +457,7 @@
     public void onDestroy() {
         mAppTransitionManager.onActivityDestroyed();
         if (mUnfoldTransitionProgressProvider != null) {
-            if (FeatureFlags.RECEIVE_UNFOLD_EVENTS_FROM_SYSUI.get()) {
-                SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null);
-            }
-
+            SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null);
             mUnfoldTransitionProgressProvider.destroy();
         }
 
@@ -493,6 +471,10 @@
             mDesktopVisibilityController.unregisterSystemUiListener();
         }
 
+        if (mSplitSelectStateController != null) {
+            mSplitSelectStateController.onDestroy();
+        }
+
         super.onDestroy();
         mHotseatPredictionController.destroy();
         mSplitWithKeyboardShortcutController.onDestroy();
@@ -615,6 +597,8 @@
             mViewCapture = SettingsAwareViewCapture.getInstance(this).startCapture(getWindow());
         }
         getWindow().addPrivateFlags(PRIVATE_FLAG_OPTIMIZE_MEASURE);
+        View.setTraceLayoutSteps(TRACE_LAYOUTS);
+        View.setTracedRequestLayoutClassClass(TRACE_RELAYOUT_CLASS);
     }
 
     @Override
@@ -914,43 +898,10 @@
     private void initUnfoldTransitionProgressProvider() {
         final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig();
         if (config.isEnabled()) {
-            if (RECEIVE_UNFOLD_EVENTS_FROM_SYSUI.get()) {
-                initRemotelyCalculatedUnfoldAnimation(config);
-            } else {
-                initLocallyCalculatedUnfoldAnimation(config);
-            }
-
+            initRemotelyCalculatedUnfoldAnimation(config);
         }
     }
 
-    /** Registers hinge angle listener and calculates the animation progress in this process. */
-    private void initLocallyCalculatedUnfoldAnimation(UnfoldTransitionConfig config) {
-        UnfoldSharedComponent unfoldComponent =
-                UnfoldTransitionFactory.createUnfoldSharedComponent(
-                        /* context= */ this,
-                        config,
-                        ProxyScreenStatusProvider.INSTANCE,
-                        new DeviceStateManagerFoldProvider(
-                                getSystemService(DeviceStateManager.class), /* context= */ this),
-                        new ActivityManagerActivityTypeProvider(
-                                getSystemService(ActivityManager.class)),
-                        getSystemService(SensorManager.class),
-                        getMainThreadHandler(),
-                        getMainExecutor(),
-                        /* backgroundExecutor= */ UI_HELPER_EXECUTOR,
-                        /* tracingTagPrefix= */ "launcher",
-                        getSystemService(DisplayManager.class)
-                );
-
-        mUnfoldTransitionProgressProvider = unfoldComponent.getUnfoldTransitionProvider()
-                .orElseThrow(() -> new IllegalStateException(
-                        "Trying to create UnfoldTransitionProgressProvider when the "
-                                + "transition is disabled"));
-
-        initUnfoldAnimationController(mUnfoldTransitionProgressProvider,
-                unfoldComponent.getRotationChangeProvider());
-    }
-
     /** Receives animation progress from sysui process. */
     private void initRemotelyCalculatedUnfoldAnimation(UnfoldTransitionConfig config) {
         RemoteUnfoldSharedComponent unfoldComponent =
@@ -1043,41 +994,6 @@
     }
 
     @Override
-    public DragOptions getDefaultWorkspaceDragOptions() {
-        if (mNextWorkspaceDragOptions != null) {
-            DragOptions options = mNextWorkspaceDragOptions;
-            mNextWorkspaceDragOptions = null;
-            return options;
-        }
-        return super.getDefaultWorkspaceDragOptions();
-    }
-
-    public void setNextWorkspaceDragOptions(DragOptions dragOptions) {
-        mNextWorkspaceDragOptions = dragOptions;
-    }
-
-    @Override
-    public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) {
-        QuickstepTransitionManager appTransitionManager = getAppTransitionManager();
-        appTransitionManager.setRemoteAnimationProvider(new RemoteAnimationProvider() {
-            @Override
-            public AnimatorSet createWindowAnimation(RemoteAnimationTarget[] appTargets,
-                    RemoteAnimationTarget[] wallpaperTargets) {
-
-                // On the first call clear the reference.
-                signal.cancel();
-
-                ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0);
-                fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(appTargets,
-                        wallpaperTargets));
-                AnimatorSet anim = new AnimatorSet();
-                anim.play(fadeAnimation);
-                return anim;
-            }
-        }, signal);
-    }
-
-    @Override
     public float[] getNormalOverviewScaleAndOffset() {
         return DisplayController.getNavigationMode(this).hasGestures
                 ? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET};
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 796840d..1ef4039 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -34,7 +34,6 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_GESTURE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
-import static com.android.launcher3.uioverrides.QuickstepLauncher.ENABLE_PIP_KEEP_CLEAR_ALGORITHM;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
@@ -194,6 +193,7 @@
                     ActiveGestureLog.INSTANCE.addLog("Launcher destroyed", LAUNCHER_DESTROYED);
                     mRecentsView = null;
                     mActivity = null;
+                    mStateCallback.clearState(STATE_LAUNCHER_PRESENT);
                 }
             };
 
@@ -518,20 +518,22 @@
         // Set up a entire animation lifecycle callback to notify the current recents view when
         // the animation is canceled
         mGestureState.runOnceAtState(STATE_RECENTS_ANIMATION_CANCELED, () -> {
-                HashMap<Integer, ThumbnailData> snapshots =
-                        mGestureState.consumeRecentsAnimationCanceledSnapshot();
-                if (snapshots != null) {
-                    mRecentsView.switchToScreenshot(snapshots, () -> {
-                        if (mRecentsAnimationController != null) {
-                            mRecentsAnimationController.cleanupScreenshot();
-                        } else if (mDeferredCleanupRecentsAnimationController != null) {
-                            mDeferredCleanupRecentsAnimationController.cleanupScreenshot();
-                            mDeferredCleanupRecentsAnimationController = null;
-                        }
-                    });
-                    mRecentsView.onRecentsAnimationComplete();
-                }
-            });
+            if (mRecentsView == null) return;
+
+            HashMap<Integer, ThumbnailData> snapshots =
+                    mGestureState.consumeRecentsAnimationCanceledSnapshot();
+            if (snapshots != null) {
+                mRecentsView.switchToScreenshot(snapshots, () -> {
+                    if (mRecentsAnimationController != null) {
+                        mRecentsAnimationController.cleanupScreenshot();
+                    } else if (mDeferredCleanupRecentsAnimationController != null) {
+                        mDeferredCleanupRecentsAnimationController.cleanupScreenshot();
+                        mDeferredCleanupRecentsAnimationController = null;
+                    }
+                });
+                mRecentsView.onRecentsAnimationComplete();
+            }
+        });
 
         setupRecentsViewUi();
         mRecentsView.runOnPageScrollsInitialized(this::linkRecentsViewScroll);
@@ -1753,11 +1755,6 @@
 
     private Rect getKeepClearAreaForHotseat() {
         Rect keepClearArea;
-        if (!ENABLE_PIP_KEEP_CLEAR_ALGORITHM) {
-            // make the height equal to hotseatBarSizePx only
-            keepClearArea = new Rect(0, 0, 0, mDp.hotseatBarSizePx);
-            return keepClearArea;
-        }
         // the keep clear area in global screen coordinates, in pixels
         if (mDp.isPhone) {
             if (mDp.isSeascape()) {
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 2e1a62c..72439de 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -37,6 +37,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Trace;
+import android.util.Log;
 import android.view.Display;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationTarget;
@@ -59,7 +60,6 @@
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
@@ -67,6 +67,7 @@
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.taskbar.FallbackTaskbarUIController;
 import com.android.launcher3.taskbar.TaskbarManager;
+import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.ActivityOptionsWrapper;
 import com.android.launcher3.util.ActivityTracker;
 import com.android.launcher3.util.RunnableList;
@@ -393,7 +394,7 @@
         super.onDestroy();
         ACTIVITY_TRACKER.onActivityDestroyed(this);
         mActivityLaunchAnimationRunner = null;
-
+        mSplitSelectStateController.onDestroy();
         mTISBindHelper.onDestroy();
     }
 
@@ -404,6 +405,7 @@
     }
 
     public void startHome() {
+        Log.d(TestProtocol.INCORRECT_HOME_STATE, "start home from recents activity");
         RecentsView recentsView = getOverviewPanel();
         recentsView.switchToScreenshot(() -> recentsView.finishRecentsAnimation(true,
                 this::startHomeInternal));
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 6dbb5bf..0b5a070 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -38,6 +38,7 @@
 
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
 import com.android.quickstep.util.ActiveGestureLog;
@@ -179,6 +180,9 @@
                         RecentsView recentsView =
                                 activityInterface.getCreatedActivity().getOverviewPanel();
                         if (recentsView != null) {
+                            Log.d(TestProtocol.INCORRECT_HOME_STATE,
+                                    "finish recents animation on "
+                                            + compat.taskInfo.description);
                             recentsView.finishRecentsAnimation(true, null);
                         }
                         return;
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 2d5b8db..af49774 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -413,20 +413,14 @@
     }
 
     /**
-     * TODO: This doesn't animate at present. Feel free to blow out everyhing in this method
-     * if needed
+     * If {@param launchingTaskView} is not null, then this will play the tasks launch animation
+     * from the position of the GroupedTaskView (when user taps on the TaskView to start it).
+     * Technically this case should be taken care of by
+     * {@link #composeRecentsSplitLaunchAnimatorLegacy} below, but the way we launch tasks whether
+     * it's a single task or multiple tasks results in different entry-points.
      *
-     * We could manually try to animate the just the bounds for the leashes we get back, but we try
-     * to do it through TaskViewSimulator(TVS) since that handles a lot of the recents UI stuff for
-     * us.
-     *
-     * First you have to call TVS#setPreview() to indicate which leash it will operate one
-     * Then operations happen in TVS#apply() on each frame callback.
-     *
-     * TVS uses DeviceProfile to try to figure out things like task height and such based on if the
-     * device is in multiWindowMode or not. It's unclear given the two calls to startTask() when the
-     * device is considered in multiWindowMode and things like insets and stuff change
-     * and calculations have to be adjusted in the animations for that
+     * If it is null, then it will simply fade in the starting apps and fade out launcher (for the
+     * case where launcher handles animating starting split tasks from app icon)
      */
     public static void composeRecentsSplitLaunchAnimator(GroupedTaskView launchingTaskView,
             @NonNull StateManager stateManager, @Nullable DepthController depthController,
@@ -461,9 +455,9 @@
             return;
         }
 
-        // TODO: consider initialTaskPendingIntent
         TransitionInfo.Change splitRoot1 = null;
         TransitionInfo.Change splitRoot2 = null;
+        final ArrayList<SurfaceControl> openingTargets = new ArrayList<>();
         for (int i = 0; i < transitionInfo.getChanges().size(); ++i) {
             final TransitionInfo.Change change = transitionInfo.getChanges().get(i);
             if (change.getTaskInfo() == null) {
@@ -484,32 +478,48 @@
             if (taskId == initialTaskId) {
                 splitRoot1 = change.getParent() == null ? change :
                         transitionInfo.getChange(change.getParent());
+                openingTargets.add(splitRoot1.getLeash());
             }
             if (taskId == secondTaskId) {
                 splitRoot2 = change.getParent() == null ? change :
                         transitionInfo.getChange(change.getParent());
+                openingTargets.add(splitRoot2.getLeash());
             }
         }
 
-        // This is where we should animate the split roots. For now, though, just make them visible.
-        animateSplitRoot(t, splitRoot1);
-        animateSplitRoot(t, splitRoot2);
+        SurfaceControl.Transaction animTransaction = new SurfaceControl.Transaction();
+        ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+        animator.setDuration(SPLIT_LAUNCH_DURATION);
+        animator.addUpdateListener(valueAnimator -> {
+            float progress = valueAnimator.getAnimatedFraction();
+            for (SurfaceControl leash: openingTargets) {
+                animTransaction.setAlpha(leash, progress);
+            }
+            animTransaction.apply();
+        });
+        animator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                for (SurfaceControl leash: openingTargets) {
+                    animTransaction.show(leash)
+                            .setAlpha(leash, 0.0f);
+                }
+                animTransaction.apply();
+            }
 
-        // This contains the initial state (before animation), so apply this at the beginning of
-        // the animation.
-        t.apply();
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                finishCallback.run();
+            }
+        });
 
-        // Once there is an animation, this should be called AFTER the animation completes.
-        finishCallback.run();
-    }
-
-    private static void animateSplitRoot(SurfaceControl.Transaction t,
-            TransitionInfo.Change splitRoot) {
-        testLogD(LAUNCH_SPLIT_PAIR, "animateSplitRoot: " + splitRoot);
-        if (splitRoot != null) {
-            t.show(splitRoot.getLeash());
-            t.setAlpha(splitRoot.getLeash(), 1.f);
+        if (splitRoot1 != null && splitRoot1.getParent() != null) {
+            // Set the highest level split root alpha; we could technically use the parent of either
+            // splitRoot1 or splitRoot2
+            t.setAlpha(transitionInfo.getChange(splitRoot1.getParent()).getLeash(), 1f);
         }
+        t.apply();
+        animator.start();
     }
 
     /**
@@ -522,7 +532,9 @@
      * it's a single task or multiple tasks results in different entry-points.
      *
      * If it is null, then it will simply fade in the starting apps and fade out launcher (for the
-     * case where launcher handles animating starting split tasks from app icon) */
+     * case where launcher handles animating starting split tasks from app icon)
+     * @deprecated with shell transitions
+     */
     public static void composeRecentsSplitLaunchAnimatorLegacy(
             @Nullable GroupedTaskView launchingTaskView, int initialTaskId, int secondTaskId,
             @NonNull RemoteAnimationTarget[] appTargets,
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 7a9f88a..22aca25 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -70,6 +70,7 @@
 import android.os.SystemClock;
 import android.util.Log;
 import android.view.Choreographer;
+import android.view.InputDevice;
 import android.view.InputEvent;
 import android.view.MotionEvent;
 import android.view.SurfaceControl;
@@ -116,7 +117,6 @@
 import com.android.quickstep.inputconsumers.TrackpadStatusBarInputConsumer;
 import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.ActiveGestureLog.CompoundString;
-import com.android.quickstep.util.ProxyScreenStatusProvider;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -302,24 +302,6 @@
 
         @BinderThread
         @Override
-        public void onScreenTurnedOn() {
-            MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurnedOn);
-        }
-
-        @BinderThread
-        @Override
-        public void onScreenTurningOn() {
-            MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurningOn);
-        }
-
-        @BinderThread
-        @Override
-        public void onScreenTurningOff() {
-            MAIN_EXECUTOR.execute(ProxyScreenStatusProvider.INSTANCE::onScreenTurningOff);
-        }
-
-        @BinderThread
-        @Override
         public void enterStageSplitFromRunningApp(boolean leftOrTop) {
             executeForTouchInteractionService(tis -> {
                 StatefulActivity activity =
@@ -771,7 +753,7 @@
         if (mGestureState.isTrackpadGesture() && (action == ACTION_POINTER_DOWN
                 || action == ACTION_POINTER_UP)) {
             // Skip ACTION_POINTER_DOWN and ACTION_POINTER_UP events from trackpad.
-        } else if (event.isHoverEvent()) {
+        } else if (isCursorHoverEvent(event)) {
             mUncheckedConsumer.onHoverEvent(event);
         } else {
             mUncheckedConsumer.onMotionEvent(event);
@@ -783,6 +765,11 @@
         traceToken.close();
     }
 
+    // Talkback generates hover events on touch, which we do not want to consume.
+    private boolean isCursorHoverEvent(MotionEvent event) {
+        return event.isHoverEvent() && event.getSource() == InputDevice.SOURCE_MOUSE;
+    }
+
     private InputConsumer tryCreateAssistantInputConsumer(
             GestureState gestureState, MotionEvent motionEvent) {
         return tryCreateAssistantInputConsumer(
@@ -914,7 +901,8 @@
                     base = new TaskbarUnstashInputConsumer(this, base, mInputMonitorCompat, tac,
                             mOverviewCommandHelper);
                 }
-            } else if (canStartSystemGesture && FeatureFlags.ENABLE_LONG_PRESS_NAV_HANDLE.get()) {
+            } else if (canStartSystemGesture && FeatureFlags.ENABLE_LONG_PRESS_NAV_HANDLE.get()
+                    && !previousGestureState.isRecentsAnimationRunning()) {
                 base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat);
             }
 
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 4b13cd1..0e90e50 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -15,7 +15,6 @@
  */
 package com.android.quickstep.inputconsumers;
 
-import static android.view.MotionEvent.ACTION_BUTTON_RELEASE;
 import static android.view.MotionEvent.INVALID_POINTER_ID;
 
 import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
@@ -29,6 +28,7 @@
 import android.graphics.Rect;
 import android.view.GestureDetector;
 import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.InputDevice;
 import android.view.MotionEvent;
 
 import androidx.annotation.Nullable;
@@ -130,8 +130,8 @@
     public void onMotionEvent(MotionEvent ev) {
         mLongPressDetector.onTouchEvent(ev);
         if (mState != STATE_ACTIVE) {
-            boolean isStashedTaskbarHovered =
-                    isStashedTaskbarHovered((int) ev.getX(), (int) ev.getY());
+            boolean isStashedTaskbarHovered = isMouseEvent(ev)
+                    && isStashedTaskbarHovered((int) ev.getX(), (int) ev.getY());
             if (!isStashedTaskbarHovered) {
                 mDelegate.onMotionEvent(ev);
             }
@@ -229,7 +229,7 @@
                         mHasPassedTaskbarNavThreshold = false;
                         mIsInBubbleBarArea = false;
                         break;
-                    case ACTION_BUTTON_RELEASE:
+                    case MotionEvent.ACTION_BUTTON_RELEASE:
                         if (isStashedTaskbarHovered) {
                             mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_HOME);
                         }
@@ -342,4 +342,8 @@
                 dp.heightPx);
         return mStashedTaskbarHandleBounds.contains(x, y);
     }
+
+    private boolean isMouseEvent(MotionEvent event) {
+        return event.getSource() == InputDevice.SOURCE_MOUSE;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/FadeOutRemoteTransition.kt b/quickstep/src/com/android/quickstep/util/FadeOutRemoteTransition.kt
new file mode 100644
index 0000000..59ff81d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/FadeOutRemoteTransition.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util
+
+import android.animation.ValueAnimator
+import android.os.IBinder
+import android.os.RemoteException
+import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
+import android.window.IRemoteTransition
+import android.window.IRemoteTransitionFinishedCallback
+import android.window.TransitionInfo
+import com.android.launcher3.anim.AnimatorListeners.forEndCallback
+import com.android.launcher3.util.Executors
+import com.android.wm.shell.util.TransitionUtil
+
+/** Remote animation which fades out the closing targets */
+class FadeOutRemoteTransition : IRemoteTransition.Stub() {
+
+    override fun mergeAnimation(
+        iBinder: IBinder,
+        transitionInfo: TransitionInfo,
+        transaction: Transaction,
+        mergeTarget: IBinder,
+        finishCB: IRemoteTransitionFinishedCallback
+    ) {
+
+        try {
+            finishCB.onTransitionFinished(null, Transaction())
+        } catch (e: RemoteException) {
+            // Ignore
+        }
+    }
+
+    override fun startAnimation(
+        transition: IBinder,
+        info: TransitionInfo,
+        startT: Transaction,
+        finishCB: IRemoteTransitionFinishedCallback
+    ) {
+        val anim = ValueAnimator.ofFloat(1f, 0f)
+
+        val closingControls: MutableList<SurfaceControl> = mutableListOf()
+        for (chg in info.changes) {
+            startT.show(chg.leash)
+            if (TransitionUtil.isClosingType(chg.mode)) {
+                closingControls.add(chg.leash)
+            }
+        }
+        startT.apply()
+
+        anim.addUpdateListener {
+            val t = Transaction()
+            closingControls.forEach { t.setAlpha(it, anim.animatedValue as Float) }
+            t.apply()
+        }
+        anim.addListener(
+            forEndCallback(
+                Runnable {
+                    val t = Transaction()
+                    closingControls.forEach { t.hide(it) }
+                    try {
+                        finishCB.onTransitionFinished(null, t)
+                    } catch (e: RemoteException) {
+                        // Ignore
+                    }
+                }
+            )
+        )
+
+        Executors.MAIN_EXECUTOR.execute { anim.start() }
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java b/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java
deleted file mode 100644
index 8f79ccf..0000000
--- a/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.util;
-
-import androidx.annotation.NonNull;
-
-import com.android.systemui.unfold.updates.screen.ScreenStatusProvider;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Screen status provider implementation that exposes methods to provide screen
- * status updates to listeners. It is used to receive screen turned on event from
- * SystemUI to Launcher.
- */
-public class ProxyScreenStatusProvider implements ScreenStatusProvider {
-
-    public static final ProxyScreenStatusProvider INSTANCE = new ProxyScreenStatusProvider();
-    private final List<ScreenListener> mListeners = new ArrayList<>();
-
-    /**
-     * Called when the screen is on and ready (windows are drawn and screen blocker is removed)
-     */
-    public void onScreenTurnedOn() {
-        mListeners.forEach(ScreenListener::onScreenTurnedOn);
-    }
-
-    /** Called when the screen is starting to turn on. */
-    public void onScreenTurningOn() {
-        mListeners.forEach(ScreenListener::onScreenTurningOn);
-    }
-
-    /** Called when the screen is starting to turn off. */
-    public void onScreenTurningOff() {
-        mListeners.forEach(ScreenListener::onScreenTurningOff);
-    }
-
-    @Override
-    public void addCallback(@NonNull ScreenListener listener) {
-        mListeners.add(listener);
-    }
-
-    @Override
-    public void removeCallback(@NonNull ScreenListener listener) {
-        mListeners.remove(listener);
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
deleted file mode 100644
index 10f2eaa..0000000
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.util;
-
-import android.animation.AnimatorSet;
-import android.view.RemoteAnimationTarget;
-
-public abstract class RemoteAnimationProvider {
-
-    public abstract AnimatorSet createWindowAnimation(RemoteAnimationTarget[] appTargets,
-            RemoteAnimationTarget[] wallpaperTargets);
-
-    /**
-     * @return the target with the lowest opaque layer for a certain app animation, or null.
-     */
-    public static RemoteAnimationTarget findLowestOpaqueLayerTarget(
-            RemoteAnimationTarget[] appTargets, int mode) {
-        int lowestLayer = Integer.MAX_VALUE;
-        int lowestLayerIndex = -1;
-        for (int i = appTargets.length - 1; i >= 0; i--) {
-            RemoteAnimationTarget target = appTargets[i];
-            if (target.mode == mode && !target.isTranslucent) {
-                int layer = target.prefixOrderIndex;
-                if (layer < lowestLayer) {
-                    lowestLayer = layer;
-                    lowestLayerIndex = i;
-                }
-            }
-        }
-        return lowestLayerIndex != -1
-                ? appTargets[lowestLayerIndex]
-                : null;
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
deleted file mode 100644
index 382cf79..0000000
--- a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.util;
-
-import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl.Transaction;
-
-import com.android.quickstep.RemoteAnimationTargets;
-
-/**
- * Animation listener which fades out the closing targets
- */
-public class RemoteFadeOutAnimationListener implements AnimatorUpdateListener {
-
-    private final RemoteAnimationTargets mTarget;
-    private boolean mFirstFrame = true;
-
-    public RemoteFadeOutAnimationListener(RemoteAnimationTarget[] appTargets,
-            RemoteAnimationTarget[] wallpaperTargets) {
-        mTarget = new RemoteAnimationTargets(appTargets, wallpaperTargets,
-                new RemoteAnimationTarget[0], MODE_CLOSING);
-    }
-
-    @Override
-    public void onAnimationUpdate(ValueAnimator valueAnimator) {
-        Transaction t = new Transaction();
-        if (mFirstFrame) {
-            for (RemoteAnimationTarget target : mTarget.unfilteredApps) {
-                t.show(target.leash);
-            }
-            mFirstFrame = false;
-        }
-
-        float alpha = 1 - valueAnimator.getAnimatedFraction();
-        for (RemoteAnimationTarget app : mTarget.apps) {
-            t.setAlpha(app.leash, alpha);
-        }
-        t.apply();
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 5565139..6d5aa16 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -113,7 +113,7 @@
 public class SplitSelectStateController {
     private static final String TAG = "SplitSelectStateCtor";
 
-    private final Context mContext;
+    private Context mContext;
     private final Handler mHandler;
     private final RecentsModel mRecentTasksModel;
     private final SplitAnimationController mSplitAnimationController;
@@ -157,6 +157,10 @@
         mSplitSelectDataHolder = new SplitSelectDataHolder(mContext);
     }
 
+    public void onDestroy() {
+        mContext = null;
+    }
+
     /**
      * @param alreadyRunningTask if set to {@link android.app.ActivityTaskManager#INVALID_TASK_ID}
      *                           then @param intent will be used to launch the initial task
@@ -592,9 +596,8 @@
                             if (mSuccessCallback != null) {
                                 mSuccessCallback.accept(true);
                             }
+                            resetState();
                         });
-                // After successful launch, call resetState
-                resetState();
             });
         }
 
diff --git a/quickstep/src/com/android/quickstep/util/SurfaceTransaction.java b/quickstep/src/com/android/quickstep/util/SurfaceTransaction.java
index 441f88d..5fd86c0 100644
--- a/quickstep/src/com/android/quickstep/util/SurfaceTransaction.java
+++ b/quickstep/src/com/android/quickstep/util/SurfaceTransaction.java
@@ -166,5 +166,10 @@
             this.shadowRadius = radius;
             return this;
         }
+
+        @Override
+        public SurfaceProperties setShow() {
+            return this;
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 1112f4d..7cc2c46 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -26,7 +26,6 @@
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.os.SystemProperties;
 import android.util.Log;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -153,14 +152,9 @@
             // Create a new overlay layer. We do not call detach on this instance, it's propagated
             // to other classes like PipTaskOrganizer / RecentsAnimationController to complete
             // the cleanup.
-            if (SystemProperties.getBoolean(
-                    "persist.wm.debug.enable_pip_app_icon_overlay", true)) {
-                mPipContentOverlay = new PipContentOverlay.PipAppIconOverlay(view.getContext(),
-                        mAppBounds, new IconProvider(context).getIcon(mActivityInfo),
-                        appIconSizePx);
-            }  else {
-                mPipContentOverlay = new PipContentOverlay.PipColorOverlay(view.getContext());
-            }
+            mPipContentOverlay = new PipContentOverlay.PipAppIconOverlay(view.getContext(),
+                    mAppBounds, new IconProvider(context).getIcon(mActivityInfo),
+                    appIconSizePx);
             final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
             mPipContentOverlay.attach(tx, mLeash);
         } else {
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 83e9945..5f3fd0c 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -22,6 +22,7 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -43,6 +44,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.IconProvider;
 import com.android.launcher3.util.RunnableList;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.SystemUiProxy;
@@ -220,7 +222,22 @@
 
     private TaskIdAttributeContainer createAttributeContainer(Task task,
             TaskThumbnailView thumbnailView) {
-        return new TaskIdAttributeContainer(task, thumbnailView, null, STAGE_POSITION_UNDEFINED);
+        return new TaskIdAttributeContainer(task, thumbnailView, createIconView(task),
+                STAGE_POSITION_UNDEFINED);
+    }
+
+    private IconView createIconView(Task task) {
+        IconView iconView = new IconView(mContext);
+        PackageManager pm = mContext.getApplicationContext().getPackageManager();
+        try {
+            IconProvider provider = new IconProvider(mContext);
+            Drawable appIcon = provider.getIcon(pm.getActivityInfo(task.topActivity,
+                    PackageManager.ComponentInfoFlags.of(0)));
+            iconView.setDrawable(appIcon);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(TAG, "Package not found: " + task.topActivity.getPackageName(), e);
+        }
+        return iconView;
     }
 
     @Nullable
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 4b8741d..cb5b457 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -5296,6 +5296,8 @@
         cleanupRemoteTargets();
 
         if (mRecentsAnimationController == null) {
+            Log.d(TestProtocol.INCORRECT_HOME_STATE, "finish recents animation but recents "
+                    + "animation controller was null. returning.");
             if (onFinishComplete != null) {
                 onFinishComplete.run();
             }
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index 5127190..20aa410 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -16,14 +16,17 @@
 
 package com.android.quickstep;
 
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
+
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.launcher3.ui.TaplTestsLauncher3;
+import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -44,9 +47,9 @@
         startTestActivity(2);
     }
 
-    @Ignore
     @Test
     @NavigationModeSwitch
+    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/187761685
     public void testStressPressHome() {
         for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
             // Destroy Launcher activity.
@@ -57,9 +60,9 @@
         }
     }
 
-    @Ignore
     @Test
     @NavigationModeSwitch
+    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/187761685
     public void testStressSwipeToOverview() {
         for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
             // Destroy Launcher activity.
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 9d188ed..40d0ac7 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -18,6 +18,8 @@
 
 import static com.android.launcher3.testing.shared.TestProtocol.FLAKY_QUICK_SWITCH_TO_PREVIOUS_APP;
 import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
+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 org.junit.Assert.assertEquals;
@@ -50,6 +52,7 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Wait;
 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.util.rule.TestStabilityRule;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
 import com.android.quickstep.views.RecentsView;
@@ -320,6 +323,7 @@
     @Test
     @ScreenRecord // b/242163205
     @PlatinumTest(focusArea = "launcher")
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/286084688
     public void testQuickSwitchToPreviousAppForTablet() throws Exception {
         assumeTrue(mLauncher.isTablet());
         startTestActivity(2);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index 3317ce1..1aa7ab6 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -16,15 +16,21 @@
 package com.android.quickstep;
 
 
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
 import android.content.Intent;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.ui.TaplTestsLauncher3;
+import com.android.launcher3.util.rule.TestStabilityRule;
 import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
 
 import org.junit.After;
@@ -36,6 +42,9 @@
     private static final String CALCULATOR_APP_PACKAGE =
             resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
 
+    private static final String READ_DEVICE_CONFIG_PERMISSION =
+            "android.permission.READ_DEVICE_CONFIG";
+
     @Override
     @Before
     public void setUp() throws Exception {
@@ -46,6 +55,8 @@
             mLauncher.enableBlockTimeout(true);
             mLauncher.showTaskbarIfHidden();
         }
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
+                READ_DEVICE_CONFIG_PERMISSION);
     }
 
     @After
@@ -64,6 +75,7 @@
     @Test
     @PortraitLandscape
     @TaskbarModeSwitch
+    @TestStabilityRule.Stability(flavors = PLATFORM_POSTSUBMIT | LOCAL) // b/295225524
     public void testSplitAppFromHomeWithItself() throws Exception {
         // Currently only tablets have Taskbar in Overview, so test is only active on tablets
         assumeTrue(mLauncher.isTablet());
diff --git a/res/drawable/all_apps_tabs_background.xml b/res/drawable/all_apps_tabs_background.xml
index 8471cd4..1e7cff2 100644
--- a/res/drawable/all_apps_tabs_background.xml
+++ b/res/drawable/all_apps_tabs_background.xml
@@ -30,7 +30,7 @@
                 android:state_selected="false">
                 <shape android:shape="rectangle">
                     <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
-                    <solid android:color="@color/all_apps_tabs_background" />
+                    <solid android:color="@color/material_color_surface_bright" />
                 </shape>
             </item>
 
@@ -39,7 +39,7 @@
                 android:state_selected="true">
                 <shape android:shape="rectangle">
                     <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
-                    <solid android:color="@color/all_apps_tab_background_selected" />
+                    <solid android:color="@color/material_color_primary" />
                 </shape>
             </item>
         </selector>
diff --git a/res/drawable/bottom_rounded_popup_ripple.xml b/res/drawable/bottom_rounded_popup_ripple.xml
deleted file mode 100644
index 739833a..0000000
--- a/res/drawable/bottom_rounded_popup_ripple.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-    android:color="?android:attr/colorControlHighlight">
-    <item android:id="@android:id/mask">
-        <shape android:shape="rectangle">
-            <solid android:color="#FFFFFFFF"/>
-            <corners android:bottomLeftRadius="@dimen/dialogCornerRadius"
-                android:bottomRightRadius="@dimen/dialogCornerRadius"
-                android:topLeftRadius="0dp"
-                android:topRightRadius="0dp"/>
-        </shape>
-    </item>
-</ripple>
\ No newline at end of file
diff --git a/res/drawable/top_rounded_popup_ripple.xml b/res/drawable/rounded_popup_ripple.xml
similarity index 80%
rename from res/drawable/top_rounded_popup_ripple.xml
rename to res/drawable/rounded_popup_ripple.xml
index 7468480..b0dcc80 100644
--- a/res/drawable/top_rounded_popup_ripple.xml
+++ b/res/drawable/rounded_popup_ripple.xml
@@ -18,10 +18,7 @@
     <item android:id="@android:id/mask">
         <shape android:shape="rectangle">
             <solid android:color="#FFFFFFFF"/>
-            <corners android:bottomLeftRadius="0dp"
-                android:bottomRightRadius="0dp"
-                android:topLeftRadius="@dimen/dialogCornerRadius"
-                android:topRightRadius="@dimen/dialogCornerRadius"/>
+            <corners android:radius="@dimen/dialogCornerRadius" />
         </shape>
     </item>
 </ripple>
\ No newline at end of file
diff --git a/res/layout/work_apps_paused.xml b/res/layout/work_apps_paused.xml
index 52c5a49..695270e 100644
--- a/res/layout/work_apps_paused.xml
+++ b/res/layout/work_apps_paused.xml
@@ -15,7 +15,7 @@
 <com.android.launcher3.allapps.WorkPausedCard xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:padding="@dimen/work_edu_card_margin"
+    android:padding="@dimen/all_apps_tabs_margin_top"
     android:orientation="vertical"
     android:gravity="center_horizontal">
 
@@ -25,7 +25,6 @@
         android:id="@+id/work_apps_paused_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="40dp"
         android:text="@string/work_apps_paused_title"
         android:textAlignment="center"
         android:textSize="18sp" />
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 1695c58..4cb6414 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -32,7 +32,8 @@
     <style name="LauncherTheme" parent="@style/BaseLauncherTheme">
         <item name="android:textColorSecondary">#DE000000</item>
         <item name="allAppsScrimColor">?attr/materialColorSurfaceDim</item>
-        <item name="allappsHeaderProtectionColor">@color/popup_color_tertiary_light</item>
+        <item name="allappsHeaderProtectionColor">
+            @color/material_color_surface_container_highest</item>
         <item name="allAppsNavBarScrimColor">#66FFFFFF</item>
         <item name="popupColorPrimary">@color/popup_color_primary_light</item>
         <item name="popupColorSecondary">@color/popup_color_secondary_light</item>
@@ -149,6 +150,7 @@
         <item name="android:colorControlHighlight">#19FFFFFF</item>
         <item name="android:colorPrimary">#FF212121</item>
         <item name="allAppsScrimColor">?attr/materialColorSurfaceDim</item>
+        <item name="allappsHeaderProtectionColor">@color/material_color_surface_container_low</item>
         <item name="allAppsNavBarScrimColor">#80000000</item>
         <item name="popupColorPrimary">@color/popup_color_primary_dark</item>
         <item name="popupColorSecondary">@color/popup_color_secondary_dark</item>
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 8876a1b..808cf70 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -17,12 +17,7 @@
 package com.android.launcher3;
 
 import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
 
-import android.app.WallpaperColors;
-import android.app.WallpaperManager;
-import android.app.WallpaperManager.OnColorsChangedListener;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Point;
@@ -32,6 +27,7 @@
 import android.view.Display;
 import android.view.View;
 
+import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
@@ -41,9 +37,11 @@
 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.OnColorHintListener;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TraceHelper;
+import com.android.launcher3.util.WallpaperColorHints;
 import com.android.launcher3.util.WindowBounds;
 
 /**
@@ -51,7 +49,7 @@
  */
 @SuppressWarnings("NewApi")
 public abstract class BaseDraggingActivity extends BaseActivity
-        implements OnColorsChangedListener, DisplayInfoChangeListener {
+        implements OnColorHintListener, DisplayInfoChangeListener {
 
     private static final String TAG = "BaseDraggingActivity";
 
@@ -63,8 +61,7 @@
     protected boolean mIsSafeModeEnabled;
 
     private Runnable mOnStartCallback;
-    private RunnableList mOnResumeCallbacks = new RunnableList();
-
+    private final RunnableList mOnResumeCallbacks = new RunnableList();
     private int mThemeRes = R.style.AppTheme;
 
     @Override
@@ -76,10 +73,7 @@
         DisplayController.INSTANCE.get(this).addChangeListener(this);
 
         // Update theme
-        if (Utilities.ATLEAST_P) {
-            THREAD_POOL_EXECUTOR.execute(() -> getSystemService(WallpaperManager.class)
-                    .addOnColorsChangedListener(this, MAIN_EXECUTOR.getHandler()));
-        }
+        WallpaperColorHints.get(this).registerOnColorHintsChangedListener(this);
         int themeRes = Themes.getActivityThemeRes(this);
         if (themeRes != mThemeRes) {
             mThemeRes = themeRes;
@@ -97,8 +91,9 @@
         mOnResumeCallbacks.add(callback);
     }
 
+    @MainThread
     @Override
-    public void onColorsChanged(WallpaperColors wallpaperColors, int which) {
+    public void onColorHintsChanged(int colorHints) {
         updateTheme();
     }
 
@@ -175,10 +170,8 @@
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        if (Utilities.ATLEAST_P) {
-            getSystemService(WallpaperManager.class).removeOnColorsChangedListener(this);
-        }
         DisplayController.INSTANCE.get(this).removeChangeListener(this);
+        WallpaperColorHints.get(this).unregisterOnColorsChangedListener(this);
     }
 
     public void runOnceOnStart(Runnable action) {
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index f94a3c5..3c90408 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -21,6 +21,7 @@
 import android.graphics.Rect;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.DragEvent;
 import android.view.KeyEvent;
 import android.view.inputmethod.InputMethodManager;
@@ -37,6 +38,8 @@
  * Note: AppCompatEditText doesn't fully support #displayCompletions and #onCommitCompletion
  */
 public class ExtendedEditText extends EditText {
+    private static final String TAG = "ExtendedEditText";
+
     private final Set<OnFocusChangeListener> mOnFocusChangeListeners = new HashSet<>();
 
     private boolean mForceDisableSuggestions = false;
@@ -89,9 +92,17 @@
         return false;
     }
 
-    public void showKeyboard() {
+    /**
+     * Synchronously shows the soft input method.
+     *
+     * @param shouldFocus whether this EditText should also request focus.
+     * @return true if the keyboard is shown correctly and focus is given to this view (if
+     *     applicable).
+     */
+    public boolean showKeyboard(boolean shouldFocus) {
         onKeyboardShown();
-        showSoftInput();
+        boolean focusResult = !shouldFocus || requestFocus();
+        return focusResult && showSoftInputInternal();
     }
 
     public void hideKeyboard() {
@@ -104,10 +115,15 @@
                 .keyboardStateManager().setKeyboardState(SHOW);
     }
 
-    private boolean showSoftInput() {
-        return requestFocus() &&
-                getContext().getSystemService(InputMethodManager.class)
-                    .showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
+    private boolean showSoftInputInternal() {
+        boolean result = false;
+        InputMethodManager imm = getContext().getSystemService(InputMethodManager.class);
+        if (imm != null) {
+            result = imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
+        } else {
+            Log.w(TAG, "Failed to retrieve InputMethodManager from the system.");
+        }
+        return result;
     }
 
     public void dispatchBackKey() {
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index be14844..e3de79e 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -50,6 +50,7 @@
 
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.DotRenderer;
+import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.DeviceGridState;
 import com.android.launcher3.provider.RestoreDbTask;
 import com.android.launcher3.testing.shared.ResourceUtils;
@@ -287,12 +288,13 @@
      * Reinitialize the current grid after a restore, where some grids might now be disabled.
      */
     public void reinitializeAfterRestore(Context context) {
+        FileLog.d(TAG, "Reinitializing grid after restore");
         String currentGridName = getCurrentGridName(context);
         String currentDbFile = dbFile;
         String newGridName = initGrid(context, currentGridName);
         String newDbFile = dbFile;
         if (!newDbFile.equals(currentDbFile)) {
-            Log.d(TAG, "Restored grid is disabled : " + currentGridName
+            FileLog.d(TAG, "Restored grid is disabled : " + currentGridName
                     + ", migrating to: " + newGridName
                     + ", removing all other grid db files");
             for (String gridDbFile : LauncherFiles.GRID_DB_FILES) {
@@ -300,7 +302,7 @@
                     continue;
                 }
                 if (context.getDatabasePath(gridDbFile).delete()) {
-                    Log.d(TAG, "Removed old grid db file: " + gridDbFile);
+                    FileLog.d(TAG, "Removed old grid db file: " + gridDbFile);
                 }
             }
             setCurrentGrid(context, newGridName);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d0a2576..94ab442 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -100,7 +100,6 @@
 import android.graphics.RectF;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.CancellationSignal;
 import android.os.Parcelable;
 import android.os.StrictMode;
 import android.os.SystemClock;
@@ -155,7 +154,6 @@
 import com.android.launcher3.dot.DotInfo;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dragndrop.LauncherDragController;
 import com.android.launcher3.folder.Folder;
@@ -2327,6 +2325,7 @@
 
     @Override
     public void bindScreens(IntArray orderedScreenIds) {
+        mWorkspace.mPageIndicator.setAreScreensBinding(true);
         int firstScreenPosition = 0;
         if (FeatureFlags.QSB_ON_FIRST_SCREEN &&
                 orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != firstScreenPosition) {
@@ -2344,13 +2343,37 @@
         mWorkspace.unlockWallpaperFromDefaultPageOnNextLayout();
     }
 
+    /**
+     * Remove odd number because they are already included when isTwoPanels and add the pair screen
+     * if not present.
+     */
+    private IntArray filterTwoPanelScreenIds(IntArray orderedScreenIds) {
+        IntSet screenIds = IntSet.wrap(orderedScreenIds);
+        orderedScreenIds.forEach(screenId -> {
+            if (screenId % 2 == 1) {
+                screenIds.remove(screenId);
+                // In case the pair is not added, add it
+                if (!mWorkspace.containsScreenId(screenId - 1)) {
+                    screenIds.add(screenId - 1);
+                }
+            }
+        });
+        return screenIds.getArray();
+    }
+
     private void bindAddScreens(IntArray orderedScreenIds) {
+
         if (mDeviceProfile.isTwoPanels) {
-            // Some empty pages might have been removed while the phone was in a single panel
-            // mode, so we want to add those empty pages back.
-            IntSet screenIds = IntSet.wrap(orderedScreenIds);
-            orderedScreenIds.forEach(screenId -> screenIds.add(mWorkspace.getScreenPair(screenId)));
-            orderedScreenIds = screenIds.getArray();
+            if (FOLDABLE_SINGLE_PAGE.get()) {
+                orderedScreenIds = filterTwoPanelScreenIds(orderedScreenIds);
+            } else {
+                // Some empty pages might have been removed while the phone was in a single panel
+                // mode, so we want to add those empty pages back.
+                IntSet screenIds = IntSet.wrap(orderedScreenIds);
+                orderedScreenIds.forEach(
+                        screenId -> screenIds.add(mWorkspace.getScreenPair(screenId)));
+                orderedScreenIds = screenIds.getArray();
+            }
         }
 
         int count = orderedScreenIds.size();
@@ -2824,8 +2847,8 @@
         getViewCache().setCacheSize(R.layout.folder_page, 2);
 
         TraceHelper.INSTANCE.endSection();
-
-        mWorkspace.removeExtraEmptyScreen(true);
+        mWorkspace.removeExtraEmptyScreen(/* stripEmptyScreens= */ true);
+        mWorkspace.mPageIndicator.setAreScreensBinding(false);
     }
 
     private boolean canAnimatePageChange() {
@@ -3250,8 +3273,6 @@
         return new TouchController[] {getDragController(), new AllAppsSwipeController(this)};
     }
 
-    public void useFadeOutAnimationForLauncherStart(CancellationSignal signal) { }
-
     public void onDragLayerHierarchyChanged() {
         updateDisallowBack();
     }
@@ -3317,10 +3338,6 @@
         return false;
     }
 
-    public DragOptions getDefaultWorkspaceDragOptions() {
-        return new DragOptions();
-    }
-
     /**
      * Animates Launcher elements during a transition to the All Apps page.
      *
diff --git a/src/com/android/launcher3/LauncherBackupAgent.java b/src/com/android/launcher3/LauncherBackupAgent.java
index 3d2700d..2617b93 100644
--- a/src/com/android/launcher3/LauncherBackupAgent.java
+++ b/src/com/android/launcher3/LauncherBackupAgent.java
@@ -34,7 +34,7 @@
         // Remove old files which might contain obsolete attributes like idp_grid_name in shared
         // preference that will obstruct backup's attribute from writing to shared preferences.
         if (destination.delete()) {
-            FileLog.d("LauncherBackupAgent", "Removed obsolete file: " + destination);
+            FileLog.d(TAG, "onRestoreFile: Removed obsolete file " + destination);
         }
         super.onRestoreFile(data, size, destination, type, mode, mtime);
     }
@@ -47,6 +47,7 @@
 
     @Override
     public void onRestoreFinished() {
+        FileLog.d(TAG, "onRestoreFinished: set pending for RestoreDbTask");
         RestoreDbTask.setPending(this);
     }
 }
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index aaccb7d..d460ba8 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -32,6 +32,8 @@
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.util.Executors;
 
+import java.util.Locale;
+
 /**
  * BroadcastReceiver to handle session commit intent.
  */
@@ -63,9 +65,20 @@
         }
 
         InstallSessionHelper packageInstallerCompat = InstallSessionHelper.INSTANCE.get(context);
+        boolean alreadyAddedPromiseIcon =
+                packageInstallerCompat.promiseIconAddedForId(info.getSessionId());
         if (TextUtils.isEmpty(info.getAppPackageName())
                 || info.getInstallReason() != PackageManager.INSTALL_REASON_USER
-                || packageInstallerCompat.promiseIconAddedForId(info.getSessionId())) {
+                || alreadyAddedPromiseIcon) {
+            FileLog.d(LOG,
+                    String.format(Locale.ENGLISH,
+                            "Removing PromiseIcon for package: %s, install reason: %d,"
+                            + " alreadyAddedPromiseIcon: %s",
+                    info.getAppPackageName(),
+                    info.getInstallReason(),
+                    alreadyAddedPromiseIcon
+                )
+            );
             packageInstallerCompat.removePromiseIconId(info.getSessionId());
             return;
         }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index adaf20f..8be8fed 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -731,6 +731,14 @@
         });
     }
 
+
+    /**
+     * Returns if the given screenId is already in the Workspace
+     */
+    public boolean containsScreenId(int screenId) {
+        return this.mWorkspaceScreens.containsKey(screenId);
+    }
+
     /**
      * Inserts extra empty pages to the end of the existing workspaces.
      * Usually we add one extra empty screen, but when two panel home is enabled we add
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 4427a49..ecbc7a9 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -160,7 +160,7 @@
      * Focuses the search field to handle key events.
      */
     public void focusSearchField() {
-        mInput.showKeyboard();
+        mInput.showKeyboard(true /* shouldFocus */);
     }
 
     /**
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 83431dc..38aa387 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -83,11 +83,11 @@
      */
     // TODO(Block 1): Clean up flags
     public static final BooleanFlag ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES = getReleaseFlag(
-            270394041, "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", TEAMFOOD,
+            270394041, "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", ENABLED,
             "Enable option to replace decorator-based search result backgrounds with drawables");
 
     public static final BooleanFlag ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION = getReleaseFlag(
-            270394392, "ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", TEAMFOOD,
+            270394392, "ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", ENABLED,
             "Enable option to launch search results using the new view container transitions");
 
     // TODO(Block 2): Clean up flags
@@ -238,7 +238,7 @@
             "COLLECT_SEARCH_HISTORY", DISABLED, "Allow launcher to collect search history for log");
 
     public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937,
-            "ENABLE_TWOLINE_ALLAPPS", ENABLED, "Enables two line label inside all apps.");
+            "ENABLE_TWOLINE_ALLAPPS", DISABLED, "Enables two line label inside all apps.");
 
     public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693,
             "IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps");
@@ -289,7 +289,7 @@
             "Enables home animation to icon when user swipes back.");
 
     public static final BooleanFlag ENABLE_DYNAMIC_TASKBAR_THRESHOLDS = getDebugFlag(294252473,
-            "ENABLE_DYNAMIC_TASKBAR_THRESHOLDS", TEAMFOOD,
+            "ENABLE_DYNAMIC_TASKBAR_THRESHOLDS", ENABLED,
             "Enables taskbar thresholds that scale based on screen size.");
 
     // TODO(Block 21): Clean up flags
@@ -297,11 +297,6 @@
             "ENABLE_APP_ICON_IN_INLINE_SHORTCUTS", DISABLED, "Show app icon for inline shortcut");
 
     // TODO(Block 22): Clean up flags
-    public static final BooleanFlag RECEIVE_UNFOLD_EVENTS_FROM_SYSUI = getDebugFlag(270397209,
-            "RECEIVE_UNFOLD_EVENTS_FROM_SYSUI", ENABLED,
-            "Enables receiving unfold animation events from sysui instead of calculating "
-                    + "them in launcher process using hinge sensor values.");
-
     public static final BooleanFlag ENABLE_WIDGET_TRANSITION_FOR_RESIZING = getDebugFlag(268553314,
             "ENABLE_WIDGET_TRANSITION_FOR_RESIZING", DISABLED,
             "Enable widget transition animation when resizing the widgets");
@@ -374,11 +369,11 @@
 
     // TODO(Block 28): Clean up flags
     public static final BooleanFlag ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS =
-            getDebugFlag(270394122, "ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", TEAMFOOD,
+            getDebugFlag(270394122, "ENABLE_SPLIT_FROM_FULLSCREEN_SHORTCUT", DISABLED,
                     "Enable splitting from fullscreen app with keyboard shortcuts");
 
     public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag(
-            270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", TEAMFOOD,
+            270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", DISABLED,
             "Enable initiating split screen from workspace to workspace.");
 
     public static final BooleanFlag ENABLE_SPLIT_FROM_DESKTOP_TO_WORKSPACE = getDebugFlag(
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 00f4285..213c458 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -26,7 +26,6 @@
 import static com.android.launcher3.widget.WidgetSections.NO_CATEGORY;
 
 import android.annotation.TargetApi;
-import android.app.ActivityOptions;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ClipData;
@@ -68,6 +67,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.pm.PinRequestHelper;
+import com.android.launcher3.uioverrides.ApiWrapper;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.views.AbstractSlideInView;
@@ -259,9 +259,7 @@
                         .setPackage(getPackageName())
                         .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         Launcher.ACTIVITY_TRACKER.registerCallback(listener);
-        startActivity(homeIntent,
-                ActivityOptions.makeCustomAnimation(this, 0, android.R.anim.fade_out)
-                        .toBundle());
+        startActivity(homeIntent, ApiWrapper.createFadeOutAnimOptions(this).toBundle());
         logCommand(LAUNCHER_ADD_EXTERNAL_ITEM_DRAGGED);
         mFinishOnPause = true;
         return false;
diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
index af43ae8..48b5646 100644
--- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java
+++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java
@@ -31,7 +31,6 @@
 import android.widget.RemoteViews;
 
 import com.android.launcher3.DragSource;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.PendingAddItemInfo;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -72,15 +71,6 @@
     }
 
     @Override
-    public boolean init(Launcher launcher, boolean alreadyOnHome) {
-        super.init(launcher, alreadyOnHome);
-        if (!alreadyOnHome) {
-            launcher.useFadeOutAnimationForLauncherStart(mCancelSignal);
-        }
-        return false;
-    }
-
-    @Override
     protected PendingItemDragHelper createDragHelper() {
         final PendingAddItemInfo item;
         if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index f38cce1..55a539a 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -535,7 +535,7 @@
                     mFolderName.selectAll();
                 }
             }
-            mFolderName.showKeyboard();
+            mFolderName.showKeyboard(true /* shouldFocus */);
             mFolderName.displayCompletions(
                     Stream.of(mInfo.suggestedFolderNames.getLabels())
                             .filter(Objects::nonNull)
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 7457f30..b51373c 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -21,10 +21,12 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
 import android.view.View;
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
 import com.android.launcher3.dragndrop.DraggableView;
 import com.android.launcher3.icons.BitmapRenderer;
@@ -37,7 +39,6 @@
  * A utility class to generate preview bitmap for dragging.
  */
 public class DragPreviewProvider {
-
     private final Rect mTempRect = new Rect();
 
     protected final View mView;
@@ -99,6 +100,14 @@
             height = mView.getHeight();
         }
 
+        if (mView instanceof BubbleTextView) {
+            FastBitmapDrawable icon = ((BubbleTextView) mView).getIcon();
+            Drawable drawable = icon.getConstantState().newDrawable();
+            float xInset = (float) blurSizeOutline / (float) (width + blurSizeOutline);
+            float yInset = (float) blurSizeOutline / (float) (height + blurSizeOutline);
+            return new InsetDrawable(drawable, xInset / 2, yInset / 2, xInset / 2, yInset / 2);
+        }
+
         return new FastBitmapDrawable(
                 BitmapRenderer.createHardwareBitmap(width + blurSizeOutline,
                         height + blurSizeOutline, (c) -> drawDragView(c, scale)));
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 68106c4..ae44f0a 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -45,12 +45,11 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.ContextThemeWrapper;
+import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowInsets;
-import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.TextClock;
 
@@ -94,6 +93,7 @@
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
+import com.android.launcher3.util.WindowBounds;
 import com.android.launcher3.util.window.WindowManagerProxy;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
@@ -206,14 +206,7 @@
         } else {
             mDpOrig = mDp;
         }
-
-        WindowInsets currentWindowInsets = context.getSystemService(WindowManager.class)
-                .getCurrentWindowMetrics().getWindowInsets();
-        mInsets = new Rect(
-                currentWindowInsets.getSystemWindowInsetLeft(),
-                currentWindowInsets.getSystemWindowInsetTop(),
-                currentWindowInsets.getSystemWindowInsetRight(),
-                mDp.isTaskbarPresent ? 0 : currentWindowInsets.getSystemWindowInsetBottom());
+        mInsets = getInsets(context);
         mDp.updateInsets(mInsets);
 
         mHomeElementInflater = LayoutInflater.from(
@@ -265,6 +258,26 @@
         mAppWidgetHost = new LauncherPreviewAppWidgetHost(context);
     }
 
+    /**
+     * Returns the insets of the screen closest to the display given by the context
+     */
+    private Rect getInsets(Context context) {
+        DisplayController.Info info = DisplayController.INSTANCE.get(context).getInfo();
+        float maxDiff = Float.MAX_VALUE;
+        Display display = context.getDisplay();
+        Rect insets = new Rect();
+        for (WindowBounds supportedBound : info.supportedBounds) {
+            double diff = Math.pow(display.getWidth() - supportedBound.availableSize.x, 2)
+                    + Math.pow(display.getHeight() - supportedBound.availableSize.y, 2);
+            if (supportedBound.rotationHint == context.getDisplay().getRotation()
+                    && diff < maxDiff) {
+                maxDiff = (float) diff;
+                insets = supportedBound.insets;
+            }
+        }
+        return new Rect(insets);
+    }
+
     /** Populate preview and render it. */
     public View getRenderedView(BgDataModel dataModel,
             Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap) {
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index e89c0c5..aebcdd4 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.graphics;
 
+import static android.view.Display.DEFAULT_DISPLAY;
+
 import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -80,11 +82,12 @@
     private static final String KEY_DISPLAY_ID = "display_id";
     private static final String KEY_COLORS = "wallpaper_colors";
 
-    private final Context mContext;
-    private final InvariantDeviceProfile mIdp;
+    private Context mContext;
     private final IBinder mHostToken;
     private final int mWidth;
     private final int mHeight;
+    private String mGridName;
+
     private final Display mDisplay;
     private final WallpaperColors mWallpaperColors;
     private final RunnableList mOnDestroyCallbacks = new RunnableList();
@@ -97,15 +100,13 @@
 
     public PreviewSurfaceRenderer(Context context, Bundle bundle) throws Exception {
         mContext = context;
-
-        String gridName = bundle.getString("name");
+        mGridName = bundle.getString("name");
         bundle.remove("name");
-        if (gridName == null) {
-            gridName = InvariantDeviceProfile.getCurrentGridName(context);
+        if (mGridName == null) {
+            mGridName = InvariantDeviceProfile.getCurrentGridName(context);
         }
         mWallpaperColors = bundle.getParcelable(KEY_COLORS);
         mHideQsb = bundle.getBoolean(GridCustomizationsProvider.KEY_HIDE_BOTTOM_ROW);
-        mIdp = new InvariantDeviceProfile(context, gridName);
 
         mHostToken = bundle.getBinder(KEY_HOST_TOKEN);
         mWidth = bundle.getInt(KEY_VIEW_WIDTH);
@@ -113,9 +114,9 @@
         mDisplay = context.getSystemService(DisplayManager.class)
                 .getDisplay(bundle.getInt(KEY_DISPLAY_ID));
 
-        mSurfaceControlViewHost = MAIN_EXECUTOR
-                .submit(() -> new SurfaceControlViewHost(mContext, mDisplay, mHostToken))
-                .get(5, TimeUnit.SECONDS);
+        mSurfaceControlViewHost = MAIN_EXECUTOR.submit(() -> new SurfaceControlViewHost(mContext,
+                context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY),
+                mHostToken)).get(5, TimeUnit.SECONDS);
         mOnDestroyCallbacks.add(mSurfaceControlViewHost::release);
     }
 
@@ -195,28 +196,33 @@
         }
     }
 
+    /***
+     * Generates a new context overriding the theme color and the display size without affecting the
+     * main application context
+     */
+    private Context getPreviewContext() {
+        Context context = mContext.createDisplayContext(mDisplay);
+        if (mWallpaperColors == null) {
+            return new ContextThemeWrapper(context,
+                    Themes.getActivityThemeRes(context));
+        }
+        if (Utilities.ATLEAST_R) {
+            context = context.createWindowContext(
+                    LayoutParams.TYPE_APPLICATION_OVERLAY, null);
+        }
+        LocalColorExtractor.newInstance(context)
+                .applyColorsOverride(context, mWallpaperColors);
+        return new ContextThemeWrapper(context,
+                Themes.getActivityThemeRes(context, mWallpaperColors.getColorHints()));
+    }
+
     @WorkerThread
     private void loadModelData() {
-        final Context inflationContext;
-        if (mWallpaperColors != null) {
-            // Create a themed context, without affecting the main application context
-            Context context = mContext.createDisplayContext(mDisplay);
-            if (Utilities.ATLEAST_R) {
-                context = context.createWindowContext(
-                        LayoutParams.TYPE_APPLICATION_OVERLAY, null);
-            }
-            LocalColorExtractor.newInstance(mContext)
-                    .applyColorsOverride(context, mWallpaperColors);
-            inflationContext = new ContextThemeWrapper(context,
-                    Themes.getActivityThemeRes(context, mWallpaperColors.getColorHints()));
-        } else {
-            inflationContext = new ContextThemeWrapper(mContext,
-                    Themes.getActivityThemeRes(mContext));
-        }
-
-        if (GridSizeMigrationUtil.needsToMigrate(inflationContext, mIdp)) {
+        final Context inflationContext = getPreviewContext();
+        final InvariantDeviceProfile idp = new InvariantDeviceProfile(inflationContext, mGridName);
+        if (GridSizeMigrationUtil.needsToMigrate(inflationContext, idp)) {
             // Start the migration
-            PreviewContext previewContext = new PreviewContext(inflationContext, mIdp);
+            PreviewContext previewContext = new PreviewContext(inflationContext, idp);
             // Copy existing data to preview DB
             LauncherDbUtils.copyTable(LauncherAppState.getInstance(mContext)
                     .getModel().getModelDbController().getDb(),
@@ -239,7 +245,7 @@
 
                 @Override
                 public void run() {
-                    DeviceProfile deviceProfile = mIdp.getDeviceProfile(previewContext);
+                    DeviceProfile deviceProfile = idp.getDeviceProfile(previewContext);
                     String query =
                             LauncherSettings.Favorites.SCREEN + " = " + Workspace.FIRST_SCREEN_ID
                                     + " or " + LauncherSettings.Favorites.CONTAINER + " = "
@@ -254,7 +260,8 @@
                             getLoadedLauncherWidgetInfo(previewContext.getBaseContext());
 
                     MAIN_EXECUTOR.execute(() -> {
-                        renderView(previewContext, mBgDataModel, mWidgetProvidersMap, spanInfo);
+                        renderView(previewContext, mBgDataModel, mWidgetProvidersMap, spanInfo,
+                                idp);
                         mOnDestroyCallbacks.add(previewContext::onDestroy);
                     });
                 }
@@ -263,7 +270,7 @@
             LauncherAppState.getInstance(inflationContext).getModel().loadAsync(dataModel -> {
                 if (dataModel != null) {
                     MAIN_EXECUTOR.execute(() -> renderView(inflationContext, dataModel, null,
-                            null));
+                            null, idp));
                 } else {
                     Log.e(TAG, "Model loading failed");
                 }
@@ -274,11 +281,11 @@
     @UiThread
     private void renderView(Context inflationContext, BgDataModel dataModel,
             Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap,
-            @Nullable final SparseArray<Size> launcherWidgetSpanInfo) {
+            @Nullable final SparseArray<Size> launcherWidgetSpanInfo, InvariantDeviceProfile idp) {
         if (mDestroyed) {
             return;
         }
-        mRenderer = new LauncherPreviewRenderer(inflationContext, mIdp,
+        mRenderer = new LauncherPreviewRenderer(inflationContext, idp,
                 mWallpaperColors, launcherWidgetSpanInfo);
         mRenderer.hideBottomRow(mHideQsb);
         View view = mRenderer.getRenderedView(dataModel, widgetProviderInfoMap);
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 933468c..0e68db2 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -374,6 +374,8 @@
             final HashMap<PackageUserKey, SessionInfo> installingPkgs =
                     mSessionHelper.getActiveSessions();
             installingPkgs.forEach(mApp.getIconCache()::updateSessionCache);
+            FileLog.d(TAG, "loadWorkspace: Packages with active install sessions: "
+                    + installingPkgs.values());
 
             final PackageUserKey tempPackageKey = new PackageUserKey(null, null);
             mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
diff --git a/src/com/android/launcher3/pageindicators/PageIndicator.java b/src/com/android/launcher3/pageindicators/PageIndicator.java
index 570d6ff..4ab2037 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicator.java
@@ -27,6 +27,14 @@
     void setMarkersCount(int numMarkers);
 
     /**
+     * Sets flag to indicate when the screens are in the process of binding so that we don't animate
+     * during that period.
+     */
+    default void setAreScreensBinding(boolean areScreensBinding) {
+        // No-op by default
+    }
+
+    /**
      * Sets the flag if the Page Indicator should autohide.
      */
     default void setShouldAutoHide(boolean shouldAutoHide) {
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 073e523..ce71275 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -130,6 +130,7 @@
      */
     private float mCurrentPosition;
     private float mFinalPosition;
+    private boolean mAreScreensBinding;
     private ObjectAnimator mAnimator;
     private @Nullable ObjectAnimator mAlphaAnimator;
 
@@ -163,7 +164,7 @@
 
     @Override
     public void setScroll(int currentScroll, int totalScroll) {
-        if (SHOW_DOT_PAGINATION.get() && mActivePage != 0 && currentScroll == 0) {
+        if (SHOW_DOT_PAGINATION.get() && currentScroll == 0 && totalScroll == 0) {
             CURRENT_POSITION.set(this, (float) mActivePage);
             return;
         }
@@ -172,6 +173,11 @@
             return;
         }
 
+        // Skip scroll update during binding. We will update it when binding completes.
+        if (mAreScreensBinding) {
+            return;
+        }
+
         if (mShouldAutoHide) {
             animatePaginationToAlpha(VISIBLE_ALPHA);
         }
@@ -359,6 +365,16 @@
     }
 
     @Override
+    public void setAreScreensBinding(boolean areScreensBinding) {
+        // Reapply correct current position which was skipped during setScroll.
+        if (mAreScreensBinding && !areScreensBinding) {
+            CURRENT_POSITION.set(this, (float) mActivePage);
+        }
+
+        mAreScreensBinding = areScreensBinding;
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // Add extra spacing of mDotRadius on all sides so than entry animation could be run.
         int width = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY ?
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index c554def..4725dd1 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -82,11 +82,15 @@
     public static final String APPWIDGET_OLD_IDS = "appwidget_old_ids";
     public static final String APPWIDGET_IDS = "appwidget_ids";
 
+    private static final String[] DB_COLUMNS_TO_LOG = {"profileId", "title", "itemType", "screen",
+            "container", "cellX", "cellY", "spanX", "spanY", "intent"};
+
     /**
      * Tries to restore the backup DB if needed
      */
     public static void restoreIfNeeded(Context context, ModelDbController dbController) {
         if (!isPending(context)) {
+            Log.d(TAG, "No restore task pending, exiting RestoreDbTask");
             return;
         }
         if (!performRestore(context, dbController)) {
@@ -106,6 +110,7 @@
 
     private static boolean performRestore(Context context, ModelDbController controller) {
         SQLiteDatabase db = controller.getDb();
+        FileLog.d(TAG, "performRestore: starting restore from db");
         try (SQLiteTransaction t = new SQLiteTransaction(db)) {
             RestoreDbTask task = new RestoreDbTask();
             task.sanitizeDB(context, controller, db, new BackupManager(context));
@@ -133,10 +138,11 @@
     @VisibleForTesting
     protected int sanitizeDB(Context context, ModelDbController controller, SQLiteDatabase db,
             BackupManager backupManager) throws Exception {
+        FileLog.d(TAG, "Old Launcher Database before sanitizing:");
         // Primary user ids
         long myProfileId = controller.getSerialNumberForUser(myUserHandle());
         long oldProfileId = getDefaultProfileId(db);
-        Log.d(TAG, "sanitizeDB: myProfileId=" + myProfileId + " oldProfileId=" + oldProfileId);
+        FileLog.d(TAG, "sanitizeDB: myProfileId=" + myProfileId + " oldProfileId=" + oldProfileId);
         LongSparseArray<Long> oldManagedProfileIds = getManagedProfileIds(db, oldProfileId);
         LongSparseArray<Long> profileMapping = new LongSparseArray<>(oldManagedProfileIds.size()
                 + 1);
@@ -149,8 +155,11 @@
             if (user != null) {
                 long newManagedProfileId = controller.getSerialNumberForUser(user);
                 profileMapping.put(oldManagedProfileId, newManagedProfileId);
-                Log.d(TAG, "sanitizeDB: managed profile id=" + oldManagedProfileId
+                FileLog.d(TAG, "sanitizeDB: managed profile id=" + oldManagedProfileId
                         + " should be mapped to new id=" + newManagedProfileId);
+            } else {
+                FileLog.e(TAG, "sanitizeDB: No User found for old profileId, Ancestral Serial "
+                        + "Number: " + oldManagedProfileId);
             }
         }
 
@@ -161,11 +170,13 @@
         for (int i = numProfiles - 1; i >= 1; --i) {
             profileIds[i] = Long.toString(profileMapping.keyAt(i));
         }
+
         final String[] args = new String[profileIds.length];
         Arrays.fill(args, "?");
         final String where = "profileId NOT IN (" + TextUtils.join(", ", Arrays.asList(args)) + ")";
-        int itemsDeleted = db.delete(Favorites.TABLE_NAME, where, profileIds);
-        FileLog.d(TAG, itemsDeleted + " items from unrestored user(s) were deleted");
+        logUnrestoredItems(db, where, profileIds);
+        int itemsDeletedCount = db.delete(Favorites.TABLE_NAME, where, profileIds);
+        FileLog.d(TAG, itemsDeletedCount + " total items from unrestored user(s) were deleted");
 
         // Mark all items as restored.
         boolean keepAllIcons = Utilities.isPropertyEnabled(LogConfig.KEEP_ALL_ICONS);
@@ -219,8 +230,48 @@
 
         // Override shortcuts
         maybeOverrideShortcuts(context, controller, db, myProfileId);
+        return itemsDeletedCount;
+    }
 
-        return itemsDeleted;
+    /**
+     * Queries and logs the items we will delete from unrestored profiles in the launcher db.
+     * This is to understand why items might be missing during the restore process for Launcher.
+     * @param database the Launcher db to query from.
+     * @param where the SELECT statement to query items that will be deleted.
+     * @param profileIds the profile ID's the user will be migrating to.
+     */
+    private void logUnrestoredItems(SQLiteDatabase database, String where, String[] profileIds) {
+        try (Cursor itemsToDelete = database.query(
+                /* table */ Favorites.TABLE_NAME,
+                /* columns */ DB_COLUMNS_TO_LOG,
+                /* selection */ where,
+                /* selection args */ profileIds,
+                /* groupBy */ null,
+                /* having */ null,
+                /* orderBy */ null
+        )) {
+            if (itemsToDelete.moveToFirst()) {
+                String[] columnNames = itemsToDelete.getColumnNames();
+                StringBuilder stringBuilder = new StringBuilder(
+                        "items to be deleted from the Favorites Table during restore:\n"
+                );
+                do {
+                    for (String columnName : columnNames) {
+                        stringBuilder.append(columnName)
+                            .append("=")
+                            .append(itemsToDelete.getString(
+                                        itemsToDelete.getColumnIndex(columnName)))
+                            .append(" ");
+                    }
+                    stringBuilder.append("\n");
+                } while (itemsToDelete.moveToNext());
+                FileLog.d(TAG, stringBuilder.toString());
+            } else {
+                FileLog.d(TAG, "logDeletedItems: No items found to delete");
+            }
+        } catch (Exception e) {
+            FileLog.e(TAG, "logDeletedItems: Error reading from database", e);
+        }
     }
 
     /**
@@ -321,7 +372,7 @@
      * Marks the DB state as pending restoration
      */
     public static void setPending(Context context) {
-        FileLog.d(TAG, "Restore data received through full backup ");
+        FileLog.d(TAG, "Restore data received through full backup");
         LauncherPrefs.get(context)
                 .putSync(RESTORE_DEVICE.to(new DeviceGridState(context).getDeviceType()));
     }
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 5306932..5d412ff 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.testing;
 
 import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_GRID_ONLY_OVERVIEW;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
 import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -253,6 +254,12 @@
                                 + l.getAppsView().getActiveRecyclerView().getPaddingBottom());
             }
 
+            case TestProtocol.REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW: {
+                response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        ENABLE_GRID_ONLY_OVERVIEW.get());
+                return response;
+            }
+
             default:
                 return null;
         }
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index 9cba19d..122b1e0 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -67,7 +67,7 @@
         if (!(v.getTag() instanceof ItemInfo)) return false;
 
         launcher.setWaitingForResult(null);
-        beginDrag(v, launcher, (ItemInfo) v.getTag(), launcher.getDefaultWorkspaceDragOptions());
+        beginDrag(v, launcher, (ItemInfo) v.getTag(), new DragOptions());
         return true;
     }
 
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index 348c8d8..f8f4b5f 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -38,8 +38,6 @@
     public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
     public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
     public static final String HOTSEAT_LONGPRESS_TIP_SEEN = "launcher.hotseat_longpress_tip_seen";
-    public static final String SEARCH_KEYBOARD_EDU_SEEN = "launcher.search_edu_seen";
-    public static final String SEARCH_SNACKBAR_COUNT = "launcher.keyboard_snackbar_count";
     public static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count";
     public static final String TASKBAR_EDU_TOOLTIP_STEP = "launcher.taskbar_edu_tooltip_step";
     // When adding a new key, add it here as well, to be able to reset it from Developer Options.
@@ -47,7 +45,6 @@
             "All Apps Bounce", new String[] { HOME_BOUNCE_SEEN, HOME_BOUNCE_COUNT },
             "Hybrid Hotseat Education", new String[] { HOTSEAT_DISCOVERY_TIP_COUNT,
                     HOTSEAT_LONGPRESS_TIP_SEEN },
-            "Search Education", new String[] { SEARCH_KEYBOARD_EDU_SEEN, SEARCH_SNACKBAR_COUNT},
             "Taskbar Education", new String[] { TASKBAR_EDU_TOOLTIP_STEP },
             "All Apps Visited Count", new String[] {ALL_APPS_VISITED_COUNT}
     );
@@ -58,7 +55,6 @@
     @StringDef(value = {
             HOME_BOUNCE_SEEN,
             HOTSEAT_LONGPRESS_TIP_SEEN,
-            SEARCH_KEYBOARD_EDU_SEEN,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventBoolKey {}
@@ -69,7 +65,6 @@
     @StringDef(value = {
             HOME_BOUNCE_COUNT,
             HOTSEAT_DISCOVERY_TIP_COUNT,
-            SEARCH_SNACKBAR_COUNT,
             ALL_APPS_VISITED_COUNT,
             TASKBAR_EDU_TOOLTIP_STEP,
     })
@@ -82,7 +77,6 @@
         Map<String, Integer> maxCounts = new ArrayMap<>(5);
         maxCounts.put(HOME_BOUNCE_COUNT, 3);
         maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5);
-        maxCounts.put(SEARCH_SNACKBAR_COUNT, 3);
         maxCounts.put(ALL_APPS_VISITED_COUNT, 20);
         maxCounts.put(TASKBAR_EDU_TOOLTIP_STEP, 2);
         MAX_COUNTS = Collections.unmodifiableMap(maxCounts);
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index a5c663f..60951ba 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -21,8 +21,6 @@
 
 import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
 
-import android.app.WallpaperColors;
-import android.app.WallpaperManager;
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Color;
@@ -48,16 +46,9 @@
 
     public static final String KEY_THEMED_ICONS = "themed_icons";
 
+    /** Gets the WallpaperColorHints and then uses those to get the correct activity theme res. */
     public static int getActivityThemeRes(Context context) {
-        final int colorHints;
-        if (Utilities.ATLEAST_P) {
-            WallpaperColors colors = context.getSystemService(WallpaperManager.class)
-                    .getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
-            colorHints = colors == null ? 0 : colors.getColorHints();
-        } else {
-            colorHints = 0;
-        }
-        return getActivityThemeRes(context, colorHints);
+        return getActivityThemeRes(context, WallpaperColorHints.get(context).getHints());
     }
 
     public static int getActivityThemeRes(Context context, int wallpaperColorHints) {
diff --git a/src/com/android/launcher3/util/WallpaperColorHints.kt b/src/com/android/launcher3/util/WallpaperColorHints.kt
new file mode 100644
index 0000000..1361c1e
--- /dev/null
+++ b/src/com/android/launcher3/util/WallpaperColorHints.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.util
+
+import android.app.WallpaperColors
+import android.app.WallpaperManager
+import android.app.WallpaperManager.FLAG_SYSTEM
+import android.app.WallpaperManager.OnColorsChangedListener
+import android.content.Context
+import androidx.annotation.MainThread
+import androidx.annotation.VisibleForTesting
+import com.android.launcher3.Utilities
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
+
+/**
+ * This class caches the system's wallpaper color hints for use by other classes as a performance
+ * enhancer. It also centralizes all the WallpaperManager color hint code in one location.
+ */
+class WallpaperColorHints(private val context: Context) : SafeCloseable {
+    var hints: Int = 0
+        private set
+    private val wallpaperManager
+        get() = context.getSystemService(WallpaperManager::class.java)!!
+    private val onColorHintsChangedListeners = mutableListOf<OnColorHintListener>()
+    private val onClose: SafeCloseable
+
+    init {
+        if (Utilities.ATLEAST_S) {
+            hints = wallpaperManager.getWallpaperColors(FLAG_SYSTEM)?.colorHints ?: 0
+            val onColorsChangedListener = OnColorsChangedListener { colors, which ->
+                onColorsChanged(colors, which)
+            }
+            UI_HELPER_EXECUTOR.execute {
+                wallpaperManager.addOnColorsChangedListener(
+                    onColorsChangedListener,
+                    MAIN_EXECUTOR.handler
+                )
+            }
+            onClose = SafeCloseable {
+                UI_HELPER_EXECUTOR.execute {
+                    wallpaperManager.removeOnColorsChangedListener(onColorsChangedListener)
+                }
+            }
+        } else {
+            onClose = SafeCloseable {}
+        }
+    }
+
+    @MainThread
+    private fun onColorsChanged(colors: WallpaperColors?, which: Int) {
+        if ((which and FLAG_SYSTEM) != 0 && Utilities.ATLEAST_S) {
+            val newHints = colors?.colorHints ?: 0
+            if (newHints != hints) {
+                hints = newHints
+                onColorHintsChangedListeners.forEach { it.onColorHintsChanged(newHints) }
+            }
+        }
+    }
+
+    override fun close() = onClose.close()
+
+    fun registerOnColorHintsChangedListener(listener: OnColorHintListener) {
+        onColorHintsChangedListeners.add(listener)
+    }
+
+    fun unregisterOnColorsChangedListener(listener: OnColorHintListener) {
+        onColorHintsChangedListeners.remove(listener)
+    }
+
+    companion object {
+        @VisibleForTesting
+        @JvmField
+        val INSTANCE = MainThreadInitializedObject { WallpaperColorHints(it) }
+        @JvmStatic fun get(context: Context): WallpaperColorHints = INSTANCE.get(context)
+    }
+}
+
+interface OnColorHintListener {
+    fun onColorHintsChanged(colorHints: Int)
+}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
index d6b41c9..599a591 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.uioverrides;
 
+import android.app.ActivityOptions;
 import android.app.Person;
 import android.content.Context;
 import android.content.pm.LauncherActivityInfo;
@@ -40,4 +41,11 @@
     public static Map<String, LauncherActivityInfo> getActivityOverrides(Context context) {
         return Collections.emptyMap();
     }
+
+    /**
+     * Creates an ActivityOptions to play fade-out animation on closing targets
+     */
+    public static ActivityOptions createFadeOutAnimOptions(Context context) {
+        return ActivityOptions.makeCustomAnimation(context, 0, android.R.anim.fade_out);
+    }
 }
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index d86a2f8..87ec260 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -161,12 +161,14 @@
     public static final String LAUNCH_SPLIT_PAIR = "b/288939273";
 
     public static final String OVERVIEW_OVER_HOME = "b/279059025";
-
+    public static final String INCORRECT_HOME_STATE = "b/293191790";
     public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
     public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
     public static final String REQUEST_IS_EMULATE_DISPLAY_RUNNING = "is-emulate-display-running";
     public static final String REQUEST_EMULATE_PRINT_DEVICE = "emulate-print-device";
 
+    public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview";
+
     /** Logs {@link Log#d(String, String)} if {@link #sDebugTracing} is true. */
     public static void testLogD(String tag, String message) {
         if (!sDebugTracing) {
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java b/tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
index e33a304..419cb3d 100644
--- a/tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
+++ b/tests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
@@ -63,8 +63,8 @@
     }
 
     public static class Board extends TestSection {
-        Point gridSize;
-        String board;
+        public Point gridSize;
+        public String board;
 
         public Board(Point gridSize, String board) {
             super(State.BOARD);
@@ -127,7 +127,7 @@
         }
     }
 
-    List<TestSection> parse() {
+    public List<TestSection> parse() {
         List<TestSection> sections = new ArrayList<>();
         String[] lines = mTest.split("\n");
         Iterator<String> it = Arrays.stream(lines).iterator();
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java b/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
index b6c55af..86a7bd3 100644
--- a/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
+++ b/tests/src/com/android/launcher3/celllayout/CellLayoutTestUtils.java
@@ -42,7 +42,7 @@
                         params.getCellX(), params.getCellY(),
                         launcher.getWorkspace().getIdForScreen(cellLayout), CONTAINER_DESKTOP);
                 int screenId = pos.screenId;
-                if (screenId > boards.size() - 1) {
+                for (int j = boards.size(); j <= screenId; j++) {
                     boards.add(new CellLayoutBoard(cellLayout.getCountX(), cellLayout.getCountY()));
                 }
                 CellLayoutBoard board = boards.get(screenId);
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 753d89d..168ed9f 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -19,6 +19,8 @@
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -61,6 +63,7 @@
 import com.android.launcher3.util.Wait;
 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
 import com.android.launcher3.util.rule.TISBindRule;
+import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
 import com.android.launcher3.widget.picker.WidgetsRecyclerView;
 
@@ -229,7 +232,18 @@
     @PortraitLandscape
     public void testAllAppsSwitchToWorkspace() {
         assertNotNull("switchToWorkspace() returned null",
-                mLauncher.getWorkspace().switchToAllApps().switchToWorkspace());
+                mLauncher.getWorkspace().switchToAllApps()
+                        .switchToWorkspace(/* swipeDown= */ true));
+        assertTrue("Launcher internal state is not Workspace",
+                isInState(() -> LauncherState.NORMAL));
+    }
+
+    @Test
+    @PortraitLandscape
+    public void testAllAppsSwipeUpToWorkspace() {
+        assertNotNull("testAllAppsSwipeUpToWorkspace() returned null",
+                mLauncher.getWorkspace().switchToAllApps()
+                        .switchToWorkspace(/* swipeDown= */ false));
         assertTrue("Launcher internal state is not Workspace",
                 isInState(() -> LauncherState.NORMAL));
     }
@@ -318,7 +332,8 @@
     }
 
     @Test
-    @Ignore // b/293191790
+    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/293191790
+    @ScreenRecord
     @PortraitLandscape
     public void testWidgets() throws Exception {
         // Test opening widgets.
@@ -520,6 +535,7 @@
     @Test
     @PortraitLandscape
     @PlatinumTest(focusArea = "launcher")
+    @ScreenRecord // TODO(b/293944634): Remove after flaky debug
     public void testUninstallFromWorkspace() throws Exception {
         installDummyAppAndWaitForUIUpdate();
         try {
diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
index 4580082..261436b 100644
--- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -227,7 +227,8 @@
                     UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE,
                     LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
                     DisplayController.INSTANCE, CustomWidgetManager.INSTANCE,
-                    SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE, LockedUserState.INSTANCE,
+                    SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE,
+                    LockedUserState.INSTANCE, WallpaperColorHints.INSTANCE,
                     ItemInstallQueue.INSTANCE, WindowManagerProxy.INSTANCE);
 
             // System settings cache content provider. Ensure that they are statically initialized
diff --git a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
index f33a50a..38de071 100644
--- a/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
+++ b/tests/src/com/android/launcher3/util/rule/TestStabilityRule.java
@@ -17,6 +17,8 @@
 
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
+import static org.junit.Assume.assumeTrue;
+
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.util.Log;
@@ -69,12 +71,9 @@
             return new Statement() {
                 @Override
                 public void evaluate() throws Throwable {
-                    if ((stability.flavors() & getRunFlavor()) != 0) {
-                        Log.d(TAG, "Running " + description.getDisplayName());
-                        base.evaluate();
-                    } else {
-                        Log.d(TAG, "Skipping " + description.getDisplayName());
-                    }
+                    assumeTrue("Ignoring the test due to @Stability annotation",
+                            (stability.flavors() & getRunFlavor()) != 0);
+                    base.evaluate();
                 }
             };
         } else {
diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
index f3f9b89..0f08eef 100644
--- a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
+++ b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
@@ -25,6 +25,7 @@
 import com.android.app.viewcapture.data.ExportedData
 import com.android.launcher3.tapl.TestHelpers
 import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter
+import com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT
 import com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer
 import java.io.BufferedOutputStream
 import java.io.FileOutputStream
@@ -116,6 +117,9 @@
         // OOP tests don't produce ViewCapture data
         if (!TestHelpers.isInLauncherProcess()) return
 
+        // Due to flakiness of ViewCapture verifier, don't run the check in presubmit
+        if (TestStabilityRule.getRunFlavor() != PLATFORM_POSTSUBMIT) return
+
         var frameCount = 0
         for (i in 0 until viewCaptureData!!.windowDataCount) {
             frameCount += viewCaptureData!!.getWindowData(i).frameDataCount
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
index 38de2fa..49abad4 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
@@ -104,12 +104,14 @@
             DRAG_LAYER + "Snackbar|TextView:id/label",
             DRAG_LAYER + "SplitInstructionsView|AppCompatTextView:id/split_instructions_text",
             DRAG_LAYER + "TaskMenuView|LinearLayout:id/menu_option_layout",
+            DRAG_LAYER + "TaskMenuViewWithArrow|LinearLayout:id/menu_option_layout",
             DRAG_LAYER + "TaskMenuView|TextView:id/task_name",
             DRAG_LAYER + "View",
             DRAG_LAYER + "WidgetsFullSheet|SpringRelativeLayout:id/container",
             DRAG_LAYER + "WidgetsTwoPaneSheet|SpringRelativeLayout:id/container",
             CONTENT + "LauncherRootView:id/launcher|FloatingIconView",
             RECENTS_DRAG_LAYER + "ArrowTipView",
+            DRAG_LAYER + "ArrowTipView",
             DRAG_LAYER + "FallbackRecentsView:id/overview_panel",
             RECENTS_DRAG_LAYER + "FallbackRecentsView:id/overview_panel",
             DRAG_LAYER
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
index 4210d06..fc17b67 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
@@ -38,9 +38,6 @@
 
     private static final IgnoreNode IGNORED_NODES_ROOT = buildIgnoreNodesTree(List.of(
             CONTENT + "LauncherRootView:id/launcher|FloatingIconView",
-            DRAG_LAYER
-                    + "SearchContainerView:id/apps_view|AllAppsRecyclerView:id/apps_list_view"
-                    + "|BubbleTextView:id/icon",
             DRAG_LAYER + "LauncherRecentsView:id/overview_panel|TaskView|TextView",
             DRAG_LAYER
                     + "LauncherAllAppsContainerView:id/apps_view|AllAppsRecyclerView:id"
@@ -57,10 +54,9 @@
                     + "|ScrollView:id/widget_preview_scroll_view|WidgetCell:id/widget_cell"
                     + "|WidgetCellPreview:id/widget_preview_container|ImageView:id/widget_badge",
             RECENTS_DRAG_LAYER + "FallbackRecentsView:id/overview_panel|TaskView|IconView:id/icon",
-            DRAG_LAYER
-                    + "SearchContainerView:id/apps_view|UniversalSearchInputView:id"
-                    + "/search_container_all_apps|View:id/ripple",
-            DRAG_LAYER + "LauncherDragView"
+            DRAG_LAYER + "SearchContainerView:id/apps_view",
+            DRAG_LAYER + "LauncherDragView",
+            DRAG_LAYER + "FloatingTaskView|FloatingTaskThumbnailView:id/thumbnail"
     ));
 
     // Per-AnalysisNode data that's specific to this detector.
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 2c3c028..aa5c770 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -324,13 +324,16 @@
         if (!hasTasks() || isClearAllVisible()) {
             return false;
         }
-        OverviewTask task = mLauncher.isTablet() ? getFocusedTaskForTablet() : getCurrentTask();
+        boolean isTablet = mLauncher.isTablet();
+        if (isTablet && mLauncher.isGridOnlyOverviewEnabled()) {
+            return false;
+        }
+        OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
         if (task == null) {
             return false;
         }
         // In tablets, if focused task is not in center, overview actions aren't visible.
-        if (mLauncher.isTablet()
-                && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) {
+        if (isTablet && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) {
             return false;
         }
         // Overview actions aren't visible for split screen tasks.
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
index 1239d7a..a03472a 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
@@ -30,23 +30,28 @@
     }
 
     /**
-     * Swipes down to Workspace.
+     * Swipes up or down to dismiss to Workspace.
+     * @param swipeDown Swipe all apps down to dismiss, otherwise swipe up to dismiss by going home.
      *
      * @return the Workspace object.
      */
     @NonNull
-    public Workspace switchToWorkspace() {
+    public Workspace switchToWorkspace(boolean swipeDown) {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c =
                      mLauncher.addContextLayer("want to switch from all apps to workspace")) {
             UiObject2 allAppsContainer = verifyActiveContainer();
 
             final int startX = allAppsContainer.getVisibleCenter().x;
-            final int startY = getTopVisibleIconBounds(allAppsContainer).centerY();
-            final int endY = mLauncher.getDevice().getDisplayHeight();
+            final int startY = swipeDown ? getTopVisibleIconBounds(allAppsContainer).centerY()
+                    : mLauncher.getDevice().getDisplayHeight();
+            final int endY =
+                    swipeDown ? mLauncher.getDevice().getDisplayHeight() : getTopVisibleIconBounds(
+                            allAppsContainer).centerY();
             LauncherInstrumentation.log(
                     "switchToWorkspace: startY = " + startY + ", endY = " + endY
-                            + ", slop = " + mLauncher.getTouchSlop());
+                            + ", slop = " + mLauncher.getTouchSlop()
+                            + ", swipeDown = " + swipeDown);
 
             mLauncher.swipeToState(
                     startX,
@@ -54,7 +59,9 @@
                     startX,
                     endY,
                     5 /* steps */,
-                    NORMAL_STATE_ORDINAL, LauncherInstrumentation.GestureScope.INSIDE);
+                    NORMAL_STATE_ORDINAL,
+                    swipeDown ? LauncherInstrumentation.GestureScope.INSIDE
+                            : LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER);
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "swiped to workspace")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 9b4d273..9a7710a 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -30,6 +30,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.SystemClock;
+import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
 
@@ -223,12 +224,14 @@
             int leftEdge = 10;
             Point taskbarUnstashArea = new Point(leftEdge, mLauncher.getRealDisplaySize().y - 1);
             mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER,
-                    new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null);
+                    new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null,
+                    InputDevice.SOURCE_MOUSE);
 
             mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
 
             mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT,
-                    new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null);
+                    new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null,
+                    InputDevice.SOURCE_MOUSE);
 
             return new Taskbar(mLauncher);
         }
@@ -245,7 +248,8 @@
             Point stashedTaskbarHintArea = new Point(mLauncher.getRealDisplaySize().x / 2,
                     mLauncher.getRealDisplaySize().y - 1);
             mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER,
-                    new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null);
+                    new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null,
+                    InputDevice.SOURCE_MOUSE);
 
             mLauncher.getDevice().wait(mStashedTaskbarHintScaleCondition,
                     LauncherInstrumentation.WAIT_TIME_MS);
@@ -256,7 +260,8 @@
                 Point taskbarUnstashArea = new Point(mLauncher.getRealDisplaySize().x / 2,
                         mLauncher.getRealDisplaySize().y - 1);
                 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT,
-                        new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null);
+                        new Point(taskbarUnstashArea.x, taskbarUnstashArea.y), null,
+                        InputDevice.SOURCE_MOUSE);
 
                 mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
                 return new Taskbar(mLauncher);
@@ -308,7 +313,8 @@
             Point stashedTaskbarHintArea = new Point(mLauncher.getRealDisplaySize().x / 2,
                     mLauncher.getRealDisplaySize().y - stashedTaskbarBottomEdge - 1);
             mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_ENTER,
-                    new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null);
+                    new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y), null,
+                    InputDevice.SOURCE_MOUSE);
 
             mLauncher.getDevice().wait(mStashedTaskbarHintScaleCondition,
                     LauncherInstrumentation.WAIT_TIME_MS);
@@ -317,19 +323,21 @@
                     "cursor clicking stashed taskbar to go home")) {
                 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_HOVER_EXIT,
                         new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y),
-                        null);
+                        null, InputDevice.SOURCE_MOUSE);
                 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
                         new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y),
-                        LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER);
+                        LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER,
+                        InputDevice.SOURCE_MOUSE);
                 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_BUTTON_PRESS,
                         new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y),
-                        null);
+                        null, InputDevice.SOURCE_MOUSE);
                 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_BUTTON_RELEASE,
                         new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y),
-                        null);
+                        null, InputDevice.SOURCE_MOUSE);
                 mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP,
                         new Point(stashedTaskbarHintArea.x, stashedTaskbarHintArea.y),
-                        LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER);
+                        LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER,
+                        InputDevice.SOURCE_MOUSE);
 
                 return mLauncher.getWorkspace();
             }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index b929293..262d5ff 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1728,11 +1728,11 @@
     }
 
     private static MotionEvent getMotionEvent(long downTime, long eventTime, int action,
-            float x, float y) {
+            float x, float y, int source) {
         return MotionEvent.obtain(downTime, eventTime, action, 1,
-                new MotionEvent.PointerProperties[] {getPointerProperties(0)},
-                new MotionEvent.PointerCoords[] {getPointerCoords(x, y)},
-                0, 0, 1.0f, 1.0f, 0, 0, InputDevice.SOURCE_TOUCHSCREEN, 0);
+                new MotionEvent.PointerProperties[]{getPointerProperties(0)},
+                new MotionEvent.PointerCoords[]{getPointerCoords(x, y)},
+                0, 0, 1.0f, 1.0f, 0, 0, source, 0);
     }
 
     private static MotionEvent.PointerProperties getPointerProperties(int pointerId) {
@@ -1761,8 +1761,19 @@
                 TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
+    boolean isGridOnlyOverviewEnabled() {
+        return getTestInfo(TestProtocol.REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW).getBoolean(
+                TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
     public void sendPointer(long downTime, long currentTime, int action, Point point,
             GestureScope gestureScope) {
+        sendPointer(downTime, currentTime, action, point, gestureScope,
+                InputDevice.SOURCE_TOUCHSCREEN);
+    }
+
+    public void sendPointer(long downTime, long currentTime, int action, Point point,
+            GestureScope gestureScope, int source) {
         final boolean hasTIS = hasTIS();
         int pointerCount = mPointerCount;
 
@@ -1862,7 +1873,7 @@
                 ? getTrackpadMotionEvent(
                         downTime, currentTime, action, point.x, point.y, pointerCount,
                         mTrackpadGestureType)
-                : getMotionEvent(downTime, currentTime, action, point.x, point.y);
+                : getMotionEvent(downTime, currentTime, action, point.x, point.y, source);
         if (action == MotionEvent.ACTION_BUTTON_PRESS
                 || action == MotionEvent.ACTION_BUTTON_RELEASE) {
             event.setActionButton(MotionEvent.BUTTON_PRIMARY);