Merge "Create drop target for bubble bar" into main
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 8eed155..1afde8f 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -95,7 +95,7 @@
     <string name="action_share" msgid="2648470652637092375">"Deli"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
     <string name="action_split" msgid="2098009717623550676">"Podeli"</string>
-    <string name="action_save_app_pair" msgid="5974823919237645229">"Čuvaj par aplikacija"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Sačuvaj par aplikacija"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podeljeni ekran"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju da biste koristili podeljeni ekran"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Otkaži"</b></string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 499a3d5..c4371ee 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -134,7 +134,7 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskleisten-Teiler"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Nach oben / Nach links verschieben"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Nach unten / Nach rechts verschieben"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# weitere App anzeigen.}other{# weitere Apps anzeigen.}}"</string>
+    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# weitere App anzeigen}other{# weitere Apps anzeigen}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> und <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Hinzufügen einer App zum Desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Abbrechen"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index f8e2ecd..65f02eb 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -95,7 +95,7 @@
     <string name="action_share" msgid="2648470652637092375">"Jaga"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
     <string name="action_split" msgid="2098009717623550676">"Eralda"</string>
-    <string name="action_save_app_pair" msgid="5974823919237645229">"Salv. rakendusepaar"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Salvesta rakendusepaar"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Tühista"</b></string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index b266263..9875823 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -95,7 +95,7 @@
     <string name="action_share" msgid="2648470652637092375">"Compartir"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividir"</string>
-    <string name="action_save_app_pair" msgid="5974823919237645229">"Gardar empar. apps"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Gardar parella apps"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Para usar a pantalla dividida, toca outra app"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolle outra aplicación para usar a pantalla dividida."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 5814779..368cc0a 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -95,7 +95,7 @@
     <string name="action_share" msgid="2648470652637092375">"शेयर करें"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट लें"</string>
     <string name="action_split" msgid="2098009717623550676">"स्प्लिट स्क्रीन मोड"</string>
