Merge "Keep track of multiple TasksIDs and Targets in GestureState" into udc-qpr-dev
diff --git a/quickstep/res/layout/split_instructions_view.xml b/quickstep/res/layout/split_instructions_view.xml
index 91fb05c..5f037f8 100644
--- a/quickstep/res/layout/split_instructions_view.xml
+++ b/quickstep/res/layout/split_instructions_view.xml
@@ -24,12 +24,15 @@
     android:paddingTop="@dimen/split_instructions_vertical_padding"
     android:paddingBottom="@dimen/split_instructions_vertical_padding"
     android:elevation="@dimen/split_instructions_elevation"
-    android:visibility="gone">
+    android:visibility="gone"
+    android:importantForAccessibility="yes">
     <androidx.appcompat.widget.AppCompatTextView
         android:id="@+id/split_instructions_text"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:gravity="center"
         android:textColor="?androidprv:attr/textColorOnAccent"
+        android:drawableEnd="@drawable/ic_split_horizontal"
+        android:drawablePadding="@dimen/split_instructions_drawable_padding"
         android:text="@string/toast_split_select_app" />
 </com.android.quickstep.views.SplitInstructionsView>
\ No newline at end of file
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 0497fe4..c186550 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -68,7 +68,7 @@
     <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Idite na početni ekran"</string>
     <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Prevucite s dna ekrana prema gore"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Sjajno!"</string>
-    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Prevucite prema gore s donjeg ruba ekrana"</string>
+    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Vodite računa da prevučete s donjeg ruba ekrana prema gore"</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Pokušajte zadržati prozor duže prije puštanja"</string>
     <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Prevucite ravno nagore, a zatim zastanite"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste kako koristiti pokrete. Idite u Postavke da isključite pokrete."</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 32a338e..d446190 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -46,29 +46,29 @@
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predicció d\'aplicació: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Gira el dispositiu"</string>
     <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Gira el dispositiu per completar el tutorial de navegació amb gestos"</string>
-    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Assegura\'t de lliscar des de l\'extrem dret o esquerre de la pantalla"</string>
+    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Assegura\'t de lliscar des de l\'extrem dret o esquerre de la pantalla."</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Assegura\'t de lliscar des de la vora dreta o esquerra cap al centre de la pantalla i deixar anar"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Has après a lliscar des de la dreta per tornar enrere. Ara, descobreix com pots canviar d\'aplicació."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Has completat el gest per tornar enrere"</string>
-    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Assegura\'t de no lliscar massa a prop de la part inferior de la pantalla"</string>
+    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Assegura\'t de no lliscar massa a prop de la part inferior de la pantalla."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Per canviar la sensibilitat del gest, ves a Configuració"</string>
     <string name="back_gesture_intro_title" msgid="19551256430224428">"Llisca per anar enrere"</string>
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Per tornar a la darrera pantalla, llisca des de la vora esquerra o dreta cap al centre de la pantalla."</string>
     <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Per tornar a la pantalla anterior, llisca amb dos dits des de l\'extrem esquerre o dret cap al centre de la pantalla."</string>
     <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Torna enrere"</string>
-    <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Llisca des de la vora esquerra o dreta cap al centre de la pantalla"</string>
+    <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Llisca des de la vora esquerra o dreta cap al centre de la pantalla."</string>
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Assegura\'t de lliscar cap amunt des de la part inferior de la pantalla"</string>
-    <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Assegura\'t de no aturar-te abans de deixar anar"</string>
-    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Assegura\'t de lliscar directament cap amunt"</string>
+    <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Assegura\'t de no aturar-te abans de deixar anar."</string>
+    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Assegura\'t de lliscar recte cap amunt."</string>
     <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Has completat el gest per anar a la pantalla d\'inici. Ara, descobreix com pots tornar enrere."</string>
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Has completat el gest per anar a la pantalla d\'inici"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Llisca per anar a la pantalla d\'inici"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Llisca cap amunt des de la part inferior de la pantalla. Aquest gest et porta a la pantalla d\'inici."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Llisca amb dos dits cap amunt des de la part inferior. Aquest gest sempre porta a la pantalla d\'inici."</string>
     <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Ves a la pàgina d\'inici"</string>
-    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Llisca cap amunt des de la part inferior de la pantalla"</string>
+    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Llisca cap amunt des de la part inferior de la pantalla."</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Ben fet!"</string>
-    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Assegura\'t de lliscar cap amunt des de la part inferior de la pantalla"</string>
+    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Assegura\'t de lliscar cap amunt des de la part inferior de la pantalla."</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Prova de mantenir premuda la finestra durant més temps abans de deixar-la anar"</string>
     <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Assegura\'t de lliscar directament cap amunt i després aturar-te"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Has après a utilitzar els gestos. Per desactivar-los, ves a Configuració."</string>
@@ -77,7 +77,7 @@
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Per canviar entre aplicacions, llisca cap amunt des de la part inferior, mantén premut i deixa anar."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Per canviar entre apps, llisca amb dos dits cap amunt des de la part inferior, mantén i deixa anar."</string>
     <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Canvia d\'aplicació"</string>
-    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Llisca cap amunt des de la part inferior de la pantalla, mantén premut i, a continuació, deixa anar"</string>
+    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Llisca cap amunt des de la part inferior de la pantalla, mantén premut i, a continuació, deixa anar."</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Ben fet!"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Tot a punt"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Fet"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index ed17516..1bf92c4 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -50,25 +50,25 @@
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pühkige ekraani paremast või vasakust servast keskele ja eemaldage sõrm"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Õppisite, kuidas tagasiliikumiseks paremalt pühkida. Nüüd vaadake, kuidas rakenduste vahel vahetada."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Tegite tagasiliikumise liigutuse"</string>
-    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Veenduge, et te ei pühiks liiga ekraani allosa lähedalt"</string>
+    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Veenduge, et te ei pühiks liiga ekraani allosa lähedalt."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Tagasiliigutuse tundlikkuse muutmiseks avage menüü Seaded"</string>
     <string name="back_gesture_intro_title" msgid="19551256430224428">"Tagasiliikumiseks pühkige"</string>
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Eelmisele ekraanikuvale naasmiseks pühkige vasakust või paremast servast ekraanikuva keskele."</string>
     <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Eelmisele ekraanikuvale naasmiseks pühkige vasakust või paremast servast kahe sõrmega ekraanikuva keskele."</string>
     <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Tagasiliikumine"</string>
-    <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Pühkige ekraani paremast või vasakust servast keskele"</string>
-    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Pühkige kindlasti ekraani alumisest servast üles"</string>
-    <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Veenduge, et te enne vabastamist liigutust ei peataks"</string>
-    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Pühkige kindlasti otse üles"</string>
+    <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Pühkige ekraani paremast või vasakust servast keskele."</string>
+    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Pühkige kindlasti ekraani alumisest servast üles."</string>
+    <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Veenduge, et te enne vabastamist liigutust ei peataks."</string>
+    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Pühkige kindlasti otse üles."</string>
     <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Tegite avakuvale minemise liigutuse. Järgmisena vaadake, kuidas minna tagasi."</string>
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Tegite avakuvale minemise liigutuse"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Pühkige avakuvale minemiseks"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Pühkige ekraani alaosast üles. See liigutus viib teid alati tagasi avakuvale."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Pühkige ekraanikuva alumisest servast 2 sõrmega üles. See liigutus viib teid alati tagasi avakuvale."</string>
     <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"Avakuvale"</string>
-    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Pühkige ekraani allosast üles"</string>
+    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"Pühkige ekraani allosast üles."</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"Väga hea!"</string>
-    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pühkige kindlasti ekraani alumisest servast üles"</string>
+    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pühkige kindlasti ekraani alumisest servast üles."</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Hoidke sõrme aknal pisut kauem, enne kui vabastate"</string>
     <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pühkige kindlasti otse üles, seejärel peatuge"</string>
     <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Õppisite liigutusi kasutama. Liigutuste väljalülitamiseks avage seaded."</string>
@@ -77,7 +77,7 @@
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Rakenduste vahel vahetamiseks pühkige ekraanikuva alaosast üles, hoidke ja seejärel vabastage."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Rakenduste vahel vahetamiseks pühkige kuva alaosast kahe sõrmega üles, hoidke ja seejärel vabastage."</string>
     <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Rakenduste vahetamine"</string>
-    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Pühkige ekraani allosast üles, hoidke ja seejärel vabastage"</string>
+    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Pühkige ekraani allosast üles, hoidke ja seejärel vabastage."</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Hästi tehtud!"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Valmis"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Valmis"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index b876cf4..c801297 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -60,7 +60,7 @@
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Ziurtatu hatza pantailaren beheko ertzetik gora pasatzen duzula"</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Ziurtatu ez duzula mugimendua gelditzen askatu arte"</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Ziurtatu hatza zuzen pasatzen duzula gora"</string>
-    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Ikasi duzu hasierako pantailara joateko keinua. Jarraian, ikasi atzera egiten."</string>
+    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Ikasi duzu hasierako pantailara joateko keinua. Orain, ikasi atzera egiten."</string>
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Ikasi duzu hasierako pantailara joateko keinua"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Pasatu hatza hasierako pantailara joateko"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Pasatu hatza pantailaren behealdetik gora. Keinu horrek hasierako pantailara eramango zaitu beti."</string>
@@ -77,7 +77,7 @@
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Aplikazio batetik bestera joateko, pasatu hatza pantailaren behealdetik gora, eduki pantaila sakatuta eta altxatu hatza."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Aplikazio batetik bestera joateko, pasatu bi hatz pantailaren behealdetik gora, eduki pantaila sakatuta eta altxatu hatza."</string>
     <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Aldatu aplikazioa"</string>
-    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Pasatu hatza pantailaren behealdetik gora, eduki sakatuta pantaila eta jaso hatza"</string>
+    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Pasatu hatza pantailaren behealdetik gora, eduki sakatuta une batez, eta jaso hatza"</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Oso ongi!"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Dena prest"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Eginda"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index fd8db85..cfdf461 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -50,7 +50,7 @@
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Экранның оң немесе сол жиегінен ортасына қарай сырғытып, саусағыңызды жіберіңіз."</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Оңнан солға сырғыту арқылы артқа қайтуды үйрендіңіз. Енді қолданбаларды ауыстыруды үйреніңіз."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Артқа қайту қимылын аяқтадыңыз."</string>
-    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Саусағыңызбен сырғыту кезінде экранның төменгі жағына тым жақындамаңыз."</string>
+    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Сырғытқанда саусақты экранның төменгі жағына қатты жақындатпаңыз."</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Артқа қайту қимылы сезгіштігін параметрлерден өзгертіңіз."</string>
     <string name="back_gesture_intro_title" msgid="19551256430224428">"Артқа қайту үшін сырғытыңыз"</string>
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Соңғы ашылған экранға оралу үшін экранның сол немесе оң жақ шетінен ортасына қарай сырғытыңыз."</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 0da707a..acf66a8 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -60,8 +60,8 @@
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಗಿನ ಅಂಚಿನಿಂದ ನೀವು ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ"</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"ವಿರಾಮಗೊಳಿಸದೆ ನಿಮ್ಮ ಬೆರಳನ್ನು ಸ್ಕ್ರೀನ್‌ನಿಂದ ಮೇಲೆತ್ತಿ"</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"ನೀವು ನೇರವಾಗಿ ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ"</string>
-    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"ನೀವು ಗೋ ಹೋಮ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ. ಮುಂದೆ, ಹಿಂದಕ್ಕೆ ಹೋಗುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿಯಿರಿ."</string>
-    <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"ನೀವು ಗೋ ಹೋಮ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string>
+    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"ನೀವು ಹೋಮ್‌ಗೆ ಹೋಗಿ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ. ಮುಂದೆ, ಹಿಂದಕ್ಕೆ ಹೋಗುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿಯಿರಿ."</string>
+    <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"ನೀವು ಹೋಮ್‌ಗೆ ಹೋಗಿ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಹಿಂತಿರುಗಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಗಿನಿಂದ ಮೇಲೆ ಸ್ವೈಪ್ ಮಾಡಿ. ಈ ಗೆಸ್ಚರ್ ಯಾವಾಗಲೂ ನಿಮ್ಮನ್ನು ಹೋಮ್‌ ಸ್ಕ್ರೀನ್‌ಗೆ ಕರೆದೊಯ್ಯುತ್ತದೆ."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"2 ಬೆರಳುಗಳಿಂದ ಸ್ಕ್ರೀನ್‌ನ ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ. ಈ ಗೆಸ್ಚರ್ ಯಾವಾಗಲೂ ನಿಮ್ಮನ್ನು ಹೋಮ್ ಸ್ಕ್ರೀನ್‌ಗೆ ಕರೆದೊಯ್ಯುತ್ತದೆ."</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 5b23744..9f44a35 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -56,7 +56,7 @@
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"이전 화면으로 돌아가려면 왼쪽 또는 오른쪽 가장자리에서 화면 중앙으로 스와이프하세요."</string>
     <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"마지막 화면으로 돌아가려면 두 손가락을 사용해 왼쪽 또는 오른쪽 가장자리에서 화면 중앙으로 스와이프하세요"</string>
     <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"뒤로"</string>
-    <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"왼쪽 또는 오른쪽 가장자리에서 화면 중앙으로 스와이프하세요"</string>
+    <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"왼쪽 또는 오른쪽 가장자리에서 화면 중앙으로 스와이프하세요."</string>
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"화면 하단 가장자리에서 위로 스와이프하세요."</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"손가락을 떼기 전에 멈추지 않아야 합니다."</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"위로 곧게 스와이프하세요."</string>
@@ -66,7 +66,7 @@
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"화면 하단에서 위로 스와이프합니다. 이 동작을 사용하면 언제든지 홈 화면으로 이동할 수 있습니다."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"두 손가락을 사용해 화면 하단에서 위로 스와이프하세요. 이 동작을 사용하면 언제든지 홈 화면으로 이동할 수 있습니다"</string>
     <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"홈으로 이동"</string>
-    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"화면 하단에서 위로 스와이프하세요"</string>
+    <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"화면 하단에서 위로 스와이프하세요."</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"아주 좋습니다"</string>
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"화면 하단 가장자리에서 위로 스와이프하세요."</string>
     <string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"창을 더 오래 누르고 있다가 손가락을 떼 보세요."</string>
@@ -77,7 +77,7 @@
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"앱 간에 전환하려면 화면 하단에서 위로 스와이프하고 잠시 멈춘 다음 손가락을 떼세요."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"앱 간에 전환하려면 두 손가락을 사용해 화면 하단에서 위로 스와이프하고 잠시 멈춘 다음 손가락을 떼세요"</string>
     <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"앱 전환"</string>