-    <string name="action_save_app_pair" msgid="5974823919237645229">"ऐप पेयर को सेव करें"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"ऐप पेयर सेव करें"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन के लिए दूसरे ऐप्लिकेशन पर टैप करें"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"स्प्लिट स्क्रीन इस्तेमाल करने के लिए, दूसरा ऐप्लिकेशन चुनें"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"अभी नहीं"</b></string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index b25c1c5..34030dd 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -134,7 +134,7 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdjelnik trake sa zadacima"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore/lijevo"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje/desno"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži više aplikacija (još #).}one{Prikaži više aplikacija (još #).}few{Prikaži više aplikacija (još #).}other{Prikaži više aplikacija (još #).}}"</string>
+    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju}one{Prikaži još # aplikaciju}few{Prikaži još # aplikacije}other{Prikaži još # aplikacija}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Dodavanje aplikacije na radnu površinu"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Odustani"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 44ab9b9..7fefe9c 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -134,7 +134,7 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pemisah Taskbar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pindahkan ke atas/kiri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pindahkan ke bawah/kanan"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lain.}other{Tampilkan # aplikasi lain.}}"</string>
+    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lainnya.}other{Tampilkan # aplikasi lainnya.}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"Menambahkan aplikasi ke Desktop"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Batalkan"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 58235bf..5fa61fb 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -95,7 +95,7 @@
     <string name="action_share" msgid="2648470652637092375">"Бөлүшүү"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
     <string name="action_split" msgid="2098009717623550676">"Бөлүү"</string>
-    <string name="action_save_app_pair" msgid="5974823919237645229">"Эки колдонмону бир маалда пайдаланууну сактоо"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Колдонмолорду сактап коюу"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлүү үчүн башка колдонмону таптап коюңуз"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Экранды бөлүү үчүн башка колдонмону тандаңыз"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Жокко чыгаруу"</b></string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 747c96b..762f669 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -95,7 +95,7 @@
     <string name="action_share" msgid="2648470652637092375">"မျှဝေရန်"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
     <string name="action_split" msgid="2098009717623550676">"ခွဲထုတ်ရန်"</string>
-    <string name="action_save_app_pair" msgid="5974823919237645229">"အက်ပ်တွဲချိတ်ခြင်း သိမ်းရန်"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"အက်ပ်အတွဲ သိမ်းရန်"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"မျက်နှာပြင် ခွဲ၍ပြသရန် အက်ပ်နောက်တစ်ခုကို တို့ပါ"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"မလုပ်တော့"</b></string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 28f0bbe..fb5ebb3 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -45,7 +45,7 @@
     <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"सिफारिस गरिएका एपहरू देखाउने सुविधा असक्षम पारिएको छ"</string>
     <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"पूर्वानुमान गरिएको एप: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
-    <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"इसारामार्फत गरिने नेभिगेसनको ट्युटोरियल पूरा गर्न कृपया आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
+    <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"जेस्चर नेभिगेसनको ट्युटोरियल पूरा गर्न कृपया आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
     <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"स्क्रिनको सबैभन्दा दायाँ किनारा वा सबैभन्दा बायाँ किनाराबाट स्वाइप गर्नुहोस्"</string>
     <string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"स्क्रिनको दायाँ वा बायाँ किनाराबाट मध्य भागसम्म स्वाइप गर्नुहोस् अनि औँला उठाउनुहोस्"</string>
     <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"तपाईंले स्क्रिनको दायाँ किनाराबाट स्वाइप गरेर अघिल्लो स्क्रिनमा फर्कने तरिका सिक्नुभयो। अब एउटा एपबाट अर्को एपमा जाने तरिका सिक्नुहोस्।"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index b7af90d..ce13890 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -36,7 +36,7 @@
     <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Aceda facilmente às suas apps mais utilizadas, diretamente no ecrã principal. As sugestões mudam em função das suas rotinas. As apps na última fila passam para o ecrã principal."</string>
     <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Aceda facilmente às suas apps mais utilizadas no ecrã principal. As sugestões mudam em função das suas rotinas. As apps na fila dos favoritos passam para o ecrã principal."</string>
     <string name="hotseat_edu_accept" msgid="1611544083278999837">"Obter sugestões de apps"</string>
-    <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Não, obrigado"</string>
+    <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Não"</string>
     <string name="hotseat_prediction_settings" msgid="6246554993566070818">"Definições"</string>
     <string name="hotseat_auto_enrolled" msgid="522100018967146807">"As apps mais utilizadas aparecem aqui e mudam em função das rotinas."</string>
     <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Arraste as apps para fora da última fila para ver sugestões de apps."</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index c4ea90d..4e1a213 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -95,7 +95,7 @@
     <string name="action_share" msgid="2648470652637092375">"Поделиться"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
     <string name="action_split" msgid="2098009717623550676">"Разделить"</string>
-    <string name="action_save_app_pair" msgid="5974823919237645229">"Сохр. одновр. исп."</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Сохранить приложения"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Для разделения экрана выберите другое приложение."</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Чтобы использовать разделенный экран, выберите другое приложение."</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Отмена"</b></string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 716e043..822d25c 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -95,7 +95,7 @@
     <string name="action_share" msgid="2648470652637092375">"Дели"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Снимак екрана"</string>
     <string name="action_split" msgid="2098009717623550676">"Подели"</string>
-    <string name="action_save_app_pair" msgid="5974823919237645229">"Чувај пар апликација"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Сачувај пар апликација"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Додирните другу апликацију за подељени екран"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Одаберите другу апликацију да бисте користили подељени екран"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Откажи"</b></string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 290ef9c..0464246 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -95,7 +95,7 @@
     <string name="action_share" msgid="2648470652637092375">"Dela"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Skärmbild"</string>
     <string name="action_split" msgid="2098009717623550676">"Delat"</string>
-    <string name="action_save_app_pair" msgid="5974823919237645229">"Spara par av appar"</string>
+    <string name="action_save_app_pair" msgid="5974823919237645229">"Spara app-par"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tryck på en annan app för att använda delad skärm"</string>
     <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Välj en annan app för att använda delad skärm"</string>
     <string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Avbryt"</b></string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index c7d79c1..2e89466 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -134,7 +134,7 @@
     <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"工作列分隔線"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到上方/左側"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右側"</string>
-    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{顯示另外 # 個應用程式。}other{顯示另外 # 個應用程式。}}"</string>
+    <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{再多顯示 # 個應用程式。}other{再多顯示 # 個應用程式。}}"</string>
     <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
     <string name="desktop_select_app_toast" msgid="2306057322833956910">"新增應用程式至桌面"</string>
     <string name="desktop_button_close_app_toast" msgid="5283096349579408560">"取消"</string>
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 0ce1cb8..c0e0587 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -18,8 +18,8 @@
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
 import static android.text.format.DateUtils.formatElapsedTime;
 
-import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
 import static com.android.launcher3.EncryptionType.ENCRYPTED;
+import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
@@ -65,7 +65,7 @@
 import com.android.launcher3.logging.InstanceIdSequence;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.UserCache;
@@ -233,7 +233,7 @@
             }
             InstanceId instanceId = new InstanceIdSequence().newInstanceId();
             for (ItemInfo info : itemsIdMap) {
-                FolderInfo parent = getContainer(info, itemsIdMap);
+                CollectionInfo parent = getContainer(info, itemsIdMap);
                 StatsLogCompatManager.writeSnapshot(info.buildProto(parent), instanceId);
             }
             additionalSnapshotEvents(instanceId);
@@ -270,7 +270,7 @@
                         }
 
                         for (ItemInfo info : itemsIdMap) {
-                            FolderInfo parent = getContainer(info, itemsIdMap);
+                            CollectionInfo parent = getContainer(info, itemsIdMap);
                             LauncherAtom.ItemInfo itemInfo = info.buildProto(parent);
                             Log.d(TAG, itemInfo.toString());
                             StatsEvent statsEvent = StatsLogCompatManager.buildStatsEvent(itemInfo,
@@ -293,18 +293,19 @@
         }
     }
 
-    private static FolderInfo getContainer(ItemInfo info, IntSparseArrayMap<ItemInfo> itemsIdMap) {
+    private static CollectionInfo getContainer(
+            ItemInfo info, IntSparseArrayMap<ItemInfo> itemsIdMap) {
         if (info.container > 0) {
             ItemInfo containerInfo = itemsIdMap.get(info.container);
 
-            if (!(containerInfo instanceof FolderInfo)) {
+            if (!(containerInfo instanceof CollectionInfo)) {
                 Log.e(TAG, String.format(
                         "Item info: %s found with invalid container: %s",
                         info,
                         containerInfo));
             }
             // Allow crash to help debug b/173838775
-            return (FolderInfo) containerInfo;
+            return (CollectionInfo) containerInfo;
         }
         return null;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index b7a92ee..8769f11 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -89,6 +89,7 @@
 import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -1086,19 +1087,19 @@
             ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
                     ActivityOptions.makeBasic());
             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
-        } else if (tag instanceof FolderInfo fi && fi.itemType == Favorites.ITEM_TYPE_FOLDER) {
+        } else if (tag instanceof FolderInfo) {
             // Tapping an expandable folder icon on Taskbar
             shouldCloseAllOpenViews = false;
             expandFolder((FolderIcon) view);
-        } else if (tag instanceof FolderInfo fi && fi.itemType == Favorites.ITEM_TYPE_APP_PAIR) {
+        } else if (tag instanceof AppPairInfo api) {
             // Tapping an app pair icon on Taskbar
             if (recents != null && recents.isSplitSelectionActive()) {
                 Toast.makeText(this, "Unable to split with an app pair. Select another app.",
                         Toast.LENGTH_SHORT).show();
             } else {
                 // Else launch the selected app pair
-                launchFromTaskbar(recents, view, fi.contents);
-                mControllers.uiController.onTaskbarIconLaunched(fi);
+                launchFromTaskbar(recents, view, api.getContents());
+                mControllers.uiController.onTaskbarIconLaunched(api);
                 mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
             }
         } else if (tag instanceof WorkspaceItemInfo) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index ca192c8..4462f20 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -116,9 +116,9 @@
                 }
             } else if (info instanceof FolderInfo && v instanceof FolderIcon) {
                 FolderInfo fi = (FolderInfo) info;
-                if (fi.contents.stream().anyMatch(matcher)) {
+                if (fi.anyMatch(matcher)) {
                     FolderDotInfo folderDotInfo = new FolderDotInfo();
-                    for (WorkspaceItemInfo si : fi.contents) {
+                    for (WorkspaceItemInfo si : fi.getContents()) {
                         folderDotInfo.addDotInfo(mPopupDataProvider.getDotInfoForItem(si));
                     }
                     ((FolderIcon) v).setDotInfo(folderDotInfo);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 7c3af57..dc2684e 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.BubbleTextView.DISPLAY_TASKBAR;
 import static com.android.launcher3.Flags.enableCursorHoverStates;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
@@ -52,6 +53,8 @@
 import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.folder.PreviewBackground;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -282,7 +285,7 @@
         removeView(view);
         view.setOnClickListener(null);
         view.setOnLongClickListener(null);
-        if (!(view.getTag() instanceof FolderInfo)) {
+        if (!(view.getTag() instanceof CollectionInfo)) {
             mActivityContext.getViewCache().recycleView(view.getSourceLayoutResId(), view);
         }
         view.setTag(null);
@@ -316,8 +319,8 @@
             boolean isCollection = false;
             if (hotseatItemInfo.isPredictedItem()) {
                 expectedLayoutResId = R.layout.taskbar_predicted_app_icon;
-            } else if (hotseatItemInfo instanceof FolderInfo fi) {
-                expectedLayoutResId = fi.itemType == ITEM_TYPE_APP_PAIR
+            } else if (hotseatItemInfo instanceof CollectionInfo ci) {
+                expectedLayoutResId = ci.itemType == ITEM_TYPE_APP_PAIR
                         ? R.layout.app_pair_icon
                         : R.layout.folder_icon;
                 isCollection = true;
@@ -345,17 +348,18 @@
 
             if (hotseatView == null) {
                 if (isCollection) {
-                    FolderInfo folderInfo = (FolderInfo) hotseatItemInfo;
+                    CollectionInfo collectionInfo = (CollectionInfo) hotseatItemInfo;
                     switch (hotseatItemInfo.itemType) {
                         case ITEM_TYPE_FOLDER:
                             hotseatView = FolderIcon.inflateFolderAndIcon(
-                                    expectedLayoutResId, mActivityContext, this, folderInfo);
+                                    expectedLayoutResId, mActivityContext, this,
+                                    (FolderInfo) collectionInfo);
                             ((FolderIcon) hotseatView).setTextVisible(false);
                             break;
                         case ITEM_TYPE_APP_PAIR:
                             hotseatView = AppPairIcon.inflateIcon(
-                                    expectedLayoutResId, mActivityContext, this, folderInfo,
-                                    BubbleTextView.DISPLAY_TASKBAR);
+                                    expectedLayoutResId, mActivityContext, this,
+                                    (AppPairInfo) collectionInfo, DISPLAY_TASKBAR);
                             ((AppPairIcon) hotseatView).setTextVisible(false);
                             break;
                         default:
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 4b1963b..1f7f0a7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -813,8 +813,8 @@
      * 3) All Apps button
      */
     public View getFirstIconMatch(Predicate<ItemInfo> matcher) {
-        Predicate<ItemInfo> folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
-        return mTaskbarView.getFirstMatch(matcher, folderMatcher);
+        Predicate<ItemInfo> collectionMatcher = ItemInfoMatcher.forFolderMatch(matcher);
+        return mTaskbarView.getFirstMatch(matcher, collectionMatcher);
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index e0e78f9..3b04602 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -35,7 +35,6 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsRecyclerView;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.config.FeatureFlags;
@@ -212,11 +211,6 @@
         super.onScaleProgressChanged();
         mAppsView.setClipChildren(!mIsBackProgressing);
         mAppsView.getAppsRecyclerViewContainer().setClipChildren(!mIsBackProgressing);
-        AllAppsRecyclerView rv = mAppsView.getActiveRecyclerView();
-        if (rv != null && rv.getScrollbar() != null) {
-            rv.getScrollbar().setVisibility(
-                    mIsBackProgressing ? INVISIBLE : VISIBLE);
-        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index d265918..e078a49 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -61,7 +61,7 @@
 import com.android.launcher3.model.AllAppsList;
 import com.android.launcher3.model.BaseModelUpdateTask;
 import com.android.launcher3.model.BgDataModel;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.LogConfig;
@@ -375,7 +375,7 @@
                 Executors.MODEL_EXECUTOR.execute(
                         () -> write(event, applyOverwrites(mItemInfo.buildProto())));
             } else {
-                // Item is inside the folder, fetch folder info in a BG thread
+                // Item is inside a collection, fetch collection info in a BG thread
                 // and then write to StatsLog.
                 appState.getModel().enqueueModelUpdateTask(
                         new BaseModelUpdateTask() {
@@ -383,8 +383,9 @@
                             public void execute(@NonNull final LauncherAppState app,
                                     @NonNull final BgDataModel dataModel,
                                     @NonNull final AllAppsList apps) {
-                                FolderInfo folderInfo = dataModel.folders.get(mItemInfo.container);
-                                write(event, applyOverwrites(mItemInfo.buildProto(folderInfo)));
+                                CollectionInfo collectionInfo =
+                                        dataModel.collections.get(mItemInfo.container);
+                                write(event, applyOverwrites(mItemInfo.buildProto(collectionInfo)));
                             }
                         });
             }
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index ecb6118..f4da867 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -53,7 +53,7 @@
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
@@ -149,25 +149,17 @@
 
         app1.rank = encodeRank(SPLIT_POSITION_TOP_OR_LEFT, snapPosition);
         app2.rank = encodeRank(SPLIT_POSITION_BOTTOM_OR_RIGHT, snapPosition);
-        FolderInfo newAppPair = FolderInfo.createAppPair(app1, app2);
-
-        if (newAppPair.contents.size() != 2) {
-            // if app pair doesn't have exactly 2 members, log an error and do not create the app
-            // pair.
-            Log.wtf(TAG,
-                    "tried to save an app pair with " + newAppPair.contents.size() + " members");
-            return;
-        }
+        AppPairInfo newAppPair = new AppPairInfo(app1, app2);
 
         IconCache iconCache = LauncherAppState.getInstance(mContext).getIconCache();
         MODEL_EXECUTOR.execute(() -> {
-            newAppPair.contents.forEach(member -> {
+            newAppPair.getContents().forEach(member -> {
                 member.title = "";
                 member.bitmap = iconCache.getDefaultIcon(newAppPair.user);
                 iconCache.getTitleAndIcon(member, member.usingLowResIcon());
             });
-            newAppPair.title = getDefaultTitle(newAppPair.contents.get(0).title,
-                    newAppPair.contents.get(1).title);
+            newAppPair.title = getDefaultTitle(newAppPair.getFirstApp().title,
+                    newAppPair.getSecondApp().title);
             MAIN_EXECUTOR.execute(() -> {
                 LauncherAccessibilityDelegate delegate =
                         Launcher.getLauncher(mContext).getAccessibilityDelegate();
@@ -194,8 +186,8 @@
      *            monitoring
      */
     public void launchAppPair(AppPairIcon appPairIcon, int cuj) {
-        WorkspaceItemInfo app1 = appPairIcon.getInfo().contents.get(0);
-        WorkspaceItemInfo app2 = appPairIcon.getInfo().contents.get(1);
+        WorkspaceItemInfo app1 = appPairIcon.getInfo().getFirstApp();
+        WorkspaceItemInfo app2 = appPairIcon.getInfo().getSecondApp();
         ComponentKey app1Key = new ComponentKey(app1.getTargetComponent(), app1.user);
         ComponentKey app2Key = new ComponentKey(app2.getTargetComponent(), app2.user);
         mSplitSelectStateController.setLaunchingCuj(cuj);
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 8f5c9c1..6b27004 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -659,8 +659,8 @@
 
         // Create a new floating view in Launcher, positioned above the launching icon
         val drawableArea = launchingIconView.iconDrawableArea
-        val appIcon1 = launchingIconView.info.contents[0].newIcon(launchingIconView.context)
-        val appIcon2 = launchingIconView.info.contents[1].newIcon(launchingIconView.context)
+        val appIcon1 = launchingIconView.info.getFirstApp().newIcon(launchingIconView.context)
+        val appIcon2 = launchingIconView.info.getSecondApp().newIcon(launchingIconView.context)
         appIcon1.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
         appIcon2.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
         val floatingView =
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index 87be091..2282c46 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -16,7 +16,6 @@
 
 package com.android.quickstep.util;
 
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 import static com.android.window.flags.Flags.enableDesktopWindowingMode;
 
@@ -44,7 +43,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -126,7 +125,7 @@
             intent = appInfo.intent;
             user = appInfo.user;
             bitmapInfo = appInfo.bitmap;
-        } else if (tag instanceof FolderInfo fi && fi.itemType == ITEM_TYPE_APP_PAIR) {
+        } else if (tag instanceof AppPairInfo) {
             // Prompt the user to select something else by wiggling the instructions view
             mController.getSplitInstructionsView().goBoing();
             return true;
diff --git a/res/layout/hotseat.xml b/res/layout/hotseat.xml
index 82b0b8d..d14dcd5 100644
--- a/res/layout/hotseat.xml
+++ b/res/layout/hotseat.xml
@@ -21,4 +21,6 @@
     android:layout_height="match_parent"
     android:theme="@style/HomeScreenElementTheme"
     android:importantForAccessibility="no"
+    android:clickable="false"
+    android:longClickable="false"
     launcher:containerType="hotseat" />
\ No newline at end of file
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index 2b5db48..185207b 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -33,7 +33,7 @@
         android:layout_centerVertical="true"
         android:gravity="center_vertical"
         android:layout_alignParentEnd="true"
-        android:animateLayoutChanges="true">
+        android:animateLayoutChanges="false">
         <ImageButton
             android:id="@+id/ps_settings_button"
             android:layout_width="@dimen/ps_header_image_height"
diff --git a/res/layout/snackbar.xml b/res/layout/snackbar.xml
index b818943..6bc1729 100644
--- a/res/layout/snackbar.xml
+++ b/res/layout/snackbar.xml
@@ -39,6 +39,7 @@
         android:paddingLeft="8dp"
         android:paddingRight="8dp"
         android:background="?android:attr/selectableItemBackground"
+        android:longClickable="false"
         android:textStyle="bold"
         android:textSize="@dimen/snackbar_max_text_size"
         android:textColor="?android:attr/colorAccent"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 8902033..9718479 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -87,7 +87,7 @@
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lys werkprogramme"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Verwyder"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deïnstalleer"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"Programinligting"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"Appinligting"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installeer privaat"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Installeer"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Moenie voorstel nie"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Misluk: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privaat ruimte"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Hou privaat apps gesluit en versteek"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privaat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privaat Ruimte-instellings"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Sluit/ontsluit Privaat Ruimte"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 0b94a4c..a19ea97 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"አጣራ"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"አልተሳካም፦ <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"የግል ቦታ"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"የግል መተግበሪያዎች እንደተቆለፉ እና እንደተበቁ እንዲቆዩ ያድርጉ"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"የግል"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"የግል ቦታ ቅንብሮች"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"የግል ቦታን ቆልፍ/ክፈት"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 7ae39e3..dfd23da 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -39,7 +39,7 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"‏العرض %1$d الطول %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"أداة <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"‏التطبيق المصغّرة \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\"، بعرض ‎%2$d وارتفاع ‎%3$d"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"انقر مع الاستمرار على التطبيق المصغّر لنقله إلى الشاشة الرئيسية."</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"انقر مع الاستمرار على التطبيق المصغّر لنقله إلى الشاشة الرئيسية"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"إضافة إلى الشاشة الرئيسية"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"تمت إضافة الأداة <xliff:g id="WIDGET_NAME">%1$s</xliff:g> إلى الشاشة الرئيسية."</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"اقتراحات"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"فلتر"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"تعذَّر <xliff:g id="WHAT">%1$s</xliff:g>."</string>
     <string name="private_space_label" msgid="2359721649407947001">"مساحة خاصة"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"إبقاء التطبيقات الخاصة مقفلة ومخفية"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"المساحة الخاصة"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"إعدادات المساحة الخاصة"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل المساحة الخاصة أو فتح قفلها"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 47586d9..898b9d6 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -187,11 +187,12 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"আনপজ কৰক"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ফিল্টাৰ"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"বিফল: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
-    <string name="private_space_label" msgid="2359721649407947001">"ব্যক্তিগত স্পে’চ"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"ব্যক্তিগত এপ্‌সমূহ লক কৰি লুকুৱাই ৰাখক"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"প্ৰাইভেট স্পে\'চ"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"ব্যক্তিগত"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পে’চৰ ছেটিং"</string>
-    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ব্যক্তিগত স্পে’চ লক/আনলক কৰক"</string>
+    <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"প্ৰাইভেট স্পে\'চ লক/আনলক কৰক"</string>
     <string name="ps_container_lock_title" msgid="2640257399982364682">"লক কৰক"</string>
     <string name="ps_container_transition" msgid="8667331812048014412">"ব্যক্তিগত স্পে’চৰ স্থানান্তৰণ"</string>
     <string name="ps_add_button_label" msgid="8611055839242385935">"এপ্‌ ইনষ্টল কৰক"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 4631f61..b714613 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtr"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Alınmadı: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Şəxsi yer"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Şəxsi tətbiqləri kilidli və gizli saxlayın"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Şəxsi"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Şəxsi məkan ayarları"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Şəxsi məkanı kilidləyin/kiliddən çıxarın"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index d96d660..6ff7970 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Neka privatne aplikacije budu zaključane i sakrivene"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Podešavanja privatnog prostora"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključaj/otključaj privatni prostor"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 7c33ff6..22642d7 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Фільтр"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Не ўдалося: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Прыватная вобласць"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Схавайце прыватныя праграмы ў асобную прастору і закрыйце доступ да яе"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Прыватная"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Налады прыватнай вобласці"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблакіраваць (разблакіраваць) прыватную вобласць"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 2a9ac1b..a9e4a26 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтър"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Неуспешно: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Лично пространство"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Заключване и скриване на частните приложения"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Лично"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Настройки за личното пространство"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заключване/отключване на личното пространство"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index ca6ee84..f20416b 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ফিল্টার"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"কাজটি করা যায়নি: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ব্যক্তিগত স্পেস"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"ব্যক্তিগত অ্যাপ লক করে লুকিয়ে রাখুন"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"ব্যক্তিগত"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পেসের সেটিংস"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ব্যক্তিগত স্পেস লক/আনলক করুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 96f45c1..3e2ed4d 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -39,7 +39,7 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"Širina %1$d, visina %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, širina %2$d, visina %3$d"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i držite vidžet da ga pomjerate po početnom ekranu"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i zadržite vidžet da ga pomjerate po početnom ekranu"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> je dodan na početni ekran"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Prijedlozi"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privatan prostor"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Ostavite privatne aplikacije zaključane i sakrivene"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 666cb15..4ffd4bb 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espai privat"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Mantén les aplicacions privades bloquejades i amagades"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configuració d\'Espai privat"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloqueja o desbloqueja Espai privat"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 1d02668..61521ae 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -29,7 +29,7 @@
     <string name="home_screen" msgid="5629429142036709174">"Domů"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Rozdělit obrazovku"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informace o aplikaci %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Uložit pár aplikací"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Uložit dvojici aplikací"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Tento pár aplikací není na tomto zařízení podporován"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Pokud chcete použít tento pár aplikací, rozložte zařízení"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtr"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Selhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Soukromý prostor"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Mějte soukromé aplikace uzamknuté a skryté"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Soukromé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Nastavení soukromého prostoru"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zamknout/odemknout soukromý prostor"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 2f1aa65..f85a2a9 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Mislykket: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privat område"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Hold private apps låste og skjulte"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Indstillinger for privat rum"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås/oplås det private område"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index e19a9b0..f6fd609 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Fehler: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privates Profil"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Hier kannst du deine privaten Apps verstecken und sperren"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Einstellungen für privaten Bereich"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaten Bereich sperren/entsperren"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 55575e7..04e42b2 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Φίλτρο"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Αποτυχία: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Ιδιωτικός χώρος"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Διατηρήστε τις ιδιωτικές εφαρμογές κλειδωμένες και κρυφές"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Ιδιωτικό"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Ρυθμίσεις Ιδιωτικού χώρου"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Κλείδωμα/Ξεκλείδωμα Ιδιωτικού χώρου"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index d86770a..6a7fbb7 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -188,7 +188,7 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Keep private apps locked and hidden"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 2967941..53c0074 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -188,7 +188,7 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Keep private apps locked and hidden"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index d86770a..6a7fbb7 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -188,7 +188,7 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Keep private apps locked and hidden"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index d86770a..6a7fbb7 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -188,7 +188,7 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Keep private apps locked and hidden"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index dab6052..f95149f 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -188,7 +188,7 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‎‎‎‏‎‏‎‎‏‎‎‎‎‎‎‎Filter‎‏‎‎‏‎"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‎‎Failed: ‎‏‎‎‏‏‎<xliff:g id="WHAT">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="private_space_label" msgid="2359721649407947001">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‏‏‏‏‏‎‎‏‎Private space‎‏‎‎‏‎"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‎‏‎‎‏‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‎Keep private apps locked and hidden‎‏‎‎‏‎"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‏‏‎Tap to set up or open‎‏‎‎‏‎"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‎Private‎‏‎‎‏‎"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‎‎‎‎‎‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎Private Space Settings‎‏‎‎‏‎"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‏‎‎‎‎‏‎‎‎‏‎‎‎‏‎‏‏‎Lock/Unlock Private Space‎‏‎‎‏‎"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 21325b9..c377990 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -29,7 +29,7 @@
     <string name="home_screen" msgid="5629429142036709174">"Pantalla principal"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la app de %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Guardar vinculación de apps"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Guardar vinculación"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"No se admite esta vinculación de apps en este dispositivo"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Abre el dispositivo para usar esta vinculación de apps"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espacio privado"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Mantén las apps privadas bloqueadas y ocultas"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configuración de Espacio privado"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear o desbloquear Espacio privado"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 1858290..5c950b1 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Se ha producido un error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espacio privado"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Bloquea y oculta tus aplicaciones privadas"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Ajustes del espacio privado"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/Desbloquear espacio privado"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 26110ae..610c243 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Nurjus: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privaatne ruum"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Hoidke privaatsed rakendused lukustatud ja peidetuna"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privaatne"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privaatse ruumi seaded"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaatse ruumi lukustamine/avamine"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index a722a58..1d25061 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Iragazi"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Huts egin du: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Eremu pribatua"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Mantendu aplikazio pribatuak blokeatuta eta ezkutatuta"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Pribatua"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Eremu pribatuaren ezarpenak"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blokeatu/Desblokeatu eremu pribatua"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index d69a590..dc48d82 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"فیلتر"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ناموفق بود: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"فضای خصوصی"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"برنامه‌های خصوصی قفل و پنهان نگه داشته می‌شود"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"خصوصی"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"تنظیمات «فضای خصوصی»"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل/ باز کردن «فضای خصوصی»"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 81790b9..820f7eb 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Suodatin"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Epäonnistui: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Yksityinen tila"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Pidä yksityiset sovellukset lukittuna ja piilossa"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Yksityinen"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Yksityisen tilan asetukset"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lukitse yksityinen tila / avaa sen lukitus"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index d21fef4..d47e63e 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -29,7 +29,7 @@
     <string name="home_screen" msgid="5629429142036709174">"Accueil"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran divisé"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Renseignements sur l\'appli pour %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Enregistrer la paire d\'applications"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Enr. paire d\'applis"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applications n\'est pas prise en charge sur cet appareil"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Déplier l\'appareil pour utiliser cette paire d\'applications"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrer"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Verrouiller et cacher les applications privées"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Paramètres de l\'Espace privé"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller l\'Espace privé"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 4244f23..54ad858 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtre"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Gardez les applications privées verrouillées et masquées."</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Paramètres d\'Espace privé"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller Espace privé"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 1089ecf..0a7c96c 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -29,7 +29,7 @@
     <string name="home_screen" msgid="5629429142036709174">"Inicio"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Información da aplicación para %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Gardar emparellamento de aplicacións"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Gardar parella de aplicacións"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"O dispositivo non admite este emparellamento de aplicacións"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Desprega o dispositivo para usar este emparellamento de aplicacións"</string>
@@ -87,7 +87,7 @@
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de aplicacións de traballo"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"Info. da aplicación"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"Información da app"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar en privado"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir aplicación"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Erro: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espazo privado"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Manter bloqueadas e ocultas as aplicacións privadas"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configuración do espazo privado"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear ou desbloquear o espazo privado"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index a30af7e..c3be263 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ફિલ્ટર કરો"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"નિષ્ફળ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ખાનગી સ્પેસ"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"ખાનગી ઍપને લૉક કરેલી અને છુપાવેલી રાખો"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"ખાનગી"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ખાનગી સ્પેસના સેટિંગ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ખાનગી સ્પેસને લૉક/અનલૉક કરો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index f65584b..7b6a9f9 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -29,7 +29,7 @@
     <string name="home_screen" msgid="5629429142036709174">"होम स्क्रीन"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रीन"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s के लिए ऐप्लिकेशन की जानकारी"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"साथ में इस्तेमाल किए जा सकने वाले ऐप्लिकेशन की जानकारी सेव करें"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"ऐप पेयर सेव करें"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"साथ में इस्तेमाल किए जा सकने वाले ये ऐप्लिकेशन, इस डिवाइस पर काम नहीं कर सकते"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"साथ में इस्तेमाल किए जा सकने वाले ये ऐप्लिकेशन इस्तेमाल करने के लिए डिवाइस को अनफ़ोल्ड करें"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"फ़िल्टर"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"पूरा नहीं हुआ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"प्राइवेट स्पेस"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"निजी ऐप्लिकेशन, लॉक करें और छिपाकर रखें"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"निजी"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"प्राइवेट स्पेस सेटिंग"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"प्राइवेट स्पेस को लॉक करें/अनलॉक करें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 5ae78a3..89f95f0 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Neka privatne aplikacije ostanu zaključane i skrivene"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 0a05ce4..626a79e 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -188,7 +188,7 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Szűrő"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Sikertelen: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privát terület"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Privát alkalmazások zárolásának és rejtve tartásának fenntartása"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Koppintson a beállításhoz vagy a megnyitáshoz"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privát"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privát terület beállításai"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privát terület zárolása/zárolásának feloldása"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 7bb79e5..bdb473b 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -29,7 +29,7 @@
     <string name="home_screen" msgid="5629429142036709174">"Հիմնական էկրան"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Տրոհել էկրանը"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Տեղեկություններ %1$s հավելվածի մասին"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Պահել հավելվածների զույգը"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Պահել հավելվ. զույգը"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Հավելվածների զույգը չի աջակցվում այս սարքում"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Բացեք սարքը՝ այս հավելվածների զույգն օգտագործելու համար"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Զտեք"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Չհաջողվեց կատարել գործողությունը (<xliff:g id="WHAT">%1$s</xliff:g>)"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Անձնական տարածք"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Անձնական հավելվածները պահեք կողպված և թաքցված"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Անձնական"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Անձնական տարածքի կարգավորումներ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Կողպել/ապակողպել անձնական տարածքը"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 246367d..b80f233 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Ruang pribadi"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Tetap kunci dan sembunyikan aplikasi pribadi"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Pribadi"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Setelan Ruang Pribadi"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka Kunci Ruang Pribadi"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 23899ad..1287322 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Sía"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Mistókst: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Einkarými"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Haltu einkaforritum læstum og földum"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Lokað"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Stillingar einkarýmis"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Læsaeinkarými/taka einkarými úr lás"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index e45f9dd..4805748 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Operazione non riuscita: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Spazio privato"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Mantieni le app private bloccate e nascoste"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privato"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Impostazioni dello Spazio privato"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blocca/sblocca Spazio privato"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 41c08e2..2f10ef3 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -29,7 +29,7 @@
     <string name="home_screen" msgid="5629429142036709174">"בית"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"מסך מפוצל"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"‏פרטים על האפליקציה %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"שמירה של צמד אפליקציות"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"שמירת צמד אפליקציות"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"צמד האפליקציות הזה לא נתמך במכשיר הזה"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"צריך לפתוח את המכשיר כדי להשתמש בצמד האפליקציות הזה"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"סינון"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"הפעולה נכשלה: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"מרחב פרטי"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"נעילה והסתרה של אפליקציות פרטיות"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"פרטי"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"הגדרות המרחב הפרטי"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"נעילה או ביטול הנעילה של המרחב הפרטי"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index d467f2c..3112a55 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"フィルタ"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"失敗: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"プライベート スペース"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"限定公開アプリをロックして非表示"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"プライベート"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"プライベート スペースの設定"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"プライベート スペースをロック / ロック解除する"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index e473052..ea5c207 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ფილტრი"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ვერ მოხერხდა: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"პირადი სივრცე"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"პირადი აპების ჩაკეტვა და დამალვა"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"პირადი"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"პირადი სივრცის პარამეტრები"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"პირადი სივრცის ჩაკეტვა/განბლოკვა"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index fce1090..56895cb 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Сүзгі"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Қате шықты: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Жеке бөлме"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Құпия кеңістіктегі қолданбаларды құлыптаулы және жасырын күйде қалдырыңыз."</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Жеке"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Жеке бөлме параметрлері"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке бөлмені құлыптау/оның құлпын ашу"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 817bb35..f955b54 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"តម្រង"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"បានបរាជ័យ៖ <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"បន្ទប់​ឯកជន"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"រក្សាកម្មវិធីឯកជនឱ្យនៅជាប់សោ និងលាក់"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"ឯកជន"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ការកំណត់ Private Space"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ចាក់សោ/ដោះសោ Private Space"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index f0e61cf..3fd334a 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -29,7 +29,7 @@
     <string name="home_screen" msgid="5629429142036709174">"ಹೋಮ್"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ಗಾಗಿ ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"ಆ್ಯಪ್ ಜೋಡಿ ಉಳಿಸಿ"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"ಆ್ಯಪ್ ಪೇರ್ ಸೇವ್ ಮಾಡಿ"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ಈ ಆ್ಯಪ್ ಜೋಡಿಯು ಈ ಸಾಧನದಲ್ಲಿ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ಈ ಆ್ಯಪ್ ಜೋಡಿಯನ್ನು ಬಳಸಲು ಸಾಧನವನ್ನು ಅನ್‌ಫೋಲ್ಡ್ ಮಾಡಿ"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ಫಿಲ್ಟರ್‌"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ವಿಫಲವಾಗಿದೆ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ಖಾಸಗಿ ಸ್ಪೇಸ್"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"ಖಾಸಗಿ ಆ್ಯಪ್‌ಗಳನ್ನು ಲಾಕ್ ಮಾಡಿ ಮತ್ತು ಮರೆಮಾಡಿ"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"ಖಾಸಗಿ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಅನ್ನು ಲಾಕ್/ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index e916cef..4814ede 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"필터"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"실패: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"비공개 스페이스"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"비공개 앱을 잠그고 숨겨진 상태로 유지"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"비공개"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"비공개 스페이스 설정"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"비공개 스페이스 잠금/잠금 해제"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 47eae5b..8d59747 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -29,7 +29,7 @@
     <string name="home_screen" msgid="5629429142036709174">"Башкы экран"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Экранды бөлүү"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s колдонмосу жөнүндө маалымат"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Эки колдонмону бир маалда пайдаланууну сактоо"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Колдонмолорду сактап коюу"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Бул эки колдонмону бул түзмөктө бир маалда пайдаланууга болбойт"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Бул эки колдонмону бир маалда пайдалануу үчүн түзмөктү ачыңыз"</string>
@@ -188,7 +188,7 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Чыпкалоо"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Аткарылган жок: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Жеке чөйрө"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Жеке колдонмолорду кулпулап жана жашырып коюңуз"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Тууралоо же ачуу үчүн таптап коюңуз"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Жеке"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Жеке чөйрөнүн параметрлери"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке чөйрөнү кулпулоо/кулпусун ачуу"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 658e8e3..5c0d6a8 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ກັ່ນຕອງ"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ບໍ່ສຳເລັດ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ພື້ນທີ່ສ່ວນຕົວ"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"ລັອກ ແລະ ເຊື່ອງແອັບສ່ວນຕົວໄວ້"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"ສ່ວນຕົວ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ການຕັ້ງຄ່າພື້ນທີ່ສ່ວນຕົວ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ລັອກ/ປົດລັອກພື້ນທີ່ສ່ວນຕົວ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 4e8c453..abcbb25 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtruoti"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Nepavyko: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privati erdvė"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Privačių programų užrakinimas ir slėpimas"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privatus"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privačios erdvės nustatymai"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Užrakinti ir (arba) atrakinti privačią erdvę"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 3e1fcdb..b400b03 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrs"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Neizdevās: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privātā telpa"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Paslēpiet privātās lietotnes un bloķējiet piekļuvi tām"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privātā mape"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Privātās mapes iestatījumi"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloķēt/atbloķēt privāto mapi"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index cf9c954..6e09073 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтер"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Не успеа: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Приватен простор"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Чувајте ги приватните апликации заклучени и скриени"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Приватен"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Поставки за „Приватен простор“"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заклучување/отклучување на „Приватен простор“"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 0b66a36..26bd635 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ഫിൽട്ടർ ചെയ്യുക"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"പരാജയപ്പെട്ടു: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"സ്വകാര്യ സ്പേസ്"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"സ്വകാര്യ ആപ്പുകൾ ലോക്ക് ചെയ്ത് മറയ്‌ക്കുക"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"സ്വകാര്യം"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"സ്വകാര്യ സ്‌പേസ് ക്രമീകരണം"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"സ്വകാര്യ സ്‌പേസ് ലോക്ക് ചെയ്യുക/അൺലോക്ക് ചെയ്യുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 0feeb10..5e86120 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Шүүлтүүр"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Амжилтгүй болсон: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Хувийн орон зай"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Хувийн аппуудыг түгжээтэй бөгөөд нуугдсан байлгана уу"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Хувийн"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Private Space-н тохиргоо"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Private Space-г түгжих/түгжээг тайлах"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 58f4f0e..9ec42c1 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -122,7 +122,7 @@
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"आपल्या प्रशासकाने अक्षम केले"</string>
     <string name="allow_rotation_title" msgid="7222049633713050106">"होम स्क्रीन फिरवण्‍याची अनुमती द्या"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"फोन फिरवला जातो तेव्हा"</string>
-    <string name="notification_dots_title" msgid="9062440428204120317">"सूचना बिंदू"</string>
+    <string name="notification_dots_title" msgid="9062440428204120317">"नोटिफिकेशन डॉट"</string>
     <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>
@@ -150,8 +150,8 @@
     <string name="action_add_to_workspace" msgid="215894119683164916">"होम स्क्रीनवर जोडा"</string>
     <string name="action_move_here" msgid="2170188780612570250">"आयटम येथे हलवा"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"आयटम मुख्य स्क्रीनवर जोडला"</string>
-    <string name="item_removed" msgid="851119963877842327">"आयटम काढला"</string>
-    <string name="undo" msgid="4151576204245173321">"पूर्ववत करा"</string>
+    <string name="item_removed" msgid="851119963877842327">"आयटम काढून टाकला"</string>
+    <string name="undo" msgid="4151576204245173321">"पहिल्यासारखे करा"</string>
     <string name="action_move" msgid="4339390619886385032">"आयटम हलवा"</string>
     <string name="move_to_empty_cell_description" msgid="5254852678218206889">"<xliff:g id="STRING">%3$s</xliff:g> मधील <xliff:g id="NUMBER_0">%1$s</xliff:g> पंक्ती <xliff:g id="NUMBER_1">%2$s</xliff:g> स्तंभ यावर हलवा"</string>
     <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> स्थानावर हलवा"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"फिल्टर"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"हे करता आले नाही: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"खाजगी स्पेस"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"खाजगी अ‍ॅप्स लॉक करून आणि लपवून ठेवा"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"खाजगी"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"खाजगी स्पेस ची सेटिंग्ज"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"खाजगी स्पेस लॉक/अनलॉक करा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 7832705..63f500a 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -187,8 +187,9 @@
     <string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Nyahjeda"</string>
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Tapis"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
-    <string name="private_space_label" msgid="2359721649407947001">"Ruang peribadi"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Pastikan apl peribadi kekal dikunci dan disembunyikan"</string>
+    <string name="private_space_label" msgid="2359721649407947001">"Ruang privasi"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Peribadi"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Tetapan Ruang Peribadi"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka kunci Ruang Peribadi"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 80fef4b..93b61f8 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -39,7 +39,7 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"အလျား %1$d နှင့် အမြင့် %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်"</string>
     <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်၊ အကျယ် %2$d နှင့် အမြင့် %3$d"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ပင်မစာမျက်နှာတွင်ရွှေ့ရန် ဝိဂျက်ကို တို့ထိ၍ ဖိထားပါ"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ဝိဂျက်ကို တို့ထိ၍ ဖိထားပြီး ပင်မစာမျက်နှာပေါ်တွင် နေရာအမျိုးမျိုးသို့ ရွှေ့နိုင်သည်"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"ပင်မစာမျက်နှာတွင် ထည့်ရန်"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်ကို ပင်မစာမျက်နှာတွင် ထည့်လိုက်ပြီ"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"အကြံပြုချက်"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"စစ်ထုတ်ရန်"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"မအောင်မြင်ပါ− <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"သီးသန့်ချတ်ခန်း"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"သီးသန့်အက်ပ်များကို လော့ခ်ချပြီး ဖျောက်ထားပါ"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"သီးသန့်"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"သီးသန့်ချတ်ခန်း ဆက်တင်များ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"သီးသန့်ချတ်ခန်း လော့ခ်ချ/ဖွင့်ရန်"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index f0c947b..4a352f5 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Mislyktes: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privat område"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Hold private apper låst og skjult"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Innstillinger for Private Space"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås / lås opp Private Space"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index e18dce4..0f5e1a5 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"फिल्टर"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"कार्य पूरा गर्न सकिएन: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"निजी स्पेस"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"निजी एपहरू लक गरिराख्नुहोस् र लुकाइराख्नुहोस्"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"निजी"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"निजी स्पेससम्बन्धी सेटिङ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"निजी स्पेस लक/अनलक गर्नुहोस्"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index c16fb3c..ace1d8e 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -39,7 +39,7 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breed en %2$d hoog"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
     <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d breed bij %3$d hoog"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tik op de widget en houd vast om deze te verplaatsen op het startscherm"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Houd je vinger op de widget om deze te verplaatsen op het startscherm"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Toevoegen aan startscherm"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> toegevoegd aan startscherm"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggesties"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filteren"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Mislukt: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privéruimte"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Privé-apps vergrendeld en verborgen houden"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Instellingen voor privéruimte"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privéruimte vergrendelen/ontgrendelen"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 21b5f03..2c03967 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -87,7 +87,7 @@
     <string name="all_apps_button_work_label" msgid="7270707118948892488">"କାର୍ଯ୍ୟକାରୀ ଆପ୍‌ ତାଲିକା"</string>
     <string name="remove_drop_target_label" msgid="7812859488053230776">"କାଢ଼ି ଦିଅନ୍ତୁ"</string>
     <string name="uninstall_drop_target_label" msgid="4722034217958379417">"ଅନଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"ଆପ୍‌ ସୂଚନା"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"ଆପ ସୂଚନା"</string>
     <string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ପ୍ରାଇଭେଟରେ ଇନଷ୍ଟଲ କର"</string>
     <string name="install_drop_target_label" msgid="2539096853673231757">"ଇନଷ୍ଟଲ୍‌ କରନ୍ତୁ"</string>
     <string name="dismiss_prediction_label" msgid="3357562989568808658">"ଆପ ପରାମର୍ଶ ଦିଅନ୍ତୁ ନାହିଁ"</string>
@@ -151,7 +151,7 @@
     <string name="action_move_here" msgid="2170188780612570250">"ଆଇଟମ୍‌କୁ ଏଠାକୁ ଘୁଞ୍ଚାନ୍ତୁ"</string>
     <string name="item_added_to_workspace" msgid="4211073925752213539">"ହୋମ ସ୍କ୍ରିନରେ ଆଇଟମ ଯୋଗ କରାଗଲା"</string>
     <string name="item_removed" msgid="851119963877842327">"ଆଇଟମକୁ କାଢ଼ି ଦିଆଯାଇଛି"</string>
-    <string name="undo" msgid="4151576204245173321">"ପୂର୍ବବତ୍‍"</string>
+    <string name="undo" msgid="4151576204245173321">"ପୂର୍ବବତ କରନ୍ତୁ"</string>
     <string name="action_move" msgid="4339390619886385032">"ଆଇଟମ୍‌ ଘୁଞ୍ଚାନ୍ତୁ"</string>
     <string name="move_to_empty_cell_description" msgid="5254852678218206889">"<xliff:g id="STRING">%3$s</xliff:g>ରେ ଧାଡି <xliff:g id="NUMBER_0">%1$s</xliff:g> ସ୍ତମ୍ଭ <xliff:g id="NUMBER_1">%2$s</xliff:g>କୁ ମୁଭ କରନ୍ତୁ"</string>
     <string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> ସ୍ଥିତିକୁ ନିଅନ୍ତୁ"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ଫିଲ୍ଟର୍"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ବିଫଳ ହୋଇଛି: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ପ୍ରାଇଭେଟ ସ୍ପେସ"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"ପ୍ରାଇଭେଟ ଆପ୍ସକୁ ଲକ ଏବଂ ଲୁକ୍କାୟିତ ରଖନ୍ତୁ"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"ପ୍ରାଇଭେଟ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ପ୍ରାଇଭେଟ ସ୍ପେସ ସେଟିଂସ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ପ୍ରାଇଭେଟ ସ୍ପେସକୁ ଲକ/ଅନଲକ କରନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 9ae784f..321d6c0 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ਫਿਲਟਰ"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ਇਹ ਕਾਰਵਾਈ ਅਸਫਲ ਹੋਈ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ਨਿੱਜੀ ਸਪੇਸ"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"ਨਿੱਜੀ ਐਪਾਂ ਨੂੰ ਲਾਕ ਕਰ ਕੇ ਅਦਿੱਖ ਰੱਖੋ"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"ਨਿੱਜੀ"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ਨਿੱਜੀ ਸਪੇਸ ਸੰਬੰਧੀ ਸੈਟਿੰਗਾਂ"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ਨਿੱਜੀ ਸਪੇਸ ਨੂੰ ਲਾਕ/ਅਣਲਾਕ ਕਰੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index a765377..7cc4f1f 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtruj"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Niepowodzenie: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Obszar prywatny"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Pozostaw aplikacje prywatne zablokowane i ukryte"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Prywatne"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Ustawienia obszaru prywatnego"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zablokuj/odblokuj obszar prywatny"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 946ed1b..25a6562 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -188,7 +188,7 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrar"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Falhou: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espaço privado"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Mantenha as apps privadas bloqueadas e ocultas"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Tocar para configurar ou abrir"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Definições do espaço privado"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear espaço privado"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 04688d1..07fe3db 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrar"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Falha: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Espaço particular"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Mantenha apps particulares bloqueados e ocultos"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Particular"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Configurações do Espaço particular"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear o Espaço particular"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 4605871..30b2ea6 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtru"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Eșuare: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Spațiu privat"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Păstrează aplicațiile private blocate și ascunse"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Setări spațiu privat"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blochează / deblochează spațiul privat"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 9a40b84..a96e2e1 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -29,7 +29,7 @@
     <string name="home_screen" msgid="5629429142036709174">"Главный экран"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Разделить экран"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Сведения о приложении \"%1$s\""</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Сохранить настройки одновременного использования двух приложений"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Сохранить приложения"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Одновременно использовать эти два приложения на устройстве нельзя."</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Чтобы одновременно использовать эти два приложения, разложите устройство."</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Фильтр"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Не удалось выполнить действие (<xliff:g id="WHAT">%1$s</xliff:g>)."</string>
     <string name="private_space_label" msgid="2359721649407947001">"Личное пространство"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Приложения в личном пространстве скрыты и доступны только вам"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Доступно только вам"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Настройки личного пространства"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Блокировка и разблокировка личного пространства"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 8780527..53aee23 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"පෙරහන"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"අසාර්ථකයි: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"පෞද්ගලික ඉඩ"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"පෞද්ගලික යෙදුම් අගුලු දමා සඟවා තබා ගන්න"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"පෞද්ගලික"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"පෞද්ගලික අවකාශ සැකසීම්"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"පෞද්ගලික අවකාශය අගුළු දමන්න/අගුළු හරින්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index e513497..e058442 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrujte"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Zlyhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Súkromný priestor"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Ponechajte súkromné aplikácie uzamknuté a skryté"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Súkromné"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Nastavenia súkromného priestoru"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Súkromný priestor zamykania a odomykania"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 70a4c08..8b67004 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -188,7 +188,7 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtriranje"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Ni uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Zasebni prostor"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Naj vaše zasebne aplikacije ostanejo zaklenjene in skrite"</string>
+    <string name="private_space_secondary_label" msgid="9203933341714508907">"Dotaknite se, da nastavite ali odprete"</string>
     <string name="ps_container_title" msgid="4391796149519594205">"Zasebno"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Nastavitve zasebnega prostora"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaklepanje/odklepanje zasebnega prostora"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 51fcf13..062a5e1 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Dështoi: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Hapësira private"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Mbaji të kyçura dhe të fshehura aplikacionet private"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Cilësimet e \"Hapësirës private\""</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kyç/Shkyç \"Hapësirën private\""</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 7a32a54..6b3a1ea 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтер"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Није успело: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Приватни простор"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Нека приватне апликације буду закључане и сакривене"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Приватно"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Подешавања приватног простора"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Закључај/откључај приватни простор"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index df2539f..94a9ff0 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -29,7 +29,7 @@
     <string name="home_screen" msgid="5629429142036709174">"Startskärm"</string>
     <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Delad skärm"</string>
     <string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformation för %1$s"</string>
-    <string name="save_app_pair" msgid="5647523853662686243">"Spara appar som ska användas tillsammans"</string>
+    <string name="save_app_pair" msgid="5647523853662686243">"Spara app-par"</string>
     <string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
     <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"De här apparna som ska användas tillsammans stöds inte på den här enheten"</string>
     <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Vik upp enheten för att använda de här apparna som ska användas tillsammans"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Misslyckades: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Privat rum"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Håll privata appar låsta och dolda"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Inställningar för privat rum"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås eller lås upp ditt privata rum"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 4d3b22f..069894b 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Kichujio"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Hitilafu: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Nafasi ya faragha"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Funga na ufiche programu za faragha"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Faragha"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Mipangilio ya Nafasi ya Faragha"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Funga/Fungua Nafasi ya Faragha"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 9e82389..043b654 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"வடிப்பான்"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"தோல்வி: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"தனிப்பட்ட சேமிப்பிடம்"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"தனிப்பட்ட ஆப்ஸை லாக் செய்தும் மறைத்தும் வைக்கலாம்"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"தனிப்பட்டது"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"தனிப்பட்ட சேமிப்பிட அமைப்புகள்"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"தனிப்பட்ட சேமிப்பிடத்தை லாக்/அன்லாக் செய்யும்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 9ad29c6..ef1cc44 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ఫిల్టర్ చేయి"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"విఫలమైంది: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"ప్రైవేట్ స్పేస్"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"ప్రైవేట్ యాప్‌లను లాక్ చేసి దాచి ఉంచండి"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"ప్రైవేట్"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"ప్రైవేట్ స్పేస్ సెట్టింగ్‌లు"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ప్రైవేట్ స్పేస్‌ను లాక్/అన్‌లాక్ చేయండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index dc92980..37e2c21 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"ตัวกรอง"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ไม่สำเร็จ: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"พื้นที่ส่วนตัว"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"ล็อกและซ่อนแอปส่วนตัวไว้"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"ส่วนตัว"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"การตั้งค่าพื้นที่ส่วนตัว"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ล็อก/ปลดล็อกพื้นที่ส่วนตัว"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 36a7b5c..33dbecf 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Hindi nagawa: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Pribadong space"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Panatilihing naka-lock at nakatago ang mga pribadong app"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Pribado"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Mga Setting ng Pribadong Space"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"I-lock/I-unlock ang Pribadong Space"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 8c00ec3..f299b2c 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtre"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Başarısız: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Gizli alan"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Özel uygulamaları kilitli ve gizli tutun"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Gizli"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Gizli Alan Ayarları"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Gizli Alanı Kilitleyin/Kilidini Açın"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index a8211f5..c1703f3 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Фільтр"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Не вдалося <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Приватний простір"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Зберігайте приватні додатки в прихованому й заблокованому сховищі"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Приватні"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Налаштування приватного простору"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблокувати/розблокувати приватний простір"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 430c835..3169e03 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"فلٹر"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"ناکام ہو گيا: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"نجی اسپیس"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"نجی ایپس کو مقفل اور پوشیدہ رکھیں"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"نجی"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"نجی اسپیس کی ترتیبات"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"نجی اسپیس کو مقفل کریں/غیر مقفل کریں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 8e03a13..b80f4cd 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Saralash"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Xato: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Shaxsiy xona"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Maxfiy ilovalar qulflangan va yashirin saqlansin"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Yopiq"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Shaxsiy xona sozlamalari"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Shaxsiy xonani ochish/qulflash"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 17817ac..a3e26d0 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Bộ lọc"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Không thực hiện được thao tác: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Không gian riêng tư"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Luôn khoá và ẩn các ứng dụng riêng tư"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Riêng tư"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Cài đặt không gian riêng tư"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khoá/mở khoá không gian riêng tư"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 4e77075..c8e524d 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -39,7 +39,7 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"宽 %1$d,高 %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件"</string>
     <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件,宽 %2$d,高 %3$d"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"轻触并按住此微件即可在主屏幕上随意移动它"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"轻触并按住此微件即可在主屏幕上随意移动"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"添加到主屏幕"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已将“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件添加到主屏幕"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"建议"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"过滤器"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"失败:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"私密空间"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"让专用应用保持锁定状态并隐藏"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"私密"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"私密空间设置"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"锁定/解锁私密空间"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 735ff2f..46669eb 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"篩選器"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"操作失敗:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"私人空間"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"讓私人應用程式保持鎖定及隱藏"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"私人"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"「私人空間」設定"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/解鎖「私人空間」"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index b74bde2..8fddcc4 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -39,7 +39,7 @@
     <string name="widget_accessible_dims_format" msgid="3640149169885301790">"寬度為 %1$d,高度為 %2$d"</string>
     <string name="widget_preview_context_description" msgid="9045841361655787574">"「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具"</string>
     <string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具 (寬 %2$d,高 %3$d)"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"按住小工具即可將它移到主畫面上的任何位置"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"按住小工具即可拖曳到主畫面的任何位置"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"新增至主畫面"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已將「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具新增到主畫面"</string>
     <string name="suggested_widgets_header_title" msgid="1844314680798145222">"建議"</string>
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"篩選器"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"失敗:<xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"私人空間"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"讓私人應用程式保持鎖定及隱藏的狀態"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"私人"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"私人空間設定"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/取消鎖定私人空間"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 3fdb6a7..308e6e0 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -188,7 +188,8 @@
     <string name="developer_options_filter_hint" msgid="5896817443635989056">"Hlunga"</string>
     <string name="remote_action_failed" msgid="1383965239183576790">"Yehlulekile: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
     <string name="private_space_label" msgid="2359721649407947001">"Isikhala esiyimfihlo"</string>
-    <string name="private_space_secondary_label" msgid="611902414159280263">"Gcina ama-app angasese ekhiyiwe futhi efihliwe"</string>
+    <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+    <skip />
     <string name="ps_container_title" msgid="4391796149519594205">"Okuyimfihlo"</string>
     <string name="ps_container_settings" msgid="6059734123353320479">"Amasethingi Esikhala Esiyimfihlo"</string>
     <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khiya/Vula Isikhala Esiyimfihlo"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9b4460a..8c58931 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -492,7 +492,7 @@
     <dimen name="ps_header_image_height">48dp</dimen>
     <dimen name="ps_header_text_height">24dp</dimen>
     <dimen name="ps_header_layout_margin">16dp</dimen>
-    <dimen name="ps_header_settings_icon_margin_end">8dp</dimen>
+    <dimen name="ps_header_settings_icon_margin_end">4dp</dimen>
     <dimen name="ps_header_text_size">16sp</dimen>
     <dimen name="ps_button_height">40dp</dimen>
     <dimen name="ps_button_width">40dp</dimen>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 5d5a28c..4c8ed15 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -435,8 +435,7 @@
     }
 
     @UiThread
-    @VisibleForTesting
-    public void applyLabel(ItemInfoWithIcon info) {
+    public void applyLabel(ItemInfo info) {
         CharSequence label = info.title;
         if (label != null) {
             mLastOriginalText = label;
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 9a5627a..58789fd 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -27,7 +27,7 @@
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -75,7 +75,7 @@
         }
 
         return (info instanceof LauncherAppWidgetInfo)
-                || (info instanceof FolderInfo);
+                || (info instanceof CollectionInfo);
     }
 
     @Override
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 912583c..cfa8967 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -202,6 +202,8 @@
 import com.android.launcher3.model.ModelWriter;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -803,13 +805,19 @@
     @Override
     public void invalidateParent(ItemInfo info) {
         if (info.container >= 0) {
-            View folderIcon = getWorkspace().getHomescreenIconByItemId(info.container);
-            if (folderIcon instanceof FolderIcon && folderIcon.getTag() instanceof FolderInfo) {
+            View collectionIcon = getWorkspace().getHomescreenIconByItemId(info.container);
+            if (collectionIcon instanceof FolderIcon folderIcon
+                    && collectionIcon.getTag() instanceof FolderInfo) {
                 if (new FolderGridOrganizer(getDeviceProfile())
                         .setFolderInfo((FolderInfo) folderIcon.getTag())
                         .isItemInPreview(info.rank)) {
                     folderIcon.invalidate();
                 }
+            } else if (collectionIcon instanceof AppPairIcon appPairIcon
+                    && collectionIcon.getTag() instanceof AppPairInfo appPairInfo) {
+                if (appPairInfo.getContents().contains(info)) {
+                    appPairIcon.getIconDrawableArea().redraw();
+                }
             }
         }
     }
@@ -2008,24 +2016,26 @@
     public boolean removeItem(View v, final ItemInfo itemInfo, boolean deleteFromDb,
             @Nullable final String reason) {
         if (itemInfo instanceof WorkspaceItemInfo) {
-            // Remove the shortcut from the folder before removing it from launcher
-            View folderIcon = mWorkspace.getHomescreenIconByItemId(itemInfo.container);
-            if (folderIcon instanceof FolderIcon) {
-                ((FolderInfo) folderIcon.getTag()).remove((WorkspaceItemInfo) itemInfo, true);
+            View collectionIcon = mWorkspace.getHomescreenIconByItemId(itemInfo.container);
+            if (collectionIcon instanceof FolderIcon) {
+                // Remove the shortcut from the folder before removing it from launcher
+                ((FolderInfo) collectionIcon.getTag()).remove((WorkspaceItemInfo) itemInfo, true);
+            } else if (collectionIcon instanceof AppPairIcon appPairIcon) {
+                removeItem(appPairIcon, appPairIcon.getInfo(), deleteFromDb,
+                        "removing app pair because one of its member apps was removed");
             } else {
                 mWorkspace.removeWorkspaceItem(v);
             }
             if (deleteFromDb) {
                 getModelWriter().deleteItemFromDatabase(itemInfo, reason);
             }
-        } else if (itemInfo instanceof FolderInfo) {
-            final FolderInfo folderInfo = (FolderInfo) itemInfo;
+        } else if (itemInfo instanceof CollectionInfo ci) {
             if (v instanceof FolderIcon) {
                 ((FolderIcon) v).removeListeners();
             }
             mWorkspace.removeWorkspaceItem(v);
             if (deleteFromDb) {
-                getModelWriter().deleteFolderAndContentsFromDatabase(folderInfo);
+                getModelWriter().deleteCollectionAndContentsFromDatabase(ci);
             }
         } else if (itemInfo instanceof LauncherAppWidgetInfo) {
             final LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) itemInfo;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index ca34dd1..ce3c55a 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -95,6 +95,7 @@
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -3313,7 +3314,7 @@
                     }
                 } else if (child instanceof FolderIcon) {
                     FolderInfo folderInfo = (FolderInfo) info;
-                    List<WorkspaceItemInfo> matches = folderInfo.contents.stream()
+                    List<WorkspaceItemInfo> matches = folderInfo.getContents().stream()
                             .filter(matcher)
                             .collect(Collectors.toList());
                     if (!matches.isEmpty()) {
@@ -3322,6 +3323,11 @@
                             ((FolderIcon) child).getFolder().close(false /* animate */);
                         }
                     }
+                } else if (info instanceof AppPairInfo api) {
+                    // If an app pair's member apps are being removed, delete the whole app pair.
+                    if (api.anyMatch(matcher)) {
+                        mLauncher.removeItem(child, info, true);
+                    }
                 }
             }
         }
@@ -3373,9 +3379,9 @@
                 }
             } else if (info instanceof FolderInfo && v instanceof FolderIcon) {
                 FolderInfo fi = (FolderInfo) info;
-                if (fi.contents.stream().anyMatch(matcher)) {
+                if (fi.anyMatch(matcher)) {
                     FolderDotInfo folderDotInfo = new FolderDotInfo();
-                    for (WorkspaceItemInfo si : fi.contents) {
+                    for (WorkspaceItemInfo si : fi.getContents()) {
                         folderDotInfo.addDotInfo(mLauncher.getDotInfoForItem(si));
                     }
                     ((FolderIcon) v).setDotInfo(folderDotInfo);
diff --git a/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
index 19d0421..29862ae 100644
--- a/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
@@ -28,7 +28,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -45,6 +45,7 @@
     public enum DragType {
         ICON,
         FOLDER,
+        APP_PAIR,
         WIDGET
     }
 
@@ -103,7 +104,7 @@
                     && item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
         }
         return (item instanceof LauncherAppWidgetInfo)
-                || (item instanceof FolderInfo);
+                || (item instanceof CollectionInfo);
     }
 
     @Override
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 66b8216..bb25b6d 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -39,6 +39,8 @@
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.keyboard.KeyboardDragAndDropView;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -317,6 +319,8 @@
         mDragInfo.dragType = DragType.ICON;
         if (info instanceof FolderInfo) {
             mDragInfo.dragType = DragType.FOLDER;
+        } else if (info instanceof AppPairInfo) {
+            mDragInfo.dragType = DragType.APP_PAIR;
         } else if (info instanceof LauncherAppWidgetInfo) {
             mDragInfo.dragType = DragType.WIDGET;
         }
@@ -430,16 +434,16 @@
                         LauncherSettings.Favorites.CONTAINER_DESKTOP,
                         screenId, coordinates[0], coordinates[1]);
                 bindItem(info, accessibility, finishCallback);
-            } else if (item instanceof FolderInfo fi) {
+            } else if (item instanceof CollectionInfo ci) {
                 Workspace<?> workspace = mContext.getWorkspace();
                 workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
-                mContext.getModelWriter().addItemToDatabase(fi,
+                mContext.getModelWriter().addItemToDatabase(ci,
                         LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, coordinates[0],
                         coordinates[1]);
-                fi.contents.forEach(member -> {
-                    mContext.getModelWriter().addItemToDatabase(member, fi.id, -1, -1, -1);
-                });
-                bindItem(fi, accessibility, finishCallback);
+                ci.getContents().forEach(member ->
+                        mContext.getModelWriter()
+                                .addItemToDatabase(member, ci.id, -1, -1, -1));
+                bindItem(ci, accessibility, finishCallback);
             }
         }));
         return true;
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
index a8624dd..52073cc 100644
--- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -149,7 +149,7 @@
                 // Find the first item in the folder.
                 FolderInfo folder = (FolderInfo) info;
                 WorkspaceItemInfo firstItem = null;
-                for (WorkspaceItemInfo shortcut : folder.contents) {
+                for (WorkspaceItemInfo shortcut : folder.getContents()) {
                     if (firstItem == null || firstItem.rank > shortcut.rank) {
                         firstItem = shortcut;
                     }
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index fbeab4e..4b65b73 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -70,7 +70,6 @@
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.Flags;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.R;
@@ -127,7 +126,6 @@
     public static final float PULL_MULTIPLIER = .02f;
     public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
     protected static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
-    private static final int SCROLL_TO_BOTTOM_DURATION = 500;
     private static final long DEFAULT_SEARCH_TRANSITION_DURATION_MS = 300;
     // Render the header protection at all times to debug clipping issues.
     private static final boolean DEBUG_HEADER_PROTECTION = false;
@@ -192,8 +190,6 @@
     private float mTotalHeaderProtectionHeight;
     @Nullable private AllAppsTransitionController mAllAppsTransitionController;
 
-    private PrivateSpaceHeaderViewController mPrivateSpaceHeaderViewController;
-
     public ActivityAllAppsContainerView(Context context) {
         this(context, null);
     }
@@ -261,10 +257,6 @@
      */
     protected void initContent() {
         mMainAdapterProvider = mSearchUiDelegate.createMainAdapterProvider();
-        if (Flags.enablePrivateSpace()) {
-            mPrivateSpaceHeaderViewController =
-                    new PrivateSpaceHeaderViewController(this, mPrivateProfileManager);
-        }
 
         mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN,
                 new AlphabeticalAppsList<>(mActivityContext,
@@ -398,7 +390,7 @@
         mAllAppsTransitionController = allAppsTransitionController;
     }
 
-    private void animateToSearchState(boolean goingToSearch, long durationMs) {
+    void animateToSearchState(boolean goingToSearch, long durationMs) {
         if (!mSearchTransitionController.isRunning() && goingToSearch == isSearching()) {
             return;
         }
@@ -499,9 +491,9 @@
     }
 
     /**
-     * Exits search and returns to A-Z apps list. Scroll to the bottom.
+     * Exits search and returns to A-Z apps list. Scroll to the private space header.
      */
-    public void resetAndScrollToBottom() {
+    public void resetAndScrollToPrivateSpaceHeader() {
         if (mTouchHandler != null) {
             mTouchHandler.endFastScrolling();
         }
@@ -518,7 +510,13 @@
             // Switch to the main tab
             switchToTab(ActivityAllAppsContainerView.AdapterHolder.MAIN);
             // Scroll to bottom
-            getActiveRecyclerView().scrollToBottomWithMotion(SCROLL_TO_BOTTOM_DURATION);
+            if (mPrivateProfileManager != null) {
+                mPrivateProfileManager.scrollForViewToBeVisibleInContainer(
+                        getActiveAppsRecyclerView(),
+                        getPersonalAppList().getAdapterItems(),
+                        mPrivateProfileManager.getPsHeaderHeight(),
+                        mActivityContext.getDeviceProfile().allAppsCellHeightPx);
+            }
         });
     }
 
@@ -906,7 +904,7 @@
 
     protected BaseAllAppsAdapter<T> createAdapter(AlphabeticalAppsList<T> appsList) {
         return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList,
-                mMainAdapterProvider, mPrivateSpaceHeaderViewController);
+                mMainAdapterProvider);
     }
 
     // TODO(b/216683257): Remove when Taskbar All Apps supports search.
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 5f002b5..df383bf 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -73,9 +73,8 @@
 
 
     public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
-            AlphabeticalAppsList apps, SearchAdapterProvider<?> adapterProvider,
-            PrivateSpaceHeaderViewController privateSpaceHeaderViewController) {
-        super(activityContext, inflater, apps, adapterProvider, privateSpaceHeaderViewController);
+            AlphabeticalAppsList apps, SearchAdapterProvider<?> adapterProvider) {
+        super(activityContext, inflater, apps, adapterProvider);
         mGridLayoutMgr = new AppsGridLayoutManager(mActivityContext);
         mGridLayoutMgr.setSpanSizeLookup(new GridSpanSizer());
         setAppsPerRow(activityContext.getDeviceProfile().numShownAllAppsColumns);
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 3678109..63f6227 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -295,9 +295,6 @@
         mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
 
         AllAppsRecyclerView rv = mLauncher.getAppsView().getActiveRecyclerView();
-        if (rv != null && rv.getScrollbar() != null) {
-            rv.getScrollbar().setVisibility(scaleProgress < 1f ? View.INVISIBLE : View.VISIBLE);
-        }
 
         // Disable view clipping from all apps' RecyclerView up to all apps view during scale
         // animation, and vice versa. The goal is to display extra roll(s) app icons (rendered in
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 81cfa86..4d4b8d2 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -206,7 +206,10 @@
      */
     @Override
     public void onAppsUpdated() {
-        if (mAllAppsStore == null) {
+        // Don't update apps when the private profile animations are running, otherwise the motion
+        // is canceled.
+        if (mAllAppsStore == null || (mPrivateProviderManager != null &&
+                mPrivateProviderManager.getAnimationRunning())) {
             return;
         }
         // Sort the list of apps
@@ -444,6 +447,10 @@
         return roundRegion;
     }
 
+    public PrivateProfileManager getPrivateProfileManager() {
+        return mPrivateProviderManager;
+    }
+
     private static class MyDiffCallback extends DiffUtil.Callback {
 
         private final List<AdapterItem> mOldList;
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 5e5795d..2190e1a 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -169,16 +169,9 @@
     protected final OnClickListener mOnIconClickListener;
     protected final OnLongClickListener mOnIconLongClickListener;
     protected OnFocusChangeListener mIconFocusListener;
-    private final PrivateSpaceHeaderViewController mPrivateSpaceHeaderViewController;
 
     public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
             AlphabeticalAppsList<T> apps, SearchAdapterProvider<?> adapterProvider) {
-        this(activityContext, inflater, apps, adapterProvider, null);
-    }
-
-    public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
-            AlphabeticalAppsList<T> apps, SearchAdapterProvider<?> adapterProvider,
-            PrivateSpaceHeaderViewController privateSpaceHeaderViewController) {
         mActivityContext = activityContext;
         mApps = apps;
         mLayoutInflater = inflater;
@@ -187,7 +180,6 @@
         mOnIconLongClickListener = mActivityContext.getAllAppsItemLongClickListener();
 
         mAdapterProvider = adapterProvider;
-        mPrivateSpaceHeaderViewController = privateSpaceHeaderViewController;
     }
 
     /** Checks if the passed viewType represents all apps divider. */
@@ -283,13 +275,10 @@
             case VIEW_TYPE_PRIVATE_SPACE_HEADER:
                 RelativeLayout psHeaderLayout = holder.itemView.findViewById(
                         R.id.ps_header_layout);
-                assert mPrivateSpaceHeaderViewController != null;
-                assert psHeaderLayout != null;
-                mPrivateSpaceHeaderViewController.addPrivateSpaceHeaderViewElements(psHeaderLayout);
+                mApps.getPrivateProfileManager().addPrivateSpaceHeaderViewElements(psHeaderLayout);
                 AdapterItem adapterItem = mApps.getAdapterItems().get(position);
                 int roundRegions = ROUND_TOP_LEFT | ROUND_TOP_RIGHT;
-                if (mPrivateSpaceHeaderViewController.getPrivateProfileManager().getCurrentState()
-                        == STATE_DISABLED) {
+                if (mApps.getPrivateProfileManager().getCurrentState() == STATE_DISABLED) {
                     roundRegions |= (ROUND_BOTTOM_LEFT | ROUND_BOTTOM_RIGHT);
                 }
                 adapterItem.decorationInfo =
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index e7bb1d0..eb967bc 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -16,26 +16,54 @@
 
 package com.android.launcher3.allapps;
 
+import static android.view.View.GONE;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
 import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER;
 import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.Intent;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
 
+import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.recyclerview.widget.LinearSmoothScroller;
+import androidx.recyclerview.widget.RecyclerView;
 
+import com.android.app.animation.Interpolators;
 import com.android.launcher3.BuildConfig;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
 import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedPropertySetter;
+import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.logging.StatsLogManager;
@@ -45,6 +73,8 @@
 import com.android.launcher3.uioverrides.ApiWrapper;
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.SettingsCache;
+import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.RecyclerViewFastScroller;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -57,14 +87,17 @@
  * logic in the Personal tab.
  */
 public class PrivateProfileManager extends UserProfileManager {
-
+    private static final int EXPAND_COLLAPSE_DURATION = 800;
+    private static final int SETTINGS_OPACITY_DURATION = 160;
     private final ActivityAllAppsContainerView<?> mAllApps;
     private final Predicate<UserHandle> mPrivateProfileMatcher;
     private Set<String> mPreInstalledSystemPackages = new HashSet<>();
     private Intent mAppInstallerIntent = new Intent();
     private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
     private boolean mPrivateSpaceSettingsAvailable;
-    private Runnable mUnlockRunnable;
+    private boolean mIsAnimationRunning;
+    private int mHeaderHeight;
+    private boolean mAnimate;
 
     public PrivateProfileManager(UserManager userManager,
             ActivityAllAppsContainerView<?> allApps,
@@ -118,20 +151,19 @@
 
     /**
      * Disables quiet mode for Private Space User Profile.
-     * The runnable passed will be executed in the {@link #reset()} method,
-     * when Launcher receives update about profile availability.
-     * The runnable passed is only executed once, and reset after execution.
+     * When called from search, a runnable is set and executed in the {@link #reset()} method, when
+     * Launcher receives update about profile availability.
+     * The runnable is only executed once, and reset after execution.
      * In case the method is called again, before the previously set runnable was executed,
      * the runnable will be updated.
      */
-    public void unlockPrivateProfile(Runnable runnable) {
-        enableQuietMode(false);
-        mUnlockRunnable = runnable;
+    public void unlockPrivateProfile() {
+        setQuietMode(false);
     }
 
     /** Enables quiet mode for Private Space User Profile. */
-    public void lockPrivateProfile() {
-        enableQuietMode(true);
+    void lockPrivateProfile() {
+        setQuietMode(true);
     }
 
     /** Whether private profile should be hidden on Launcher. */
@@ -149,7 +181,9 @@
         setCurrentState(updatedState);
         resetPrivateSpaceDecorator(updatedState);
         if (transitioningFromLockedToUnlocked(previousState, updatedState)) {
-            applyUnlockRunnable();
+            postUnlock();
+        } else if (transitioningFromUnlockedToLocked(previousState, updatedState)){
+            executeLock();
         }
     }
 
@@ -235,23 +269,45 @@
         }
     }
 
-    /** Posts quiet mode enable/disable call for private profile. */
-    private void enableQuietMode(boolean enable) {
-        setQuietMode(enable);
+    @Override
+    public void setQuietMode(boolean enable) {
+        super.setQuietMode(enable);
+        mAnimate = true;
     }
 
-    void applyUnlockRunnable() {
-        if (mUnlockRunnable != null) {
-            // reset the runnable to prevent re-execution.
-            MAIN_EXECUTOR.post(mUnlockRunnable);
-            mUnlockRunnable = null;
+    /**
+     * Expand the private space after the app list has been added and updated from
+     * {@link AlphabeticalAppsList#onAppsUpdated()}
+     */
+    void postUnlock() {
+        if (mAllApps.isSearching()) {
+            MAIN_EXECUTOR.post(this::exitSearchAndExpand);
+        } else {
+            MAIN_EXECUTOR.post(this::expandPrivateSpace);
         }
     }
 
+    /** Collapses the private space before the app list has been updated. */
+    void executeLock() {
+        MAIN_EXECUTOR.execute(this::collapsePrivateSpace);
+    }
+
+    void setAnimationRunning(boolean isAnimationRunning) {
+        mIsAnimationRunning = isAnimationRunning;
+    }
+
+    boolean getAnimationRunning() {
+        return mIsAnimationRunning;
+    }
+
     private boolean transitioningFromLockedToUnlocked(int previousState, int updatedState) {
         return previousState == STATE_DISABLED && updatedState == STATE_ENABLED;
     }
 
+    private boolean transitioningFromUnlockedToLocked(int previousState, int updatedState) {
+        return previousState == STATE_ENABLED && updatedState == STATE_DISABLED;
+    }
+
     @Override
     public Predicate<UserHandle> getUserMatcher() {
         return mPrivateProfileMatcher;
@@ -266,4 +322,349 @@
                 && (appInfo.componentName == null
                 || !(mPreInstalledSystemPackages.contains(appInfo.componentName.getPackageName())));
     }
+
+    /** Add Private Space Header view elements based upon {@link UserProfileState} */
+    public void addPrivateSpaceHeaderViewElements(RelativeLayout parent) {
+        // Set the transition duration for the settings and lock button to animate.
+        ViewGroup settingAndLockGroup = parent.findViewById(R.id.settingsAndLockGroup);
+        if (mAnimate) {
+            enableLayoutTransition(settingAndLockGroup);
+        } else {
+            // Ensure any unwanted animations to not happen.
+            settingAndLockGroup.setLayoutTransition(null);
+        }
+
+        //Add quietMode image and action for lock/unlock button
+        ViewGroup lockButton =
+                parent.findViewById(R.id.ps_lock_unlock_button);
+        assert lockButton != null;
+        addLockButton(lockButton);
+
+        //Trigger lock/unlock action from header.
+        addHeaderOnClickListener(parent);
+
+        //Add image and action for private space settings button
+        ImageButton settingsButton = parent.findViewById(R.id.ps_settings_button);
+        assert settingsButton != null;
+        addPrivateSpaceSettingsButton(settingsButton);
+
+        //Add image for private space transitioning view
+        ImageView transitionView = parent.findViewById(R.id.ps_transition_image);
+        assert transitionView != null;
+        addTransitionImage(transitionView);
+        mHeaderHeight = parent.getHeight();
+    }
+
+    /**
+     *  Adds the quietModeButton and attach onClickListener for the header to animate different
+     *  states when clicked.
+     */
+    private void addLockButton(ViewGroup lockButton) {
+        TextView lockText = lockButton.findViewById(R.id.lock_text);
+        switch (getCurrentState()) {
+            case STATE_ENABLED -> {
+                lockText.setVisibility(VISIBLE);
+                lockButton.setVisibility(VISIBLE);
+                lockButton.setOnClickListener(view -> lockingAction(/* lock */ true));
+            }
+            case STATE_DISABLED -> {
+                lockText.setVisibility(GONE);
+                lockButton.setVisibility(VISIBLE);
+                lockButton.setOnClickListener(view -> lockingAction(/* lock */ false));
+            }
+            default -> lockButton.setVisibility(GONE);
+        }
+    }
+
+    private void addHeaderOnClickListener(RelativeLayout header) {
+        if (getCurrentState() == STATE_DISABLED) {
+            header.setOnClickListener(view -> lockingAction(/* lock */ false));
+        } else {
+            header.setOnClickListener(null);
+        }
+    }
+
+    /** Sets the enablement of the profile when header or button is clicked. */
+    private void lockingAction(boolean lock) {
+        logEvents(lock ? LAUNCHER_PRIVATE_SPACE_LOCK_TAP : LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP);
+        if (lock) {
+            lockPrivateProfile();
+        } else {
+            unlockPrivateProfile();
+        }
+    }
+
+    private void addPrivateSpaceSettingsButton(ImageButton settingsButton) {
+        if (getCurrentState() == STATE_ENABLED
+                && isPrivateSpaceSettingsAvailable()) {
+            settingsButton.setVisibility(VISIBLE);
+            settingsButton.setAlpha(1f);
+            settingsButton.setOnClickListener(
+                    view -> {
+                        logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
+                        openPrivateSpaceSettings();
+                    });
+        } else {
+            settingsButton.setVisibility(GONE);
+        }
+    }
+
+    private void addTransitionImage(ImageView transitionImage) {
+        if (getCurrentState() == STATE_TRANSITION) {
+            transitionImage.setVisibility(VISIBLE);
+        } else {
+            transitionImage.setVisibility(GONE);
+        }
+    }
+
+    /** Finds the private space header to scroll to and set the private space icons to GONE. */
+    private void collapse() {
+        AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
+        List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems =
+                allAppsRecyclerView.getApps().getAdapterItems();
+        for (int i = appListAdapterItems.size() - 1; i > 0; i--) {
+            BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
+            // Scroll to the private space header.
+            if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+                // Note: SmoothScroller is meant to be used once.
+                RecyclerView.SmoothScroller smoothScroller =
+                        new LinearSmoothScroller(mAllApps.getContext()) {
+                            @Override protected int getVerticalSnapPreference() {
+                                return LinearSmoothScroller.SNAP_TO_END;
+                            }
+                        };
+                smoothScroller.setTargetPosition(i);
+                RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
+                if (layoutManager != null) {
+                    layoutManager.startSmoothScroll(smoothScroller);
+                }
+                break;
+            }
+            // Make the private space apps gone to "collapse".
+            if (currentItem.decorationInfo != null) {
+                RecyclerView.ViewHolder viewHolder =
+                        allAppsRecyclerView.findViewHolderForAdapterPosition(i);
+                if (viewHolder != null) {
+                    viewHolder.itemView.setVisibility(GONE);
+                }
+            }
+        }
+    }
+
+    /**
+     * Upon expanding, only scroll to the item position in the adapter that allows the header to be
+     * visible.
+     */
+    public int scrollForViewToBeVisibleInContainer(
+            AllAppsRecyclerView allAppsRecyclerView,
+            List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems,
+            int psHeaderHeight,
+            int allAppsCellHeight) {
+        int rowToExpandToWithRespectToHeader = -1;
+        int itemToScrollTo = -1;
+        // Looks for the item in the app list to scroll to so that the header is visible.
+        for (int i = 0; i < appListAdapterItems.size(); i++) {
+            BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
+            if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+                itemToScrollTo = i;
+                continue;
+            }
+            if (itemToScrollTo != -1) {
+                itemToScrollTo = i;
+                if (rowToExpandToWithRespectToHeader == -1) {
+                    rowToExpandToWithRespectToHeader = currentItem.rowIndex;
+                }
+                int rowToScrollTo =
+                        (int) Math.floor((double) (mAllApps.getHeight() - psHeaderHeight
+                                - mAllApps.getHeaderProtectionHeight()) / allAppsCellHeight);
+                int currentRowDistance = currentItem.rowIndex - rowToExpandToWithRespectToHeader;
+                // rowToScrollTo - 1 since the item to scroll to is 0 indexed.
+                if (currentRowDistance == rowToScrollTo - 1) {
+                    break;
+                }
+            }
+        }
+        if (itemToScrollTo != -1) {
+            // Note: SmoothScroller is meant to be used once.
+            RecyclerView.SmoothScroller smoothScroller =
+                    new LinearSmoothScroller(mAllApps.getContext()) {
+                        @Override protected int getVerticalSnapPreference() {
+                            return LinearSmoothScroller.SNAP_TO_ANY;
+                        }
+                    };
+            smoothScroller.setTargetPosition(itemToScrollTo);
+            RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
+            if (layoutManager != null) {
+                layoutManager.startSmoothScroll(smoothScroller);
+            }
+        }
+        return itemToScrollTo;
+    }
+
+    /**
+     * Scrolls up to the private space header and animates the collapsing of the text.
+     */
+    private ValueAnimator animateCollapseAnimation() {
+        float from = 1;
+        float to = 0;
+        RecyclerViewFastScroller scrollBar = mAllApps.getActiveRecyclerView().getScrollbar();
+        ValueAnimator collapseAnim = ValueAnimator.ofFloat(from, to);
+        collapseAnim.setDuration(EXPAND_COLLAPSE_DURATION);
+        collapseAnim.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                if (scrollBar != null) {
+                    scrollBar.setVisibility(INVISIBLE);
+                }
+                // Scroll up to header.
+                collapse();
+            }
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                if (scrollBar != null) {
+                    scrollBar.setThumbOffsetY(-1);
+                    scrollBar.setVisibility(VISIBLE);
+                }
+            }
+        });
+        return collapseAnim;
+    }
+
+    /**
+     * Using PropertySetter{@link PropertySetter}, we can update the view's attributes within an
+     * animation. At the moment, collapsing, setting alpha changes, and animating the text is done
+     * here.
+     */
+    private void updatePrivateStateAnimator(boolean expand, @Nullable ViewGroup psHeader) {
+        if (psHeader == null) {
+            return;
+        }
+        ViewGroup settingsAndLockGroup = psHeader.findViewById(R.id.settingsAndLockGroup);
+        ViewGroup lockButton = psHeader.findViewById(R.id.ps_lock_unlock_button);
+        if (settingsAndLockGroup.getLayoutTransition() == null) {
+            // Set a new transition if the current ViewGroup does not already contain one as each
+            // transition should only happen once when applied.
+            enableLayoutTransition(settingsAndLockGroup);
+        }
+
+        PropertySetter setter = new AnimatedPropertySetter();
+        ImageButton settingsButton = psHeader.findViewById(R.id.ps_settings_button);
+        updateSettingsGearAlpha(settingsButton, expand, setter);
+        AnimatorSet animatorSet = setter.buildAnim();
+        animatorSet.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                // Animate the collapsing of the text at the same time while updating lock button.
+                lockButton.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
+                setAnimationRunning(true);
+            }
+        });
+        animatorSet.addListener(forEndCallback(() -> {
+            setAnimationRunning(false);
+            mAnimate = false;
+            if (!expand) {
+                // Call onAppsUpdated() because it may be canceled when this animation occurs.
+                mAllApps.getPersonalAppList().onAppsUpdated();
+            }
+        }));
+        // Play the collapsing together of the stateAnimator to avoid being unable to scroll to the
+        // header. Otherwise the smooth scrolling will scroll higher when played with the state
+        // animator.
+        if (!expand) {
+            animatorSet.playTogether(animateCollapseAnimation());
+        }
+        animatorSet.setDuration(EXPAND_COLLAPSE_DURATION);
+        animatorSet.start();
+    }
+
+    /** Animates the layout changes when the text of the button becomes visible/gone. */
+    private void enableLayoutTransition(ViewGroup settingsAndLockGroup) {
+        LayoutTransition settingsAndLockTransition = new LayoutTransition();
+        settingsAndLockTransition.enableTransitionType(LayoutTransition.CHANGING);
+        settingsAndLockTransition.setDuration(EXPAND_COLLAPSE_DURATION);
+        settingsAndLockTransition.addTransitionListener(new LayoutTransition.TransitionListener() {
+            @Override
+            public void startTransition(LayoutTransition transition, ViewGroup viewGroup,
+                    View view, int i) {
+            }
+            @Override
+            public void endTransition(LayoutTransition transition, ViewGroup viewGroup,
+                    View view, int i) {
+                settingsAndLockGroup.setLayoutTransition(null);
+                mAnimate = false;
+            }
+        });
+        settingsAndLockGroup.setLayoutTransition(settingsAndLockTransition);
+    }
+
+    /** Change the settings gear alpha when expanded or collapsed. */
+    private void updateSettingsGearAlpha(ImageButton settingsButton, boolean expand,
+            PropertySetter setter) {
+        float toAlpha = expand ? 1 : 0;
+        setter.setFloat(settingsButton, VIEW_ALPHA, toAlpha, Interpolators.LINEAR)
+                .setDuration(SETTINGS_OPACITY_DURATION).setStartDelay(0);
+    }
+
+    void expandPrivateSpace() {
+        // If we are on main adapter view, we apply the PS Container expansion animation and
+        // scroll down to load the entire container, making animation visible.
+        ActivityAllAppsContainerView<?>.AdapterHolder mainAdapterHolder = mAllApps.mAH.get(MAIN);
+        List<BaseAllAppsAdapter.AdapterItem> adapterItems =
+                mainAdapterHolder.mAppsList.getAdapterItems();
+        if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()
+                && mAllApps.isPersonalTab()) {
+            // Animate the text and settings icon.
+            DeviceProfile deviceProfile =
+                    ActivityContext.lookupContext(mAllApps.getContext()).getDeviceProfile();
+            scrollForViewToBeVisibleInContainer(mainAdapterHolder.mRecyclerView, adapterItems,
+                    getPsHeaderHeight(), deviceProfile.allAppsCellHeightPx);
+            ViewGroup psHeader = getPsHeader(mainAdapterHolder.mRecyclerView, adapterItems);
+            updatePrivateStateAnimator(true, psHeader);
+        }
+    }
+
+    private void exitSearchAndExpand() {
+        mAllApps.updateHeaderScroll(0);
+        // Animate to A-Z with 0 time to reset the animation with proper state management.
+        mAllApps.animateToSearchState(false, 0);
+        MAIN_EXECUTOR.post(() -> {
+            mAllApps.mSearchUiManager.resetSearch();
+            mAllApps.switchToTab(ActivityAllAppsContainerView.AdapterHolder.MAIN);
+            expandPrivateSpace();
+        });
+    }
+
+    private void collapsePrivateSpace() {
+        AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
+        AlphabeticalAppsList<?> appList = allAppsRecyclerView.getApps();
+        if (appList == null) {
+            return;
+        }
+        ViewGroup psHeader = getPsHeader(allAppsRecyclerView, appList.getAdapterItems());
+        assert psHeader != null;
+        updatePrivateStateAnimator(false, psHeader);
+    }
+
+    int getPsHeaderHeight() {
+        return mHeaderHeight;
+    }
+
+    /** Get the private space header from the adapter items. */
+    @Nullable
+    private ViewGroup getPsHeader(AllAppsRecyclerView allAppsRecyclerView,
+            List<BaseAllAppsAdapter.AdapterItem> adapterItems){
+        ViewGroup psHeader = null;
+        for (int i = 0; i < adapterItems.size(); i++) {
+            BaseAllAppsAdapter.AdapterItem currentItem = adapterItems.get(i);
+            if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+                RecyclerView.ViewHolder viewHolder =
+                        allAppsRecyclerView.findViewHolderForAdapterPosition(i);
+                if (viewHolder != null) {
+                    psHeader = (ViewGroup) viewHolder.itemView;
+                }
+            }
+        }
+        return psHeader;
+    }
 }
diff --git a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
deleted file mode 100644
index fdc035e..0000000
--- a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.allapps;
-
-import static android.view.View.GONE;
-import static android.view.View.INVISIBLE;
-import static android.view.View.VISIBLE;
-
-import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
-import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
-import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
-import static com.android.launcher3.allapps.PrivateProfileManager.STATE_DISABLED;
-import static com.android.launcher3.allapps.PrivateProfileManager.STATE_ENABLED;
-import static com.android.launcher3.allapps.PrivateProfileManager.STATE_TRANSITION;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_TAP;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.LayoutTransition;
-import android.animation.ValueAnimator;
-import android.view.ViewGroup;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.recyclerview.widget.LinearSmoothScroller;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.app.animation.Interpolators;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Flags;
-import com.android.launcher3.R;
-import com.android.launcher3.allapps.UserProfileManager.UserProfileState;
-import com.android.launcher3.anim.AnimatedPropertySetter;
-import com.android.launcher3.anim.PropertySetter;
-import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.RecyclerViewFastScroller;
-
-import java.util.List;
-
-/**
- * Controller which returns views to be added to Private Space Header based upon
- * {@link UserProfileState}
- */
-public class PrivateSpaceHeaderViewController {
-    private static final int EXPAND_COLLAPSE_DURATION = 800;
-    private static final int SETTINGS_OPACITY_DURATION = 160;
-    private final ActivityAllAppsContainerView mAllApps;
-    private final PrivateProfileManager mPrivateProfileManager;
-
-    public PrivateSpaceHeaderViewController(ActivityAllAppsContainerView allApps,
-            PrivateProfileManager privateProfileManager) {
-        this.mAllApps = allApps;
-        this.mPrivateProfileManager = privateProfileManager;
-    }
-
-    /** Add Private Space Header view elements based upon {@link UserProfileState} */
-    public void addPrivateSpaceHeaderViewElements(RelativeLayout parent) {
-        // Set the transition duration for the settings and lock button to animate.
-        ViewGroup settingsAndLockGroup = parent.findViewById(R.id.settingsAndLockGroup);
-        LayoutTransition settingsAndLockTransition = settingsAndLockGroup.getLayoutTransition();
-        settingsAndLockTransition.enableTransitionType(LayoutTransition.CHANGING);
-        settingsAndLockTransition.setDuration(EXPAND_COLLAPSE_DURATION);
-
-        //Add quietMode image and action for lock/unlock button
-        ViewGroup lockButton =
-                parent.findViewById(R.id.ps_lock_unlock_button);
-        assert lockButton != null;
-        addLockButton(parent, lockButton);
-
-        //Trigger lock/unlock action from header.
-        addHeaderOnClickListener(parent);
-
-        //Add image and action for private space settings button
-        ImageButton settingsButton = parent.findViewById(R.id.ps_settings_button);
-        assert settingsButton != null;
-        addPrivateSpaceSettingsButton(settingsButton);
-
-        //Add image for private space transitioning view
-        ImageView transitionView = parent.findViewById(R.id.ps_transition_image);
-        assert transitionView != null;
-        addTransitionImage(transitionView);
-    }
-
-    /**
-     *  Adds the quietModeButton and attach onClickListener for the header to animate different
-     *  states when clicked.
-     */
-    private void addLockButton(ViewGroup psHeader, ViewGroup lockButton) {
-        TextView lockText = lockButton.findViewById(R.id.lock_text);
-        switch (mPrivateProfileManager.getCurrentState()) {
-            case STATE_ENABLED -> {
-                lockText.setVisibility(VISIBLE);
-                lockButton.setVisibility(VISIBLE);
-                lockButton.setOnClickListener(view -> lockAction(psHeader));
-            }
-            case STATE_DISABLED -> {
-                lockText.setVisibility(GONE);
-                lockButton.setVisibility(VISIBLE);
-                lockButton.setOnClickListener(view -> unlockAction(psHeader));
-            }
-            default -> lockButton.setVisibility(GONE);
-        }
-    }
-
-    private void addHeaderOnClickListener(RelativeLayout header) {
-        if (mPrivateProfileManager.getCurrentState() == STATE_DISABLED) {
-            header.setOnClickListener(view -> unlockAction(header));
-        } else {
-            header.setOnClickListener(null);
-        }
-    }
-
-    private void unlockAction(ViewGroup psHeader) {
-        mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP);
-        mPrivateProfileManager.unlockPrivateProfile((() -> onPrivateProfileUnlocked(psHeader)));
-    }
-
-    private void lockAction(ViewGroup psHeader) {
-        mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_LOCK_TAP);
-        if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()) {
-            updatePrivateStateAnimator(false, psHeader);
-        } else {
-            mPrivateProfileManager.lockPrivateProfile();
-        }
-    }
-
-    private void addPrivateSpaceSettingsButton(ImageButton settingsButton) {
-        if (mPrivateProfileManager.getCurrentState() == STATE_ENABLED
-                && mPrivateProfileManager.isPrivateSpaceSettingsAvailable()) {
-            settingsButton.setVisibility(VISIBLE);
-            settingsButton.setAlpha(1f);
-            settingsButton.setOnClickListener(
-                    view -> {
-                        mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
-                        mPrivateProfileManager.openPrivateSpaceSettings();
-                    });
-        } else {
-            settingsButton.setVisibility(GONE);
-        }
-    }
-
-    private void addTransitionImage(ImageView transitionImage) {
-        if (mPrivateProfileManager.getCurrentState() == STATE_TRANSITION) {
-            transitionImage.setVisibility(VISIBLE);
-        } else {
-            transitionImage.setVisibility(GONE);
-        }
-    }
-
-    private void onPrivateProfileUnlocked(ViewGroup header) {
-        // If we are on main adapter view, we apply the PS Container expansion animation and
-        // then scroll down to load the entire container, making animation visible.
-        ActivityAllAppsContainerView<?>.AdapterHolder mainAdapterHolder =
-                (ActivityAllAppsContainerView<?>.AdapterHolder) mAllApps.mAH.get(MAIN);
-        if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()
-                && mAllApps.getActiveRecyclerView() == mainAdapterHolder.mRecyclerView) {
-            // Animate the text and settings icon.
-            updatePrivateStateAnimator(true, header);
-            DeviceProfile deviceProfile =
-                    ActivityContext.lookupContext(mAllApps.getContext()).getDeviceProfile();
-            AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
-            scrollForViewToBeVisibleInContainer(allAppsRecyclerView,
-                    allAppsRecyclerView.getApps().getAdapterItems(),
-                    header.getHeight(), deviceProfile.allAppsCellHeightPx);
-        }
-    }
-
-    /** Finds the private space header to scroll to and set the private space icons to GONE. */
-    private void collapse() {
-        AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
-        List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems =
-                allAppsRecyclerView.getApps().getAdapterItems();
-        for (int i = appListAdapterItems.size() - 1; i > 0; i--) {
-            BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
-            // Scroll to the private space header.
-            if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
-                // Note: SmoothScroller is meant to be used once.
-                RecyclerView.SmoothScroller smoothScroller =
-                        new LinearSmoothScroller(mAllApps.getContext()) {
-                            @Override protected int getVerticalSnapPreference() {
-                                return LinearSmoothScroller.SNAP_TO_END;
-                            }
-                        };
-                smoothScroller.setTargetPosition(i);
-                RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
-                if (layoutManager != null) {
-                    layoutManager.startSmoothScroll(smoothScroller);
-                }
-                break;
-            }
-            // Make the private space apps gone to "collapse".
-            if (currentItem.decorationInfo != null) {
-                RecyclerView.ViewHolder viewHolder =
-                        allAppsRecyclerView.findViewHolderForAdapterPosition(i);
-                if (viewHolder != null) {
-                    viewHolder.itemView.setVisibility(GONE);
-                }
-            }
-        }
-    }
-
-    /**
-     * Upon expanding, only scroll to the item position in the adapter that allows the header to be
-     * visible.
-     */
-    @VisibleForTesting
-    public int scrollForViewToBeVisibleInContainer(
-            AllAppsRecyclerView allAppsRecyclerView,
-            List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems,
-            int psHeaderHeight,
-            int allAppsCellHeight) {
-        int rowToExpandToWithRespectToHeader = -1;
-        int itemToScrollTo = -1;
-        // Looks for the item in the app list to scroll to so that the header is visible.
-        for (int i = 0; i < appListAdapterItems.size(); i++) {
-            BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
-            if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
-                itemToScrollTo = i;
-                continue;
-            }
-            if (itemToScrollTo != -1) {
-                if (rowToExpandToWithRespectToHeader == -1) {
-                    rowToExpandToWithRespectToHeader = currentItem.rowIndex;
-                }
-                int rowToScrollTo =
-                        (int) Math.floor((double) (mAllApps.getHeight() - psHeaderHeight
-                                - mAllApps.getHeaderProtectionHeight()) / allAppsCellHeight);
-                int currentRowDistance = currentItem.rowIndex - rowToExpandToWithRespectToHeader;
-                // rowToScrollTo - 1 since the item to scroll to is 0 indexed.
-                if (currentRowDistance == rowToScrollTo - 1) {
-                    itemToScrollTo = i;
-                    break;
-                }
-            }
-        }
-        if (itemToScrollTo != -1) {
-            // Note: SmoothScroller is meant to be used once.
-            RecyclerView.SmoothScroller smoothScroller =
-                    new LinearSmoothScroller(mAllApps.getContext()) {
-                        @Override protected int getVerticalSnapPreference() {
-                            return LinearSmoothScroller.SNAP_TO_ANY;
-                        }
-                    };
-            smoothScroller.setTargetPosition(itemToScrollTo);
-            RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
-            if (layoutManager != null) {
-                layoutManager.startSmoothScroll(smoothScroller);
-            }
-        }
-        return itemToScrollTo;
-    }
-
-    PrivateProfileManager getPrivateProfileManager() {
-        return mPrivateProfileManager;
-    }
-
-    /**
-     * Scrolls up to the private space header and animates the collapsing of the text.
-     */
-    private ValueAnimator animateCollapseAnimation(ViewGroup lockButton) {
-        float from = 1;
-        float to = 0;
-        RecyclerViewFastScroller scrollBar = mAllApps.getActiveRecyclerView().getScrollbar();
-        ValueAnimator collapseAnim = ValueAnimator.ofFloat(from, to);
-        collapseAnim.setDuration(EXPAND_COLLAPSE_DURATION);
-        collapseAnim.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                if (scrollBar != null) {
-                    scrollBar.setVisibility(INVISIBLE);
-                }
-                // scroll up
-                collapse();
-                // Animate the collapsing of the text.
-                lockButton.findViewById(R.id.lock_text).setVisibility(GONE);
-            }
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                super.onAnimationEnd(animation);
-                if (scrollBar != null) {
-                    scrollBar.setThumbOffsetY(-1);
-                    scrollBar.setVisibility(VISIBLE);
-                }
-                mPrivateProfileManager.lockPrivateProfile();
-            }
-        });
-        return collapseAnim;
-    }
-
-    /**
-     * Using PropertySetter{@link PropertySetter}, we can update the view's attributes within an
-     * animation. At the moment, collapsing, setting alpha changes, and animating the text is done
-     * here.
-     */
-    private void updatePrivateStateAnimator(boolean expand, ViewGroup psHeader) {
-        PropertySetter setter = new AnimatedPropertySetter();
-        ViewGroup lockButton = psHeader.findViewById(R.id.ps_lock_unlock_button);
-        ImageButton settingsButton = psHeader.findViewById(R.id.ps_settings_button);
-        updateSettingsGearAlpha(settingsButton, expand, setter);
-        AnimatorSet animatorSet = setter.buildAnim();
-        animatorSet.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                // Animate the collapsing of the text at the same time while updating lock button.
-                lockButton.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
-            }
-        });
-        // Play the collapsing together of the stateAnimator to avoid being unable to scroll to the
-        // header. Otherwise the smooth scrolling will scroll higher when played with the state
-        // animator.
-        if (!expand) {
-            animatorSet.playTogether(animateCollapseAnimation(lockButton));
-        }
-        animatorSet.setDuration(EXPAND_COLLAPSE_DURATION);
-        animatorSet.start();
-     }
-
-    /** Change the settings gear alpha when expanded or collapsed. */
-     private void updateSettingsGearAlpha(ImageButton settingsButton, boolean expand,
-            PropertySetter setter) {
-        float toAlpha = expand ? 1 : 0;
-        setter.setFloat(settingsButton, VIEW_ALPHA, toAlpha, Interpolators.LINEAR)
-                .setDuration(SETTINGS_OPACITY_DURATION).setStartDelay(0);
-    }
-}
diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java
index bbeb341..9010f82 100644
--- a/src/com/android/launcher3/apppairs/AppPairIcon.java
+++ b/src/com/android/launcher3/apppairs/AppPairIcon.java
@@ -33,7 +33,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Reorderable;
 import com.android.launcher3.dragndrop.DraggableView;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.MultiTranslateDelegate;
 import com.android.launcher3.views.ActivityContext;