-    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"화면 하단에서 위로 스와이프하고 잠시 멈춘 다음 손가락을 떼세요"</string>
+    <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"화면 하단에서 위로 스와이프하고 잠시 멈춘 다음 손가락을 떼세요."</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"잘하셨습니다"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"설정 완료"</string>
     <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"완료"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 9b16ea9..b3ee4ea 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -50,7 +50,7 @@
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Повлечете од десниот или левиот раб кон средината на екранот и пуштете"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Научивте како да повлекувате оддесно за враќање назад. Научете и како да се префрлате помеѓу апликациите."</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Завршивте со упатството за враќање назад"</string>
-    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Не повлекувајте преблиску до долниот раб на екранот"</string>
+    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Не повлекувајте преблиску до дното на екранот"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"За да ја промените чувствителноста, одете во „Поставки“"</string>
     <string name="back_gesture_intro_title" msgid="19551256430224428">"Повлечете за да се вратите назад"</string>
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"За да се вратите на последниот екран, повлечете од левиот или десниот раб кон средината на екранот."</string>
@@ -60,7 +60,7 @@
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Повлечете нагоре од долниот раб на екранот"</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Не правете пауза пред да пуштите"</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Повлечете право нагоре"</string>
-    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Го научивте движењето за враќање на почетниот екран. Следно, дознајте како да се вратите назад."</string>
+    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Го научивте движењето за отворање на почетниот екран. Научете го и движењето за враќање назад."</string>
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Го научивте движењето за враќање на почетниот екран"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Повлечете за да одите на почетниот екран"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Повлечете нагоре од долниот раб на екранот. Ова движење секогаш ќе ве одведе на почетниот екран."</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 52777c2..ac45415 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -60,7 +60,7 @@
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"ଆପଣ ସ୍କ୍ରିନର ତଳ ଧାରରୁ ଉପରକୁ ସ୍ୱାଇପ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"ଆପଣ ଛାଡ଼ିବା ପୂର୍ବରୁ ବିରତ କରୁନଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"ଆପଣ ସିଧା ଉପରକୁ ସ୍ୱାଇପ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
-    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"ଆପଣ \'ମୂଳପୃଷ୍ଠାକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି। ତା\'ପରେ, ପଛକୁ କିପରି ଫେରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
+    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"ଆପଣ \'ହୋମକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି। ତା\'ପରେ, ପଛକୁ କିପରି ଫେରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"ଆପଣ \'ମୂଳପୃଷ୍ଠାକୁ ଯାଆନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି।"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"ହୋମକୁ ଯିବା ପାଇଁ ସ୍ୱାଇପ କରନ୍ତୁ"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ଆପଣଙ୍କ ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ କରନ୍ତୁ। ଏହି ଜେଶ୍ଚର ସର୍ବଦା ଆପଣଙ୍କୁ ହୋମ ସ୍କ୍ରିନକୁ ନେଇଥାଏ।"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 19b7e4b..a82f29a 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -58,8 +58,8 @@
     <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Voltar"</string>
     <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Deslize rapidamente a partir da extremidade esquerda ou direita para o meio do ecrã"</string>
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Deslize rapidamente com o dedo a partir do limite inferior do ecrã"</string>
-    <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Garanta que não faz uma pausa antes de soltar"</string>
-    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Garanta que desliza rapidamente com o dedo para cima"</string>
+    <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Não faça uma pausa antes de soltar"</string>
+    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Deslize rapidamente com o dedo para cima"</string>
     <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Concluiu o gesto para aceder ao ecrã principal. A seguir, saiba como retroceder."</string>
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Concluiu o gesto para aceder ao ecrã principal"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Deslize rapidamente com o dedo para aceder ao ecrã principal"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 75790ce..8ff0a04 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -59,8 +59,8 @@
     <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Deslize da borda esquerda ou direita até o meio da tela"</string>
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Deslize da borda inferior da tela para cima"</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Não pare antes de soltar"</string>
-    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Deslize para cima"</string>
-    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Você concluiu o gesto para acessar a tela inicial A seguir, aprenda a voltar."</string>
+    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Deslize para cima em linha reta"</string>
+    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Você concluiu o gesto para acessar a tela inicial. Agora, aprenda a voltar."</string>
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Você concluiu o gesto para acessar a tela inicial"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Deslizar para voltar à tela inicial"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Deslize de baixo para cima na tela. Esse gesto sempre leva você para a tela inicial."</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index b34cf93..11b091e 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -60,8 +60,8 @@
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Musíte potiahnuť nahor z dolného okraja obrazovky"</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Pred uvoľnením nesmiete zastať"</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Musíte potiahnuť priamo nahor"</string>
-    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Dokončili ste gesto na prechod na plochu. V ďalšom kroku sa naučíte, ako sa vrátiť späť."</string>
-    <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Dokončili ste gesto na prechod na plochu"</string>
+    <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Dokončili ste gesto prechodu na plochu. Teraz sa naučíte, ako sa vrátiť späť."</string>
+    <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Dokončili ste gesto prechodu na plochu"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"Prechod na plochu potiahnutím"</string>
     <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Potiahnite nahor zdola obrazovky. Týmto gestom sa vždy vrátite na plochu."</string>
     <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Postiahnite dvoma prstami z dolnej časti obrazovky. Týmto gestom sa vždy vrátite na plochu."</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 3202588..2b9906e 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -50,16 +50,16 @@
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ตรวจสอบว่าปัดจากขอบด้านขวาหรือซ้ายไปตรงกลางหน้าจอ แล้วยกนิ้วขึ้น"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"คุณรู้วิธีปัดจากด้านขวาเพื่อย้อนกลับแล้ว ต่อไปดูวิธีสลับแอป"</string>
     <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว"</string>
-    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ตรวจสอบว่าไม่ได้ปัดใกล้กับด้านล่างของหน้าจอมากเกินไป"</string>
+    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ไม่ปัดใกล้กับด้านล่างของหน้าจอมากเกินไป"</string>
     <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"เปลี่ยนความไวของท่าทางสัมผัสเพื่อย้อนกลับได้ที่การตั้งค่า"</string>
     <string name="back_gesture_intro_title" msgid="19551256430224428">"ปัดเพื่อย้อนกลับ"</string>
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"หากต้องการย้อนกลับไปที่หน้าจอล่าสุด ให้ปัดจากขอบด้านซ้ายหรือขวาไปตรงกลางหน้าจอ"</string>
     <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"หากต้องการย้อนกลับไปที่หน้าจอล่าสุด ให้ใช้ 2 นิ้วปัดจากขอบด้านซ้ายหรือขวาไปตรงกลางหน้าจอ"</string>
     <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"ย้อนกลับ"</string>
     <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"ปัดจากขอบด้านซ้ายหรือขวาไปตรงกลางหน้าจอ"</string>
-    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"ตรวจสอบว่าปัดขึ้นจากขอบด้านล่างของหน้าจอ"</string>
-    <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"ตรวจสอบว่าไม่มีการหยุดชั่วคราวก่อนยกนิ้วขึ้น"</string>
-    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"ตรวจสอบว่าปัดขึ้นในแนวตรง"</string>
+    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"ปัดขึ้นจากขอบด้านล่างของหน้าจอ"</string>
+    <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"ไม่ต้องหยุดชั่วคราวก่อนยกนิ้วขึ้น"</string>
+    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"ปัดขึ้นในแนวตรง"</string>
     <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกเสร็จแล้ว ต่อไปดูวิธีย้อนกลับ"</string>
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกเสร็จแล้ว"</string>
     <string name="home_gesture_intro_title" msgid="836590312858441830">"ปัดเพื่อไปที่หน้าแรก"</string>
@@ -68,7 +68,7 @@
     <string name="home_gesture_tutorial_title" msgid="3126834347496917376">"ไปที่หน้าจอหลัก"</string>
     <string name="home_gesture_tutorial_subtitle" msgid="7245995490408668778">"ปัดขึ้นจากด้านล่างของหน้าจอ"</string>
     <string name="home_gesture_tutorial_success" msgid="1736295017642244751">"เก่งมาก"</string>
-    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"ตรวจสอบว่าปัดขึ้นจากขอบด้านล่างของหน้าจอ"</string>
+    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"ปัดขึ้นจากขอบด้านล่างของหน้าจอ"</string>
     <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>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 606eb9b..242ee0c 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -55,7 +55,7 @@
     <string name="back_gesture_intro_title" msgid="19551256430224428">"Geri dönmek için kaydırma"</string>
     <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Son ekrana geri gitmek için sol veya sağ kenardan ekranın ortasına doğru kaydırın."</string>
     <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Son ekrana geri gitmek için sol veya sağ kenardan ekranın ortasına doğru 2 parmağınızla kaydırın."</string>
-    <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Geri dönün"</string>
+    <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"Geri dönme"</string>
     <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"Sol veya sağ kenardan ekranın ortasına doğru kaydırın"</string>
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Ekranın alt kenarından yukarı kaydırdığınızdan emin olun"</string>
     <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Bırakmadan önce parmağınızı duraklatmadığınızdan emin olun"</string>
@@ -76,7 +76,7 @@
     <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Uygulamalar arasında geçiş yapmak için kaydırma"</string>
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Uygulamalar arasında geçiş yapmak için ekranınızın altından yukarı kaydırıp basılı tutun ve sonra bırakın."</string>
     <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Uygulamalara geçiş yapmak için ekranın altından 2 parmakla yukarı kaydırıp basılı tutun ve bırakın."</string>
-    <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Uygulamalar arasında geçiş yapın"</string>
+    <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Uygulamalar arasında geçiş yapma"</string>
     <string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Ekranınızın alt tarafından yukarı doğru kaydırın, tutun ve sonra bırakın"</string>
     <string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Tebrikler!"</string>
     <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Hepsi bu kadar"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index d51f46a..5db869d 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -58,7 +58,7 @@
     <string name="back_gesture_tutorial_title" msgid="1944737946101059789">"返回"</string>
     <string name="back_gesture_tutorial_subtitle" msgid="6639993416000920142">"从屏幕左侧或右侧边缘滑动到中间"</string>
     <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"确保从屏幕底部边缘向上滑动"</string>
-    <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"松开手指前,确保不要停下来"</string>
+    <string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"松开手指前,请勿中途停顿"</string>
     <string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"确保笔直向上滑动"</string>
     <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"您完成了“转到主屏幕”手势。接下来了解如何返回。"</string>
     <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"您完成了“转到主屏幕”手势"</string>
@@ -71,7 +71,7 @@
     <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"确保从屏幕底部边缘向上滑动"</string>
     <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_with_follow_up" msgid="3544611727467765026">"您已了解如何使用手势了。如要关闭手势,请前往“设置”。"</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>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 77799e6..dd9fc63 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -230,6 +230,7 @@
     <string name="action_split">Split</string>
     <!-- Label for toast with instructions for split screen selection mode. [CHAR_LIMIT=50] -->
     <string name="toast_split_select_app">Tap another app to use split screen</string>
+    <string name="toast_split_select_cont_desc">Exit split screen selection</string>
     <!-- Label for toast when app selected for split isn't supported. [CHAR_LIMIT=50] -->
     <string name="toast_split_app_unsupported">Choose another app to use split screen</string>
     <!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] -->
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 21b7fd5..fc03704 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -298,4 +298,9 @@
     <style name="rotate_prompt_subtitle" parent="TextAppearance.GestureTutorial.Dialog.Subtitle">
         <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceVariant</item>
     </style>
+
+    <style name="ArrowTipTaskbarStyle">
+        <item name="arrowTipBackground">?androidprv:attr/materialColorSurfaceContainer</item>
+        <item name="arrowTipTextColor">?androidprv:attr/materialColorOnSurface</item>
+    </style>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
index 70999e7..8ab2ffa 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
@@ -45,6 +45,8 @@
     public static final int FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER = 1 << 4;
     // Transient Taskbar is temporarily unstashed (pending a timeout).
     public static final int FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR = 1 << 5;
+    // User has hovered the taskbar.
+    public static final int FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS = 1 << 6;
 
     @IntDef(flag = true, value = {
             FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
@@ -53,6 +55,7 @@
             FLAG_AUTOHIDE_SUSPEND_EDU_OPEN,
             FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER,
             FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
+            FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AutohideSuspendFlag {}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 64ba5aa..3c7196a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -20,11 +20,13 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
+import android.app.PendingIntent;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Intent;
@@ -73,6 +75,7 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.views.BubbleTextHolder;
 import com.android.quickstep.util.LogUtils;
 import com.android.quickstep.util.MultiValueUpdateListener;
 import com.android.systemui.shared.recents.model.Task;
@@ -149,6 +152,9 @@
             View view,
             @Nullable DragPreviewProvider dragPreviewProvider,
             @Nullable Point iconShift) {
+        if (view instanceof BubbleTextHolder) {
+            view = ((BubbleTextHolder) view).getBubbleText();
+        }
         if (!(view instanceof BubbleTextView) || mDisallowLongClick) {
             return false;
         }
@@ -193,13 +199,21 @@
         dragLayerY += dragRect.top;
 
         DragOptions dragOptions = new DragOptions();
-        dragOptions.preDragCondition = null;
-        PopupContainerWithArrow<BaseTaskbarContext> popupContainer =
-                mControllers.taskbarPopupController.showForIcon(btv);
-        if (popupContainer != null) {
-            dragOptions.preDragCondition = popupContainer.createPreDragCondition(false);
-        }
+        // First, see if view is a search result that needs custom pre-drag conditions.
+        dragOptions.preDragCondition =
+                mControllers.taskbarAllAppsController.createPreDragConditionForSearch(btv);
+
         if (dragOptions.preDragCondition == null) {
+            // See if view supports a popup container.
+            PopupContainerWithArrow<BaseTaskbarContext> popupContainer =
+                    mControllers.taskbarPopupController.showForIcon(btv);
+            if (popupContainer != null) {
+                dragOptions.preDragCondition = popupContainer.createPreDragCondition(false);
+            }
+        }
+
+        if (dragOptions.preDragCondition == null) {
+            // Fallback pre-drag condition.
             dragOptions.preDragCondition = new DragOptions.PreDragCondition() {
                 private DragView mDragView;
 
@@ -213,13 +227,8 @@
                     mDragView = dragObject.dragView;
 
                     if (!shouldStartDrag(0)) {
-                        mDragView.setOnAnimationEndCallback(() -> {
-                            // Drag might be cancelled during the DragView animation, so check
-                            // mIsPreDrag again.
-                            if (mIsInPreDrag) {
-                                callOnDragStart();
-                            }
-                        });
+                        mDragView.setOnScaleAnimEndCallback(
+                                TaskbarDragController.this::onPreDragAnimationEnd);
                     }
                 }
 
@@ -230,12 +239,13 @@
             };
         }
 
+        Point dragOffset = dragOptions.preDragCondition.getDragOffset();
         return startDrag(
                 drawable,
                 /* view = */ null,
                 /* originalView = */ btv,
-                dragLayerX,
-                dragLayerY,
+                dragLayerX + dragOffset.x,
+                dragLayerY + dragOffset.y,
                 (View target, DropTarget.DragObject d, boolean success) -> {} /* DragSource */,
                 (ItemInfo) btv.getTag(),
                 dragRect,
@@ -290,6 +300,11 @@
         mDragObject.dragInfo = dragInfo;
         mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy();
 
+        if (mOptions.preDragCondition != null) {
+            dragView.setHasDragOffset(mOptions.preDragCondition.getDragOffset().x != 0
+                    || mOptions.preDragCondition.getDragOffset().y != 0);
+        }
+
         if (dragRegion != null) {
             dragView.setDragRegion(new Rect(dragRegion));
         }
@@ -308,6 +323,14 @@
         return dragView;
     }
 
+    /** Invoked when an animation running as part of pre-drag finishes. */
+    public void onPreDragAnimationEnd() {
+        // Drag might be cancelled during the DragView animation, so check mIsPreDrag again.
+        if (mIsInPreDrag) {
+            callOnDragStart();
+        }
+    }
+
     @Override
     protected void callOnDragStart() {
         super.callOnDragStart();
@@ -383,6 +406,17 @@
                                 item.user));
                 intent.putExtra(Intent.EXTRA_PACKAGE_NAME, item.getIntent().getPackage());
                 intent.putExtra(Intent.EXTRA_SHORTCUT_ID, deepShortcutId);
+            } else if (item.itemType == ITEM_TYPE_SEARCH_ACTION) {
+                // TODO(b/289261756): Buggy behavior when split opposite to an existing search pane.
+                intent.putExtra(
+                        ClipDescription.EXTRA_PENDING_INTENT,
+                        PendingIntent.getActivityAsUser(
+                                mActivity,
+                                /* requestCode= */ 0,
+                                item.getIntent(),
+                                PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
+                                /* options= */ null,
+                                item.user));
             } else {
                 intent.putExtra(ClipDescription.EXTRA_PENDING_INTENT,
                         launcherApps.getMainActivityLaunchIntent(item.getIntent().getComponent(),
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
new file mode 100644
index 0000000..363f915
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static android.view.MotionEvent.ACTION_HOVER_ENTER;
+import static android.view.MotionEvent.ACTION_HOVER_EXIT;
+import static android.view.View.ALPHA;
+import static android.view.View.SCALE_Y;
+import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_TEXT;
+
+import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_EXCEPT_ON_BOARD_POPUP;
+import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS;
+import static com.android.launcher3.views.ArrowTipView.TEXT_ALPHA;
+
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.ContextThemeWrapper;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.app.animation.Interpolators;
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.views.ArrowTipView;
+
+/**
+ * Controls showing a tooltip in the taskbar above each icon when it is hovered.
+ */
+public class TaskbarHoverToolTipController implements View.OnHoverListener {
+
+    private static final int HOVER_TOOL_TIP_REVEAL_START_DELAY = 400;
+    private static final int HOVER_TOOL_TIP_REVEAL_DURATION = 300;
+    private static final int HOVER_TOOL_TIP_EXIT_DURATION = 150;
+
+    private final Handler mHoverToolTipHandler = new Handler(Looper.getMainLooper());
+    private final Runnable mRevealHoverToolTipRunnable = this::revealHoverToolTip;
+    private final Runnable mHideHoverToolTipRunnable = this::hideHoverToolTip;
+
+    private final TaskbarActivityContext mActivity;
+    private final TaskbarView mTaskbarView;
+    private final View mHoverView;
+    private final ArrowTipView mHoverToolTipView;
+    private final String mToolTipText;
+
+    public TaskbarHoverToolTipController(TaskbarActivityContext activity, TaskbarView taskbarView,
+            View hoverView) {
+        mActivity = activity;
+        mTaskbarView = taskbarView;
+        mHoverView = hoverView;
+
+        if (mHoverView instanceof BubbleTextView) {
+            mToolTipText = ((BubbleTextView) mHoverView).getText().toString();
+        } else if (mHoverView instanceof FolderIcon
+                && ((FolderIcon) mHoverView).mInfo.title != null) {
+            mToolTipText = ((FolderIcon) mHoverView).mInfo.title.toString();
+        } else {
+            mToolTipText = null;
+        }
+
+        ContextThemeWrapper arrowContextWrapper = new ContextThemeWrapper(mActivity,
+                R.style.ArrowTipTaskbarStyle);
+        mHoverToolTipView = new ArrowTipView(arrowContextWrapper, /* isPointingUp = */ false,
+                R.layout.arrow_toast);
+
+        AnimatorSet hoverCloseAnimator = new AnimatorSet();
+        ObjectAnimator textCloseAnimator = ObjectAnimator.ofInt(mHoverToolTipView, TEXT_ALPHA, 0);
+        textCloseAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0, 0.33f));
+        ObjectAnimator alphaCloseAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, ALPHA, 0);
+        alphaCloseAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0.33f, 0.66f));
+        ObjectAnimator scaleCloseAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, SCALE_Y, 0);
+        scaleCloseAnimator.setInterpolator(Interpolators.STANDARD);
+        hoverCloseAnimator.playTogether(
+                textCloseAnimator,
+                alphaCloseAnimator,
+                scaleCloseAnimator);
+        hoverCloseAnimator.setStartDelay(0);
+        hoverCloseAnimator.setDuration(HOVER_TOOL_TIP_EXIT_DURATION);
+        mHoverToolTipView.setCustomCloseAnimation(hoverCloseAnimator);
+
+        AnimatorSet hoverOpenAnimator = new AnimatorSet();
+        ObjectAnimator textOpenAnimator = ObjectAnimator.ofInt(mHoverToolTipView, TEXT_ALPHA, 255);
+        textOpenAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0.33f, 1f));
+        ObjectAnimator scaleOpenAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, SCALE_Y, 1f);
+        scaleOpenAnimator.setInterpolator(Interpolators.EMPHASIZED);
+        ObjectAnimator alphaOpenAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, ALPHA, 1f);
+        alphaOpenAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0.1f, 0.33f));
+        hoverOpenAnimator.playTogether(
+                scaleOpenAnimator,
+                textOpenAnimator,
+                alphaOpenAnimator);
+        hoverOpenAnimator.setStartDelay(HOVER_TOOL_TIP_REVEAL_START_DELAY);
+        hoverOpenAnimator.setDuration(HOVER_TOOL_TIP_REVEAL_DURATION);
+        mHoverToolTipView.setCustomOpenAnimation(hoverOpenAnimator);
+
+        mHoverToolTipView.addOnLayoutChangeListener(
+                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+                    mHoverToolTipView.setPivotY(bottom);
+                    mHoverToolTipView.setY(mTaskbarView.getTop() - (bottom - top));
+                });
+        mHoverToolTipView.setScaleY(0f);
+        mHoverToolTipView.setAlpha(0f);
+    }
+
+    @Override
+    public boolean onHover(View v, MotionEvent event) {
+        boolean isAnyOtherFloatingViewOpen =
+                AbstractFloatingView.hasOpenView(mActivity, TYPE_ALL_EXCEPT_ON_BOARD_POPUP);
+        if (isAnyOtherFloatingViewOpen) {
+            mHoverToolTipHandler.removeCallbacksAndMessages(null);
+        }
+        // If hover leaves a taskbar icon animate the tooltip closed.
+        if (event.getAction() == ACTION_HOVER_EXIT) {
+            startHideHoverToolTip();
+            mActivity.setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS, false);
+            return true;
+        } else if (!isAnyOtherFloatingViewOpen && event.getAction() == ACTION_HOVER_ENTER) {
+            // If hovering above a taskbar icon starts, animate the tooltip open. Do not
+            // reveal if any floating views such as folders or edu pop-ups are open.
+            startRevealHoverToolTip();
+            mActivity.setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS, true);
+            return true;
+        }
+        return false;
+    }
+
+    private void startRevealHoverToolTip() {
+        mActivity.setTaskbarWindowFullscreen(true);
+        mHoverToolTipHandler.postDelayed(mRevealHoverToolTipRunnable,
+                HOVER_TOOL_TIP_REVEAL_START_DELAY);
+    }
+
+    private void revealHoverToolTip() {
+        if (mHoverView == null || mToolTipText == null) {
+            return;
+        }
+        if (mHoverView instanceof FolderIcon && !((FolderIcon) mHoverView).getIconVisible()) {
+            return;
+        }
+        Rect iconViewBounds = Utilities.getViewBounds(mHoverView);
+        mHoverToolTipView.showAtLocation(mToolTipText, iconViewBounds.centerX(),
+                mTaskbarView.getTop(), /* shouldAutoClose= */ false);
+    }
+
+    private void startHideHoverToolTip() {
+        mHoverToolTipHandler.removeCallbacks(mRevealHoverToolTipRunnable);
+        int accessibilityHideTimeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(
+                mActivity, /* originalTimeout= */ 0, FLAG_CONTENT_TEXT);
+        mHoverToolTipHandler.postDelayed(mHideHoverToolTipRunnable, accessibilityHideTimeout);
+    }
+
+    private void hideHoverToolTip() {
+        mHoverToolTipView.close(/* animate = */ true);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 4ad3d5a..296e0db 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -249,7 +249,6 @@
 
         mIconAlignment.finishAnimation();
 
-        Log.d("b/260135164", "onDestroy - updateIconAlphaForHome(1)");
         mLauncher.getHotseat().setIconsAlpha(1f);
         mLauncher.getStateManager().removeStateListener(mStateListener);
 
@@ -645,8 +644,6 @@
                 public void onAnimationEnd(Animator animation) {
                     if (isInStashedState && committed) {
                         // Reset hotseat alpha to default
-                        Log.d("b/260135164",
-                                "playStateTransitionAnim#onAnimationEnd - setIconsAlpha(1)");
                         mLauncher.getHotseat().setIconsAlpha(1);
                     }
                 }
@@ -714,8 +711,6 @@
 
     private void updateIconAlphaForHome(float alpha) {
         if (mControllers.taskbarActivityContext.isDestroyed()) {
-            Log.e("b/260135164", "updateIconAlphaForHome is called after Taskbar is destroyed",
-                    new Exception());
             return;
         }
         mIconAlphaForHome.setValue(alpha);
@@ -726,9 +721,6 @@
          * Hide Launcher Hotseat icons when Taskbar icons have opacity. Both icon sets
          * should not be visible at the same time.
          */
-        Log.d("b/260135164",
-                "updateIconAlphaForHome - setIconsAlpha(" + (hotseatVisible ? 1 : 0)
-                        + "), isTaskbarPresent: " + mLauncher.getDeviceProfile().isTaskbarPresent);
         mLauncher.getHotseat().setIconsAlpha(hotseatVisible ? 1 : 0);
         if (mIsQsbInline) {
             mLauncher.getHotseat().setQsbAlpha(hotseatVisible ? 1 : 0);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index bf3b932..074cbe1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -18,6 +18,7 @@
 import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
 
+import static com.android.launcher3.config.FeatureFlags.ENABLE_CURSOR_HOVER_STATES;
 import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
 
 import android.content.Context;
@@ -319,6 +320,9 @@
                 }
             }
             setClickAndLongClickListenersForIcon(hotseatView);
+            if (ENABLE_CURSOR_HOVER_STATES.get()) {
+                setHoverListenerForIcon(hotseatView);
+            }
             nextViewIndex++;
         }
         // Remove remaining views
@@ -366,6 +370,13 @@
         icon.setOnLongClickListener(mIconLongClickListener);
     }
 
+    /**
+     * Sets OnHoverListener for the given view.
+     */
+    private void setHoverListenerForIcon(View icon) {
+        icon.setOnHoverListener(mControllerCallbacks.getIconOnHoverListener(icon));
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         int count = getChildCount();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 1b45404..3d22e78 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -690,6 +690,11 @@
                     .updateAndAnimateIsManuallyStashedInApp(true);
         }
 
+        /** Gets the hover listener for the provided icon view. */
+        public View.OnHoverListener getIconOnHoverListener(View icon) {
+            return new TaskbarHoverToolTipController(mActivity, mTaskbarView, icon);
+        }
+
         /**
          * Get the first chance to handle TaskbarView#onTouchEvent, and return whether we want to
          * consume the touch so TaskbarView treats it as an ACTION_CANCEL.
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index cf0b36a..3e1fef9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -15,11 +15,14 @@
  */
 package com.android.launcher3.taskbar.allapps;
 
+import android.view.View;
+
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.R;
 import com.android.launcher3.appprediction.PredictionRowView;
+import com.android.launcher3.dragndrop.DragOptions.PreDragCondition;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.taskbar.TaskbarControllers;
@@ -208,4 +211,12 @@
         // Allow null-pointer since this should only be null if the apps view is not showing.
         return mAppsView.getActiveRecyclerView().computeVerticalScrollOffset();
     }
+
+    /** @see TaskbarSearchSessionController#createPreDragConditionForSearch(View) */
+    @Nullable
+    public PreDragCondition createPreDragConditionForSearch(View view) {
+        return mSearchSessionController != null
+                ? mSearchSessionController.createPreDragConditionForSearch(view)
+                : null;
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
index 324c1a2..52e2ce1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
@@ -17,8 +17,10 @@
 package com.android.launcher3.taskbar.allapps
 
 import android.content.Context
+import android.view.View
 import com.android.launcher3.R
 import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.dragndrop.DragOptions.PreDragCondition
 import com.android.launcher3.model.data.ItemInfo
 import com.android.launcher3.util.ResourceBasedOverride
 import com.android.launcher3.util.ResourceBasedOverride.Overrides
@@ -38,6 +40,9 @@
     /** Updates the search suggestions shown in the zero-state. */
     open fun setZeroStateSearchSuggestions(items: List<ItemInfo>) {}
 
+    /** Creates a [PreDragCondition] for [view], if it is a search result that requires one. */
+    open fun createPreDragConditionForSearch(view: View): PreDragCondition? = null
+
     companion object {
         @JvmStatic
         fun newInstance(context: Context): TaskbarSearchSessionController {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index fbe0a8f..6c73a2d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -544,17 +544,9 @@
 
         ArrayList<TouchController> list = new ArrayList<>();
         list.add(getDragController());
-        Consumer<AnimatorSet> splitAnimator = animatorSet -> {
-            AnimatorSet anim = mSplitSelectStateController.getSplitAnimationController()
-                    .createPlaceholderDismissAnim(QuickstepLauncher.this);
-            anim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mSplitSelectStateController.resetState();
-                }
-            });
-            animatorSet.play(anim);
-        };
+        Consumer<AnimatorSet> splitAnimator = animatorSet ->
+                animatorSet.play(mSplitSelectStateController.getSplitAnimationController()
+                        .createPlaceholderDismissAnim(this));
         switch (mode) {
             case NO_BUTTON:
                 list.add(new NoButtonQuickSwitchTouchController(this));
@@ -673,6 +665,8 @@
                 mSplitSelectStateController.resetState();
             }
         });
+        anim.add(mSplitSelectStateController.getSplitAnimationController()
+                .getShowSplitInstructionsAnim(this).buildAnim());
         anim.buildAnim().start();
     }
 
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 33a8261..2e1a62c 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -45,6 +45,7 @@
 import android.window.RemoteTransition;
 import android.window.SplashScreen;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import com.android.app.animation.Interpolators;
@@ -240,6 +241,11 @@
         }
 
         final TaskView taskView = (TaskView) v;