@@ -50,17 +50,12 @@
 public class AppPairIcon extends FrameLayout implements DraggableView, Reorderable {
     private static final String TAG = "AppPairIcon";
 
-    /**
-     * Indicates that the app pair is currently launchable on the current screen.
-     */
-    private boolean mIsLaunchableAtScreenSize = true;
-
     // A view that holds the app pair icon graphic.
     private AppPairIconGraphic mIconGraphic;
     // A view that holds the app pair's title.
     private BubbleTextView mAppPairName;
     // The underlying ItemInfo that stores info about the app pair members, etc.
-    private FolderInfo mInfo;
+    private AppPairInfo mInfo;
     // The containing element that holds this icon: workspace, taskbar, folder, etc. Affects certain
     // aspects of how the icon is drawn.
     private int mContainer;
@@ -81,7 +76,7 @@
      * Builds an AppPairIcon to be added to the Launcher.
      */
     public static AppPairIcon inflateIcon(int resId, ActivityContext activity,
-            @Nullable ViewGroup group, FolderInfo appPairInfo, int container) {
+            @Nullable ViewGroup group, AppPairInfo appPairInfo, int container) {
         DeviceProfile grid = activity.getDeviceProfile();
         LayoutInflater inflater = (group != null)
                 ? LayoutInflater.from(group.getContext())
@@ -89,7 +84,7 @@
         AppPairIcon icon = (AppPairIcon) inflater.inflate(resId, group, false);
 
         // Sort contents, so that left-hand app comes first
-        appPairInfo.contents.sort(Comparator.comparingInt(a -> a.rank));
+        appPairInfo.getContents().sort(Comparator.comparingInt(a -> a.rank));
 
         icon.setTag(appPairInfo);
         icon.setOnClickListener(activity.getItemOnClickListener());
@@ -100,8 +95,6 @@
         icon.mIconGraphic = icon.findViewById(R.id.app_pair_icon_graphic);
         icon.mIconGraphic.init(icon, container);
 
-        icon.checkDisabledState();
-
         // Set up app pair title
         icon.mAppPairName = icon.findViewById(R.id.app_pair_icon_name);
         FrameLayout.LayoutParams lp =
@@ -115,7 +108,7 @@
         // For some reason, app icons have setIncludeFontPadding(false) inside folders, so we set it
         // here to match that.
         icon.mAppPairName.setIncludeFontPadding(container != DISPLAY_FOLDER);
-        icon.mAppPairName.setText(appPairInfo.title);
+        icon.mAppPairName.applyLabel(appPairInfo);
 
         // Set up accessibility
         icon.setContentDescription(icon.getAccessibilityTitle(appPairInfo));
@@ -127,9 +120,9 @@
     /**
      * Returns a formatted accessibility title for app pairs.
      */
-    public String getAccessibilityTitle(FolderInfo appPairInfo) {
-        CharSequence app1 = appPairInfo.contents.get(0).title;
-        CharSequence app2 = appPairInfo.contents.get(1).title;
+    public String getAccessibilityTitle(AppPairInfo appPairInfo) {
+        CharSequence app1 = appPairInfo.getFirstApp().title;
+        CharSequence app2 = appPairInfo.getSecondApp().title;
         return getContext().getString(R.string.app_pair_name_format, app1, app2);
     }
 
@@ -174,7 +167,7 @@
         return mScaleForReorderBounce;
     }
 
-    public FolderInfo getInfo() {
+    public AppPairInfo getInfo() {
         return mInfo;
     }
 
@@ -186,41 +179,20 @@
         return mIconGraphic;
     }
 
-    public boolean isLaunchableAtScreenSize() {
-        return mIsLaunchableAtScreenSize;
-    }
-
-    /**
-     * Updates the "disabled" state of the app pair in the current device configuration.
-     * App pairs can be "disabled" in two ways:
-     * 1) One of the member WorkspaceItemInfos is disabled (i.e. the app software itself is paused
-     * by the user or can't be launched for some other reason).
-     * 2) This specific instance of an app pair can't be launched due to screen size requirements.
-     */
-    public void checkDisabledState() {
-        DeviceProfile dp = ActivityContext.lookupContext(getContext()).getDeviceProfile();
-        // If user is on a small screen, we can't launch if either of the apps is non-resizeable
-        mIsLaunchableAtScreenSize =
-                dp.isTablet || getInfo().contents.stream().noneMatch(
-                        wii -> wii.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE));
-        // Invalidate to update icons
-        mIconGraphic.redraw();
-    }
-
     /**
      * Called when WorkspaceItemInfos get updated, and the app pair icon may need to be redrawn.
      */
     public void maybeRedrawForWorkspaceUpdate(Predicate<WorkspaceItemInfo> itemCheck) {
         // If either of the app pair icons return true on the predicate (i.e. in the list of
         // updated apps), redraw the icon graphic (icon background and both icons).
-        if (getInfo().contents.stream().anyMatch(itemCheck)) {
-            checkDisabledState();
+        if (getInfo().anyMatch(itemCheck)) {
+            mIconGraphic.redraw();
         }
     }
 
     /**
      * Inside folders, icons are vertically centered in their rows. See
-     * {@link BubbleTextView#onMeasure(int, int)} for comparison.
+     * {@link BubbleTextView} for comparison.
      */
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
diff --git a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
index 04050b0..a3a1cfc 100644
--- a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
+++ b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
@@ -23,12 +23,12 @@
 import android.util.AttributeSet
 import android.view.Gravity
 import android.widget.FrameLayout
+import androidx.annotation.OpenForTesting
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener
 import com.android.launcher3.icons.BitmapInfo
 import com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter
-import com.android.launcher3.model.data.FolderInfo
-import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.model.data.AppPairInfo
 import com.android.launcher3.util.Themes
 import com.android.launcher3.views.ActivityContext
 
@@ -36,29 +36,32 @@
  * A FrameLayout marking the area on an [AppPairIcon] where the visual icon will be drawn. One of
  * two child UI elements on an [AppPairIcon], along with a BubbleTextView holding the text title.
  */
-class AppPairIconGraphic @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
+@OpenForTesting
+open class AppPairIconGraphic
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) :
     FrameLayout(context, attrs), OnDeviceProfileChangeListener {
     private val TAG = "AppPairIconGraphic"
 
     companion object {
-        /** Composes a drawable for this icon, consisting of a background and 2 app icons. */
+        /**
+         * Composes a drawable for this icon, consisting of a background and 2 app icons. The app
+         * pair will draw as "disabled" if either of the following is true:
+         * 1) One of the member WorkspaceItemInfos is disabled (i.e. the app software itself is
+         *    paused or can't be launched for some other reason).
+         * 2) One of the member apps can't be launched due to screen size requirements.
+         */
         @JvmStatic
-        fun composeDrawable(appPairInfo: FolderInfo, p: AppPairIconDrawingParams): Drawable {
+        fun composeDrawable(appPairInfo: AppPairInfo, p: AppPairIconDrawingParams): Drawable {
             // Generate new icons, using themed flag if needed.
             val flags = if (Themes.isThemedIconEnabled(p.context)) BitmapInfo.FLAG_THEMED else 0
-            val appIcon1 = appPairInfo.contents[0].newIcon(p.context, flags)
-            val appIcon2 = appPairInfo.contents[1].newIcon(p.context, flags)
+            val appIcon1 = appPairInfo.getFirstApp().newIcon(p.context, flags)
+            val appIcon2 = appPairInfo.getSecondApp().newIcon(p.context, flags)
             appIcon1.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt())
             appIcon2.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt())
 
-            // Check disabled status.
-            val activity: ActivityContext = ActivityContext.lookupContext(p.context)
-            val isLaunchableAtScreenSize =
-                activity.deviceProfile.isTablet ||
-                    appPairInfo.contents.stream().noneMatch { wii: WorkspaceItemInfo ->
-                        wii.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE)
-                    }
-            val shouldDrawAsDisabled = appPairInfo.isDisabled || !isLaunchableAtScreenSize
+            val shouldDrawAsDisabled =
+                appPairInfo.isDisabled || !appPairInfo.isLaunchable(p.context)
 
             // Set disabled status on icons.
             appIcon1.setIsDisabled(shouldDrawAsDisabled)
@@ -124,7 +127,6 @@
      */
     fun getIconBounds(outBounds: Rect) {
         outBounds.set(0, 0, drawParams.backgroundSize.toInt(), drawParams.backgroundSize.toInt())
-
         outBounds.offset(
             // x-coordinate in parent's coordinate system
             ((parentIcon.width - drawParams.backgroundSize) / 2).toInt(),
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 6d64c22..1c34c72 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -397,11 +397,6 @@
                     + "waiting for SystemUI and then merging the SystemUI progress whenever we "
                     + "start receiving the events");
 
-    // TODO(Block 24): Clean up flags
-    public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag(270393455,
-            "ENABLE_NEW_MIGRATION_LOGIC", ENABLED,
-            "Enable the new grid migration logic, keeping pages when src < dest");
-
     // TODO(Block 25): Clean up flags
     public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257,
             "ENABLE_NEW_GESTURE_NAV_TUTORIAL", ENABLED,
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index b6e5977..bc5a164 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.Flags;
 import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -289,7 +290,8 @@
         // Cancel the current drag if we are removing an app that we are dragging
         if (mDragObject != null) {
             ItemInfo dragInfo = mDragObject.dragInfo;
-            if (dragInfo instanceof WorkspaceItemInfo && matcher.test(dragInfo)) {
+            if ((dragInfo instanceof WorkspaceItemInfo && matcher.test(dragInfo))
+                    || (dragInfo instanceof AppPairInfo api && api.anyMatch(matcher))) {
                 cancelDrag();
             }
         }
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index c8c634a..aa3c5ba 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -493,7 +493,7 @@
         mInfo = info;
         mFromTitle = info.title;
         mFromLabelState = info.getFromLabelState();
-        ArrayList<WorkspaceItemInfo> children = info.contents;
+        ArrayList<WorkspaceItemInfo> children = info.getContents();
         Collections.sort(children, ITEM_POS_COMPARATOR);
         updateItemLocationsInDatabaseBatch(true);
 
@@ -626,7 +626,7 @@
         // onDropComplete. Perform cleanup once drag-n-drop ends.
         mDragController.addDragListener(this);
 
-        ArrayList<WorkspaceItemInfo> items = new ArrayList<>(mInfo.contents);
+        ArrayList<WorkspaceItemInfo> items = new ArrayList<>(mInfo.getContents());
         mEmptyCellRank = items.size();
         items.add(null);    // Add an empty spot at the end
 
@@ -639,7 +639,7 @@
      * is played.
      */
     public void animateOpen() {
-        animateOpen(mInfo.contents, 0);
+        animateOpen(mInfo.getContents(), 0);
     }
 
     /**
@@ -1097,9 +1097,9 @@
                 mActivityContext.getDeviceProfile()).setFolderInfo(mInfo);
 
         ArrayList<ItemInfo> items = new ArrayList<>();
-        int total = mInfo.contents.size();
+        int total = mInfo.getContents().size();
         for (int i = 0; i < total; i++) {
-            WorkspaceItemInfo itemInfo = mInfo.contents.get(i);
+            WorkspaceItemInfo itemInfo = mInfo.getContents().get(i);
             if (verifier.updateRankAndPos(itemInfo, i)) {
                 items.add(itemInfo);
             }
@@ -1113,7 +1113,7 @@
                 FolderNameInfos nameInfos = new FolderNameInfos();
                 FolderNameProvider fnp = FolderNameProvider.newInstance(getContext());
                 fnp.getSuggestedFolderName(
-                        getContext(), mInfo.contents, nameInfos);
+                        getContext(), mInfo.getContents(), nameInfos);
                 mInfo.suggestedFolderNames = nameInfos;
             });
         }
@@ -1217,7 +1217,7 @@
     }
 
     public int getItemCount() {
-        return mInfo.contents.size();
+        return mInfo.getContents().size();
     }
 
     void replaceFolderWithFinalItem() {
diff --git a/src/com/android/launcher3/folder/FolderGridOrganizer.java b/src/com/android/launcher3/folder/FolderGridOrganizer.java
index cc24761..593673d 100644
--- a/src/com/android/launcher3/folder/FolderGridOrganizer.java
+++ b/src/com/android/launcher3/folder/FolderGridOrganizer.java
@@ -57,7 +57,7 @@
      * Updates the organizer with the provided folder info
      */
     public FolderGridOrganizer setFolderInfo(FolderInfo info) {
-        return setContentSize(info.contents.size());
+        return setContentSize(info.getContents().size());
     }
 
     /**
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index ee0d5fc..62ce311 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -215,7 +215,7 @@
 
         // Keep the notification dot up to date with the sum of all the content's dots.
         FolderDotInfo folderDotInfo = new FolderDotInfo();
-        for (WorkspaceItemInfo si : folderInfo.contents) {
+        for (WorkspaceItemInfo si : folderInfo.getContents()) {
             folderDotInfo.addDotInfo(activity.getDotInfoForItem(si));
         }
         icon.setDotInfo(folderDotInfo);
@@ -422,7 +422,7 @@
             FolderNameInfos nameInfos = new FolderNameInfos();
             Executors.MODEL_EXECUTOR.post(() -> {
                 d.folderNameProvider.getSuggestedFolderName(
-                        getContext(), mInfo.contents, nameInfos);
+                        getContext(), mInfo.getContents(), nameInfos);
                 postDelayed(() -> {
                     setLabelSuggestion(nameInfos, d.logInstanceId);
                     invalidate();
@@ -487,7 +487,7 @@
         }
         mFolder.notifyDrop();
         onDrop(item, d, null, 1.0f,
-                itemReturnedOnFailedDrop ? item.rank : mInfo.contents.size(),
+                itemReturnedOnFailedDrop ? item.rank : mInfo.getContents().size(),
                 itemReturnedOnFailedDrop
         );
     }
@@ -666,7 +666,7 @@
      * Returns the list of items which should be visible in the preview
      */
     public List<WorkspaceItemInfo> getPreviewItemsOnPage(int page) {
-        return mPreviewVerifier.setFolderInfo(mInfo).previewItemsForPage(page, mInfo.contents);
+        return mPreviewVerifier.setFolderInfo(mInfo).previewItemsForPage(page, mInfo.getContents());
     }
 
     @Override
@@ -809,7 +809,7 @@
      * Returns a formatted accessibility title for folder
      */
     public String getAccessiblityTitle(CharSequence title) {
-        int size = mInfo.contents.size();
+        int size = mInfo.getContents().size();
         if (size < MAX_NUM_ITEMS_IN_PREVIEW) {
             return getContext().getString(R.string.folder_name_format_exact, title, size);
         } else {
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index bf59594..5d2bb3a 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -35,7 +35,7 @@
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.IntSparseArrayMap;
 import com.android.launcher3.util.Preconditions;
@@ -62,7 +62,7 @@
      * name edit box can also be used to provide suggestion.
      */
     public static final int SUGGEST_MAX = 4;
-    protected IntSparseArrayMap<FolderInfo> mFolderInfos;
+    protected IntSparseArrayMap<CollectionInfo> mCollectionInfos;
     protected List<AppInfo> mAppInfos;
 
     /**
@@ -79,7 +79,7 @@
     }
 
     public static FolderNameProvider newInstance(Context context, List<AppInfo> appInfos,
-            IntSparseArrayMap<FolderInfo> folderInfos) {
+            IntSparseArrayMap<CollectionInfo> folderInfos) {
         Preconditions.assertWorkerThread();
         FolderNameProvider fnp = Overrides.getObject(FolderNameProvider.class,
                 context.getApplicationContext(), R.string.folder_name_provider_class);
@@ -93,9 +93,9 @@
                 new FolderNameWorker());
     }
 
-    private void load(List<AppInfo> appInfos, IntSparseArrayMap<FolderInfo> folderInfos) {
+    private void load(List<AppInfo> appInfos, IntSparseArrayMap<CollectionInfo> folderInfos) {
         mAppInfos = appInfos;
-        mFolderInfos = folderInfos;
+        mCollectionInfos = folderInfos;
     }
 
     /**
@@ -195,7 +195,7 @@
         @Override
         public void execute(@NonNull final LauncherAppState app,
                 @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
-            mFolderInfos = dataModel.folders.clone();
+            mCollectionInfos = dataModel.collections.clone();
             mAppInfos = Arrays.asList(apps.copyData());
         }
     }
diff --git a/src/com/android/launcher3/folder/LauncherDelegate.java b/src/com/android/launcher3/folder/LauncherDelegate.java
index 78298b3..33bcf21 100644
--- a/src/com/android/launcher3/folder/LauncherDelegate.java
+++ b/src/com/android/launcher3/folder/LauncherDelegate.java
@@ -93,7 +93,7 @@
                         // folder
                         CellLayout cellLayout = mLauncher.getCellLayout(info.container,
                                 mLauncher.getCellPosMapper().mapModelToPresenter(info).screenId);
-                        finalItem =  info.contents.remove(0);
+                        finalItem =  info.getContents().remove(0);
                         newIcon = mLauncher.getItemInflater().inflateItem(
                                 finalItem, mLauncher.getModelWriter(), cellLayout);
                         mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem,
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 9aee379..6b3bb51 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -82,6 +82,8 @@
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -388,16 +390,16 @@
         addInScreenFromBind(icon, info);
     }
 
-    private void inflateAndAddCollectionIcon(FolderInfo info) {
+    private void inflateAndAddCollectionIcon(CollectionInfo info) {
         boolean isOnDesktop = info.container == Favorites.CONTAINER_DESKTOP;
         CellLayout screen = isOnDesktop
                 ? mWorkspaceScreens.get(info.screenId)
                 : mHotseat;
-        FrameLayout folderIcon = info.itemType == Favorites.ITEM_TYPE_FOLDER
-                ? FolderIcon.inflateIcon(R.layout.folder_icon, this, screen, info)
-                : AppPairIcon.inflateIcon(R.layout.app_pair_icon, this, screen, info,
+        FrameLayout collectionIcon = info.itemType == Favorites.ITEM_TYPE_FOLDER
+                ? FolderIcon.inflateIcon(R.layout.folder_icon, this, screen, (FolderInfo) info)
+                : AppPairIcon.inflateIcon(R.layout.app_pair_icon, this, screen, (AppPairInfo) info,
                         isOnDesktop ? DISPLAY_WORKSPACE : DISPLAY_TASKBAR);
-        addInScreenFromBind(folderIcon, info);
+        addInScreenFromBind(collectionIcon, info);
     }
 
     private void inflateAndAddWidgets(
@@ -501,7 +503,7 @@
                     break;
                 case Favorites.ITEM_TYPE_FOLDER:
                 case Favorites.ITEM_TYPE_APP_PAIR:
-                    inflateAndAddCollectionIcon((FolderInfo) itemInfo);
+                    inflateAndAddCollectionIcon((CollectionInfo) itemInfo);
                     break;
                 default:
                     break;
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 96a8da9..ce563b7 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -31,7 +31,7 @@
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -131,8 +131,8 @@
                 int screenId = coords[0];
 
                 ItemInfo itemInfo;
-                if (item instanceof WorkspaceItemInfo || item instanceof FolderInfo ||
-                        item instanceof LauncherAppWidgetInfo) {
+                if (item instanceof WorkspaceItemInfo || item instanceof CollectionInfo
+                        || item instanceof LauncherAppWidgetInfo) {
                     itemInfo = item;
                 } else if (item instanceof WorkspaceItemFactory) {
                     itemInfo = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 0e1c8f4..44e45da 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -44,6 +44,7 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -102,9 +103,9 @@
     public final ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>();
 
     /**
-     * Map of id to FolderInfos of all the folders created by LauncherModel
+     * Map of id to CollectionInfos of all the folders or app pairs created by LauncherModel
      */
-    public final IntSparseArrayMap<FolderInfo> folders = new IntSparseArrayMap<>();
+    public final IntSparseArrayMap<CollectionInfo> collections = new IntSparseArrayMap<>();
 
     /**
      * Extra container based items
@@ -144,7 +145,7 @@
     public synchronized void clear() {
         workspaceItems.clear();
         appWidgets.clear();
-        folders.clear();
+        collections.clear();
         itemsIdMap.clear();
         deepShortcutMap.clear();
         extraItems.clear();
@@ -179,9 +180,9 @@
         for (int i = 0; i < appWidgets.size(); i++) {
             writer.println(prefix + '\t' + appWidgets.get(i).toString());
         }
-        writer.println(prefix + " ---- folder items ");
-        for (int i = 0; i < folders.size(); i++) {
-            writer.println(prefix + '\t' + folders.valueAt(i).toString());
+        writer.println(prefix + " ---- collection items ");
+        for (int i = 0; i < collections.size(); i++) {
+            writer.println(prefix + '\t' + collections.valueAt(i).toString());
         }
         writer.println(prefix + " ---- extra items ");
         for (int i = 0; i < extraItems.size(); i++) {
@@ -211,12 +212,12 @@
             switch (item.itemType) {
                 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
                 case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
-                    folders.remove(item.id);
+                    collections.remove(item.id);
                     if (FeatureFlags.IS_STUDIO_BUILD) {
                         for (ItemInfo info : itemsIdMap) {
                             if (info.container == item.id) {
-                                // We are deleting a folder which still contains items that
-                                // think they are contained by that folder.
+                                // We are deleting a collection which still contains items that
+                                // think they are contained by that collection.
                                 String msg = "deleting a collection (" + item + ") which still "
                                         + "contains items (" + info + ")";
                                 Log.e(TAG, msg);
@@ -259,7 +260,7 @@
         switch (item.itemType) {
             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
             case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
-                folders.put(item.id, (FolderInfo) item);
+                collections.put(item.id, (CollectionInfo) item);
                 workspaceItems.add(item);
                 break;
             case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
@@ -269,14 +270,14 @@
                     workspaceItems.add(item);
                 } else {
                     if (newItem) {
-                        if (!folders.containsKey(item.container)) {
+                        if (!collections.containsKey(item.container)) {
                             // Adding an item to a nonexistent collection.
                             String msg = "attempted to add item: " + item + " to a nonexistent app"
                                     + " collection";
                             Log.e(TAG, msg);
                         }
                     } else {
-                        findOrMakeFolder(item.container).add((WorkspaceItemInfo) item, false);
+                        findOrMakeFolder(item.container).add((WorkspaceItemInfo) item);
                     }
                 }
                 break;
@@ -371,15 +372,18 @@
      * Return an existing FolderInfo object if we have encountered this ID previously,
      * or make a new one.
      */
-    public synchronized FolderInfo findOrMakeFolder(int id) {
+    public synchronized CollectionInfo findOrMakeFolder(int id) {
         // See if a placeholder was created for us already
-        FolderInfo folderInfo = folders.get(id);
-        if (folderInfo == null) {
-            // No placeholder -- create a new instance
-            folderInfo = new FolderInfo();
-            folders.put(id, folderInfo);
+        CollectionInfo collectionInfo = collections.get(id);
+        if (collectionInfo == null) {
+            // No placeholder -- create a new blank folder instance. At this point, we don't know
+            // if the desired container is supposed to be a folder or an app pair. In the case that
+            // it is an app pair, the blank folder will be replaced by a blank app pair when the app
+            // pair is getting processed, in WorkspaceItemProcessor.processFolderOrAppPair().
+            collectionInfo = new FolderInfo();
+            collections.put(id, collectionInfo);
         }
-        return folderInfo;
+        return collectionInfo;
     }
 
     /**
diff --git a/src/com/android/launcher3/model/DeviceGridState.java b/src/com/android/launcher3/model/DeviceGridState.java
index 8c68eb8..729b381 100644
--- a/src/com/android/launcher3/model/DeviceGridState.java
+++ b/src/com/android/launcher3/model/DeviceGridState.java
@@ -156,11 +156,11 @@
     }
 
     public Integer getColumns() {
-        return Integer.parseInt(String.valueOf(mGridSizeString.charAt(0)));
+        return Integer.parseInt(String.valueOf(mGridSizeString.split(",")[0]));
     }
 
     public Integer getRows() {
-        return Integer.parseInt(String.valueOf(mGridSizeString.charAt(2)));
+        return Integer.parseInt(String.valueOf(mGridSizeString.split(",")[1]));
     }
 
     @Override
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java
index 9e91b9d..1deb665 100644
--- a/src/com/android/launcher3/model/FirstScreenBroadcast.java
+++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java
@@ -36,6 +36,7 @@
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -67,7 +68,8 @@
     private static final String ACTION_FIRST_SCREEN_ACTIVE_INSTALLS
             = "com.android.launcher3.action.FIRST_SCREEN_ACTIVE_INSTALLS";
 
-    private static final String FOLDER_ITEM_EXTRA = "folderItem";
+    // String retained as "folderItem" for back-compatibility reasons.
+    private static final String COLLECTION_ITEM_EXTRA = "folderItem";
     private static final String WORKSPACE_ITEM_EXTRA = "workspaceItem";
     private static final String HOTSEAT_ITEM_EXTRA = "hotseatItem";
     private static final String WIDGET_ITEM_EXTRA = "widgetItem";
@@ -105,20 +107,19 @@
     @WorkerThread
     private void sendBroadcastToInstaller(Context context, String installerPackageName,
             Set<String> packages, List<ItemInfo> firstScreenItems) {
-        Set<String> folderItems = new HashSet<>();
+        Set<String> collectionItems = new HashSet<>();
         Set<String> workspaceItems = new HashSet<>();
         Set<String> hotseatItems = new HashSet<>();
         Set<String> widgetItems = new HashSet<>();
 
         for (ItemInfo info : firstScreenItems) {
-            if (info instanceof FolderInfo) {
-                FolderInfo folderInfo = (FolderInfo) info;
-                String folderItemInfoPackage;
-                for (ItemInfo folderItemInfo : cloneOnMainThread(folderInfo.contents)) {
-                    folderItemInfoPackage = getPackageName(folderItemInfo);
-                    if (folderItemInfoPackage != null
-                            && packages.contains(folderItemInfoPackage)) {
-                        folderItems.add(folderItemInfoPackage);
+            if (info instanceof CollectionInfo ci) {
+                String collectionItemInfoPackage;
+                for (ItemInfo collectionItemInfo : cloneOnMainThread(ci.getContents())) {
+                    collectionItemInfoPackage = getPackageName(collectionItemInfo);
+                    if (collectionItemInfoPackage != null
+                            && packages.contains(collectionItemInfoPackage)) {
+                        collectionItems.add(collectionItemInfoPackage);
                     }
                 }
             }
@@ -137,13 +138,13 @@
         }
 
         if (DEBUG) {
-            printList(installerPackageName, "Folder item", folderItems);
+            printList(installerPackageName, "Collection item", collectionItems);
             printList(installerPackageName, "Workspace item", workspaceItems);
             printList(installerPackageName, "Hotseat item", hotseatItems);
             printList(installerPackageName, "Widget item", widgetItems);
         }
 
-        if (folderItems.isEmpty()
+        if (collectionItems.isEmpty()
                 && workspaceItems.isEmpty()
                 && hotseatItems.isEmpty()
                 && widgetItems.isEmpty()) {
@@ -152,7 +153,7 @@
         }
         context.sendBroadcast(new Intent(ACTION_FIRST_SCREEN_ACTIVE_INSTALLS)
                 .setPackage(installerPackageName)
-                .putStringArrayListExtra(FOLDER_ITEM_EXTRA, new ArrayList<>(folderItems))
+                .putStringArrayListExtra(COLLECTION_ITEM_EXTRA, new ArrayList<>(collectionItems))
                 .putStringArrayListExtra(WORKSPACE_ITEM_EXTRA, new ArrayList<>(workspaceItems))
                 .putStringArrayListExtra(HOTSEAT_ITEM_EXTRA, new ArrayList<>(hotseatItems))
                 .putStringArrayListExtra(WIDGET_ITEM_EXTRA, new ArrayList<>(widgetItems))
@@ -180,7 +181,7 @@
     }
 
     /**
-     * Clone the provided list on UI thread. This is used for {@link FolderInfo#contents} which
+     * Clone the provided list on UI thread. This is used for {@link FolderInfo#getContents()} which
      * is always modified on UI thread.
      */
     @AnyThread
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index 15190c7..299c952 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -223,19 +223,13 @@
             screens.add(screenId);
         }
 
-        boolean preservePages = false;
-        if (screens.isEmpty() && FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.get()) {
-            preservePages = destDeviceState.compareTo(srcDeviceState) >= 0
-                    && destDeviceState.getColumns() - srcDeviceState.getColumns() <= 2;
-        }
-
         // Then we place the items on the screens
         for (int screenId : screens) {
             if (DEBUG) {
                 Log.d(TAG, "Migrating " + screenId);
             }
             solveGridPlacement(helper, srcReader,
-                    destReader, screenId, trgX, trgY, workspaceToBeAdded, false);
+                    destReader, screenId, trgX, trgY, workspaceToBeAdded);
             if (workspaceToBeAdded.isEmpty()) {
                 break;
             }
@@ -245,8 +239,8 @@
         // any of the screens, in this case we add them to new screens until all of them are placed.
         int screenId = destReader.mLastScreenId + 1;
         while (!workspaceToBeAdded.isEmpty()) {
-            solveGridPlacement(helper, srcReader,
-                    destReader, screenId, trgX, trgY, workspaceToBeAdded, preservePages);
+            solveGridPlacement(helper, srcReader, destReader, screenId, trgX, trgY,
+                    workspaceToBeAdded);
             screenId++;
         }
 
@@ -348,7 +342,7 @@
     private static void solveGridPlacement(@NonNull final DatabaseHelper helper,
             @NonNull final DbReader srcReader, @NonNull final DbReader destReader,
             final int screenId, final int trgX, final int trgY,
-            @NonNull final List<DbEntry> sortedItemsToPlace, final boolean matchingScreenIdOnly) {
+            @NonNull final List<DbEntry> sortedItemsToPlace) {
         final GridOccupancy occupied = new GridOccupancy(trgX, trgY);
         final Point trg = new Point(trgX, trgY);
         final Point next = new Point(0, screenId == 0
@@ -366,8 +360,6 @@
         Iterator<DbEntry> iterator = sortedItemsToPlace.iterator();
         while (iterator.hasNext()) {
             final DbEntry entry = iterator.next();
-            if (matchingScreenIdOnly && entry.screenId < screenId) continue;
-            if (matchingScreenIdOnly && entry.screenId > screenId) break;
             if (entry.minSpanX > trgX || entry.minSpanY > trgY) {
                 iterator.remove();
                 continue;
@@ -435,7 +427,8 @@
         }
     }
 
-    protected static class DbReader {
+    @VisibleForTesting
+    public static class DbReader {
 
         private final SQLiteDatabase mDb;
         private final String mTableName;
@@ -446,7 +439,7 @@
         private final Map<Integer, ArrayList<DbEntry>> mWorkspaceEntriesByScreenId =
                 new ArrayMap<>();
 
-        DbReader(SQLiteDatabase db, String tableName, Context context,
+        public DbReader(SQLiteDatabase db, String tableName, Context context,
                 Set<String> validPackages) {
             mDb = db;
             mTableName = tableName;
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index f3d04b7..30cccd5 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -20,7 +20,6 @@
 import static com.android.launcher3.Flags.enableLauncherBrMetricsFixed;
 import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
 import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
 import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
 import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
@@ -77,9 +76,12 @@
 import com.android.launcher3.icons.cache.IconCacheUpdateHandler;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.IconRequestInfo;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.InstallSessionHelper;
@@ -99,7 +101,6 @@
 import com.android.launcher3.widget.WidgetInflater;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -234,6 +235,7 @@
             if (Objects.equals(mApp.getInvariantDeviceProfile().dbFile, mDbName)) {
                 verifyNotStopped();
                 sanitizeFolders(mItemsDeleted);
+                sanitizeAppPairs();
                 sanitizeWidgetsShortcutsAndPackages();
                 logASplit("sanitizeData");
             }
@@ -482,14 +484,20 @@
     }
 
     /**
-     * After all items have been processed and added to the BgDataModel, this method requests
-     * high-res icons for the items that are part of an app pair
+     * After all items have been processed and added to the BgDataModel, this method sorts and
+     * requests high-res icons for the items that are part of an app pair.
      */
     private void processAppPairItems() {
-        mBgDataModel.workspaceItems.stream()
-                .filter((itemInfo -> itemInfo.itemType == ITEM_TYPE_APP_PAIR))
-                .forEach(fi -> ((FolderInfo) fi).contents.forEach(item ->
-                        mIconCache.getTitleAndIcon(item, false /*useLowResIcon*/)));
+        for (CollectionInfo collection : mBgDataModel.collections) {
+            if (!(collection instanceof AppPairInfo appPair)) {
+                continue;
+            }
+
+            appPair.getContents().sort(Folder.ITEM_POS_COMPARATOR);
+            // Fetch hi-res icons if needed.
+            appPair.getContents().stream().filter(ItemInfoWithIcon::usingLowResIcon)
+                    .forEach(member -> mIconCache.getTitleAndIcon(member, false));
+        }
     }
 
     /**
@@ -545,20 +553,21 @@
         // Sort the folder items, update ranks, and make sure all preview items are high res.
         List<FolderGridOrganizer> verifiers = mApp.getInvariantDeviceProfile().supportedProfiles
                 .stream().map(FolderGridOrganizer::new).toList();
-        for (FolderInfo folder : mBgDataModel.folders) {
-            Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);
+        for (CollectionInfo collection : mBgDataModel.collections) {
+            if (!(collection instanceof FolderInfo folder)) {
+                continue;
+            }
+
+            folder.getContents().sort(Folder.ITEM_POS_COMPARATOR);
             verifiers.forEach(verifier -> verifier.setFolderInfo(folder));
-            int size = folder.contents.size();
+            int size = folder.getContents().size();
 
             // Update ranks here to ensure there are no gaps caused by removed folder items.
             // Ranks are the source of truth for folder items, so cellX and cellY can be
             // ignored for now. Database will be updated once user manually modifies folder.
             for (int rank = 0; rank < size; ++rank) {
-                WorkspaceItemInfo info = folder.contents.get(rank);
-                // rank is used differently in app pairs, so don't reset
-                if (folder.itemType != ITEM_TYPE_APP_PAIR) {
-                    info.rank = rank;
-                }
+                WorkspaceItemInfo info = folder.getContents().get(rank);
+                info.rank = rank;
 
                 if (info.usingLowResIcon() && info.itemType == Favorites.ITEM_TYPE_APPLICATION
                         && verifiers.stream().anyMatch(it -> it.isItemInPreview(info.rank))) {
@@ -611,14 +620,32 @@
             IntArray deletedFolderIds = mApp.getModel().getModelDbController().deleteEmptyFolders();
             synchronized (mBgDataModel) {
                 for (int folderId : deletedFolderIds) {
-                    mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId));
-                    mBgDataModel.folders.remove(folderId);
+                    mBgDataModel.workspaceItems.remove(mBgDataModel.collections.get(folderId));
+                    mBgDataModel.collections.remove(folderId);
                     mBgDataModel.itemsIdMap.remove(folderId);
                 }
             }
         }
     }
 
+    /** Cleans up app pairs if they don't have the right number of member apps (2). */
+    private void sanitizeAppPairs() {
+        IntArray deletedAppPairIds = mApp.getModel().getModelDbController().deleteBadAppPairs();
+        IntArray deletedAppIds = mApp.getModel().getModelDbController().deleteUnparentedApps();
+
+        IntArray deleted = new IntArray();
+        deleted.addAll(deletedAppPairIds);
+        deleted.addAll(deletedAppIds);
+
+        synchronized (mBgDataModel) {
+            for (int id : deleted) {
+                mBgDataModel.workspaceItems.remove(mBgDataModel.collections.get(id));
+                mBgDataModel.collections.remove(id);
+                mBgDataModel.itemsIdMap.remove(id);
+            }
+        }
+    }
+
     private void sanitizeWidgetsShortcutsAndPackages() {
         Context context = mApp.getContext();
 
@@ -754,16 +781,16 @@
 
     private void loadFolderNames() {
         FolderNameProvider provider = FolderNameProvider.newInstance(mApp.getContext(),
-                mBgAllAppsList.data, mBgDataModel.folders);
+                mBgAllAppsList.data, mBgDataModel.collections);
 
         synchronized (mBgDataModel) {
-            for (int i = 0; i < mBgDataModel.folders.size(); i++) {
+            for (int i = 0; i < mBgDataModel.collections.size(); i++) {
                 FolderNameInfos suggestionInfos = new FolderNameInfos();
-                FolderInfo info = mBgDataModel.folders.valueAt(i);
-                if (info.suggestedFolderNames == null) {
-                    provider.getSuggestedFolderName(mApp.getContext(), info.contents,
+                CollectionInfo info = mBgDataModel.collections.valueAt(i);
+                if (info instanceof FolderInfo fi && fi.suggestedFolderNames == null) {
+                    provider.getSuggestedFolderName(mApp.getContext(), fi.getContents(),
                             suggestionInfos);
-                    info.suggestedFolderNames = suggestionInfos;
+                    fi.suggestedFolderNames = suggestionInfos;
                 }
             }
         }
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index 8ed554a..7e1d40d 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -15,11 +15,15 @@
  */
 package com.android.launcher3.model;
 
+import static android.provider.BaseColumns._ID;
 import static android.util.Base64.NO_PADDING;
 import static android.util.Base64.NO_WRAP;
 
 import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
+import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
 import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb;
 import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY;
 import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL;
@@ -391,6 +395,68 @@
         }
     }
 
+    /**
+     * Deletes any app pair that doesn't contain 2 member apps from the DB.
+     * @return Ids of deleted app pairs.
+     */
+    @WorkerThread
+    public IntArray deleteBadAppPairs() {
+        createDbIfNotExists();
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        try (SQLiteTransaction t = new SQLiteTransaction(db)) {
+            // Select all entries with ITEM_TYPE = ITEM_TYPE_APP_PAIR whose id does not appear
+            // exactly twice in the CONTAINER column.
+            String selection =
+                    ITEM_TYPE + " = " + ITEM_TYPE_APP_PAIR
+                            + " AND " + _ID +  " NOT IN"
+                            + " (SELECT " + CONTAINER + " FROM " + TABLE_NAME
+                            + " GROUP BY " + CONTAINER + " HAVING COUNT(*) = 2)";
+
+            IntArray appPairIds = LauncherDbUtils.queryIntArray(false, db, TABLE_NAME,
+                    _ID, selection, null, null);
+            if (!appPairIds.isEmpty()) {
+                db.delete(TABLE_NAME, Utilities.createDbSelectionQuery(
+                        _ID, appPairIds), null);
+            }
+            t.commit();
+            return appPairIds;
+        } catch (SQLException ex) {
+            Log.e(TAG, ex.getMessage(), ex);
+            return new IntArray();
+        }
+    }
+
+    /**
+     * Deletes any app with a container id that doesn't exist.
+     * @return Ids of deleted apps.
+     */
+    @WorkerThread
+    public IntArray deleteUnparentedApps() {
+        createDbIfNotExists();
+
+        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+        try (SQLiteTransaction t = new SQLiteTransaction(db)) {
+            // Select all entries whose container id does not appear in the database.
+            String selection =
+                    CONTAINER + " >= 0"
+                            + " AND " + CONTAINER + " NOT IN"
+                            + " (SELECT " + _ID + " FROM " + TABLE_NAME + ")";
+
+            IntArray appIds = LauncherDbUtils.queryIntArray(false, db, TABLE_NAME,
+                    _ID, selection, null, null);
+            if (!appIds.isEmpty()) {
+                db.delete(TABLE_NAME, Utilities.createDbSelectionQuery(
+                        _ID, appIds), null);
+            }
+            t.commit();
+            return appIds;
+        } catch (SQLException ex) {
+            Log.e(TAG, ex.getMessage(), ex);
+            return new IntArray();
+        }
+    }
+
     private static void addModifiedTime(ContentValues values) {
         values.put(LauncherSettings.Favorites.MODIFIED, System.currentTimeMillis());
     }
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 55093a3..b477cb1 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -37,7 +37,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -275,7 +275,7 @@
     public void deleteItemsFromDatabase(@NonNull final Predicate<ItemInfo> matcher,
             @Nullable final String reason) {
         deleteItemsFromDatabase(StreamSupport.stream(mBgDataModel.itemsIdMap.spliterator(), false)
-                        .filter(matcher).collect(Collectors.toList()), reason);
+                .filter(matcher).collect(Collectors.toList()), reason);
     }
 
     /**
@@ -302,15 +302,15 @@
     /**
      * Remove the specified folder and all its contents from the database.
      */
-    public void deleteFolderAndContentsFromDatabase(final FolderInfo info) {
+    public void deleteCollectionAndContentsFromDatabase(final CollectionInfo info) {
         ModelVerifier verifier = new ModelVerifier();
         notifyDelete(Collections.singleton(info));
 
         enqueueDeleteRunnable(newModelTask(() -> {
             mModel.getModelDbController().delete(Favorites.TABLE_NAME,
                     Favorites.CONTAINER + "=" + info.id, null);
-            mBgDataModel.removeItem(mContext, info.contents);
-            info.contents.clear();
+            mBgDataModel.removeItem(mContext, info.getContents());
+            info.getContents().clear();
 
             mModel.getModelDbController().delete(Favorites.TABLE_NAME,
                     Favorites._ID + "=" + info.id, null);
@@ -458,12 +458,12 @@
 
                 if (item.container != Favorites.CONTAINER_DESKTOP &&
                         item.container != Favorites.CONTAINER_HOTSEAT) {
-                    // Item is in a folder, make sure this folder exists
-                    if (!mBgDataModel.folders.containsKey(item.container)) {
+                    // Item is in a collection, make sure this collection exists
+                    if (!mBgDataModel.collections.containsKey(item.container)) {
                         // An items container is being set to a that of an item which is not in
                         // the list of Folders.
                         String msg = "item: " + item + " container being set to: " +
-                                item.container + ", not in the list of folders";
+                                item.container + ", not in the list of collections";
                         Log.e(TAG, msg);
                     }
                 }
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 0ba468d..ea1ae2e 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -361,17 +361,10 @@
         }
 
         if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
-            // This predicate is used to mark an ItemInfo for removal if its package or component
-            // is marked for removal.
-            Predicate<ItemInfo> removeAppMatch =
+            Predicate<ItemInfo> removeMatch =
                     ItemInfoMatcher.ofPackages(removedPackages, mUser)
                             .or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
                             .and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
-            // This predicate is used to mark an app pair for removal if it contains an app marked
-            // for removal.
-            Predicate<ItemInfo> removeAppPairMatch =
-                    ItemInfoMatcher.forAppPairMatch(removeAppMatch);
-            Predicate<ItemInfo> removeMatch = removeAppMatch.or(removeAppPairMatch);
             deleteAndBindComponentsRemoved(removeMatch,
                     "removed because the corresponding package or component is removed. "
                             + "mOp=" + mOp + " removedPackages=" + removedPackages.stream().collect(
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index 22e5eb4..aa29290 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -32,6 +32,8 @@
 import com.android.launcher3.Utilities
 import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError
 import com.android.launcher3.logging.FileLog
+import com.android.launcher3.model.data.AppPairInfo
+import com.android.launcher3.model.data.FolderInfo
 import com.android.launcher3.model.data.IconRequestInfo
 import com.android.launcher3.model.data.ItemInfoWithIcon
 import com.android.launcher3.model.data.LauncherAppWidgetInfo
@@ -360,25 +362,40 @@
     }
 
     /**
-     * Loads the folder information from the database and formats it into a FolderInfo. Some of the
-     * processing for folder content items is done in LoaderTask after all the items in the
-     * workspace have been loaded. The loaded FolderInfos are stored in the BgDataModel.
+     * Loads CollectionInfo information from the database and formats it. This function runs while
+     * LoaderTask is still active; some of the processing for folder content items is done after all
+     * the items in the workspace have been loaded. The loaded and formatted CollectionInfo is then
+     * stored in the BgDataModel.
      */
     private fun processFolderOrAppPair() {
-        val folderInfo =
-            bgDataModel.findOrMakeFolder(c.id).apply {
-                c.applyCommonProperties(this)
-                itemType = c.itemType
-                // Do not trim the folder label, as is was set by the user.
-                title = c.getString(c.mTitleIndex)
-                spanX = 1
-                spanY = 1
-                options = c.options
-            }
+        var collection = bgDataModel.findOrMakeFolder(c.id)
+        // If we generated a placeholder Folder before this point, it may need to be replaced with
+        // an app pair.
+        if (c.itemType == Favorites.ITEM_TYPE_APP_PAIR && collection is FolderInfo) {
+            val folderInfo: FolderInfo = collection
+            val newAppPair = AppPairInfo()
+            // Move the placeholder's contents over to the new app pair.
+            folderInfo.contents.forEach(newAppPair::add)
+            collection = newAppPair
+            // Remove the placeholder and add the app pair into the data model.
+            bgDataModel.collections.remove(c.id)
+            bgDataModel.collections.put(c.id, collection)
+        }
 
-        // no special handling required for restored folders
+        c.applyCommonProperties(collection)
+        // Do not trim the folder label, as is was set by the user.
+        collection.title = c.getString(c.mTitleIndex)
+        collection.spanX = 1
+        collection.spanY = 1
+        if (collection is FolderInfo) {
+            collection.options = c.options
+        } else {
+            // An app pair may be inside another folder, so it needs to preserve rank information.
+            collection.rank = c.rank
+        }
+
         c.markRestored()
-        c.checkAndAddItem(folderInfo, bgDataModel, memoryLogger)
+        c.checkAndAddItem(collection, bgDataModel, memoryLogger)
     }
 
     /**
diff --git a/src/com/android/launcher3/model/data/AppPairInfo.kt b/src/com/android/launcher3/model/data/AppPairInfo.kt
new file mode 100644
index 0000000..4081316
--- /dev/null
+++ b/src/com/android/launcher3/model/data/AppPairInfo.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 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.model.data
+
+import android.content.Context
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.logger.LauncherAtom
+import com.android.launcher3.views.ActivityContext
+
+/** A type of app collection that launches multiple apps into split screen. */
+class AppPairInfo() : CollectionInfo() {
+    init {
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR
+    }
+
+    /** Convenience constructor, calls primary constructor and init block */
+    constructor(app1: WorkspaceItemInfo, app2: WorkspaceItemInfo) : this() {
+        add(app1)
+        add(app2)
+    }
+
+    /** Adds an element to the contents array. */
+    override fun add(item: WorkspaceItemInfo) {
+        contents.add(item)
+    }
+
+    /** Returns the first app in the pair. */
+    fun getFirstApp() = contents[0]
+
+    /** Returns the second app in the pair. */
+    fun getSecondApp() = contents[1]
+
+    /** Returns if either of the app pair members is currently disabled. */
+    override fun isDisabled() = anyMatch { it.isDisabled }
+
+    /** Checks if the app pair is launchable at the current screen size. */
+    fun isLaunchable(context: Context) =
+        (ActivityContext.lookupContext(context) as ActivityContext).getDeviceProfile().isTablet ||
+            noneMatch { it.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE) }
+
+    /** Generates an ItemInfo for logging. */
+    override fun buildProto(cInfo: CollectionInfo?): LauncherAtom.ItemInfo {
+        val appPairIcon = LauncherAtom.FolderIcon.newBuilder().setCardinality(contents.size)
+        appPairIcon.setLabelInfo(title.toString())
+        return getDefaultItemInfoBuilder()
+            .setFolderIcon(appPairIcon)
+            .setRank(rank)
+            .setContainerInfo(getContainerInfo())
+            .build()
+    }
+}
diff --git a/src/com/android/launcher3/model/data/CollectionInfo.kt b/src/com/android/launcher3/model/data/CollectionInfo.kt
new file mode 100644
index 0000000..2b865a5
--- /dev/null
+++ b/src/com/android/launcher3/model/data/CollectionInfo.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 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.model.data
+
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.logger.LauncherAtom
+import com.android.launcher3.util.ContentWriter
+import java.util.function.Predicate
+
+abstract class CollectionInfo : ItemInfo() {
+    var contents: ArrayList<WorkspaceItemInfo> = ArrayList()
+
+    abstract fun add(item: WorkspaceItemInfo)
+
+    /** Convenience function. Checks contents to see if any match a given predicate. */
+    fun anyMatch(matcher: Predicate<in WorkspaceItemInfo>): Boolean {
+        return contents.stream().anyMatch(matcher)
+    }
+
+    /** Convenience function. Returns true if none of the contents match a given predicate. */
+    fun noneMatch(matcher: Predicate<in WorkspaceItemInfo>): Boolean {
+        return contents.stream().noneMatch(matcher)
+    }
+
+    override fun onAddToDatabase(writer: ContentWriter) {
+        super.onAddToDatabase(writer)
+        writer.put(LauncherSettings.Favorites.TITLE, title)
+    }
+
+    /** Returns the collection wrapped as {@link LauncherAtom.ItemInfo} for logging. */
+    override fun buildProto(): LauncherAtom.ItemInfo {
+        return buildProto(null)
+    }
+}
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index 83ba2b3..1bbb2fe 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -24,8 +24,6 @@
 import static com.android.launcher3.logger.LauncherAtom.Attribute.MANUAL_LABEL;
 import static com.android.launcher3.logger.LauncherAtom.Attribute.SUGGESTED_LABEL;
 
-import android.os.Process;
-
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
@@ -49,7 +47,7 @@
 /**
  * Represents a folder containing shortcuts or apps.
  */
-public class FolderInfo extends ItemInfo {
+public class FolderInfo extends CollectionInfo {
 
     public static final int NO_FLAGS = 0x00000000;
 
@@ -100,27 +98,15 @@
 
     public FolderNameInfos suggestedFolderNames;
 
-    /**
-     * The apps and shortcuts
-     */
-    public ArrayList<WorkspaceItemInfo> contents = new ArrayList<>();
-
     private ArrayList<FolderListener> mListeners = new ArrayList<>();
 
     public FolderInfo() {
         itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
-        user = Process.myUserHandle();
     }
 
-    /**
-     * Create an app pair, a type of app collection that launches multiple apps into split screen
-     */
-    public static FolderInfo createAppPair(WorkspaceItemInfo app1, WorkspaceItemInfo app2) {
-        FolderInfo newAppPair = new FolderInfo();
-        newAppPair.itemType = LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
-        newAppPair.add(app1, /* animate */ false);
-        newAppPair.add(app2, /* animate */ false);
-        return newAppPair;
+    /** Adds a app or shortcut to the contents array without animation. */
+    public void add(@NonNull WorkspaceItemInfo item) {
+        add(item, false /* animate */);
     }
 
     /**
@@ -129,15 +115,15 @@
      * @param item
      */
     public void add(WorkspaceItemInfo item, boolean animate) {
-        add(item, contents.size(), animate);
+        add(item, getContents().size(), animate);
     }
 
     /**
      * Add an app or shortcut for a specified rank.
      */
     public void add(WorkspaceItemInfo item, int rank, boolean animate) {
-        rank = Utilities.boundToRange(rank, 0, contents.size());
-        contents.add(rank, item);
+        rank = Utilities.boundToRange(rank, 0, getContents().size());
+        getContents().add(rank, item);
         for (int i = 0; i < mListeners.size(); i++) {
             mListeners.get(i).onAdd(item, rank);
         }
@@ -157,7 +143,7 @@
      * Remove all matching app or shortcut. Does not change the DB.
      */
     public void removeAll(List<WorkspaceItemInfo> items, boolean animate) {
-        contents.removeAll(items);
+        getContents().removeAll(items);
         for (int i = 0; i < mListeners.size(); i++) {
             mListeners.get(i).onRemove(items);
         }
@@ -167,8 +153,7 @@
     @Override
     public void onAddToDatabase(@NonNull ContentWriter writer) {
         super.onAddToDatabase(writer);
-        writer.put(LauncherSettings.Favorites.TITLE, title)
-                .put(LauncherSettings.Favorites.OPTIONS, options);
+        writer.put(LauncherSettings.Favorites.OPTIONS, options);
     }
 
     public void addListener(FolderListener listener) {
@@ -219,9 +204,9 @@
 
     @NonNull
     @Override
-    public LauncherAtom.ItemInfo buildProto(@Nullable FolderInfo fInfo) {
+    public LauncherAtom.ItemInfo buildProto(@Nullable CollectionInfo cInfo) {
         FolderIcon.Builder folderIcon = FolderIcon.newBuilder()
-                .setCardinality(contents.size());
+                .setCardinality(getContents().size());
         if (LabelState.SUGGESTED.equals(getLabelState())) {
             folderIcon.setLabelInfo(title.toString());
         }
@@ -278,20 +263,11 @@
     public ItemInfo makeShallowCopy() {
         FolderInfo folderInfo = new FolderInfo();
         folderInfo.copyFrom(this);
-        folderInfo.contents = this.contents;
+        folderInfo.setContents(this.getContents());
         return folderInfo;
     }
 
     /**
-     * Returns {@link LauncherAtom.FolderIcon} wrapped as {@link LauncherAtom.ItemInfo} for logging.
-     */
-    @NonNull
-    @Override
-    public LauncherAtom.ItemInfo buildProto() {
-        return buildProto(null);
-    }
-
-    /**
      * Returns index of the accepted suggestion.
      */
     public OptionalInt getAcceptedSuggestionIndex() {
@@ -371,13 +347,4 @@
         }
         return LauncherAtom.ToState.TO_STATE_UNSPECIFIED;
     }
-
-    @Override
-    public boolean isDisabled() {
-        if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR) {
-            return contents.stream().anyMatch((WorkspaceItemInfo::isDisabled));
-        }
-
-        return super.isDisabled();
-    }
 }
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index f7cff78..8c3efd7 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -349,10 +349,9 @@
 
     /**
      * Creates {@link LauncherAtom.ItemInfo} with important fields and parent container info.
-     * @param fInfo
      */
     @NonNull
-    public LauncherAtom.ItemInfo buildProto(@Nullable final FolderInfo fInfo) {
+    public LauncherAtom.ItemInfo buildProto(@Nullable final CollectionInfo cInfo) {
         LauncherAtom.ItemInfo.Builder itemBuilder = getDefaultItemInfoBuilder();
         Optional<ComponentName> nullableComponent = Optional.ofNullable(getTargetComponent());
         switch (itemType) {
@@ -398,21 +397,21 @@
             default:
                 break;
         }
-        if (fInfo != null) {
+        if (cInfo != null) {
             LauncherAtom.FolderContainer.Builder folderBuilder =
                     LauncherAtom.FolderContainer.newBuilder();
             folderBuilder.setGridX(cellX).setGridY(cellY).setPageIndex(screenId);
 
-            switch (fInfo.container) {
+            switch (cInfo.container) {
                 case CONTAINER_HOTSEAT:
                 case CONTAINER_HOTSEAT_PREDICTION:
                     folderBuilder.setHotseat(LauncherAtom.HotseatContainer.newBuilder()
-                            .setIndex(fInfo.screenId));
+                            .setIndex(cInfo.screenId));
                     break;
                 case CONTAINER_DESKTOP:
                     folderBuilder.setWorkspace(LauncherAtom.WorkspaceContainer.newBuilder()
-                            .setPageIndex(fInfo.screenId)
-                            .setGridX(fInfo.cellX).setGridY(fInfo.cellY));
+                            .setPageIndex(cInfo.screenId)
+                            .setGridX(cInfo.cellX).setGridY(cInfo.cellY));
                     break;
             }
             itemBuilder.setContainerInfo(ContainerInfo.newBuilder().setFolder(folderBuilder));
diff --git a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
index 6fa8c54..f4dda55 100644
--- a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
@@ -271,8 +271,8 @@
 
     @NonNull
     @Override
-    public LauncherAtom.ItemInfo buildProto(@Nullable FolderInfo folderInfo) {
-        LauncherAtom.ItemInfo info = super.buildProto(folderInfo);
+    public LauncherAtom.ItemInfo buildProto(@Nullable CollectionInfo collectionInfo) {
+        LauncherAtom.ItemInfo info = super.buildProto(collectionInfo);
         return info.toBuilder()
                 .setWidget(info.getWidget().toBuilder().setWidgetFeatures(widgetFeatures))
                 .addItemAttributes(getAttribute(sourceContainer))
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 911568c..0c25e96 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -53,6 +53,7 @@
 import com.android.launcher3.logging.InstanceIdSequence;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -101,11 +102,9 @@
         if (tag instanceof WorkspaceItemInfo) {
             onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher);
         } else if (tag instanceof FolderInfo) {
-            if (v instanceof FolderIcon) {
-                onClickFolderIcon(v);
-            } else if (v instanceof AppPairIcon) {
-                onClickAppPairIcon(v);
-            }
+            onClickFolderIcon(v);
+        } else if (tag instanceof AppPairInfo) {
+            onClickAppPairIcon(v);
         } else if (tag instanceof AppInfo) {
             startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
         } else if (tag instanceof LauncherAppWidgetInfo) {
@@ -150,7 +149,7 @@
     private static void onClickAppPairIcon(View v) {
         Launcher launcher = Launcher.getLauncher(v.getContext());
         AppPairIcon appPairIcon = (AppPairIcon) v;
-        if (!appPairIcon.isLaunchableAtScreenSize()) {
+        if (!appPairIcon.getInfo().isLaunchable(launcher)) {
             // Display a message for app pairs that are disabled due to screen size
             boolean isFoldable = InvariantDeviceProfile.INSTANCE.get(launcher)
                     .supportedProfiles.stream().anyMatch(dp -> dp.isTwoPanels);
@@ -159,8 +158,8 @@
                             : R.string.app_pair_unlaunchable_at_screen_size,
                     Toast.LENGTH_SHORT).show();
         } else if (appPairIcon.getInfo().isDisabled()) {
-            WorkspaceItemInfo app1 = appPairIcon.getInfo().contents.get(0);
-            WorkspaceItemInfo app2 = appPairIcon.getInfo().contents.get(1);
+            WorkspaceItemInfo app1 = appPairIcon.getInfo().getFirstApp();
+            WorkspaceItemInfo app2 = appPairIcon.getInfo().getSecondApp();
             // Show the user why the app pair is disabled.
             if (app1.isDisabled() && !handleDisabledItemClicked(app1, launcher)) {
                 // If handleDisabledItemClicked() did not handle the error message, we initiate an
diff --git a/src/com/android/launcher3/util/ItemInflater.kt b/src/com/android/launcher3/util/ItemInflater.kt
index 0f8311d..ebf4656 100644
--- a/src/com/android/launcher3/util/ItemInflater.kt
+++ b/src/com/android/launcher3/util/ItemInflater.kt
@@ -29,6 +29,7 @@
 import com.android.launcher3.apppairs.AppPairIcon
 import com.android.launcher3.folder.FolderIcon
 import com.android.launcher3.model.ModelWriter
+import com.android.launcher3.model.data.AppPairInfo
 import com.android.launcher3.model.data.FolderInfo
 import com.android.launcher3.model.data.ItemInfo
 import com.android.launcher3.model.data.LauncherAppWidgetInfo
@@ -81,7 +82,7 @@
                     R.layout.app_pair_icon,
                     context,
                     parent,
-                    item as FolderInfo,
+                    item as AppPairInfo,
                     BubbleTextView.DISPLAY_WORKSPACE
                 )
             Favorites.ITEM_TYPE_APPWIDGET,
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index 3074111..063313a 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -65,20 +65,11 @@
      * Returns a matcher for items within folders.
      */
     public static Predicate<ItemInfo> forFolderMatch(Predicate<ItemInfo> childOperator) {
-        return info -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
+        return info -> info instanceof FolderInfo && ((FolderInfo) info).getContents().stream()
                 .anyMatch(childOperator);
     }
 
     /**
-     * Returns a matcher for items within app pairs.
-     */
-    public static Predicate<ItemInfo> forAppPairMatch(Predicate<ItemInfo> childOperator) {
-        Predicate<ItemInfo> isAppPair = info ->
-                info instanceof FolderInfo fi && fi.itemType == Favorites.ITEM_TYPE_APP_PAIR;
-        return isAppPair.and(forFolderMatch(childOperator));
-    }
-
-    /**
      * Returns a matcher for items with provided ids
      */
     public static Predicate<ItemInfo> ofItemIds(IntSet ids) {
diff --git a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
index 69786bb..02779ce 100644
--- a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
+++ b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
@@ -23,6 +23,7 @@
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.graphics.PreloadIconDrawable;
+import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -59,7 +60,7 @@
                                 : null);
             } else if (info instanceof FolderInfo && v instanceof FolderIcon) {
                 ((FolderIcon) v).updatePreviewItems(updates::contains);
-            } else if (info instanceof FolderInfo && v instanceof AppPairIcon appPairIcon) {
+            } else if (info instanceof AppPairInfo && v instanceof AppPairIcon appPairIcon) {
                 appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
             }
 
@@ -89,7 +90,7 @@
                 ((PendingAppWidgetHostView) v).applyState();
             } else if (v instanceof FolderIcon && info instanceof FolderInfo) {
                 ((FolderIcon) v).updatePreviewItems(updates::contains);
-            } else if (info instanceof FolderInfo && v instanceof AppPairIcon appPairIcon) {
+            } else if (info instanceof AppPairInfo && v instanceof AppPairIcon appPairIcon) {
                 appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
             }
             // process all the shortcuts
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
index a501960..a916252 100644
--- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -25,7 +25,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.PendingAddItemInfo;
 import com.android.launcher3.logger.LauncherAtom;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.widget.picker.WidgetRecommendationCategory;
 import com.android.launcher3.widget.util.WidgetSizes;
@@ -82,8 +82,8 @@
 
     @NonNull
     @Override
-    public LauncherAtom.ItemInfo buildProto(@Nullable FolderInfo folderInfo) {
-        LauncherAtom.ItemInfo info = super.buildProto(folderInfo);
+    public LauncherAtom.ItemInfo buildProto(@Nullable CollectionInfo collectionInfo) {
+        LauncherAtom.ItemInfo info = super.buildProto(collectionInfo);
         return info.toBuilder()
                 .addItemAttributes(LauncherAppWidgetInfo.getAttribute(sourceContainer))
                 .build();
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index ba6c4cf..fcd2571 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -27,7 +27,6 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.Process;
@@ -47,12 +46,9 @@
 import android.widget.Button;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-import android.window.BackEvent;
 
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.Px;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 import androidx.recyclerview.widget.DefaultItemAnimator;
 import androidx.recyclerview.widget.RecyclerView;
@@ -904,17 +900,6 @@
     }
 
     @Override
-    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
-    public void onBackProgressed(@NonNull BackEvent backEvent) {
-        super.onBackProgressed(backEvent);
-        // In two pane picker, scroll bar is always hidden.
-        if (!isTwoPane()) {
-            mFastScroller.setVisibility(
-                    backEvent.getProgress() > 0 ? View.INVISIBLE : View.VISIBLE);
-        }
-    }
-
-    @Override
     public void onBackInvoked() {
         if (mIsInSearchMode) {
             mSearchBar.reset();
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
index b86333c..0c3081f 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
@@ -26,7 +26,7 @@
 import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.model.ModelDbController;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
 import com.android.launcher3.util.ContentWriter;
@@ -73,9 +73,8 @@
                     ContentWriter writer = new ContentWriter(mContext);
                     ItemInfo item = mItemsToSubmit.get(i).get();
 
-                    if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
-                        FolderInfo folderInfo = (FolderInfo) item;
-                        for (ItemInfo itemInfo : folderInfo.contents) {
+                    if (item instanceof CollectionInfo ci) {
+                        for (ItemInfo itemInfo : ci.getContents()) {
                             itemInfo.container = i;
                             containerItems.add(itemInfo);
                         }
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index eea4fe5..476bda5 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -26,7 +26,7 @@
 import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.doNothing;
@@ -80,7 +80,7 @@
 
     private PrivateProfileManager mPrivateProfileManager;
     @Mock
-    private ActivityAllAppsContainerView mActivityAllAppsContainerView;
+    private ActivityAllAppsContainerView mAllApps;
     @Mock
     private StatsLogManager mStatsLogManager;
     @Mock
@@ -90,13 +90,13 @@
     @Mock
     private Context mContext;
     @Mock
-    private AllAppsStore mAllAppsStore;
+    private AllAppsStore<?> mAllAppsStore;
     @Mock
     private PackageManager mPackageManager;
     @Mock
     private LauncherApps mLauncherApps;
-
-    private boolean mRunnableCalled = false;
+    @Mock
+    private AllAppsRecyclerView mAllAppsRecyclerView;
 
     @Before
     public void setUp() {
@@ -105,8 +105,9 @@
                 .thenReturn(Arrays.asList(MAIN_HANDLE, PRIVATE_HANDLE));
         when(mUserCache.getUserInfo(Process.myUserHandle())).thenReturn(MAIN_ICON_INFO);
         when(mUserCache.getUserInfo(PRIVATE_HANDLE)).thenReturn(PRIVATE_ICON_INFO);
-        when(mActivityAllAppsContainerView.getContext()).thenReturn(mContext);
-        when(mActivityAllAppsContainerView.getAppsStore()).thenReturn(mAllAppsStore);
+        when(mAllApps.getContext()).thenReturn(mContext);
+        when(mAllApps.getAppsStore()).thenReturn(mAllAppsStore);
+        when(mAllApps.getActiveRecyclerView()).thenReturn(mAllAppsRecyclerView);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
         when(mPackageManager.resolveActivity(any(), any())).thenReturn(new ResolveInfo());
         when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps);
@@ -117,7 +118,7 @@
                 .thenReturn("com.android.launcher3.tests.privateProfileManager");
         when(mLauncherApps.getPreInstalledSystemPackages(any())).thenReturn(new ArrayList<>());
         mPrivateProfileManager = new PrivateProfileManager(mUserManager,
-                mActivityAllAppsContainerView, mStatsLogManager, mUserCache);
+                mAllApps, mStatsLogManager, mUserCache);
     }
 
     @Test
@@ -134,7 +135,7 @@
     public void unlockPrivateProfile_requestsQuietModeAsFalse() throws Exception {
         when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED)).thenReturn(true);
 
-        mPrivateProfileManager.unlockPrivateProfile(() -> {});
+        mPrivateProfileManager.unlockPrivateProfile();
 
         awaitTasksCompleted();
         Mockito.verify(mUserManager).requestQuietModeEnabled(false, PRIVATE_HANDLE);
@@ -160,20 +161,36 @@
 
     @Test
     @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/320703862
-    public void transitioningToUnlocked_resetCallsPendingRunnable() throws Exception {
+    public void transitioningToUnlocked_resetCallsPostUnlock() throws Exception {
         PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
         doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
         when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
                 .thenReturn(false);
+        doNothing().when(privateProfileManager).expandPrivateSpace();
         when(privateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
-        mRunnableCalled = false;
 
-        privateProfileManager.unlockPrivateProfile(this::testRunnable);
+        privateProfileManager.unlockPrivateProfile();
         privateProfileManager.reset();
 
         awaitTasksCompleted();
-        Mockito.verify(privateProfileManager).applyUnlockRunnable();
-        assertTrue("Unlock Runnable not Invoked", mRunnableCalled);
+        Mockito.verify(privateProfileManager).postUnlock();
+    }
+
+    @Test
+    @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+    public void transitioningToLocked_resetCallsExecuteLock() throws Exception {
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
+        when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
+                .thenReturn(true);
+        doNothing().when(privateProfileManager).expandPrivateSpace();
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+
+        privateProfileManager.lockPrivateProfile();
+        privateProfileManager.reset();
+
+        awaitTasksCompleted();
+        Mockito.verify(privateProfileManager).executeLock();
     }
 
     @Test
@@ -191,8 +208,4 @@
     private static void awaitTasksCompleted() throws Exception {
         UI_HELPER_EXECUTOR.submit(() -> null).get();
     }
-
-    private void testRunnable() {
-        mRunnableCalled = true;
-    }
 }
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
similarity index 75%
rename from tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
rename to tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
index 043461d..7ac276a 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
@@ -28,6 +28,10 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.AdditionalAnswers.answer;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.content.ComponentName;
@@ -39,6 +43,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Process;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.ImageButton;
@@ -51,8 +56,11 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.launcher3.R;
+import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.ActivityContextWrapper;
+import com.android.launcher3.util.UserIconInfo;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -61,14 +69,20 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class PrivateSpaceHeaderViewControllerTest {
+public class PrivateSpaceHeaderViewTest {
 
     private static final UserHandle MAIN_HANDLE = Process.myUserHandle();
     private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
+    private static final UserIconInfo MAIN_ICON_INFO =
+            new UserIconInfo(MAIN_HANDLE, UserIconInfo.TYPE_MAIN);
+    private static final UserIconInfo PRIVATE_ICON_INFO =
+            new UserIconInfo(PRIVATE_HANDLE, UserIconInfo.TYPE_PRIVATE);
+    private static final String CAMERA_PACKAGE_NAME = "com.android.launcher3.tests.camera";
     private static final int CONTAINER_HEADER_ELEMENT_COUNT = 1;
     private static final int LOCK_UNLOCK_BUTTON_COUNT = 1;
     private static final int PS_SETTINGS_BUTTON_COUNT_VISIBLE = 1;
@@ -84,37 +98,41 @@
     private static final float HEADER_PROTECTION_HEIGHT = 1F;
 
     private Context mContext;
-    private PrivateSpaceHeaderViewController mPsHeaderViewController;
     private RelativeLayout mPsHeaderLayout;
     private AlphabeticalAppsList<?> mAlphabeticalAppsList;
-    @Mock
     private PrivateProfileManager mPrivateProfileManager;
     @Mock
     private ActivityAllAppsContainerView mAllApps;
     @Mock
     private AllAppsStore<?> mAllAppsStore;
+    @Mock
+    private UserCache mUserCache;
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private StatsLogManager mStatsLogManager;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = new ActivityContextWrapper(getApplicationContext());
-        when(mPrivateProfileManager.getItemInfoMatcher()).thenReturn(info ->
-                info != null && info.user.equals(PRIVATE_HANDLE));
-        mPsHeaderViewController = new PrivateSpaceHeaderViewController(mAllApps,
-                mPrivateProfileManager);
+        when(mAllApps.getContext()).thenReturn(mContext);
+        when(mUserCache.getUserInfo(PRIVATE_HANDLE)).thenReturn(PRIVATE_ICON_INFO);
+        when(mUserCache.getUserProfiles())
+                .thenReturn(Arrays.asList(MAIN_HANDLE, PRIVATE_HANDLE));
+        when(mUserCache.getUserInfo(Process.myUserHandle())).thenReturn(MAIN_ICON_INFO);
+        mPrivateProfileManager = new PrivateProfileManager(mUserManager,
+                mAllApps, mStatsLogManager, mUserCache);
         mPsHeaderLayout = (RelativeLayout) LayoutInflater.from(mContext).inflate(
                 R.layout.private_space_header, null);
-        mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
-                null, mPrivateProfileManager);
-        mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
     }
 
     @Test
     public void privateProfileDisabled_psHeaderContainsLockedView() throws Exception {
         Bitmap unlockButton = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
-        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
-
-        mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
+        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
         awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;
@@ -137,6 +155,7 @@
                 assertEquals(View.GONE, view.getVisibility());
             }
         }
+
         assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
         assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
     }
@@ -145,10 +164,10 @@
     public void privateProfileEnabled_psHeaderContainsUnlockedView() throws Exception {
         Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
         Bitmap settingsImage = getBitmap(mContext.getDrawable(R.drawable.ic_ps_settings));
-        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(mPrivateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(true);
-
-        mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        when(privateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(true);
+        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
         awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;
@@ -177,6 +196,7 @@
                 assertEquals(View.GONE, view.getVisibility());
             }
         }
+
         assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
         assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
         assertEquals(PS_SETTINGS_BUTTON_COUNT_VISIBLE, totalSettingsImageView);
@@ -186,10 +206,10 @@
     public void privateProfileEnabledAndNoSettingsIntent_psHeaderContainsUnlockedView()
             throws Exception {
         Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
-        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(mPrivateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(false);
-
-        mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        when(privateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(false);
+        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
         awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;
@@ -216,6 +236,7 @@
                 assertEquals(View.GONE, view.getVisibility());
             }
         }
+
         assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
         assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
         assertEquals(PS_SETTINGS_BUTTON_COUNT_INVISIBLE, totalSettingsImageView);
@@ -224,9 +245,9 @@
     @Test
     public void privateProfileTransitioning_psHeaderContainsTransitionView() throws Exception {
         Bitmap transitionImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_transition_image));
-        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_TRANSITION);
-
-        mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_TRANSITION);
+        privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
         awaitTasksCompleted();
 
         int totalContainerHeaderView = 0;
@@ -248,6 +269,7 @@
                 assertEquals(View.GONE, view.getVisibility());
             }
         }
+
         assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
         assertEquals(PS_TRANSITION_IMAGE_COUNT, totalLockUnlockButtonView);
     }
@@ -255,18 +277,25 @@
     @Test
     public void scrollForViewToBeVisibleInContainer_withHeader() {
         when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
-        when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
-                .thenAnswer(answer(this::addPrivateSpaceHeader));
-        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
                 .thenReturn(iteminfo -> iteminfo.componentName == null
                         || !iteminfo.componentName.getPackageName()
-                        .equals("com.android.launcher3.tests.camera"));
-        when(mAllApps.getContext()).thenReturn(mContext);
-        mAlphabeticalAppsList.updateItemFilter(info -> info != null
-                && info.user.equals(MAIN_HANDLE));
+                        .equals(CAMERA_PACKAGE_NAME));
+        doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
+        doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
+                .addPrivateSpaceHeader(any());
+        doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
+        doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
         when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
         when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+        mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+                null, privateProfileManager);
+        mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
         int rows = (int) (ALL_APPS_HEIGHT - PS_HEADER_HEIGHT - HEADER_PROTECTION_HEIGHT);
         int position = rows * NUM_APP_COLS - (NUM_APP_COLS-1) + 1;
 
@@ -274,7 +303,7 @@
         assertEquals(NUM_PRIVATE_SPACE_APPS + 1 + 1,
                 mAlphabeticalAppsList.getAdapterItems().size());
         assertEquals(position,
-                mPsHeaderViewController.scrollForViewToBeVisibleInContainer(
+                privateProfileManager.scrollForViewToBeVisibleInContainer(
                         new AllAppsRecyclerView(mContext),
                         mAlphabeticalAppsList.getAdapterItems(),
                         PS_HEADER_HEIGHT,
@@ -284,18 +313,25 @@
     @Test
     public void scrollForViewToBeVisibleInContainer_withHeaderAndLessAppRowSpace() {
         when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
-        when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
-                .thenAnswer(answer(this::addPrivateSpaceHeader));
-        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
                 .thenReturn(iteminfo -> iteminfo.componentName == null
                         || !iteminfo.componentName.getPackageName()
-                        .equals("com.android.launcher3.tests.camera"));
-        when(mAllApps.getContext()).thenReturn(mContext);
-        mAlphabeticalAppsList.updateItemFilter(info -> info != null
-                && info.user.equals(MAIN_HANDLE));
+                        .equals(CAMERA_PACKAGE_NAME));
+        doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
+        doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
+                .addPrivateSpaceHeader(any());
+        doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
+        doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
         when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
         when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+        mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+                null, privateProfileManager);
+        mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
+
         int rows = (int) (ALL_APPS_HEIGHT - BIGGER_PS_HEADER_HEIGHT - HEADER_PROTECTION_HEIGHT);
         int position = rows * NUM_APP_COLS - (NUM_APP_COLS-1) + 1;
 
@@ -303,7 +339,7 @@
         assertEquals(NUM_PRIVATE_SPACE_APPS + 1 + 1,
                 mAlphabeticalAppsList.getAdapterItems().size());
         assertEquals(position,
-                mPsHeaderViewController.scrollForViewToBeVisibleInContainer(
+                privateProfileManager.scrollForViewToBeVisibleInContainer(
                         new AllAppsRecyclerView(mContext),
                         mAlphabeticalAppsList.getAdapterItems(),
                         BIGGER_PS_HEADER_HEIGHT,
@@ -313,21 +349,27 @@
     @Test
     public void scrollForViewToBeVisibleInContainer_withNoHeader() {
         when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
-        when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
-        when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+        PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+        when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+        when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
                 .thenReturn(iteminfo -> iteminfo.componentName == null
                         || !iteminfo.componentName.getPackageName()
-                        .equals("com.android.launcher3.tests.camera"));
-        when(mAllApps.getContext()).thenReturn(mContext);
-        mAlphabeticalAppsList.updateItemFilter(info -> info != null
-                && info.user.equals(MAIN_HANDLE));
+                        .equals(CAMERA_PACKAGE_NAME));
+        doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
+        doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
+        doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
         when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
         when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+        mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+                null, privateProfileManager);
+        mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
+        mAlphabeticalAppsList.updateItemFilter(info -> info != null
+                && info.user.equals(MAIN_HANDLE));
 
         // The number of adapterItems should be the private space apps + one main app.
         assertEquals(NUM_PRIVATE_SPACE_APPS + 1,
                 mAlphabeticalAppsList.getAdapterItems().size());
-        assertEquals(SCROLL_NO_WHERE, mPsHeaderViewController.scrollForViewToBeVisibleInContainer(
+        assertEquals(SCROLL_NO_WHERE, privateProfileManager.scrollForViewToBeVisibleInContainer(
                 new AllAppsRecyclerView(mContext),
                 mAlphabeticalAppsList.getAdapterItems(),
                 BIGGER_PS_HEADER_HEIGHT,
@@ -376,7 +418,7 @@
                 AppInfo(gmailComponentName, "Gmail", MAIN_HANDLE, new Intent());
         appInfos.add(gmailAppInfo);
         ComponentName privateCameraComponentName = new ComponentName(
-                "com.android.launcher3.tests.camera", "CameraActivity");
+                CAMERA_PACKAGE_NAME, "CameraActivity");
         for (int i = 0; i < NUM_PRIVATE_SPACE_APPS; i++) {
             AppInfo privateCameraAppInfo = new AppInfo(privateCameraComponentName,
                     "Private Camera " + i, PRIVATE_HANDLE, new Intent());
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt b/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
index c5dbce4..ff46987 100644
--- a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
+++ b/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
@@ -21,6 +21,13 @@
 
 /** Generates a random CellLayoutBoard. */
 open class RandomBoardGenerator(generator: Random) : DeterministicRandomGenerator(generator) {
+
+    companion object {
+        // This is the max number of widgets because we encode the widgets as letters A-Z and we
+        // already have some of those letter used by other things so 22 is a safe number
+        val MAX_NUMBER_OF_WIDGETS = 22
+    }
+
     /**
      * @param remainingEmptySpaces the maximum number of spaces we will fill with icons and widgets
      *   meaning that if the number is 100 we will try to fill the board with at most 100 spaces
@@ -33,9 +40,9 @@
     }
 
     protected fun fillBoard(
-            board: CellLayoutBoard,
-            area: Rect,
-            remainingEmptySpacesArg: Int
+        board: CellLayoutBoard,
+        area: Rect,
+        remainingEmptySpacesArg: Int
     ): CellLayoutBoard {
         var remainingEmptySpaces = remainingEmptySpacesArg
         if (area.height() * area.width() <= 0) return board
@@ -45,11 +52,18 @@
         val y = area.top + getRandom(0, area.height() - height)
         if (remainingEmptySpaces > 0) {
             remainingEmptySpaces -= width * height
-        } else if (board.widgets.size <= 22 && width * height > 1) {
+        }
+
+        if (board.widgets.size <= MAX_NUMBER_OF_WIDGETS && width * height > 1) {
             board.addWidget(x, y, width, height)
         } else {
             board.addIcon(x, y)
         }
+
+        if (remainingEmptySpaces < 0) {
+            // optimization, no need to keep going
+            return board
+        }
         fillBoard(board, Rect(area.left, area.top, area.right, y), remainingEmptySpaces)
         fillBoard(board, Rect(area.left, y, x, area.bottom), remainingEmptySpaces)
         fillBoard(board, Rect(x, y + height, area.right, area.bottom), remainingEmptySpaces)
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt b/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
new file mode 100644
index 0000000..e773a86
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2024 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.celllayout.testgenerator
+
+import android.graphics.Point
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.celllayout.board.CellLayoutBoard
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.gridmigration.WorkspaceItem
+import java.util.Random
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * Generate a list of WorkspaceItem's for the given test case.
+ *
+ * @param repeatAfter a number after which we would repeat the same number of icons and widgets to
+ *   account for cases where the user have the same item multiple times.
+ */
+fun generateItemsForTest(
+    testCase: GridMigrationUnitTestCase,
+    repeatAfter: Int
+): List<WorkspaceItem> {
+    val id = AtomicInteger(0)
+    val widgetId = AtomicInteger(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - 1)
+    val boards = testCase.boards
+    // Repeat the same appWidgetProvider and intent to have repeating widgets and icons and test
+    // that case too
+    val getIntent = { i: Int -> "Intent ${i % repeatAfter}" }
+    val getProvider = { i: Int -> "com.test/test.Provider${i % repeatAfter}" }
+    val hotseatEntries =
+        (0 until boards[0].width).map {
+            WorkspaceItem(
+                x = it,
+                y = 0,
+                spanX = 1,
+                spanY = 1,
+                id = id.getAndAdd(1),
+                screenId = it,
+                title = "Hotseat ${id.get()}",
+                appWidgetId = -1,
+                appWidgetProvider = "Hotseat icons don't have a provider",
+                intent = getIntent(id.get()),
+                type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
+                container = LauncherSettings.Favorites.CONTAINER_HOTSEAT
+            )
+        }
+    var widgetEntries =
+        boards
+            .flatMapIndexed { i, board -> board.widgets.map { Pair(i, it) } }
+            .map {
+                WorkspaceItem(
+                    x = it.second.cellX,
+                    y = it.second.cellY,
+                    spanX = it.second.spanX,
+                    spanY = it.second.spanY,
+                    id = id.getAndAdd(1),
+                    screenId = it.first,
+                    title = "Title Widget ${id.get()}",
+                    appWidgetId = widgetId.getAndAdd(-1),
+                    appWidgetProvider = getProvider(id.get()),
+                    intent = "Widgets don't have intent",
+                    type = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET,
+                    container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+                )
+            }
+    widgetEntries = widgetEntries.filter { it.appWidgetProvider.contains("Provider4") }
+    val iconEntries =
+        boards
+            .flatMapIndexed { i, board -> board.icons.map { Pair(i, it) } }
+            .map {
+                WorkspaceItem(
+                    x = it.second.coord.x,
+                    y = it.second.coord.y,
+                    spanX = 1,
+                    spanY = 1,
+                    id = id.getAndAdd(1),
+                    screenId = it.first,
+                    title = "Title Icon ${id.get()}",
+                    appWidgetId = -1,
+                    appWidgetProvider = "Icons don't have providers",
+                    intent = getIntent(id.get()),
+                    type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
+                    container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+                )
+            }
+    return widgetEntries + hotseatEntries // + iconEntries
+}
+
+data class GridMigrationUnitTestCase(
+    val boards: List<CellLayoutBoard>,
+    val srcSize: Point,
+    val targetSize: Point,
+    val seed: Long
+)
+
+class ValidGridMigrationTestCaseGenerator(private val generator: Random) :
+    DeterministicRandomGenerator(generator) {
+
+    companion object {
+        const val MAX_BOARD_SIZE = 12
+        const val MAX_BOARD_COUNT = 10
+        const val SEED = 10342
+    }
+
+    private fun generateBoards(
+        boardGenerator: RandomBoardGenerator,
+        width: Int,
+        height: Int,
+        boardCount: Int
+    ): List<CellLayoutBoard> {
+        val boards = mutableListOf<CellLayoutBoard>()
+        for (i in 0 until boardCount) {
+            boards.add(
+                boardGenerator.generateBoard(
+                    width,
+                    height,
+                    boardGenerator.getRandom(0, width * height)
+                )
+            )
+        }
+        return boards
+    }
+
+    fun generateTestCase(): GridMigrationUnitTestCase {
+        var seed = generator.nextLong()
+        val randomBoardGenerator = RandomBoardGenerator(Random(seed))
+        val width = randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
+        val height = randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
+        return GridMigrationUnitTestCase(
+            boards =
+                generateBoards(
+                    boardGenerator = randomBoardGenerator,
+                    width = width,
+                    height = height,
+                    boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT)
+                ),
+            srcSize = Point(width, height),
+            targetSize =
+                Point(
+                    randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE),
+                    randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
+                ),
+            seed = seed
+        )
+    }
+}
diff --git a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
index 4ec5b0e..3a1883c 100644
--- a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
+++ b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -28,6 +28,7 @@
 import com.android.launcher3.icons.BaseIconFactory
 import com.android.launcher3.icons.FastBitmapDrawable
 import com.android.launcher3.icons.UserBadgeDrawable
+import com.android.launcher3.model.data.FolderInfo
 import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.util.ActivityContextWrapper
 import com.android.launcher3.util.FlagOp
@@ -71,8 +72,8 @@
                     .build()
             )
             .loadModelSync()
-        folderItems = modelHelper.bgDataModel.folders.valueAt(0).contents
-        folderIcon.mInfo = modelHelper.bgDataModel.folders.valueAt(0)
+        folderItems = modelHelper.bgDataModel.collections.valueAt(0).contents
+        folderIcon.mInfo = modelHelper.bgDataModel.collections.valueAt(0) as FolderInfo
         folderIcon.mInfo.contents = folderItems
 
         // Set first icon to be themed.
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index 7a0b60a..abb0c39 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -160,6 +160,6 @@
     }
 
     private List<WorkspaceItemInfo> allItems() {
-        return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).contents;
+        return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).getContents();
     }
 }
diff --git a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
index 2b89321..10785f7 100644
--- a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
+++ b/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
@@ -87,7 +87,7 @@
         assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
         ItemInfo info = mModelHelper.getBgDataModel().workspaceItems.get(0);
         assertEquals(LauncherSettings.Favorites.ITEM_TYPE_FOLDER, info.itemType);
-        assertEquals(3, ((FolderInfo) info).contents.size());
+        assertEquals(3, ((FolderInfo) info).getContents().size());
     }
 
     @Test
@@ -102,7 +102,7 @@
         assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
         ItemInfo info = mModelHelper.getBgDataModel().workspaceItems.get(0);
         assertEquals(LauncherSettings.Favorites.ITEM_TYPE_FOLDER, info.itemType);
-        assertEquals(3, ((FolderInfo) info).contents.size());
+        assertEquals(3, ((FolderInfo) info).getContents().size());
         assertEquals("CustomFolder", info.title.toString());
     }
 
@@ -154,11 +154,11 @@
         // Verify folder
         assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
         FolderInfo info = (FolderInfo) mModelHelper.getBgDataModel().workspaceItems.get(0);
-        assertEquals(3, info.contents.size());
+        assertEquals(3, info.getContents().size());
 
         // Verify last icon
         assertEquals(LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT,
-                info.contents.get(info.contents.size() - 1).itemType);
+                info.getContents().get(info.getContents().size() - 1).itemType);
     }
 
     private void writeLayoutAndLoad(LauncherLayoutBuilder builder) throws Exception {
diff --git a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
index 2118ed6..ed587a1 100644
--- a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
+++ b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
@@ -165,11 +165,11 @@
         // Reload again with correct icon state
         app.model.forceReload()
         modelHelper.loadModelSync()
-        val folders = modelHelper.getBgDataModel().folders
+        val collections = modelHelper.getBgDataModel().collections
 
-        assertThat(folders.size()).isEqualTo(1)
-        assertThat(folders.valueAt(0).contents.size).isEqualTo(itemCount)
-        return folders.valueAt(0).contents
+        assertThat(collections.size()).isEqualTo(1)
+        assertThat(collections.valueAt(0).contents.size).isEqualTo(itemCount)
+        return collections.valueAt(0).contents
     }
 
     private fun verifyHighRes(items: ArrayList<WorkspaceItemInfo>, vararg indices: Int) {
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
index 04735f2..761f06d 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
+++ b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
@@ -28,7 +28,6 @@
 import com.android.launcher3.LauncherPrefs
 import com.android.launcher3.LauncherPrefs.Companion.WORKSPACE_SIZE
 import com.android.launcher3.LauncherSettings.Favorites.*
-import com.android.launcher3.config.FeatureFlags
 import com.android.launcher3.model.GridSizeMigrationUtil.DbReader
 import com.android.launcher3.pm.UserCache
 import com.android.launcher3.provider.LauncherDbUtils
@@ -98,10 +97,7 @@
         modelHelper.destroy()
     }
 
-    /**
-     * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
-     * needed anymore
-     */
+    /** Old migration logic, should be modified once is not needed anymore */
     @Test
     @Throws(Exception::class)
     fun testMigration() {
@@ -208,10 +204,7 @@
         assertThat(locMap[testPackage9]).isEqualTo(Point(0, 2))
     }
 
-    /**
-     * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
-     * needed anymore
-     */
+    /** Old migration logic, should be modified once is not needed anymore */
     @Test
     @Throws(Exception::class)
     fun testMigrationBackAndForth() {
@@ -606,68 +599,6 @@
     }
 
     /**
-     * Migrating from a smaller grid to a large one should keep the pages if the column difference
-     * is less than 2
-     */
-    @Test
-    @Throws(Exception::class)
-    fun migrateFromSmallerGridSmallDifference() {
-        enableNewMigrationLogic("4,4")
-
-        // Setup src grid
-        addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage1, 5, TMP_TABLE)
-        addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage2, 6, TMP_TABLE)
-        addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 1, testPackage3, 7, TMP_TABLE)
-        addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 2, testPackage4, 8, TMP_TABLE)
-        addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 3, 3, testPackage5, 9, TMP_TABLE)
-
-        idp.numDatabaseHotseatIcons = 4
-        idp.numColumns = 6
-        idp.numRows = 5
-
-        val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
-        val destReader = DbReader(db, TABLE_NAME, context, validPackages)
-        GridSizeMigrationUtil.migrate(
-            dbHelper,
-            srcReader,
-            destReader,
-            idp.numDatabaseHotseatIcons,
-            Point(idp.numColumns, idp.numRows),
-            DeviceGridState(context),
-            DeviceGridState(idp)
-        )
-
-        // Get workspace items
-        val c =
-            db.query(
-                TABLE_NAME,
-                arrayOf(INTENT, SCREEN),
-                "container=$CONTAINER_DESKTOP",
-                null,
-                null,
-                null,
-                null
-            )
-                ?: throw IllegalStateException()
-        val intentIndex = c.getColumnIndex(INTENT)
-        val screenIndex = c.getColumnIndex(SCREEN)
-
-        // Get in which screen the icon is
-        val locMap = HashMap<String?, Int>()
-        while (c.moveToNext()) {
-            locMap[Intent.parseUri(c.getString(intentIndex), 0).getPackage()] =
-                c.getInt(screenIndex)
-        }
-        c.close()
-        assertThat(locMap.size).isEqualTo(5)
-        assertThat(locMap[testPackage1]).isEqualTo(0)
-        assertThat(locMap[testPackage2]).isEqualTo(0)
-        assertThat(locMap[testPackage3]).isEqualTo(1)
-        assertThat(locMap[testPackage4]).isEqualTo(1)
-        assertThat(locMap[testPackage5]).isEqualTo(2)
-    }
-
-    /**
      * Migrating from a smaller grid to a large one should reflow the pages if the column difference
      * is more than 2
      */
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index bbe8265..5731e2a 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -103,7 +103,7 @@
                 .runSyncOnBackgroundThread()
             Truth.assertThat(workspaceItems.size).isAtLeast(25)
             Truth.assertThat(appWidgets.size).isAtLeast(7)
-            Truth.assertThat(folders.size()).isAtLeast(8)
+            Truth.assertThat(collections.size()).isAtLeast(8)
             Truth.assertThat(itemsIdMap.size()).isAtLeast(40)
         }
 
diff --git a/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt b/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
new file mode 100644
index 0000000..cc8e61d
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2024 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.model.gridmigration
+
+import android.content.ContentValues
+import android.database.sqlite.SQLiteDatabase
+import android.graphics.Point
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.celllayout.board.CellLayoutBoard
+
+class MockSet(override val size: Int) : Set<String> {
+    override fun contains(element: String): Boolean = true
+    override fun containsAll(elements: Collection<String>): Boolean = true
+    override fun isEmpty(): Boolean = false
+    override fun iterator(): Iterator<String> = listOf<String>().iterator()
+}
+
+fun itemListToBoard(itemsArg: List<WorkspaceItem>, boardSize: Point): List<CellLayoutBoard> {
+    val items = itemsArg.filter { it.container != Favorites.CONTAINER_HOTSEAT }
+    val boardList =
+        List(items.maxOf { it.screenId + 1 }) { CellLayoutBoard(boardSize.x, boardSize.y) }
+    items.forEach {
+        when (it.type) {
+            Favorites.ITEM_TYPE_FOLDER,
+            Favorites.ITEM_TYPE_APP_PAIR -> throw Exception("Not implemented")
+            Favorites.ITEM_TYPE_APPWIDGET ->
+                boardList[it.screenId].addWidget(it.x, it.y, it.spanX, it.spanY)
+            Favorites.ITEM_TYPE_APPLICATION -> boardList[it.screenId].addIcon(it.x, it.y)
+        }
+    }
+    return boardList
+}
+
+fun insertIntoDb(tableName: String, entry: WorkspaceItem, db: SQLiteDatabase) {
+    val values = ContentValues()
+    values.put(Favorites.SCREEN, entry.screenId)
+    values.put(Favorites.CELLX, entry.x)
+    values.put(Favorites.CELLY, entry.y)
+    values.put(Favorites.SPANX, entry.spanX)
+    values.put(Favorites.SPANY, entry.spanY)
+    values.put(Favorites.TITLE, entry.title)
+    values.put(Favorites.INTENT, entry.intent)
+    values.put(Favorites.APPWIDGET_PROVIDER, entry.appWidgetProvider)
+    values.put(Favorites.APPWIDGET_ID, entry.appWidgetId)
+    values.put(Favorites.CONTAINER, entry.container)
+    values.put(Favorites.ITEM_TYPE, entry.type)
+    values.put(Favorites._ID, entry.id)
+    db.insert(tableName, null, values)
+}
+
+fun readDb(tableName: String, db: SQLiteDatabase): List<WorkspaceItem> {
+    val result = mutableListOf<WorkspaceItem>()
+    val cursor = db.query(tableName, null, null, null, null, null, null)
+    val indexCellX: Int = cursor.getColumnIndexOrThrow(Favorites.CELLX)
+    val indexCellY: Int = cursor.getColumnIndexOrThrow(Favorites.CELLY)
+    val indexSpanX: Int = cursor.getColumnIndexOrThrow(Favorites.SPANX)
+    val indexSpanY: Int = cursor.getColumnIndexOrThrow(Favorites.SPANY)
+    val indexId: Int = cursor.getColumnIndexOrThrow(Favorites._ID)
+    val indexScreen: Int = cursor.getColumnIndexOrThrow(Favorites.SCREEN)
+    val indexTitle: Int = cursor.getColumnIndexOrThrow(Favorites.TITLE)
+    val indexAppWidgetId: Int = cursor.getColumnIndexOrThrow(Favorites.APPWIDGET_ID)
+    val indexWidgetProvider: Int = cursor.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER)
+    val indexIntent: Int = cursor.getColumnIndexOrThrow(Favorites.INTENT)
+    val indexItemType: Int = cursor.getColumnIndexOrThrow(Favorites.ITEM_TYPE)
+    val container: Int = cursor.getColumnIndexOrThrow(Favorites.CONTAINER)
+    while (cursor.moveToNext()) {
+        result.add(
+            WorkspaceItem(
+                x = cursor.getInt(indexCellX),
+                y = cursor.getInt(indexCellY),
+                spanX = cursor.getInt(indexSpanX),
+                spanY = cursor.getInt(indexSpanY),
+                id = cursor.getInt(indexId),
+                screenId = cursor.getInt(indexScreen),
+                title = cursor.getString(indexTitle),
+                appWidgetId = cursor.getInt(indexAppWidgetId),
+                appWidgetProvider = cursor.getString(indexWidgetProvider),
+                intent = cursor.getString(indexIntent),
+                type = cursor.getInt(indexItemType),
+                container = cursor.getInt(container)
+            )
+        )
+    }
+    return result
+}
+
+data class WorkspaceItem(
+    val x: Int,
+    val y: Int,
+    val spanX: Int,
+    val spanY: Int,
+    val id: Int,
+    val screenId: Int,
+    val title: String,
+    val appWidgetId: Int,
+    val appWidgetProvider: String,
+    val intent: String,
+    val type: Int,
+    val container: Int,
+)
diff --git a/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
new file mode 100644
index 0000000..1002976
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
@@ -0,0 +1,173 @@
+/*
+ * 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.model.gridmigration
+
+import android.content.Context
+import android.database.sqlite.SQLiteDatabase
+import android.graphics.Point
+import android.os.Process
+import android.util.Log
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.celllayout.testgenerator.ValidGridMigrationTestCaseGenerator
+import com.android.launcher3.celllayout.testgenerator.generateItemsForTest
+import com.android.launcher3.model.DatabaseHelper
+import com.android.launcher3.model.DeviceGridState
+import com.android.launcher3.model.GridSizeMigrationUtil
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.provider.LauncherDbUtils
+import com.android.launcher3.util.rule.TestStabilityRule
+import com.android.launcher3.util.rule.TestStabilityRule.Stability
+import java.util.Random
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ValidGridMigrationUnitTest {
+
+    companion object {
+        const val SEED = 1044542
+        const val REPEAT_AFTER = 10
+        const val TAG = "ValidGridMigrationUnitTest"
+    }
+
+    private lateinit var context: Context
+
+    @Before
+    fun setUp() {
+        context = InstrumentationRegistry.getInstrumentation().targetContext
+    }
+
+    private fun validate(
+        srcItems: List<WorkspaceItem>,
+        dstItems: List<WorkspaceItem>,
+        destinationSize: Point
+    ) {
+        // This returns a map with the number of repeated elements
+        // ex { calculatorIcon : 6, weatherWidget : 2 }
+        val itemsToSet = { it: List<WorkspaceItem> ->
+            it.filter { it.container != Favorites.CONTAINER_HOTSEAT }
+                .groupingBy {
+                    when (it.type) {
+                        Favorites.ITEM_TYPE_FOLDER,
+                        Favorites.ITEM_TYPE_APP_PAIR -> throw Exception("Not implemented")
+                        Favorites.ITEM_TYPE_APPWIDGET -> it.appWidgetProvider
+                        Favorites.ITEM_TYPE_APPLICATION -> it.intent
+                        else -> it.title
+                    }
+                }
+                .eachCount()
+        }
+        for (it in dstItems) {
+            assert((it.x in 0..destinationSize.x) && (it.y in 0..destinationSize.y)) {
+                "Item outside of the board size. Size = $destinationSize Item = $it"
+            }
+            assert(
+                (it.x + it.spanX in 0..destinationSize.x) &&
+                    (it.y + it.spanY in 0..destinationSize.y)
+            ) {
+                "Item doesn't fit in the grid. Size = $destinationSize Item = $it"
+            }
+        }
+
+        assert(itemsToSet(srcItems) == itemsToSet(dstItems)) {
+            "The srcItems do not match the dstItems src = $srcItems  dst = $dstItems"
+        }
+    }
+
+    private fun addItemsToDb(db: SQLiteDatabase, tableName: String, items: List<WorkspaceItem>) {
+        LauncherDbUtils.SQLiteTransaction(db).use { transaction ->
+            items.forEach { insertIntoDb(tableName, it, transaction.db) }
+            transaction.commit()
+        }
+    }
+
+    private fun migrate(
+        srcItems: List<WorkspaceItem>,
+        srcSize: Point,
+        targetSize: Point
+    ): List<WorkspaceItem> {
+        val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
+        val dbHelper =
+            DatabaseHelper(
+                context,
+                null,
+                { UserCache.INSTANCE.get(context).getSerialNumberForUser(it) },
+                {}
+            )
+        val srcTableName = Favorites.TMP_TABLE
+        val dstTableName = Favorites.TABLE_NAME
+        Favorites.addTableToDb(dbHelper.writableDatabase, userSerial, false, srcTableName)
+        addItemsToDb(dbHelper.writableDatabase, srcTableName, srcItems)
+        LauncherDbUtils.SQLiteTransaction(dbHelper.writableDatabase).use {
+            GridSizeMigrationUtil.migrate(
+                dbHelper,
+                GridSizeMigrationUtil.DbReader(it.db, srcTableName, context, MockSet(1)),
+                GridSizeMigrationUtil.DbReader(it.db, dstTableName, context, MockSet(1)),
+                targetSize.x,
+                targetSize,
+                DeviceGridState(
+                    srcSize.x,
+                    srcSize.y,
+                    srcSize.x,
+                    InvariantDeviceProfile.TYPE_PHONE,
+                    srcTableName
+                ),
+                DeviceGridState(
+                    targetSize.x,
+                    targetSize.y,
+                    targetSize.x,
+                    InvariantDeviceProfile.TYPE_PHONE,
+                    dstTableName
+                )
+            )
+            it.commit()
+        }
+        return readDb(dstTableName, dbHelper.readableDatabase)
+    }
+
+    @Test
+    fun runTestCase() {
+        val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
+        for (i in 0..50) {
+            val testCase = caseGenerator.generateTestCase()
+            Log.d(TAG, "Test case = $testCase")
+            val srcItemList = generateItemsForTest(testCase, REPEAT_AFTER)
+            val dstItemList = migrate(srcItemList, testCase.srcSize, testCase.targetSize)
+            validate(srcItemList, dstItemList, testCase.targetSize)
+        }
+    }
+
+    // This test takes about 4 minutes, there is no need to run it in presubmit.
+    @Stability(flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT)
+    @Test
+    fun runExtensiveTestCases() {
+        val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
+        for (i in 0..1000) {
+            val testCase = caseGenerator.generateTestCase()
+            Log.d(TAG, "Test case = $testCase")
+            val srcItemList = generateItemsForTest(testCase, REPEAT_AFTER)
+            val dstItemList = migrate(srcItemList, testCase.srcSize, testCase.targetSize)
+            validate(srcItemList, dstItemList, testCase.targetSize)
+        }
+    }
+}
diff --git a/tests/src/com/android/launcher3/util/ItemInflaterTest.kt b/tests/src/com/android/launcher3/util/ItemInflaterTest.kt
index efad899..0065527 100644
--- a/tests/src/com/android/launcher3/util/ItemInflaterTest.kt
+++ b/tests/src/com/android/launcher3/util/ItemInflaterTest.kt
@@ -36,6 +36,7 @@
 import com.android.launcher3.folder.FolderIcon
 import com.android.launcher3.model.ModelWriter
 import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.AppPairInfo
 import com.android.launcher3.model.data.FolderInfo
 import com.android.launcher3.model.data.LauncherAppWidgetInfo
 import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_ID_NOT_VALID
@@ -170,7 +171,7 @@
 
     @Test
     fun test_app_pair_inflated_on_UI() {
-        val itemInfo = FolderInfo()
+        val itemInfo = AppPairInfo()
         itemInfo.itemType = ITEM_TYPE_APP_PAIR
         itemInfo.contents.add(workspaceItemInfo())
         itemInfo.contents.add(workspaceItemInfo())
@@ -186,7 +187,7 @@
     fun test_app_pair_inflated_on_BG() {
         setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
 
-        val itemInfo = FolderInfo()
+        val itemInfo = AppPairInfo()
         itemInfo.itemType = ITEM_TYPE_APP_PAIR
         itemInfo.contents.add(workspaceItemInfo())
         itemInfo.contents.add(workspaceItemInfo())
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index c7d3754..0a52955 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -24,6 +24,7 @@
 import static android.view.MotionEvent.ACTION_SCROLL;
 import static android.view.MotionEvent.ACTION_UP;
 import static android.view.MotionEvent.AXIS_GESTURE_SWIPE_FINGER_COUNT;
+import static android.view.Surface.ROTATION_90;
 
 import static com.android.launcher3.tapl.Folder.FOLDER_CONTENT_RES_ID;
 import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;
@@ -474,12 +475,25 @@
         logShellCommand(cmd);
     }
 
+    /**
+     * Retrieves a resource value from context that defines if nav bar can change position or if it
+     * is fixed position regardless of device orientation.
+     */
+    private boolean getNavBarCanMove() {
+        final Context baseContext = mInstrumentation.getTargetContext();
+        try {
+            final Context ctx = getLauncherContext(baseContext);
+            return getNavBarCanMove(ctx);
+        } catch (Exception e) {
+            fail(e.toString());
+        }
+        return false;
+    }
+
     public NavigationModel getNavigationModel() {
         final Context baseContext = mInstrumentation.getTargetContext();
         try {
-            // Workaround, use constructed context because both the instrumentation context and the
-            // app context are not constructed with resources that take overlays into account
-            final Context ctx = baseContext.createPackageContext(getLauncherPackageName(), 0);
+            final Context ctx = getLauncherContext(baseContext);
             for (int i = 0; i < 100; ++i) {
                 final int currentInteractionMode = getCurrentInteractionMode(ctx);
                 final NavigationModel model = getNavigationModel(currentInteractionMode);
@@ -1101,19 +1115,31 @@
     /**
      * Goes to home from immersive fullscreen app by first swiping up to bring navbar, and then
      * performing {@code goHome()} action.
-     * Currently only supports gesture navigation mode.
      *
      * @return the Workspace object.
      */
     public Workspace goHomeFromImmersiveFullscreenApp() {
-        assertTrue("expected gesture navigation mode",
-                getNavigationModel() == NavigationModel.ZERO_BUTTON);
-        final Point displaySize = getRealDisplaySize();
-        linearGesture(
-                displaySize.x / 2, displaySize.y - 1,
-                displaySize.x / 2, 0,
-                ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
-                false, GestureScope.EXPECT_PILFER);
+        final boolean navBarCanMove = getNavBarCanMove();
+        if (getNavigationModel() == NavigationModel.ZERO_BUTTON || !navBarCanMove) {
+            // in gesture nav we can swipe up at the bottom to bring the navbar handle
+            final Point displaySize = getRealDisplaySize();
+            linearGesture(
+                    displaySize.x / 2, displaySize.y - 1,
+                    displaySize.x / 2, 0,
+                    ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+                    false, GestureScope.EXPECT_PILFER);
+        } else {
+            // in 3 button nav we swipe up on the side edge of the screen to bring the navbar
+            final boolean rotated90degrees = mDevice.getDisplayRotation() == ROTATION_90;
+            final Point displaySize = getRealDisplaySize();
+            final int startX = rotated90degrees ? displaySize.x : 0;
+            final int endX = rotated90degrees ? 0 : displaySize.x;
+            linearGesture(
+                    startX, displaySize.y / 2,
+                    endX, displaySize.y / 2,
+                    ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+                    false, GestureScope.EXPECT_PILFER);
+        }
         return goHome();
     }
 
@@ -2126,6 +2152,13 @@
         return getSystemIntegerRes(context, "config_navBarInteractionMode");
     }
 
+    /**
+     * Retrieve the resource value that defines if nav bar can moved or if it is fixed position.
+     */
+    private static boolean getNavBarCanMove(Context context) {
+        return getSystemBooleanRes(context, "config_navBarCanMove");
+    }
+
     @NonNull
     UiObject2 clickAndGet(
             @NonNull final UiObject2 target, @NonNull String resName, Pattern longClickEvent) {
@@ -2166,6 +2199,18 @@
         }
     }
 
+    private static boolean getSystemBooleanRes(Context context, String resName) {
+        Resources res = context.getResources();
+        int resId = res.getIdentifier(resName, "bool", "android");
+
+        if (resId != 0) {
+            return res.getBoolean(resId);
+        } else {
+            Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+            return false;
+        }
+    }
+
     private static int getSystemIntegerRes(Context context, String resName) {
         Resources res = context.getResources();
         int resId = res.getIdentifier(resName, "integer", "android");
@@ -2431,6 +2476,13 @@
         return Math.max(topRadius, bottomRadius) + tmpBuffer;
     }
 
+    private Context getLauncherContext(Context baseContext)
+            throws PackageManager.NameNotFoundException {
+        // Workaround, use constructed context because both the instrumentation context and the
+        // app context are not constructed with resources that take overlays into account
+        return baseContext.createPackageContext(getLauncherPackageName(), 0);
+    }
+
     private static boolean supportsRoundedCornersOnWindows(Resources resources) {
         return ResourceUtils.getBoolByName(
                 "config_supportsRoundedCornersOnWindows", resources, false);