+        final RecentsView recentsView = taskView.getRecentsView();
+        if (recentsView == null) {
+            return super.getActivityLaunchOptions(v, item);
+        }
+
         RunnableList onEndCallback = new RunnableList();
 
         mActivityLaunchAnimationRunner = new RemoteAnimationFactory() {
@@ -248,7 +254,7 @@
                     RemoteAnimationTarget[] wallpaperTargets,
                     RemoteAnimationTarget[] nonAppTargets, AnimationResult result) {
                 mHandler.removeCallbacks(mAnimationStartTimeoutRunnable);
-                AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets,
+                AnimatorSet anim = composeRecentsLaunchAnimator(recentsView, taskView, appTargets,
                         wallpaperTargets, nonAppTargets);
                 anim.addListener(resetStateListener());
                 result.setAnimation(anim, RecentsActivity.this, onEndCallback::executeAllAndDestroy,
@@ -285,14 +291,16 @@
     /**
      * Composes the animations for a launch from the recents list if possible.
      */
-    private AnimatorSet  composeRecentsLaunchAnimator(TaskView taskView,
+    private AnimatorSet  composeRecentsLaunchAnimator(
+            @NonNull RecentsView recentsView,
+            @NonNull TaskView taskView,
             RemoteAnimationTarget[] appTargets,
             RemoteAnimationTarget[] wallpaperTargets,
             RemoteAnimationTarget[] nonAppTargets) {
         AnimatorSet target = new AnimatorSet();
         boolean activityClosing = taskIsATargetWithMode(appTargets, getTaskId(), MODE_CLOSING);
         PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
-        createRecentsWindowAnimator(taskView, !activityClosing, appTargets,
+        createRecentsWindowAnimator(recentsView, taskView, !activityClosing, appTargets,
                 wallpaperTargets, nonAppTargets, null /* depthController */, pa);
         target.play(pa.buildAnim());
 
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index c9bad38..538aba9 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -160,13 +160,14 @@
     }
 
     public static void createRecentsWindowAnimator(
-            @NonNull TaskView v, boolean skipViewChanges,
+            @NonNull RecentsView recentsView,
+            @NonNull TaskView v,
+            boolean skipViewChanges,
             @NonNull RemoteAnimationTarget[] appTargets,
             @NonNull RemoteAnimationTarget[] wallpaperTargets,
             @NonNull RemoteAnimationTarget[] nonAppTargets,
             @Nullable DepthController depthController,
             PendingAnimation out) {
-        RecentsView recentsView = v.getRecentsView();
         boolean isQuickSwitch = v.isEndQuickswitchCuj();
         v.setEndQuickswitchCuj(false);
 
@@ -606,8 +607,8 @@
 
         TaskView taskView = findTaskViewToLaunch(recentsView, v, appTargets);
         PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
-        createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
-                nonAppTargets, depthController, pa);
+        createRecentsWindowAnimator(recentsView, taskView, skipLauncherChanges, appTargets,
+                wallpaperTargets, nonAppTargets, depthController, pa);
         if (launcherClosing) {
             // TODO(b/182592057): differentiate between "restore split" vs "launch fullscreen app"
             TaskViewUtils.createSplitAuxiliarySurfacesAnimator(nonAppTargets, true /*shown*/,
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 5740991..56d6857 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -26,15 +26,17 @@
 import android.graphics.RectF
 import android.graphics.drawable.Drawable
 import android.view.View
+import com.android.app.animation.Interpolators
 import com.android.launcher3.DeviceProfile
-import com.android.launcher3.Launcher
 import com.android.launcher3.Utilities
 import com.android.launcher3.anim.PendingAnimation
-import com.android.launcher3.dragndrop.DragLayer
+import com.android.launcher3.statemanager.StatefulActivity
 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource
+import com.android.launcher3.views.BaseDragLayer
 import com.android.quickstep.views.FloatingTaskView
 import com.android.quickstep.views.IconView
 import com.android.quickstep.views.RecentsView
+import com.android.quickstep.views.SplitInstructionsView
 import com.android.quickstep.views.TaskThumbnailView
 import com.android.quickstep.views.TaskView
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
@@ -58,6 +60,8 @@
         )
     }
 
+    var splitInstructionsView: SplitInstructionsView? = null
+
     /**
      * Returns different elements to animate for the initial split selection animation
      * depending on the state of the surface from which the split was initiated
@@ -188,31 +192,26 @@
     }
 
     /** Does not play any animation if user is not currently in split selection state. */
-    fun playPlaceholderDismissAnim(launcher: Launcher) {
+    fun playPlaceholderDismissAnim(launcher: StatefulActivity<*>) {
         if (!splitSelectStateController.isSplitSelectActive) {
             return
         }
 
         val anim = createPlaceholderDismissAnim(launcher)
-        anim.addListener(object : AnimatorListenerAdapter() {
-            override fun onAnimationEnd(animation: Animator) {
-                splitSelectStateController.resetState()
-            }
-        })
         anim.start()
     }
 
     /** Returns [AnimatorSet] which slides initial split placeholder view offscreen. */
-    fun createPlaceholderDismissAnim(launcher: Launcher) : AnimatorSet {
+    fun createPlaceholderDismissAnim(launcher: StatefulActivity<*>) : AnimatorSet {
         val animatorSet = AnimatorSet()
         val recentsView : RecentsView<*, *> = launcher.getOverviewPanel()
         val floatingTask: FloatingTaskView = splitSelectStateController.firstFloatingTaskView
                 ?: return animatorSet
 
         // We are in split selection state currently, transitioning to another state
-        val dragLayer: DragLayer = launcher.dragLayer
+        val dragLayer: BaseDragLayer<*> = launcher.dragLayer
         val onScreenRectF = RectF()
-        Utilities.getBoundsForViewInDragLayer(launcher.dragLayer, floatingTask,
+        Utilities.getBoundsForViewInDragLayer(dragLayer, floatingTask,
                 Rect(0, 0, floatingTask.width, floatingTask.height),
                 false, null, onScreenRectF)
         // Get the part of the floatingTask that intersects with the DragLayer (i.e. the
@@ -233,6 +232,42 @@
                                 floatingTask.stagePosition,
                                 launcher.deviceProfile
                         )))
+        animatorSet.addListener(object : AnimatorListenerAdapter() {
+            override fun onAnimationEnd(animation: Animator) {
+                splitSelectStateController.resetState()
+                safeRemoveViewFromDragLayer(launcher, splitInstructionsView)
+            }
+        })
         return animatorSet
     }
+
+    /**
+     * Returns a [PendingAnimation] to animate in the chip to instruct a user to select a second
+     * app for splitscreen
+     */
+    fun getShowSplitInstructionsAnim(launcher: StatefulActivity<*>) : PendingAnimation {
+        safeRemoveViewFromDragLayer(launcher, splitInstructionsView)
+        splitInstructionsView = SplitInstructionsView.getSplitInstructionsView(launcher)
+        val timings = AnimUtils.getDeviceOverviewToSplitTimings(launcher.deviceProfile.isTablet)
+        val anim = PendingAnimation(100 /*duration */)
+        anim.setViewAlpha(splitInstructionsView, 1f,
+                Interpolators.clampToProgress(Interpolators.LINEAR,
+                        timings.instructionsContainerFadeInStartOffset,
+                        timings.instructionsContainerFadeInEndOffset))
+        anim.setViewAlpha(splitInstructionsView!!.textView, 1f,
+                Interpolators.clampToProgress(Interpolators.LINEAR,
+                        timings.instructionsTextFadeInStartOffset,
+                        timings.instructionsTextFadeInEndOffset))
+        anim.addFloat(splitInstructionsView, SplitInstructionsView.UNFOLD, 0.1f, 1f,
+                Interpolators.clampToProgress(Interpolators.EMPHASIZED_DECELERATE,
+                        timings.instructionsUnfoldStartOffset,
+                        timings.instructionsUnfoldEndOffset))
+        return anim
+    }
+
+    private fun safeRemoveViewFromDragLayer(launcher: StatefulActivity<*>, view: View?) {
+        if (view != null) {
+            launcher.dragLayer.removeView(view)
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
index e073264..ae500a1 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
@@ -45,7 +45,11 @@
  *
  * After setting the correct fields for initial/second.* variables, this converts them into the
  * correct [PendingIntent] and [ShortcutInfo] objects where applicable and sends the necessary
- * data back via [getSplitLaunchData].
+ * data back via [getSplitLaunchData]. Note: there should be only one "initial" field and one
+ * "second" field set, with the rest remaining null. (Exception: [Intent] and [UserHandle] are
+ * always passed in together as a set, and are converted to a single [PendingIntent] or
+ * [ShortcutInfo]+[PendingIntent] before launch.)
+ *
  * [SplitLaunchType] indicates the type of tasks/apps/intents being launched given the provided
  * state
  */
@@ -80,21 +84,21 @@
         const val SPLIT_SINGLE_SHORTCUT_FULLSCREEN = 8
     }
 
-
     @StagePosition
     private var initialStagePosition: Int = STAGE_POSITION_UNDEFINED
-    private var initialTaskId: Int = INVALID_TASK_ID
-    private var secondTaskId: Int = INVALID_TASK_ID
-    private var initialUser: UserHandle? = null
-    private var secondUser: UserHandle? = null
-    private var initialIntent: Intent? = null
-    private var secondIntent: Intent? = null
-    private var secondPendingIntent: PendingIntent? = null
     private var itemInfo: ItemInfo? = null
     private var splitEvent: EventEnum? = null
+
+    private var initialTaskId: Int = INVALID_TASK_ID
+    private var secondTaskId: Int = INVALID_TASK_ID
+    private var initialIntent: Intent? = null
+    private var secondIntent: Intent? = null
+    private var initialUser: UserHandle? = null
+    private var secondUser: UserHandle? = null
+    private var initialPendingIntent: PendingIntent? = null
+    private var secondPendingIntent: PendingIntent? = null
     private var initialShortcut: ShortcutInfo? = null
     private var secondShortcut: ShortcutInfo? = null
-    private var initialPendingIntent: PendingIntent? = null
 
     /**
      * @param alreadyRunningTask if set to [android.app.ActivityTaskManager.INVALID_TASK_ID]
@@ -217,7 +221,7 @@
      *   split task in fullscreen
      */
     fun getFullscreenLaunchData() : SplitLaunchData {
-        // Convert all intents to shortcut infos to see if determine if we launch shortcut or intent
+        // Convert all intents to shortcut infos to determine if we launch shortcut or intent
         convertIntentsToFinalTypes()
         val splitLaunchType = getFullscreenLaunchType()
 
@@ -370,6 +374,18 @@
         return secondTaskId
     }
 
+    fun getSplitEvent(): EventEnum? {
+        return splitEvent
+    }
+
+    fun getInitialStagePosition(): Int {
+        return initialStagePosition
+    }
+
+    fun getItemInfo(): ItemInfo? {
+        return itemInfo
+    }
+
     private fun isSecondTaskIntentSet(): Boolean {
         return secondTaskId != INVALID_TASK_ID || secondIntent != null
                 || secondPendingIntent != null
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 970cf64..51211df 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -16,14 +16,9 @@
 
 package com.android.quickstep.util;
 
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT;
-import static android.app.PendingIntent.FLAG_MUTABLE;
-
 import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
-import static com.android.launcher3.util.SplitConfigurationOptions.getOppositeStagePosition;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_PENDINGINTENT_PENDINGINTENT;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_PENDINGINTENT_TASK;
 import static com.android.quickstep.util.SplitSelectDataHolder.SPLIT_SHORTCUT_TASK;
@@ -41,7 +36,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
 import android.os.Bundle;
 import android.os.Handler;
@@ -64,13 +58,11 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.SplitSelectionListener;
@@ -100,30 +92,11 @@
     private final SplitAnimationController mSplitAnimationController;
     private final AppPairsController mAppPairsController;
     private final SplitSelectDataHolder mSplitSelectDataHolder;
-    private StatsLogManager mStatsLogManager;
+    private final StatsLogManager mStatsLogManager;
     private final SystemUiProxy mSystemUiProxy;
     private final StateManager mStateManager;
     @Nullable
     private DepthController mDepthController;
-    private @StagePosition int mInitialStagePosition;
-    private ItemInfo mItemInfo;
-    /** {@link #mInitialTaskIntent} and {@link #mInitialUser} (the user of the Intent) are set
-     * together when split is initiated from an Intent. */
-    private Intent mInitialTaskIntent;
-    private UserHandle mInitialUser;
-    private int mInitialTaskId = INVALID_TASK_ID;
-    /** {@link #mSecondTaskIntent} and {@link #mSecondUser} (the user of the Intent) are set
-     * together when split is confirmed with an Intent. Either this or {@link #mSecondPendingIntent}
-     * will be set, but not both
-     */
-    private Intent mSecondTaskIntent;
-    /**
-     * Set when split is confirmed via a widget. Either this or {@link #mSecondTaskIntent} will be
-     * set, but not both
-     */
-    private PendingIntent mSecondPendingIntent;
-    private UserHandle mSecondUser;
-    private int mSecondTaskId = INVALID_TASK_ID;
     private boolean mRecentsAnimationRunning;
     /** If {@code true}, animates the existing task view split placeholder view */
     private boolean mAnimateCurrentTaskDismissal;
@@ -135,8 +108,6 @@
     /** If not null, this is the TaskView we want to launch from */
     @Nullable
     private GroupedTaskView mLaunchingTaskView;
-    /** Represents where split is intended to be invoked from. */
-    private StatsLogManager.EventEnum mSplitEvent;
 
     private FloatingTaskView mFirstFloatingTaskView;
 
@@ -165,19 +136,8 @@
     public void setInitialTaskSelect(@Nullable Intent intent, @StagePosition int stagePosition,
             @NonNull ItemInfo itemInfo, StatsLogManager.EventEnum splitEvent,
             int alreadyRunningTask) {
-        if (alreadyRunningTask != INVALID_TASK_ID) {
-            mInitialTaskId = alreadyRunningTask;
-        } else {
-            mInitialTaskIntent = intent;
-            mInitialUser = itemInfo.user;
-        }
-
-        setInitialData(stagePosition, splitEvent, itemInfo);
-
-        if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            mSplitSelectDataHolder.setInitialTaskSelect(intent, stagePosition, itemInfo, splitEvent,
-                    alreadyRunningTask);
-        }
+        mSplitSelectDataHolder.setInitialTaskSelect(intent, stagePosition, itemInfo, splitEvent,
+                alreadyRunningTask);
     }
 
     /**
@@ -187,19 +147,7 @@
     public void setInitialTaskSelect(ActivityManager.RunningTaskInfo info,
             @StagePosition int stagePosition, @NonNull ItemInfo itemInfo,
             StatsLogManager.EventEnum splitEvent) {
-        mInitialTaskId = info.taskId;
-        setInitialData(stagePosition, splitEvent, itemInfo);
-
-        if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            mSplitSelectDataHolder.setInitialTaskSelect(info, stagePosition, itemInfo, splitEvent);
-        }
-    }
-
-    private void setInitialData(@StagePosition int stagePosition,
-            StatsLogManager.EventEnum splitEvent, ItemInfo itemInfo) {
-        mItemInfo = itemInfo;
-        mInitialStagePosition = stagePosition;
-        mSplitEvent = splitEvent;
+        mSplitSelectDataHolder.setInitialTaskSelect(info, stagePosition, itemInfo, splitEvent);
     }
 
     /**
@@ -243,7 +191,7 @@
      */
     public boolean isInstanceOfComponent(@Nullable Task task, @NonNull ComponentKey componentKey) {
         // Exclude the task that is already staged
-        if (task == null || task.key.id == mInitialTaskId) {
+        if (task == null || task.key.id == mSplitSelectDataHolder.getInitialTaskId()) {
             return false;
         }
 
@@ -273,20 +221,19 @@
     }
 
     /**
-     * To be called when the actual tasks ({@link #mInitialTaskId}, {@link #mSecondTaskId}) are
-     * to be launched. Call after launcher side animations are complete.
+     * To be called when the both split tasks are ready to be launched. Call after launcher side
+     * animations are complete.
      */
     public void launchSplitTasks(Consumer<Boolean> callback) {
         Pair<InstanceId, com.android.launcher3.logging.InstanceId> instanceIds =
                 LogUtils.getShellShareableInstanceId();
-        launchTasks(mInitialTaskId, mInitialTaskIntent, mSecondTaskId, mSecondTaskIntent,
-                mInitialStagePosition, callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO,
+        launchTasks(callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO,
                 instanceIds.first);
 
         mStatsLogManager.logger()
-                .withItemInfo(mItemInfo)
+                .withItemInfo(mSplitSelectDataHolder.getItemInfo())
                 .withInstanceId(instanceIds.second)
-                .log(mSplitEvent);
+                .log(mSplitSelectDataHolder.getSplitEvent());
     }
 
     /**
@@ -294,11 +241,7 @@
      * @param task The second task that will be launched.
      */
     public void setSecondTask(Task task) {
-        mSecondTaskId = task.key.id;
-
-        if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            mSplitSelectDataHolder.setSecondTask(task.key.id);
-        }
+        mSplitSelectDataHolder.setSecondTask(task.key.id);
     }
 
     /**
@@ -307,108 +250,29 @@
      * @param user The user of that intent.
      */
     public void setSecondTask(Intent intent, UserHandle user) {
-        mSecondTaskIntent = intent;
-        mSecondUser = user;
-
-        if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            mSplitSelectDataHolder.setSecondTask(intent, user);
-        }
+        mSplitSelectDataHolder.setSecondTask(intent, user);
     }
 
     /**
      * To be called as soon as user selects the second app (even if animations aren't complete)
-     * Sets {@link #mSecondUser} from that of the pendingIntent
      * @param pendingIntent The second PendingIntent that will be launched.
      */
     public void setSecondTask(PendingIntent pendingIntent) {
-        mSecondPendingIntent = pendingIntent;
-        mSecondUser = pendingIntent.getCreatorUserHandle();
-
-        if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            mSplitSelectDataHolder.setSecondTask(pendingIntent);
-        }
+        mSplitSelectDataHolder.setSecondTask(pendingIntent);
     }
 
     /**
      * To be called when we want to launch split pairs from Overview. Split can be initiated from
      * either Overview or home, or all apps. Either both taskIds are set, or a pending intent + a
      * fill in intent with a taskId2 are set.
-     * @param intent1 is null when split is initiated from Overview
-     * @param stagePosition representing location of task1
      * @param shellInstanceId loggingId to be used by shell, will be non-null for actions that
      *                   create a split instance, null for cases that bring existing instaces to the
      *                   foreground (quickswitch, launching previous pairs from overview)
      */
-    public void launchTasks(int taskId1, @Nullable Intent intent1, int taskId2,
-            @Nullable Intent intent2, @StagePosition int stagePosition,
-            Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio,
+    public void launchTasks(Consumer<Boolean> callback, boolean freezeTaskList, float splitRatio,
             @Nullable InstanceId shellInstanceId) {
         TestLogging.recordEvent(
                 TestProtocol.SEQUENCE_MAIN, "launchSplitTasks");
-        if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            launchTasksRefactored(callback, freezeTaskList, splitRatio, shellInstanceId);
-            return;
-        }
-
-        final ActivityOptions options1 = ActivityOptions.makeBasic();
-        if (freezeTaskList) {
-            options1.setFreezeRecentTasksReordering();
-        }
-        boolean hasSecondaryPendingIntent = mSecondPendingIntent != null;
-        if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
-            final RemoteTransition remoteTransition = getShellRemoteTransition(taskId1, taskId2,
-                    callback);
-            if (intent1 == null && (intent2 == null && !hasSecondaryPendingIntent)) {
-                mSystemUiProxy.startTasks(taskId1, options1.toBundle(), taskId2,
-                        null /* options2 */, stagePosition, splitRatio, remoteTransition,
-                        shellInstanceId);
-            } else if (intent2 == null && !hasSecondaryPendingIntent) {
-                launchIntentOrShortcut(intent1, mInitialUser, options1, taskId2, stagePosition,
-                        splitRatio, remoteTransition, shellInstanceId);
-            } else if (intent1 == null) {
-                launchIntentOrShortcut(intent2, mSecondUser, options1, taskId1,
-                        getOppositeStagePosition(stagePosition), splitRatio, remoteTransition,
-                        shellInstanceId);
-            } else {
-                mSystemUiProxy.startIntents(getPendingIntent(intent1, mInitialUser),
-                        mInitialUser.getIdentifier(), getShortcutInfo(intent1, mInitialUser),
-                        options1.toBundle(), hasSecondaryPendingIntent
-                                ? mSecondPendingIntent
-                                : getPendingIntent(intent2, mSecondUser),
-                        mSecondUser.getIdentifier(), getShortcutInfo(intent2, mSecondUser),
-                        null /* options2 */, stagePosition, splitRatio, remoteTransition,
-                        shellInstanceId);
-            }
-        } else {
-            final RemoteAnimationAdapter adapter = getLegacyRemoteAdapter(taskId1, taskId2,
-                    callback);
-
-            if (intent1 == null && (intent2 == null && !hasSecondaryPendingIntent)) {
-                mSystemUiProxy.startTasksWithLegacyTransition(taskId1, options1.toBundle(),
-                        taskId2, null /* options2 */, stagePosition, splitRatio, adapter,
-                        shellInstanceId);
-            } else if (intent2 == null && !hasSecondaryPendingIntent) {
-                launchIntentOrShortcutLegacy(intent1, mInitialUser, options1, taskId2,
-                        stagePosition, splitRatio, adapter, shellInstanceId);
-            } else if (intent1 == null) {
-                launchIntentOrShortcutLegacy(intent2, mSecondUser, options1, taskId1,
-                        getOppositeStagePosition(stagePosition), splitRatio, adapter,
-                        shellInstanceId);
-            } else {
-                mSystemUiProxy.startIntentsWithLegacyTransition(
-                        getPendingIntent(intent1, mInitialUser), mInitialUser.getIdentifier(),
-                        getShortcutInfo(intent1, mInitialUser), options1.toBundle(),
-                        hasSecondaryPendingIntent
-                                ? mSecondPendingIntent
-                                : getPendingIntent(intent2, mSecondUser),
-                        mSecondUser.getIdentifier(), getShortcutInfo(intent2, mSecondUser),
-                        null /* options2 */, stagePosition, splitRatio, adapter, shellInstanceId);
-            }
-        }
-    }
-
-    private void launchTasksRefactored(Consumer<Boolean> callback, boolean freezeTaskList,
-            float splitRatio, @Nullable InstanceId shellInstanceId) {
         final ActivityOptions options1 = ActivityOptions.makeBasic();
         if (freezeTaskList) {
             options1.setFreezeRecentTasksReordering();
@@ -502,9 +366,8 @@
 
     /**
      * Used to launch split screen from a split pair that already exists (usually accessible through
-     * Overview). This is different than
-     * {@link #launchTasks(int, Intent, int, Intent, int, Consumer, boolean, float, InstanceId)} in
-     * that this only launches split screen that are existing tasks. This doesn't determine which
+     * Overview). This is different than {@link #launchTasks(Consumer, boolean, float, InstanceId)}
+     * in that this only launches split screen that are existing tasks. This doesn't determine which
      * API should be used (i.e. launching split with existing tasks vs intents vs shortcuts, etc).
      *
      * <p/>
@@ -541,11 +404,6 @@
      * split and fullscreen tasks)
      */
     public void launchInitialAppFullscreen(Consumer<Boolean> callback) {
-        if (!FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            launchSplitTasks(callback);
-            return;
-        }
-
         final ActivityOptions options1 = ActivityOptions.makeBasic();
         SplitSelectDataHolder.SplitLaunchData launchData =
                 mSplitSelectDataHolder.getFullscreenLaunchData();
@@ -612,95 +470,18 @@
                 ActivityThread.currentActivityThread().getApplicationThread());
     }
 
-    private void launchIntentOrShortcut(Intent intent, UserHandle user, ActivityOptions options1,
-            int taskId, @StagePosition int stagePosition, float splitRatio,
-            RemoteTransition remoteTransition, @Nullable InstanceId shellInstanceId) {
-        final ShortcutInfo shortcutInfo = getShortcutInfo(intent, user);
-        if (shortcutInfo != null) {
-            mSystemUiProxy.startShortcutAndTask(shortcutInfo,
-                    options1.toBundle(), taskId, null /* options2 */, stagePosition,
-                    splitRatio, remoteTransition, shellInstanceId);
-        } else {
-            mSystemUiProxy.startIntentAndTask(getPendingIntent(intent, user), user.getIdentifier(),
-                    options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio,
-                    remoteTransition, shellInstanceId);
-        }
-    }
-
-    private void launchIntentOrShortcutLegacy(Intent intent, UserHandle user,
-            ActivityOptions options1, int taskId, @StagePosition int stagePosition,
-            float splitRatio, RemoteAnimationAdapter adapter,
-            @Nullable InstanceId shellInstanceId) {
-        final ShortcutInfo shortcutInfo = getShortcutInfo(intent, user);
-        if (shortcutInfo != null) {
-            mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(shortcutInfo,
-                    options1.toBundle(), taskId, null /* options2 */, stagePosition,
-                    splitRatio, adapter, shellInstanceId);
-        } else {
-            mSystemUiProxy.startIntentAndTaskWithLegacyTransition(
-                    getPendingIntent(intent, user), user.getIdentifier(), options1.toBundle(),
-                    taskId, null /* options2 */, stagePosition, splitRatio, adapter,
-                    shellInstanceId);
-        }
-    }
-
-    /**
-     * We treat launching by intents as grouped in two ways,
-     * If {@param intent} represents the first app, we always convert the intent to pending intent
-     * It it represents second app, either the second intent OR mSecondPendingIntent will be used
-     *    convert second intent to a pendingIntent OR return mSecondPendingIntent as is
-     */
-    private PendingIntent getPendingIntent(Intent intent, UserHandle user) {
-        boolean isParamFirstIntent = intent != null && intent == mInitialTaskIntent;
-        if (!isParamFirstIntent && mSecondPendingIntent != null) {
-            // Because mSecondPendingIntent and mSecondTaskIntent can't both be set, we know we need
-            // to be using mSecondPendingIntent
-            return mSecondPendingIntent;
-        }
-
-        // intent param must either be mInitialTaskIntent or mSecondTaskIntent, convert either to
-        // a new PendingIntent
-        return intent == null ? null : (user != null
-                ? PendingIntent.getActivityAsUser(mContext, 0, intent,
-                FLAG_MUTABLE | FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT, null /* options */, user)
-                : PendingIntent.getActivity(mContext, 0, intent,
-                        FLAG_MUTABLE | FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT));
-    }
-
     public @StagePosition int getActiveSplitStagePosition() {
-        return mInitialStagePosition;
+        return mSplitSelectDataHolder.getInitialStagePosition();
     }
 
     public StatsLogManager.EventEnum getSplitEvent() {
-        return mSplitEvent;
+        return mSplitSelectDataHolder.getSplitEvent();
     }
 
     public void setRecentsAnimationRunning(boolean running) {
         mRecentsAnimationRunning = running;
     }
 
-    @Nullable
-    private ShortcutInfo getShortcutInfo(Intent intent, UserHandle user) {
-        if (intent == null || intent.getPackage() == null) {
-            return null;
-        }
-
-        final String shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID);
-        if (shortcutId == null) {
-            return null;
-        }
-
-        try {
-            final Context context = mContext.createPackageContextAsUser(
-                    intent.getPackage(), 0 /* flags */, user);
-            return new ShortcutInfo.Builder(context, shortcutId).build();
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "Failed to create a ShortcutInfo for " + intent.getPackage());
-        }
-
-        return null;
-    }
-
     public boolean isAnimateCurrentTaskDismissal() {
         return mAnimateCurrentTaskDismissal;
     }
@@ -821,24 +602,12 @@
      * other state.
      */
     public void resetState() {
-        if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            mSplitSelectDataHolder.resetState();
-        }
+        mSplitSelectDataHolder.resetState();
         dispatchOnSplitSelectionExit();
-        mInitialTaskId = INVALID_TASK_ID;
-        mInitialTaskIntent = null;
-        mSecondTaskId = INVALID_TASK_ID;
-        mSecondTaskIntent = null;
-        mInitialUser = null;
-        mSecondUser = null;
-        mInitialStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
         mRecentsAnimationRunning = false;
         mLaunchingTaskView = null;
-        mItemInfo = null;
-        mSplitEvent = null;
         mAnimateCurrentTaskDismissal = false;
         mDismissingFromSplitPair = false;
-        mSecondPendingIntent = null;
         mFirstFloatingTaskView = null;
     }
 
@@ -847,11 +616,7 @@
      *         chosen
      */
     public boolean isSplitSelectActive() {
-        if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            return mSplitSelectDataHolder.isSplitSelectActive();
-        } else {
-            return isInitialTaskIntentSet() && !isSecondTaskIntentSet();
-        }
+        return mSplitSelectDataHolder.isSplitSelectActive();
     }
 
     /**
@@ -859,36 +624,15 @@
      *          be launched
      */
     public boolean isBothSplitAppsConfirmed() {
-        if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            return mSplitSelectDataHolder.isBothSplitAppsConfirmed();
-        } else {
-            return isInitialTaskIntentSet() && isSecondTaskIntentSet();
-        }
-    }
-
-    private boolean isInitialTaskIntentSet() {
-        return (mInitialTaskId != INVALID_TASK_ID || mInitialTaskIntent != null);
+        return mSplitSelectDataHolder.isBothSplitAppsConfirmed();
     }
 
     public int getInitialTaskId() {
-        if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            return mSplitSelectDataHolder.getInitialTaskId();
-        } else {
-            return mInitialTaskId;
-        }
+        return mSplitSelectDataHolder.getInitialTaskId();
     }
 
     public int getSecondTaskId() {
-        if (FeatureFlags.ENABLE_SPLIT_LAUNCH_DATA_REFACTOR.get()) {
-            return mSplitSelectDataHolder.getSecondTaskId();
-        } else {
-            return mSecondTaskId;
-        }
-    }
-
-    private boolean isSecondTaskIntentSet() {
-        return (mSecondTaskId != INVALID_TASK_ID || mSecondTaskIntent != null
-                || mSecondPendingIntent != null);
+        return mSplitSelectDataHolder.getSecondTaskId();
     }
 
     public void setFirstFloatingTaskView(FloatingTaskView floatingTaskView) {
diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
index 0d9e412..4ca02e0 100644
--- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
@@ -17,15 +17,21 @@
 package com.android.quickstep.views;
 
 import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
+import android.view.MotionEvent;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
 
 import androidx.annotation.Nullable;
 import androidx.appcompat.widget.AppCompatTextView;
 
+import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.statemanager.StatefulActivity;
 
 /**
@@ -65,7 +71,7 @@
         mLauncher = (StatefulActivity) context;
     }
 
-    static SplitInstructionsView getSplitInstructionsView(StatefulActivity launcher) {
+    public static SplitInstructionsView getSplitInstructionsView(StatefulActivity launcher) {
         ViewGroup dragLayer = launcher.getDragLayer();
         final SplitInstructionsView splitInstructionsView =
                 (SplitInstructionsView) launcher.getLayoutInflater().inflate(
@@ -73,9 +79,7 @@
                         dragLayer,
                         false
                 );
-
-        splitInstructionsView.mTextView = splitInstructionsView.findViewById(
-                R.id.split_instructions_text);
+        splitInstructionsView.init();
 
         // Since textview overlays base view, and we sometimes manipulate the alpha of each
         // simultaneously, force overlapping rendering to false prevents redrawing of pixels,
@@ -92,6 +96,71 @@
         ensureProperRotation();
     }
 
+    private void init() {
+        mTextView = findViewById(R.id.split_instructions_text);
+
+        if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+            mTextView.setCompoundDrawables(null, null, null, null);
+            return;
+        }
+
+        mTextView.setOnTouchListener((v, event) -> {
+            if (isTouchInsideRightCompoundDrawable(event)) {
+                if (event.getAction() == MotionEvent.ACTION_UP) {
+                    exitSplitSelection();
+                }
+                return true;
+            }
+            return false;
+        });
+    }
+
+    private void exitSplitSelection() {
+        ((RecentsView) mLauncher.getOverviewPanel()).getSplitSelectController()
+                .getSplitAnimationController().playPlaceholderDismissAnim(mLauncher);
+        mLauncher.getStateManager().goToState(LauncherState.NORMAL);
+    }
+
+    private boolean isTouchInsideRightCompoundDrawable(MotionEvent event) {
+        // Get the right compound drawable of the TextView.
+        Drawable rightDrawable = mTextView.getCompoundDrawablesRelative()[2];
+
+        // Check if the touch event intersects with the drawable's bounds.
+        if (rightDrawable != null) {
+            // We can get away w/o caring about the Y bounds since it's such a small view, if it's
+            // above/below the drawable just assume they meant to touch it. ¯\_(ツ)_/¯
+            return  event.getX() >= (mTextView.getWidth() - rightDrawable.getBounds().width());
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+            return;
+        }
+
+        info.addAction(new AccessibilityNodeInfo.AccessibilityAction(
+                R.string.toast_split_select_cont_desc,
+                getResources().getString(R.string.toast_split_select_cont_desc)
+        ));
+    }
+
+    @Override
+    public boolean performAccessibilityAction(int action, Bundle arguments) {
+        if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+            return super.performAccessibilityAction(action, arguments);
+        }
+
+        if (action == R.string.toast_split_select_cont_desc) {
+            exitSplitSelection();
+            return true;
+        }
+        return super.performAccessibilityAction(action, arguments);
+    }
+
     void ensureProperRotation() {
         ((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler()
                 .setSplitInstructionsParams(
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarHoverToolTipControllerTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarHoverToolTipControllerTest.java
new file mode 100644
index 0000000..82849be
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarHoverToolTipControllerTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.Display;
+import android.view.MotionEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.folder.Folder;
+import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.util.ActivityContextWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+/**
+ * Tests for TaskbarHoverToolTipController.
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class TaskbarHoverToolTipControllerTest extends TaskbarBaseTestCase {
+
+    private TaskbarHoverToolTipController mTaskbarHoverToolTipController;
+    private TestableLooper mTestableLooper;
+
+    @Mock private TaskbarView mTaskbarView;
+    @Mock private MotionEvent mMotionEvent;
+    @Mock private BubbleTextView mHoverBubbleTextView;
+    @Mock private FolderIcon mHoverFolderIcon;
+    @Mock private Display mDisplay;
+    @Mock private TaskbarDragLayer mTaskbarDragLayer;
+    private Folder mSpyFolderView;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+
+        Context context = getApplicationContext();
+
+        doAnswer((Answer<Object>) invocation -> context.getSystemService(
+                (String) invocation.getArgument(0)))
+                .when(taskbarActivityContext).getSystemService(anyString());
+        when(taskbarActivityContext.getResources()).thenReturn(context.getResources());
+        when(taskbarActivityContext.getApplicationInfo()).thenReturn(
+                context.getApplicationInfo());
+        when(taskbarActivityContext.getDragLayer()).thenReturn(mTaskbarDragLayer);
+        when(taskbarActivityContext.getMainLooper()).thenReturn(context.getMainLooper());
+        when(taskbarActivityContext.getDisplay()).thenReturn(mDisplay);
+
+        when(mTaskbarDragLayer.getChildCount()).thenReturn(1);
+        mSpyFolderView = spy(new Folder(new ActivityContextWrapper(context), null));
+        when(mTaskbarDragLayer.getChildAt(anyInt())).thenReturn(mSpyFolderView);
+        doReturn(false).when(mSpyFolderView).isOpen();
+
+        when(mHoverBubbleTextView.getText()).thenReturn("tooltip");
+        doAnswer((Answer<Void>) invocation -> {
+            Object[] args = invocation.getArguments();
+            ((int[]) args[0])[0] = 0;
+            ((int[]) args[0])[1] = 0;
+            return null;
+        }).when(mHoverBubbleTextView).getLocationOnScreen(any(int[].class));
+        when(mHoverBubbleTextView.getWidth()).thenReturn(100);
+        when(mHoverBubbleTextView.getHeight()).thenReturn(100);
+
+        mHoverFolderIcon.mInfo = new FolderInfo();
+        mHoverFolderIcon.mInfo.title = "tooltip";
+        doAnswer((Answer<Void>) invocation -> {
+            Object[] args = invocation.getArguments();
+            ((int[]) args[0])[0] = 0;
+            ((int[]) args[0])[1] = 0;
+            return null;
+        }).when(mHoverFolderIcon).getLocationOnScreen(any(int[].class));
+        when(mHoverFolderIcon.getWidth()).thenReturn(100);
+        when(mHoverFolderIcon.getHeight()).thenReturn(100);
+
+        when(mTaskbarView.getTop()).thenReturn(200);
+
+        mTaskbarHoverToolTipController = new TaskbarHoverToolTipController(
+                taskbarActivityContext, mTaskbarView, mHoverBubbleTextView);
+        mTestableLooper = TestableLooper.get(this);
+    }
+
+    @Test
+    public void onHover_hoverEnterIcon_revealToolTip() {
+        when(mMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_HOVER_ENTER);
+        when(mMotionEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_HOVER_ENTER);
+
+        boolean hoverHandled =
+                mTaskbarHoverToolTipController.onHover(mHoverBubbleTextView, mMotionEvent);
+        waitForIdleSync();
+
+        assertThat(hoverHandled).isTrue();
+        verify(taskbarActivityContext).setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS,
+                true);
+        verify(taskbarActivityContext).setTaskbarWindowFullscreen(true);
+    }
+
+    @Test
+    public void onHover_hoverExitIcon_closeToolTip() {
+        when(mMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_HOVER_EXIT);
+        when(mMotionEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_HOVER_EXIT);
+
+        boolean hoverHandled =
+                mTaskbarHoverToolTipController.onHover(mHoverBubbleTextView, mMotionEvent);
+        waitForIdleSync();
+
+        assertThat(hoverHandled).isTrue();
+        verify(taskbarActivityContext).setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS,
+                false);
+    }
+
+    @Test
+    public void onHover_hoverEnterFolderIcon_revealToolTip() {
+        when(mMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_HOVER_ENTER);
+        when(mMotionEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_HOVER_ENTER);
+
+        boolean hoverHandled =
+                mTaskbarHoverToolTipController.onHover(mHoverFolderIcon, mMotionEvent);
+        waitForIdleSync();
+
+        assertThat(hoverHandled).isTrue();
+        verify(taskbarActivityContext).setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS,
+                true);
+        verify(taskbarActivityContext).setTaskbarWindowFullscreen(true);
+    }
+
+    @Test
+    public void onHover_hoverExitFolderIcon_closeToolTip() {
+        when(mMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_HOVER_EXIT);
+        when(mMotionEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_HOVER_EXIT);
+
+        boolean hoverHandled =
+                mTaskbarHoverToolTipController.onHover(mHoverFolderIcon, mMotionEvent);
+        waitForIdleSync();
+
+        assertThat(hoverHandled).isTrue();
+        verify(taskbarActivityContext).setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS,
+                false);
+    }
+
+    @Test
+    public void onHover_hoverExitFolderOpen_closeToolTip() {
+        when(mMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_HOVER_EXIT);
+        when(mMotionEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_HOVER_EXIT);
+        doReturn(true).when(mSpyFolderView).isOpen();
+
+        boolean hoverHandled =
+                mTaskbarHoverToolTipController.onHover(mHoverFolderIcon, mMotionEvent);
+        waitForIdleSync();
+
+        assertThat(hoverHandled).isTrue();
+        verify(taskbarActivityContext).setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS,
+                false);
+    }
+
+    @Test
+    public void onHover_hoverEnterFolderOpen_noToolTip() {
+        when(mMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_HOVER_ENTER);
+        when(mMotionEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_HOVER_ENTER);
+        doReturn(true).when(mSpyFolderView).isOpen();
+
+        boolean hoverHandled =
+                mTaskbarHoverToolTipController.onHover(mHoverFolderIcon, mMotionEvent);
+
+        assertThat(hoverHandled).isFalse();
+    }
+
+    @Test
+    public void onHover_hoverMove_noUpdate() {
+        when(mMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_HOVER_MOVE);
+        when(mMotionEvent.getActionMasked()).thenReturn(MotionEvent.ACTION_HOVER_MOVE);
+
+        boolean hoverHandled =
+                mTaskbarHoverToolTipController.onHover(mHoverFolderIcon, mMotionEvent);
+
+        assertThat(hoverHandled).isFalse();
+    }
+
+    private void waitForIdleSync() {
+        mTestableLooper.processAllMessages();
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitSelectDataHolderTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitSelectDataHolderTest.kt
new file mode 100644
index 0000000..fc767fa
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitSelectDataHolderTest.kt
@@ -0,0 +1,395 @@
+/*
+ *  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.app.ActivityManager.RunningTaskInfo
+import android.app.ActivityTaskManager.INVALID_TASK_ID
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.Intent
+import android.os.UserHandle
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.ui.AbstractLauncherUiTest
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
+import com.android.quickstep.util.SplitSelectDataHolder.Companion.SPLIT_PENDINGINTENT_PENDINGINTENT
+import com.android.quickstep.util.SplitSelectDataHolder.Companion.SPLIT_PENDINGINTENT_TASK
+import com.android.quickstep.util.SplitSelectDataHolder.Companion.SPLIT_SHORTCUT_TASK
+import com.android.quickstep.util.SplitSelectDataHolder.Companion.SPLIT_SINGLE_INTENT_FULLSCREEN
+import com.android.quickstep.util.SplitSelectDataHolder.Companion.SPLIT_SINGLE_SHORTCUT_FULLSCREEN
+import com.android.quickstep.util.SplitSelectDataHolder.Companion.SPLIT_SINGLE_TASK_FULLSCREEN
+import com.android.quickstep.util.SplitSelectDataHolder.Companion.SPLIT_TASK_PENDINGINTENT
+import com.android.quickstep.util.SplitSelectDataHolder.Companion.SPLIT_TASK_SHORTCUT
+import com.android.quickstep.util.SplitSelectDataHolder.Companion.SPLIT_TASK_TASK
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+
+class SplitSelectDataHolderTest {
+    private lateinit var splitSelectDataHolder: SplitSelectDataHolder
+
+    private val context: Context =
+        ContextWrapper(InstrumentationRegistry.getInstrumentation().targetContext)
+    private val sampleTaskInfo = RunningTaskInfo()
+    private val sampleTaskId = 10
+    private val sampleTaskId2 = 11
+    private val sampleUser = UserHandle(0)
+    private val sampleIntent = Intent()
+    private val sampleIntent2 = Intent()
+    private val sampleShortcut = Intent()
+    private val sampleShortcut2 = Intent()
+    private val sampleItemInfo = ItemInfo()
+    private val samplePackage =
+        AbstractLauncherUiTest.resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)
+
+    @Before
+    fun setup() {
+        splitSelectDataHolder = SplitSelectDataHolder(context)
+
+        sampleTaskInfo.taskId = sampleTaskId
+        sampleItemInfo.user = sampleUser
+        sampleIntent.setPackage(samplePackage)
+        sampleIntent2.setPackage(samplePackage)
+        sampleShortcut.setPackage(samplePackage)
+        sampleShortcut2.setPackage(samplePackage)
+        sampleShortcut.putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "sampleShortcut")
+        sampleShortcut2.putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "sampleShortcut2")
+    }
+
+    @Test
+    fun setInitialAsTask() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleTaskInfo,
+            STAGE_POSITION_TOP_OR_LEFT,
+            null,
+            null
+        )
+        assertTrue(splitSelectDataHolder.isSplitSelectActive())
+    }
+
+    @Test
+    fun setInitialAsIntent() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleIntent,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null,
+            INVALID_TASK_ID
+        )
+        assertTrue(splitSelectDataHolder.isSplitSelectActive())
+    }
+
+    @Test
+    fun setInitialAsIntentWithAlreadyRunningTask() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleIntent,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null,
+            sampleTaskId
+        )
+        assertTrue(splitSelectDataHolder.isSplitSelectActive())
+    }
+
+    @Test
+    fun setInitialAsShortcut() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleShortcut,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null,
+            INVALID_TASK_ID
+        )
+        assertTrue(splitSelectDataHolder.isSplitSelectActive())
+    }
+
+    @Test
+    fun setSecondAsTask() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleShortcut,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null,
+            INVALID_TASK_ID
+        )
+        splitSelectDataHolder.setSecondTask(sampleTaskId)
+        assertTrue(splitSelectDataHolder.isBothSplitAppsConfirmed())
+    }
+
+    @Test
+    fun setSecondAsIntent() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleTaskInfo,
+            STAGE_POSITION_TOP_OR_LEFT,
+            null,
+            null
+        )
+        splitSelectDataHolder.setSecondTask(sampleIntent, sampleUser)
+        assertTrue(splitSelectDataHolder.isBothSplitAppsConfirmed())
+    }
+
+    @Test
+    fun setSecondAsShortcut() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleIntent,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null,
+            INVALID_TASK_ID
+        )
+        splitSelectDataHolder.setSecondTask(sampleShortcut, sampleUser)
+        assertTrue(splitSelectDataHolder.isBothSplitAppsConfirmed())
+    }
+
+    @Test
+    fun generateLaunchData_Task_Task() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleTaskInfo,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null
+        )
+        splitSelectDataHolder.setSecondTask(sampleTaskId2)
+        val launchData = splitSelectDataHolder.getSplitLaunchData()
+
+        assertEquals(launchData.splitLaunchType, SPLIT_TASK_TASK)
+
+        // should contain a valid task ID for first app, and no intent or shortcut
+        assertNotEquals(launchData.initialTaskId, INVALID_TASK_ID)
+        assertNull(launchData.initialPendingIntent)
+        assertNull(launchData.initialShortcut)
+
+        // should contain a valid task ID for second app, and no intent or shortcut
+        assertNotEquals(launchData.secondTaskId, INVALID_TASK_ID)
+        assertNull(launchData.secondPendingIntent)
+        assertNull(launchData.secondShortcut)
+    }
+
+    @Test
+    fun generateLaunchData_Task_Intent() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleTaskInfo,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null
+        )
+        splitSelectDataHolder.setSecondTask(sampleIntent, sampleUser)
+        val launchData = splitSelectDataHolder.getSplitLaunchData()
+
+        assertEquals(launchData.splitLaunchType, SPLIT_TASK_PENDINGINTENT)
+
+        // should contain a valid task ID for first app, and no intent or shortcut
+        assertNotEquals(launchData.initialTaskId, INVALID_TASK_ID)
+        assertNull(launchData.initialPendingIntent)
+        assertNull(launchData.initialShortcut)
+
+        // should contain a valid intent for second app, and no task ID or shortcut
+        assertNotNull(launchData.secondPendingIntent)
+        assertEquals(launchData.secondTaskId, INVALID_TASK_ID)
+        assertNull(launchData.secondShortcut)
+    }
+
+    @Test
+    fun generateLaunchData_Task_Shortcut() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleTaskInfo,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null
+        )
+        splitSelectDataHolder.setSecondTask(sampleShortcut, sampleUser)
+        val launchData = splitSelectDataHolder.getSplitLaunchData()
+
+        assertEquals(launchData.splitLaunchType, SPLIT_TASK_SHORTCUT)
+
+        // should contain a valid task ID for first app, and no intent or shortcut
+        assertNotEquals(launchData.initialTaskId, INVALID_TASK_ID)
+        assertNull(launchData.initialPendingIntent)
+        assertNull(launchData.initialShortcut)
+
+        // should contain a valid shortcut and intent for second app, and no task ID
+        assertNotNull(launchData.secondShortcut)
+        assertNotNull(launchData.secondPendingIntent)
+        assertEquals(launchData.secondTaskId, INVALID_TASK_ID)
+    }
+
+    @Test
+    fun generateLaunchData_Intent_Task() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleIntent,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null,
+            INVALID_TASK_ID
+        )
+        splitSelectDataHolder.setSecondTask(sampleTaskId)
+        val launchData = splitSelectDataHolder.getSplitLaunchData()
+
+        assertEquals(launchData.splitLaunchType, SPLIT_PENDINGINTENT_TASK)
+
+        // should contain a valid intent for first app, and no task ID or shortcut
+        assertNotNull(launchData.initialPendingIntent)
+        assertEquals(launchData.initialTaskId, INVALID_TASK_ID)
+        assertNull(launchData.initialShortcut)
+
+        // should contain a valid task ID for second app, and no intent or shortcut
+        assertNotEquals(launchData.secondTaskId, INVALID_TASK_ID)
+        assertNull(launchData.secondPendingIntent)
+        assertNull(launchData.secondShortcut)
+    }
+
+    @Test
+    fun generateLaunchData_Shortcut_Task() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleShortcut,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null,
+            INVALID_TASK_ID
+        )
+        splitSelectDataHolder.setSecondTask(sampleTaskId)
+        val launchData = splitSelectDataHolder.getSplitLaunchData()
+
+        assertEquals(launchData.splitLaunchType, SPLIT_SHORTCUT_TASK)
+
+        // should contain a valid shortcut and intent for first app, and no task ID
+        assertNotNull(launchData.initialShortcut)
+        assertNotNull(launchData.initialPendingIntent)
+        assertEquals(launchData.initialTaskId, INVALID_TASK_ID)
+
+        // should contain a valid task ID for second app, and no intent or shortcut
+        assertNotEquals(launchData.secondTaskId, INVALID_TASK_ID)
+        assertNull(launchData.secondPendingIntent)
+        assertNull(launchData.secondShortcut)
+    }
+
+    @Test
+    fun generateLaunchData_Intent_Intent() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleIntent,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null,
+            INVALID_TASK_ID
+        )
+        splitSelectDataHolder.setSecondTask(sampleIntent2, sampleUser)
+        val launchData = splitSelectDataHolder.getSplitLaunchData()
+
+        assertEquals(launchData.splitLaunchType, SPLIT_PENDINGINTENT_PENDINGINTENT)
+
+        // should contain a valid intent for first app, and no task ID or shortcut
+        assertNotNull(launchData.initialPendingIntent)
+        assertEquals(launchData.initialTaskId, INVALID_TASK_ID)
+        assertNull(launchData.initialShortcut)
+
+        // should contain a valid intent for second app, and no task ID or shortcut
+        assertNotNull(launchData.secondPendingIntent)
+        assertEquals(launchData.secondTaskId, INVALID_TASK_ID)
+        assertNull(launchData.secondShortcut)
+    }
+
+    @Test
+    fun generateLaunchData_Single_Task() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleTaskInfo,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null
+        )
+        val launchData = splitSelectDataHolder.getFullscreenLaunchData()
+
+        assertEquals(launchData.splitLaunchType, SPLIT_SINGLE_TASK_FULLSCREEN)
+
+        // should contain a valid task ID for first app, and no intent or shortcut
+        assertNotEquals(launchData.initialTaskId, INVALID_TASK_ID)
+        assertNull(launchData.initialPendingIntent)
+        assertNull(launchData.initialShortcut)
+
+        // should contain no task ID, intent, or shortcut for second app
+        assertEquals(launchData.secondTaskId, INVALID_TASK_ID)
+        assertNull(launchData.secondPendingIntent)
+        assertNull(launchData.secondShortcut)
+    }
+
+    @Test
+    fun generateLaunchData_Single_Intent() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleIntent,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null,
+            INVALID_TASK_ID
+        )
+        val launchData = splitSelectDataHolder.getFullscreenLaunchData()
+
+        assertEquals(launchData.splitLaunchType, SPLIT_SINGLE_INTENT_FULLSCREEN)
+
+        // should contain a valid intent for first app, and no task ID or shortcut
+        assertNotNull(launchData.initialPendingIntent)
+        assertEquals(launchData.initialTaskId, INVALID_TASK_ID)
+        assertNull(launchData.initialShortcut)
+
+        // should contain no task ID, intent, or shortcut for second app
+        assertEquals(launchData.secondTaskId, INVALID_TASK_ID)
+        assertNull(launchData.secondPendingIntent)
+        assertNull(launchData.secondShortcut)
+    }
+
+    @Test
+    fun generateLaunchData_Single_Shortcut() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleShortcut,
+            STAGE_POSITION_TOP_OR_LEFT,
+            sampleItemInfo,
+            null,
+            INVALID_TASK_ID
+        )
+        val launchData = splitSelectDataHolder.getFullscreenLaunchData()
+
+        assertEquals(launchData.splitLaunchType, SPLIT_SINGLE_SHORTCUT_FULLSCREEN)
+
+        // should contain a valid shortcut and intent for first app, and no task ID
+        assertNotNull(launchData.initialShortcut)
+        assertNotNull(launchData.initialPendingIntent)
+        assertEquals(launchData.initialTaskId, INVALID_TASK_ID)
+
+        // should contain no task ID, intent, or shortcut for second app
+        assertEquals(launchData.secondTaskId, INVALID_TASK_ID)
+        assertNull(launchData.secondPendingIntent)
+        assertNull(launchData.secondShortcut)
+    }
+
+    @Test
+    fun clearState() {
+        splitSelectDataHolder.setInitialTaskSelect(
+            sampleTaskInfo,
+            STAGE_POSITION_TOP_OR_LEFT,
+            null,
+            null
+        )
+        splitSelectDataHolder.setSecondTask(sampleIntent, sampleUser)
+        splitSelectDataHolder.resetState()
+        assertFalse(splitSelectDataHolder.isSplitSelectActive())
+    }
+}
diff --git a/res/drawable/arrow_toast_rounded_background.xml b/res/drawable/arrow_toast_rounded_background.xml
index 1206ddd..d7d6255 100644
--- a/res/drawable/arrow_toast_rounded_background.xml
+++ b/res/drawable/arrow_toast_rounded_background.xml
@@ -14,6 +14,6 @@
     limitations under the License.
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
-    <solid android:color="@color/arrow_tip_view_bg" />
+    <solid android:color="?attr/arrowTipBackground" />
     <corners android:radius="@dimen/dialogCornerRadius" />
 </shape>
diff --git a/res/layout/arrow_toast.xml b/res/layout/arrow_toast.xml
index 88a92eb..004e778 100644
--- a/res/layout/arrow_toast.xml
+++ b/res/layout/arrow_toast.xml
@@ -28,7 +28,7 @@
         android:padding="16dp"
         android:background="@drawable/arrow_toast_rounded_background"
         android:elevation="@dimen/arrow_toast_elevation"
-        android:textColor="@color/arrow_tip_view_content"
+        android:textColor="?attr/arrowTipTextColor"
         android:textSize="14sp"/>
 
     <View
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 5113da8..134cbb0 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -47,7 +47,7 @@
     <string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Ryd teksten i søgefeltet"</string>
     <string name="no_widgets_available" msgid="4337693382501046170">"Der er ingen tilgængelige widgets eller genveje"</string>
     <string name="no_search_results" msgid="3787956167293097509">"Der blev ikke fundet nogen widgets eller genveje"</string>
-    <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Personlige"</string>
+    <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Personlig"</string>
     <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Arbejde"</string>
     <string name="widget_category_conversations" msgid="8894438636213590446">"Samtaler"</string>
     <string name="widget_category_note_taking" msgid="3469689394504266039">"Notetagning"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index ee9280b..7f5c39f 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -56,7 +56,7 @@
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"વિજેટના સેટિંગ બદલવા માટે ટૅપ કરો"</string>
     <string name="widget_education_close_button" msgid="8676165703104836580">"સમજાઈ ગયું"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"વિજેટના સેટિંગ બદલો"</string>
-    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"શોધ ઍપ્લિકેશનો"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ઍપ શોધો"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ઍપ્લિકેશનો લોડ કરી રહ્યું છે…"</string>
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"થી મેળ ખાતી કોઈ ઍપ્લિકેશનો મળી નથી"</string>
     <string name="label_application" msgid="8531721983832654978">"ઍપ"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 6866a8e..7c718e59 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -56,7 +56,7 @@
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेट की सेटिंग में बदलाव करने के लिए टैप करें"</string>
     <string name="widget_education_close_button" msgid="8676165703104836580">"ठीक है"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"विजेट की सेटिंग में बदलाव करें"</string>
-    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ऐप सर्च करें"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ऐप्लिकेशन खोजें"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ऐप्लिकेशन लोड हो रहे हैं…"</string>
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" से मिलता-जुलता कोई ऐप्लिकेशन नहीं मिला"</string>
     <string name="label_application" msgid="8531721983832654978">"ऐप्लिकेशन"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 957cc4f..72ab9b2 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -56,7 +56,7 @@
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ವಿಜೆಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="widget_education_close_button" msgid="8676165703104836580">"ಅರ್ಥವಾಯಿತು"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ವಿಜೆಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
-    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಹುಡುಕಿ"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ಆ್ಯಪ್‍ಗಳನ್ನು ಹುಡುಕಿ"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
     <string name="label_application" msgid="8531721983832654978">"ಆ್ಯಪ್"</string>
@@ -109,7 +109,7 @@
     <string name="notification_dots_desc_on" msgid="1679848116452218908">"ಆನ್ ಆಗಿದೆ"</string>
     <string name="notification_dots_desc_off" msgid="1760796511504341095">"ಆಫ್ ಆಗಿದೆ"</string>
     <string name="title_missing_notification_access" msgid="7503287056163941064">"ನೋಟಿಫಿಕೇಶನ್ ಆ್ಯಕ್ಸೆಸ್ ಅಗತ್ಯವಿದೆ"</string>
-    <string name="msg_missing_notification_access" msgid="281113995110910548">"ಅಧಿಸೂಚನೆ ಚುಕ್ಕೆಗಳನ್ನು ತೋರಿಸಲು, <xliff:g id="NAME">%1$s</xliff:g> ಗೆ ಅಪ್ಲಿಕೇಶನ್‌ ಅಧಿಸೂಚನೆಗಳನ್ನು ಆನ್‌ ಮಾಡಿ"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"ನೋಟಿಫಿಕೇಶನ್ ಚುಕ್ಕೆಗಳನ್ನು ತೋರಿಸಲು, <xliff:g id="NAME">%1$s</xliff:g> ಗೆ ಆ್ಯಪ್ ನೋಟಿಫಿಕೇಶನ್‍ಗಳನ್ನು ಆನ್‌ ಮಾಡಿ"</string>
     <string name="title_change_settings" msgid="1376365968844349552">"ಸೆಟ್ಟಿಂಗ್‌‌ಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
     <string name="notification_dots_service_title" msgid="4284221181793592871">"ನೋಟಿಫಿಕೇಶನ್ ಡಾಟ್‌ಗಳನ್ನು ತೋರಿಸಿ"</string>
     <string name="developer_options_title" msgid="700788437593726194">"ಡೆವಲಪರ್ ಆಯ್ಕೆಗಳು"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 6aa8fb5..a73f2a3 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -56,7 +56,7 @@
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"विजेटका सेटिङ बदल्न ट्याप गर्नुहोस्"</string>
     <string name="widget_education_close_button" msgid="8676165703104836580">"बुझेँ"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"विजेटका सेटिङ बदल्नुहोस्"</string>
-    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"खोजसम्बन्धी एपहरू"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"एपहरू खोज्नुहोस्"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"एपहरू लोड गर्दै…"</string>
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" सँग मिल्दो कुनै एप भेटिएन"</string>
     <string name="label_application" msgid="8531721983832654978">"एप"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 2493af3..45062fc 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -56,7 +56,7 @@
     <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ୱିଜେଟ ସେଟିଂସ ପରିବର୍ତ୍ତନ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
     <string name="widget_education_close_button" msgid="8676165703104836580">"ବୁଝିଗଲି"</string>
     <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"ୱିଜେଟ ସେଟିଂସ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
-    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ଆପ୍‌ ଖୋଜନ୍ତୁ"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"ଆପ ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
     <string name="all_apps_loading_message" msgid="5813968043155271636">"ଆପ୍‌ ଲୋଡ୍‌ ହେଉଛି..."</string>
     <string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ସହିତ ମେଳ ହେଉଥିବା କୌଣସି ଆପ୍‌ ମିଳିଲା ନାହିଁ"</string>
     <string name="label_application" msgid="8531721983832654978">"ଆପ୍"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 73e392d..733f527 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -587,5 +587,6 @@
 
     <declare-styleable name="ArrowTipView">
         <attr name="arrowTipBackground" format="color" />
+        <attr name="arrowTipTextColor" format="color" />
     </declare-styleable>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 6796d4b..1079e00 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -411,6 +411,7 @@
     <dimen name="split_instructions_elevation">1dp</dimen>
     <dimen name="split_instructions_horizontal_padding">24dp</dimen>
     <dimen name="split_instructions_vertical_padding">12dp</dimen>
+    <dimen name="split_instructions_drawable_padding">10dp</dimen>
     <dimen name="split_instructions_bottom_margin_phone_landscape">24dp</dimen>
     <dimen name="split_instructions_bottom_margin_phone_portrait">60dp</dimen>
     
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 14454bd..1695c58 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -425,5 +425,6 @@
 
     <style name="ArrowTipStyle">
         <item name="arrowTipBackground">@color/arrow_tip_view_bg</item>
+        <item name="arrowTipTextColor">@color/arrow_tip_view_content</item>
     </style>
 </resources>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 31f9bfe..b845c88 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -133,6 +133,8 @@
     public static final int TYPE_TASKBAR_OVERLAYS =
             TYPE_TASKBAR_ALL_APPS | TYPE_TASKBAR_EDUCATION_DIALOG;
 
+    public static final int TYPE_ALL_EXCEPT_ON_BOARD_POPUP = TYPE_ALL & ~TYPE_ON_BOARD_POPUP;
+
     protected boolean mIsOpen;
 
     public AbstractFloatingView(Context context, AttributeSet attrs) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d85c384..bfbd660 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -424,7 +424,6 @@
     @Override
     @TargetApi(Build.VERSION_CODES.S)
     protected void onCreate(Bundle savedInstanceState) {
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onCreate 1");
         mStartupLatencyLogger = createStartupLatencyLogger(
                 sIsNewProcess
                         ? LockedUserState.get(this).isUserUnlockedAtLauncherStartup()
@@ -583,7 +582,6 @@
         }
         setTitle(R.string.home_screen);
         mStartupLatencyLogger.logEnd(LAUNCHER_LATENCY_STARTUP_ACTIVITY_ON_CREATE);
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onCreate 2");
     }
 
     /**
@@ -1058,7 +1056,6 @@
 
     @Override
     protected void onStop() {
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onStop 1");
         super.onStop();
         if (mDeferOverlayCallbacks) {
             checkIfOverlayStillDeferred();
@@ -1070,12 +1067,10 @@
         mAppWidgetHolder.setActivityStarted(false);
         NotificationListener.removeNotificationsChangedListener(getPopupDataProvider());
         FloatingIconView.resetIconLoadResult();
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onStop 2");
     }
 
     @Override
     protected void onStart() {
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onStart 1");
         TraceHelper.INSTANCE.beginSection(ON_START_EVT);
         super.onStart();
         if (!mDeferOverlayCallbacks) {
@@ -1084,7 +1079,6 @@
 
         mAppWidgetHolder.setActivityStarted(true);
         TraceHelper.INSTANCE.endSection();
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onStart 2");
     }
 
     @Override
@@ -1255,7 +1249,6 @@
 
     @Override
     protected void onResume() {
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onResume 1");
         TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT);
         super.onResume();
 
@@ -1267,12 +1260,10 @@
 
         DragView.removeAllViews(this);
         TraceHelper.INSTANCE.endSection();
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onResume 2");
     }
 
     @Override
     protected void onPause() {
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onPause 1");
         // Ensure that items added to Launcher are queued until Launcher returns
         ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_ACTIVITY_PAUSED);
 
@@ -1285,7 +1276,6 @@
             mOverlayManager.onActivityPaused(this);
         }
         mAppWidgetHolder.setActivityResumed(false);
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onPause 2");
     }
 
     /**
@@ -1402,9 +1392,10 @@
      * @param info   The data structure describing the shortcut.
      * @return A View inflated from layoutResId.
      */
-    public View createShortcut(ViewGroup parent, WorkspaceItemInfo info) {
-        BubbleTextView favorite = (BubbleTextView) LayoutInflater.from(parent.getContext())
-                .inflate(R.layout.app_icon, parent, false);
+    public View createShortcut(@Nullable ViewGroup parent, WorkspaceItemInfo info) {
+        BubbleTextView favorite =
+                (BubbleTextView) LayoutInflater.from(parent != null ? parent.getContext() : this)
+                        .inflate(R.layout.app_icon, parent, false);
         favorite.applyFromWorkspaceItem(info);
         favorite.setOnClickListener(getItemOnClickListener());
         favorite.setOnFocusChangeListener(mFocusHandler);
@@ -1758,8 +1749,6 @@
 
     @Override
     protected void onSaveInstanceState(Bundle outState) {
-        TestProtocol.testLogD(
-                TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onSaveInstanceState 1");
         outState.putIntArray(RUNTIME_STATE_CURRENT_SCREEN_IDS,
                 mWorkspace.getCurrentPageScreenIds().getArray().toArray());
         outState.putInt(RUNTIME_STATE, mStateManager.getState().ordinal);
@@ -1791,13 +1780,10 @@
 
         super.onSaveInstanceState(outState);
         mOverlayManager.onActivitySaveInstanceState(this, outState);
-        TestProtocol.testLogD(
-                TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onSaveInstanceState 2");
     }
 
     @Override
     public void onDestroy() {
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onDestroy 1");
         super.onDestroy();
         ACTIVITY_TRACKER.onActivityDestroyed(this);
 
@@ -1820,7 +1806,6 @@
         LauncherAppState.getIDP(this).removeOnChangeListener(this);
 
         mOverlayManager.onActivityDestroyed(this);
-        TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE, "Launcher.onDestroy 2");
     }
 
     public LauncherAccessibilityDelegate getAccessibilityDelegate() {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 5426532..e3e1400 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -387,9 +387,6 @@
             "Use local overrides for search request timeout");
 
     // TODO(Block 31): Clean up flags
-    public static final BooleanFlag ENABLE_SPLIT_LAUNCH_DATA_REFACTOR = getDebugFlag(279494325,
-            "ENABLE_SPLIT_LAUNCH_DATA_REFACTOR", ENABLED,
-            "Use refactored split launching code path");
 
     // TODO(Block 32): Clean up flags
     public static final BooleanFlag ENABLE_RESPONSIVE_WORKSPACE = getDebugFlag(241386436,
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index b9bb52c..adfdc89 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -99,7 +99,9 @@
 
     // Whether mAnim has started. Unlike mAnim.isStarted(), this is true even after mAnim ends.
     private boolean mScaleAnimStarted;
-    private Runnable mOnAnimEndCallback = null;
+    private boolean mShiftAnimStarted;
+    private Runnable mOnScaleAnimEndCallback;
+    private Runnable mOnShiftAnimEndCallback;
 
     private int mLastTouchX;
     private int mLastTouchY;
@@ -186,13 +188,26 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 super.onAnimationEnd(animation);
-                if (mOnAnimEndCallback != null) {
-                    mOnAnimEndCallback.run();
+                if (mOnScaleAnimEndCallback != null) {
+                    mOnScaleAnimEndCallback.run();
                 }
             }
         });
         // Set up the shift animator.
         mShiftAnim = ValueAnimator.ofFloat(0f, 1f);
+        mShiftAnim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mShiftAnimStarted = true;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (mOnShiftAnimEndCallback != null) {
+                    mOnShiftAnimEndCallback.run();
+                }
+            }
+        });
 
         setDragRegion(new Rect(0, 0, width, height));
 
@@ -211,8 +226,14 @@
         setWillNotDraw(false);
     }
 
-    public void setOnAnimationEndCallback(Runnable callback) {
-        mOnAnimEndCallback = callback;
+    /** Callback invoked when the scale animation ends. */
+    public void setOnScaleAnimEndCallback(Runnable callback) {
+        mOnScaleAnimEndCallback = callback;
+    }
+
+    /** Callback invoked when the shift animation ends. */
+    public void setOnShiftAnimEndCallback(Runnable callback) {
+        mOnShiftAnimEndCallback = callback;
     }
 
     /**
@@ -416,10 +437,16 @@
         }
     }
 
+    /** {@code true} if the scale animation has finished. */
     public boolean isScaleAnimationFinished() {
         return mScaleAnimStarted && !mScaleAnim.isRunning();
     }
 
+    /** {@code true} if the shift animation has finished. */
+    public boolean isShiftAnimationFinished() {
+        return mShiftAnimStarted && !mShiftAnim.isRunning();
+    }
+
     /**
      * Move the window containing this view.
      *
diff --git a/src/com/android/launcher3/folder/LauncherDelegate.java b/src/com/android/launcher3/folder/LauncherDelegate.java
index 7ac2472..c06a0f3 100644
--- a/src/com/android/launcher3/folder/LauncherDelegate.java
+++ b/src/com/android/launcher3/folder/LauncherDelegate.java
@@ -94,9 +94,6 @@
                         // folder
                         CellLayout cellLayout = mLauncher.getCellLayout(info.container,
                                 mLauncher.getCellPosMapper().mapModelToPresenter(info).screenId);
-                        if (cellLayout == null) {
-                            return;
-                        }
                         finalItem =  info.contents.remove(0);
                         newIcon = mLauncher.createShortcut(cellLayout, finalItem);
                         mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem,
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index 1b1b38f..e10e72d 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -466,7 +466,7 @@
                 () -> parser, AutoInstallsLayout.TAG_WORKSPACE);
     }
 
-    private static Uri getLayoutUri(String authority, Context ctx) {
+    public static Uri getLayoutUri(String authority, Context ctx) {
         InvariantDeviceProfile grid = LauncherAppState.getIDP(ctx);
         return new Uri.Builder().scheme("content").authority(authority).path("launcher_layout")
                 .appendQueryParameter("version", "1")
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
index 717164e..e8be12c 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
@@ -240,9 +240,8 @@
                 public void onPreDragStart(DropTarget.DragObject dragObject) {
                     mDragView = dragObject.dragView;
                     if (!shouldStartDrag(0)) {
-                        mDragView.setOnAnimationEndCallback(() -> {
-                            mActivity.beginDragShared(v, mActivity.getAppsView(), options);
-                        });
+                        mDragView.setOnScaleAnimEndCallback(() ->
+                                mActivity.beginDragShared(v, mActivity.getAppsView(), options));
                     }
                 }
 
diff --git a/src/com/android/launcher3/views/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java
index 8e05650..b44dbeb 100644
--- a/src/com/android/launcher3/views/ArrowTipView.java
+++ b/src/com/android/launcher3/views/ArrowTipView.java
@@ -28,7 +28,9 @@
 import android.graphics.Rect;
 import android.graphics.drawable.ShapeDrawable;
 import android.os.Handler;
+import android.util.IntProperty;
 import android.util.Log;
+import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
@@ -43,6 +45,7 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.graphics.TriangleShape;
 
@@ -57,6 +60,19 @@
     private static final long SHOW_DURATION_MS = 300;
     private static final long HIDE_DURATION_MS = 100;
 
+    public static final IntProperty<ArrowTipView> TEXT_ALPHA =
+            new IntProperty<>("textAlpha") {
+                @Override
+                public void setValue(ArrowTipView view, int v) {
+                    view.setTextAlpha(v);
+                }
+
+                @Override
+                public Integer get(ArrowTipView view) {
+                    return view.getTextAlpha();
+                }
+            };
+
     private final ActivityContext mActivityContext;
     private final Handler mHandler = new Handler();
     private boolean mIsPointingUp;
@@ -69,6 +85,8 @@
     private AnimatorSet mOpenAnimator = new AnimatorSet();
     private AnimatorSet mCloseAnimator = new AnimatorSet();
 
+    private int mTextAlpha;
+
     public ArrowTipView(Context context) {
         this(context, false);
     }
@@ -86,6 +104,11 @@
         mArrowMinOffset = context.getResources().getDimensionPixelSize(
                 R.dimen.dynamic_grid_cell_border_spacing);
         TypedArray ta = context.obtainStyledAttributes(R.styleable.ArrowTipView);
+        // Set style to default to avoid inflation issues with missing attributes.
+        if (!ta.hasValue(R.styleable.ArrowTipView_arrowTipBackground)
+                || !ta.hasValue(R.styleable.ArrowTipView_arrowTipTextColor)) {
+            context = new ContextThemeWrapper(context, R.style.ArrowTipStyle);
+        }
         mArrowViewPaintColor = ta.getColor(R.styleable.ArrowTipView_arrowTipBackground,
                 context.getColor(R.color.arrow_tip_view_bg));
         ta.recycle();
@@ -110,6 +133,8 @@
         }
         if (mIsOpen) {
             if (animate) {
+                mCloseAnimator.addListener(AnimatorListeners.forSuccessCallback(
+                        () -> mActivityContext.getDragLayer().removeView(this)));
                 mCloseAnimator.start();
             } else {
                 mCloseAnimator.cancel();
@@ -414,4 +439,16 @@
     public void setCustomCloseAnimation(AnimatorSet animator) {
         mCloseAnimator = animator;
     }
+
+    private void setTextAlpha(int textAlpha) {
+        if (mTextAlpha != textAlpha) {
+            mTextAlpha = textAlpha;
+            TextView textView = findViewById(R.id.text);
+            textView.setTextColor(textView.getTextColors().withAlpha(mTextAlpha));
+        }
+    }
+
+    private int getTextAlpha() {
+        return mTextAlpha;
+    }
 }
diff --git a/tests/Android.bp b/tests/Android.bp
index e7f4084..5a52440 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -50,14 +50,13 @@
       "src/com/android/launcher3/util/Wait.java",
       "src/com/android/launcher3/util/WidgetUtils.java",
       "src/com/android/launcher3/util/rule/FailureWatcher.java",
-      "src/com/android/launcher3/util/rule/LauncherActivityRule.java",
       "src/com/android/launcher3/util/rule/ViewCaptureRule.kt",
       "src/com/android/launcher3/util/rule/SamplerRule.java",
       "src/com/android/launcher3/util/rule/ScreenRecordRule.java",
       "src/com/android/launcher3/util/rule/ShellCommandRule.java",
-      "src/com/android/launcher3/util/rule/SimpleActivityRule.java",
       "src/com/android/launcher3/util/rule/TestStabilityRule.java",
       "src/com/android/launcher3/util/rule/TISBindRule.java",
+      "src/com/android/launcher3/util/viewcapture_analysis/*.java",
       "src/com/android/launcher3/testcomponent/BaseTestingActivity.java",
       "src/com/android/launcher3/testcomponent/OtherBaseTestingActivity.java",
       "src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java",
@@ -87,6 +86,7 @@
         "launcher_log_protos_lite",
         "truth-prebuilt",
         "platform-test-rules",
+        "testables",
     ],
     manifest: "AndroidManifest-common.xml",
     platform_apis: true,
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 75cee2f..4073517 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -157,7 +157,6 @@
     public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
     public static final String FLAKY_ACTIVITY_COUNT = "b/260260325";
     public static final String ICON_MISSING = "b/282963545";
-    public static final String ACTIVITY_LIFECYCLE_RULE = "b/289161193";
 
     public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
     public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index a82b005..d22a353 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -65,7 +65,6 @@
 import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.util.Wait;
 import com.android.launcher3.util.rule.FailureWatcher;
-import com.android.launcher3.util.rule.LauncherActivityRule;
 import com.android.launcher3.util.rule.SamplerRule;
 import com.android.launcher3.util.rule.ScreenRecordRule;
 import com.android.launcher3.util.rule.ShellCommandRule;
@@ -182,8 +181,6 @@
         mLauncher.setOnLauncherCrashed(() -> mLauncherPid = 0);
     }
 
-    protected final LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
-
     @Rule
     public ShellCommandRule mDisableHeadsUpNotification =
             ShellCommandRule.disableHeadsUpNotification();
@@ -204,7 +201,8 @@
     }
 
     protected TestRule getRulesInsideActivityMonitor() {
-        final ViewCaptureRule viewCaptureRule = new ViewCaptureRule(mActivityMonitor::getActivity);
+        final ViewCaptureRule viewCaptureRule = new ViewCaptureRule(
+                Launcher.ACTIVITY_TRACKER::getCreatedActivity);
         final RuleChain inner = RuleChain
                 .outerRule(new PortraitLandscapeRunner(this))
                 .around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
@@ -219,7 +217,6 @@
     public TestRule mOrderSensitiveRules = RuleChain
             .outerRule(new SamplerRule())
             .around(new TestStabilityRule())
-            .around(mActivityMonitor)
             .around(getRulesInsideActivityMonitor());
 
     public UiDevice getDevice() {
@@ -322,7 +319,7 @@
 
     protected <T> T getFromLauncher(Function<Launcher, T> f) {
         if (!TestHelpers.isInLauncherProcess()) return null;
-        return getOnUiThread(() -> f.apply(mActivityMonitor.getActivity()));
+        return getOnUiThread(() -> f.apply(Launcher.ACTIVITY_TRACKER.getCreatedActivity()));
     }
 
     protected void executeOnLauncher(Consumer<Launcher> f) {
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 82bf644..b2ce400 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -30,6 +30,7 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.celllayout.FavoriteItemsTransaction;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -124,7 +125,10 @@
 
         @Override
         public boolean isTrue() throws Throwable {
-            return mMainThreadExecutor.submit(mActivityMonitor.itemExists(this)).get();
+            return mMainThreadExecutor.submit(() -> {
+                Launcher l = Launcher.ACTIVITY_TRACKER.getCreatedActivity();
+                return l != null && l.getWorkspace().getFirstMatch(this) != null;
+            }).get();
         }
 
         @Override
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index b05ebf8..9dca24b 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -18,7 +18,6 @@
 import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
 
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
 
 import android.platform.test.annotations.PlatinumTest;
 import android.platform.test.rule.ScreenRecordRule;
@@ -27,7 +26,6 @@
 import androidx.test.filters.LargeTest;
 
 import com.android.launcher3.celllayout.FavoriteItemsTransaction;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.tapl.Widget;
 import com.android.launcher3.tapl.WidgetResizeFrame;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
@@ -70,11 +68,6 @@
                 .getWidget(widgetInfo.getLabel(mTargetContext.getPackageManager()))
                 .dragWidgetToWorkspace();
 
-        assertTrue(mActivityMonitor.itemExists(
-                (info, view) -> info instanceof LauncherAppWidgetInfo &&
-                        ((LauncherAppWidgetInfo) info).providerName.getClassName().equals(
-                                widgetInfo.provider.getClassName())).call());
-
         assertNotNull("Widget resize frame not shown after widget add", resizeFrame);
         resizeFrame.dismiss();
 
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index 384fa46..a6b5369 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -32,6 +32,7 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.celllayout.FavoriteItemsTransaction;
 import com.android.launcher3.model.data.ItemInfo;
@@ -193,7 +194,10 @@
 
         @Override
         public boolean isTrue() throws Throwable {
-            return mMainThreadExecutor.submit(mActivityMonitor.itemExists(mOp)).get();
+            return mMainThreadExecutor.submit(() -> {
+                Launcher l = Launcher.ACTIVITY_TRACKER.getCreatedActivity();
+                return l != null && l.getWorkspace().getFirstMatch(mOp) != null;
+            }).get();
         }
     }
 }
diff --git a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
deleted file mode 100644
index e9a52f8..0000000
--- a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2017 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.rule;
-
-import android.app.Activity;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
-
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.util.concurrent.Callable;
-
-/**
- * Test rule to get the current Launcher activity.
- */
-public class LauncherActivityRule extends SimpleActivityRule<Launcher> {
-
-    public LauncherActivityRule() {
-        super(Launcher.class);
-    }
-
-    @Override
-    public Statement apply(Statement base, Description description) {
-
-        return new MyStatement(base) {
-            @Override
-            public void onActivityStarted(Activity activity) {
-                if (activity instanceof Launcher) {
-                    ((Launcher) activity).getRotationHelper().forceAllowRotationForTesting(true);
-                }
-            }
-        };
-    }
-
-    public Callable<Boolean> itemExists(final ItemOperator op) {
-        return () -> {
-            Launcher launcher = getActivity();
-            if (launcher == null) {
-                return false;
-            }
-            return launcher.getWorkspace().getFirstMatch(op) != null;
-        };
-    }
-}
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java b/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java
deleted file mode 100644
index b5d8193..0000000
--- a/tests/src/com/android/launcher3/util/rule/SimpleActivityRule.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2019 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.rule;
-
-import android.app.Activity;
-import android.app.Application;
-import android.app.Application.ActivityLifecycleCallbacks;
-import android.os.Bundle;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.launcher3.testing.shared.TestProtocol;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-/**
- * Test rule to get the current activity.
- */
-public class SimpleActivityRule<T extends Activity> implements TestRule {
-
-    private final Class<T> mClass;
-    private T mActivity;
-
-    public SimpleActivityRule(Class<T> clazz) {
-        mClass = clazz;
-    }
-
-    @Override
-    public Statement apply(Statement base, Description description) {
-        return new MyStatement(base);
-    }
-
-    public T getActivity() {
-        return mActivity;
-    }
-
-    protected class MyStatement extends Statement implements ActivityLifecycleCallbacks {
-
-        private final Statement mBase;
-
-        public MyStatement(Statement base) {
-            mBase = base;
-        }
-
-        @Override
-        public void evaluate() throws Throwable {
-            Application app = (Application)
-                    InstrumentationRegistry.getTargetContext().getApplicationContext();
-            app.registerActivityLifecycleCallbacks(this);
-            try {
-                mBase.evaluate();
-            } finally {
-                app.unregisterActivityLifecycleCallbacks(this);
-                mActivity = null;
-            }
-        }
-
-        @Override
-        public void onActivityCreated(Activity activity, Bundle bundle) {
-            if (activity != null && mClass.isInstance(activity)) {
-                TestProtocol.testLogD(
-                        TestProtocol.ACTIVITY_LIFECYCLE_RULE, "MyStatement.onActivityCreated");
-                mActivity = (T) activity;
-            }
-        }
-
-        @Override
-        public void onActivityStarted(Activity activity) {
-            if (activity == mActivity) {
-                TestProtocol.testLogD(
-                        TestProtocol.ACTIVITY_LIFECYCLE_RULE, "MyStatement.onActivityStarted");
-            }
-        }
-
-        @Override
-        public void onActivityResumed(Activity activity) {
-            if (activity == mActivity) {
-                TestProtocol.testLogD(
-                        TestProtocol.ACTIVITY_LIFECYCLE_RULE, "MyStatement.onActivityResumed");
-            }
-        }
-
-        @Override
-        public void onActivityPaused(Activity activity) {
-            if (activity == mActivity) {
-                TestProtocol.testLogD(
-                        TestProtocol.ACTIVITY_LIFECYCLE_RULE, "MyStatement.onActivityPaused");
-            }
-        }
-
-        @Override
-        public void onActivityStopped(Activity activity) {
-            if (activity == mActivity) {
-                TestProtocol.testLogD(
-                        TestProtocol.ACTIVITY_LIFECYCLE_RULE, "MyStatement.onAcgtivityStopped");
-            }
-        }
-
-        @Override
-        public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
-            if (activity == mActivity) {
-                TestProtocol.testLogD(TestProtocol.ACTIVITY_LIFECYCLE_RULE,
-                        "MyStatement.onActivitySaveInstanceState");
-            }
-        }
-
-        @Override
-        public void onActivityDestroyed(Activity activity) {
-            if (activity == mActivity) {
-                TestProtocol.testLogD(
-                        TestProtocol.ACTIVITY_LIFECYCLE_RULE, "MyStatement.onActivityDestroyed");
-                mActivity = null;
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
index 8e2aea8..b2a2f7f 100644
--- a/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
+++ b/tests/src/com/android/launcher3/util/rule/ViewCaptureRule.kt
@@ -24,6 +24,7 @@
 import com.android.app.viewcapture.ViewCapture.MAIN_EXECUTOR
 import com.android.app.viewcapture.data.ExportedData
 import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter
+import com.android.launcher3.util.viewcapture_analysis.ViewCaptureAnalyzer
 import java.util.function.Supplier
 import org.junit.rules.TestRule
 import org.junit.runner.Description
@@ -82,6 +83,8 @@
                     // is removed while onDraw is running, resulting in an IllegalStateException.
                     MAIN_EXECUTOR.execute { windowListenerCloseables.onEach(SafeCloseable::close) }
                 }
+
+                ViewCaptureAnalyzer.assertNoAnomalies(viewCaptureData)
             }
 
             private fun startCapture(
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 e40fb79..2501801 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
@@ -28,33 +28,101 @@
  * Invisible views are treated as if they had zero alpha.
  */
 final class AlphaJumpDetector extends AnomalyDetector {
+    // Commonly used parts of the paths to ignore.
+    private static final String CONTENT = "DecorView|LinearLayout|FrameLayout:id/content|";
+    private static final String DRAG_LAYER =
+            CONTENT + "LauncherRootView:id/launcher|DragLayer:id/drag_layer|";
+
     // Paths of nodes that are excluded from analysis.
     private static final Collection<String> PATHS_TO_IGNORE = Set.of(
-            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
-                    + ":id/drag_layer|SearchContainerView:id/apps_view|SearchRecyclerView:id"
-                    + "/search_results_list_view|SearchResultSmallIconRow",
-            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
-                    + ":id/drag_layer|SearchContainerView:id/apps_view|SearchRecyclerView:id"
-                    + "/search_results_list_view|SearchResultIcon",
-            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
-                    + ":id/drag_layer|LauncherRecentsView:id/overview_panel|TaskView",
-            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
-                    + ":id/drag_layer|WidgetsFullSheet|SpringRelativeLayout:id/container"
-                    + "|WidgetsRecyclerView:id/primary_widgets_list_view|WidgetsListHeader:id"
-                    + "/widgets_list_header",
-            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
-                    + ":id/drag_layer|WidgetsFullSheet|SpringRelativeLayout:id/container"
-                    + "|WidgetsRecyclerView:id/primary_widgets_list_view"
-                    + "|StickyHeaderLayout$EmptySpaceView",
-            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
-                    + ":id/drag_layer|SearchContainerView:id/apps_view|AllAppsRecyclerView:id"
-                    + "/apps_list_view|BubbleTextView:id/icon",
-            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
-                    + ":id/drag_layer|LauncherRecentsView:id/overview_panel|ClearAllButton:id"
-                    + "/clear_all",
-            "DecorView|LinearLayout|FrameLayout:id/content|LauncherRootView:id/launcher|DragLayer"
-                    + ":id/drag_layer|NexusOverviewActionsView:id/overview_actions_view"
-                    + "|LinearLayout:id/action_buttons"
+            CONTENT
+                    + "AddItemDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
+                    + "/add_item_bottom_sheet|LinearLayout:id/add_item_bottom_sheet_content"
+                    + "|ScrollView:id/widget_preview_scroll_view|WidgetCell:id/widget_cell"
+                    + "|WidgetCellPreview:id/widget_preview_container|ImageView:id/widget_badge",
+            CONTENT
+                    + "AddItemDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
+                    + "/add_item_bottom_sheet|LinearLayout:id/add_item_bottom_sheet_content"
+                    + "|ScrollView:id/widget_preview_scroll_view|WidgetCell:id/widget_cell"
+                    + "|WidgetCellPreview:id/widget_preview_container|WidgetCell$1|FrameLayout"
+                    + "|ImageView:id/icon",
+            CONTENT + "AddItemDragLayer:id/add_item_drag_layer|View",
+            DRAG_LAYER
+                    + "AppWidgetResizeFrame|FrameLayout|ImageButton:id/widget_reconfigure_button",
+            DRAG_LAYER
+                    + "AppWidgetResizeFrame|FrameLayout|ImageView:id/widget_resize_bottom_handle",
+            DRAG_LAYER + "AppWidgetResizeFrame|FrameLayout|ImageView:id/widget_resize_frame",
+            DRAG_LAYER + "AppWidgetResizeFrame|FrameLayout|ImageView:id/widget_resize_left_handle",
+            DRAG_LAYER + "AppWidgetResizeFrame|FrameLayout|ImageView:id/widget_resize_right_handle",
+            DRAG_LAYER + "AppWidgetResizeFrame|FrameLayout|ImageView:id/widget_resize_top_handle",
+            DRAG_LAYER + "FloatingTaskView|FloatingTaskThumbnailView:id/thumbnail",
+            DRAG_LAYER + "FloatingTaskView|SplitPlaceholderView:id/split_placeholder",
+            DRAG_LAYER + "Folder|FolderPagedView:id/folder_content",
+            DRAG_LAYER + "LauncherAllAppsContainerView:id/apps_view",
+            DRAG_LAYER + "LauncherDragView",
+            DRAG_LAYER + "LauncherRecentsView:id/overview_panel",
+            DRAG_LAYER
+                    + "NexusOverviewActionsView:id/overview_actions_view|FrameLayout:id"
+                    + "/select_mode_buttons|ImageButton:id/close",
+            DRAG_LAYER
+                    + "NexusOverviewActionsView:id/overview_actions_view|LinearLayout:id"
+                    + "/action_buttons|Button:id/action_screenshot",
+            DRAG_LAYER
+                    + "NexusOverviewActionsView:id/overview_actions_view|LinearLayout:id"
+                    + "/action_buttons|Button:id/action_select",
+            DRAG_LAYER
+                    + "NexusOverviewActionsView:id/overview_actions_view|LinearLayout:id"
+                    + "/action_buttons|Button:id/action_split",
+            DRAG_LAYER
+                    + "NexusOverviewActionsView:id/overview_actions_view|LinearLayout:id"
+                    + "/action_buttons|Space:id/action_split_space",
+            DRAG_LAYER
+                    + "PopupContainerWithArrow:id/popup_container|LinearLayout:id"
+                    + "/deep_shortcuts_container|DeepShortcutView:id/deep_shortcut_material"
+                    + "|DeepShortcutTextView:id/bubble_text",
+            DRAG_LAYER
+                    + "PopupContainerWithArrow:id/popup_container|LinearLayout:id"
+                    + "/deep_shortcuts_container|DeepShortcutView:id/deep_shortcut_material|View"
+                    + ":id/icon",
+            DRAG_LAYER
+                    + "PopupContainerWithArrow:id/popup_container|LinearLayout:id"
+                    + "/system_shortcuts_container|DeepShortcutView:id/system_shortcut"
+                    + "|BubbleTextView:id/bubble_text",
+            DRAG_LAYER
+                    + "PopupContainerWithArrow:id/popup_container|LinearLayout:id"
+                    + "/system_shortcuts_container|DeepShortcutView:id/system_shortcut|View:id"
+                    + "/icon",
+            DRAG_LAYER
+                    + "PopupContainerWithArrow:id/popup_container|LinearLayout:id"
+                    + "/system_shortcuts_container|ImageView",
+            DRAG_LAYER
+                    + "PopupContainerWithArrow:id/popup_container|LinearLayout:id"
+                    + "/widget_shortcut_container|DeepShortcutView:id/system_shortcut"
+                    + "|BubbleTextView:id/bubble_text",
+            DRAG_LAYER
+                    + "PopupContainerWithArrow:id/popup_container|LinearLayout:id"
+                    + "/widget_shortcut_container|DeepShortcutView:id/system_shortcut|View:id/icon",
+            DRAG_LAYER + "SearchContainerView:id/apps_view",
+            DRAG_LAYER + "Snackbar|TextView:id/action",
+            DRAG_LAYER + "Snackbar|TextView:id/label",
+            DRAG_LAYER + "SplitInstructionsView|AppCompatTextView:id/split_instructions_text",
+            DRAG_LAYER + "TaskMenuView|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",
+            CONTENT
+                    + "LauncherRootView|RecentsDragLayer:id/drag_layer|FallbackRecentsView:id"
+                    + "/overview_panel",
+            CONTENT
+                    + "LauncherRootView|RecentsDragLayer:id/drag_layer|NexusOverviewActionsView"
+                    + ":id/overview_actions_view|LinearLayout:id/action_buttons|Button:id"
+                    + "/action_screenshot",
+            CONTENT
+                    + "LauncherRootView|RecentsDragLayer:id/drag_layer|NexusOverviewActionsView"
+                    + ":id/overview_actions_view|LinearLayout:id/action_buttons|Button:id"
+                    + "/action_select"
     );
     // Minimal increase or decrease of view's alpha between frames that triggers the error.
     private static final float ALPHA_JUMP_THRESHOLD = 1f;