Merge "Add overview taskbar split support for 3P launcher" into tm-qpr-dev
diff --git a/OWNERS b/OWNERS
index 560b562..962d63a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,31 +4,36 @@
 # People who can approve changes for submission
 #
 
-alexchau@google.com
-andraskloczl@google.com
-patmanning@google.com
 adamcohen@google.com
-hyunyoungs@google.com
-mrcasey@google.com
-sunnygoyal@google.com
+alexchau@google.com
+andonian@google.com
 awickham@google.com
-twickham@google.com
-winsonc@google.com
-zakcohen@google.com
-santie@google.com
-vadimt@google.com
-jonmiranda@google.com
-pinyaoting@google.com
-gwasserman@google.com
-jamesoleary@google.com
-joshtrask@google.com
-mrenouf@google.com
-mkephart@google.com
-hwwang@google.com
-tracyzhou@google.com
-peanutbutter@google.com
-xuqiu@google.com
+brdayauon@google.com
 brianji@google.com
+captaincole@google.com
+charlander@google.com
+fbaron@google.com
+ganjam@google.com
+hwwang@google.com
+hyunyoungs@google.com
+jagrutdesai@google.com
+jeremysim@google.com
+jiuyu@google.com
+jonmiranda@google.com
+kylim@google.com
+patmanning@google.com
+peanutbutter@google.com
+pinyaoting@google.com
+randypfohl@google.com
+saumyaprakash@google.com
+sihua@google.com
+sunnygoyal@google.com
+tracyzhou@google.com
+twickham@google.com
+vadimt@google.com
+victortulias@google.com
+winsonc@google.com
+xuqiu@google.com
 
 per-file FeatureFlags.java, globs = set noparent
-per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, zakcohen@google.com, mrcasey@google.com, adamcohen@google.com, hyunyoungs@google.com
+per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, adamcohen@google.com, hyunyoungs@google.com
diff --git a/quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml b/quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml
new file mode 100644
index 0000000..286a3c4
--- /dev/null
+++ b/quickstep/res/drawable/keyboard_quick_switch_overview_button_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:shape="rectangle">
+    <solid android:color="?androidprv:attr/colorSurfaceVariant" />
+    <corners android:radius="@dimen/keyboard_quick_switch_task_view_radius" />
+</shape>
diff --git a/quickstep/res/drawable/keyboard_quick_switch_task_view_background.xml b/quickstep/res/drawable/keyboard_quick_switch_task_view_background.xml
new file mode 100644
index 0000000..d0aac8c
--- /dev/null
+++ b/quickstep/res/drawable/keyboard_quick_switch_task_view_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@android:color/transparent" />
+    <corners android:radius="@dimen/keyboard_quick_switch_task_view_radius" />
+</shape>
diff --git a/quickstep/res/drawable/keyboard_quick_switch_view_background.xml b/quickstep/res/drawable/keyboard_quick_switch_view_background.xml
new file mode 100644
index 0000000..19aaed4
--- /dev/null
+++ b/quickstep/res/drawable/keyboard_quick_switch_view_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="?attr/overviewScrimColor" />
+    <corners android:radius="@dimen/keyboard_quick_switch_view_radius" />
+</shape>
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
new file mode 100644
index 0000000..18c0e1f
--- /dev/null
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+    android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+    android:importantForAccessibility="yes"
+    android:background="@drawable/keyboard_quick_switch_task_view_background"
+    android:clipToOutline="true"
+    launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
+
+    <include
+        layout="@layout/keyboard_quick_switch_thumbnail"
+        android:id="@+id/thumbnail1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/thumbnail2"/>
+
+    <include
+        layout="@layout/keyboard_quick_switch_thumbnail"
+        android:id="@+id/thumbnail2"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:visibility="gone"
+        android:layout_marginStart="@dimen/keyboard_quick_switch_split_view_spacing"
+
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toEndOf="@id/thumbnail1"
+        app:layout_constraintEnd_toEndOf="parent"/>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/keyboard_quick_switch_overview.xml b/quickstep/res/layout/keyboard_quick_switch_overview.xml
new file mode 100644
index 0000000..bf21a3e
--- /dev/null
+++ b/quickstep/res/layout/keyboard_quick_switch_overview.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+    android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+    android:background="@drawable/keyboard_quick_switch_overview_button_background"
+    android:clipToOutline="true"
+    android:importantForAccessibility="yes"
+    launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
+
+    <ImageView
+        android:id="@+id/icon"
+        android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
+        android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
+        android:layout_marginBottom="8dp"
+        android:src="@drawable/ic_empty_recents"
+
+        app:tint="?android:attr/textColorPrimary"
+        app:layout_constraintVertical_chainStyle="packed"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toTopOf="@id/text"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"/>
+
+    <TextView
+        style="@style/KeyboardQuickSwitchOverview"
+        android:id="@+id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAlignment="center"
+
+        app:layout_constraintTop_toBottomOf="@id/icon"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"/>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
new file mode 100644
index 0000000..48e6276
--- /dev/null
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:layout_width="@dimen/keyboard_quick_switch_taskview_width"
+    android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
+    android:importantForAccessibility="yes"
+    android:background="@drawable/keyboard_quick_switch_task_view_background"
+    android:clipToOutline="true"
+    launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
+
+        <include
+            layout="@layout/keyboard_quick_switch_thumbnail"
+            android:id="@+id/thumbnail1"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+
+            app:layout_constraintTop_toTopOf="parent"
+            app:layout_constraintBottom_toTopOf="@id/thumbnail2"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"/>
+
+        <include
+            layout="@layout/keyboard_quick_switch_thumbnail"
+            android:id="@+id/thumbnail2"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:visibility="gone"
+            android:layout_marginTop="@dimen/keyboard_quick_switch_split_view_spacing"
+
+            app:layout_constraintTop_toBottomOf="@id/thumbnail1"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"/>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchTaskView>
diff --git a/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml b/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml
new file mode 100644
index 0000000..cd6587c
--- /dev/null
+++ b/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ImageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:scaleType="centerCrop"
+    android:background="@drawable/keyboard_quick_switch_task_view_background"
+    android:clipToOutline="true"/>
diff --git a/quickstep/res/layout/keyboard_quick_switch_view.xml b/quickstep/res/layout/keyboard_quick_switch_view.xml
new file mode 100644
index 0000000..5c20a2d
--- /dev/null
+++ b/quickstep/res/layout/keyboard_quick_switch_view.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.taskbar.KeyboardQuickSwitchView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingVertical="@dimen/keyboard_quick_switch_view_spacing"
+    android:layout_marginTop="@dimen/keyboard_quick_switch_margin_top"
+    android:layout_marginHorizontal="@dimen/keyboard_quick_switch_margin_ends"
+    android:background="@drawable/keyboard_quick_switch_view_background"
+    android:clipToOutline="true"
+    android:alpha="0"
+    android:visibility="invisible"
+    android:focusableInTouchMode="true">
+
+    <HorizontalScrollView
+        android:id="@+id/scroll_view"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:fillViewport="true"
+        android:scrollbars="none"
+        android:alpha="0"
+        android:visibility="invisible"
+
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintStart_toStartOf="parent">
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/content"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </HorizontalScrollView>
+
+</com.android.launcher3.taskbar.KeyboardQuickSwitchView>
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index bd11c1e..1642fd4 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -17,11 +17,14 @@
      file, they need to be loaded at runtime. -->
 <com.android.quickstep.views.TaskView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
     android:defaultFocusHighlightEnabled="false"
-    android:focusable="true">
+    android:focusable="true"
+    launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
 
     <com.android.quickstep.views.TaskThumbnailView
         android:id="@+id/snapshot"
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 96aabb4..2ec9d4c 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -17,12 +17,15 @@
 
 <com.android.quickstep.views.DesktopTaskView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="true"
     android:clipToOutline="true"
     android:defaultFocusHighlightEnabled="false"
-    android:focusable="true">
+    android:focusable="true"
+    launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
 
     <View
         android:id="@+id/background"
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index ec03c69..a8d5b50 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -22,11 +22,14 @@
 
 <com.android.quickstep.views.GroupedTaskView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
     android:defaultFocusHighlightEnabled="false"
-    android:focusable="true">
+    android:focusable="true"
+    launcher:borderColor="?androidprv:attr/colorAccentSecondaryVariant">
 
     <com.android.quickstep.views.TaskThumbnailView
         android:id="@+id/snapshot"
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 5406e17..cfe7894 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"مشاركة"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"لقطة شاشة"</string>
     <string name="action_split" msgid="2098009717623550676">"تقسيم"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"انقر على تطبيق آخر لاستخدام وضع تقسيم الشاشة."</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"اختَر تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"لا يسمح التطبيق أو لا تسمح مؤسستك بهذا الإجراء."</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"هل تريد تخطي الدليل التوجيهي؟"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 8007cab..f37bcbb 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"শ্বেয়াৰ কৰক"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"স্ক্ৰীনশ্বট"</string>
     <string name="action_split" msgid="2098009717623550676">"বিভাজন কৰক"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপত টিপক"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপ্ বাছক"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"এপ্‌টোৱে অথবা আপোনাৰ প্ৰতিষ্ঠানে এই কাৰ্যটোৰ অনুমতি নিদিয়ে"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"নেভিগেশ্বনৰ টিউট’ৰিয়েল এৰিব বিচাৰে নেকি?"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 3ad5eae..d2c535c 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -86,8 +86,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>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podeljeni ekran"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu aplikaciju za podeljeni ekran"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili organizacija ne dozvoljavaju ovu radnju"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite da preskočite vodič za kretanje?"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index df265f3..a3bd17c 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Абагуліць"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Здымак экрана"</string>
     <string name="action_split" msgid="2098009717623550676">"Падзелены экран"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Каб падзяліць экран, націсніце на іншую праграму"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Каб падзяліць экран, выберыце іншую праграму"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Гэта дзеянне не дазволена праграмай ці вашай арганізацыяй"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Прапусціць дапаможнік па навігацыі?"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 1ba96e4..2756c47 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"শেয়ার করুন"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"স্ক্রিনশট নিন"</string>
     <string name="action_split" msgid="2098009717623550676">"স্প্লিট"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"স্প্লিট স্ক্রিন ব্যবহারের জন্য অ্যাপে ট্যাপ করুন"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"স্প্লিট স্ক্রিন ব্যবহার করতে অন্য অ্যাপ বেছে নিন"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"এই অ্যাপ বা আপনার প্রতিষ্ঠান এই অ্যাকশনটি পারফর্ম করার অনুমতি দেয়নি"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"নেভিগেশন টিউটোরিয়াল এড়িয়ে যেতে চান?"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index d47b773..872fcfe 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -86,7 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Dijeli"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
     <string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
-    <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podijeljeni zaslon"</string>
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu apl. da koristite podijeljeni ekran"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Odaberite drugu apl. da koristite podijeljeni ekran"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Ovu radnju ne dozvoljava aplikacija ili vaša organizacija"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Preskočiti vodič za navigiranje?"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 1ce4f69..00ee4c1 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Comparteix"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
     <string name="action_split" msgid="2098009717623550676">"Divideix"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Toca una altra app per utilitzar pantalla dividida"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Tria una altra app per utilitzar pantalla dividida"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"L\'aplicació o la teva organització no permeten aquesta acció"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vols ometre el tutorial de navegació?"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 287b582..801cb71 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Del"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Opdel"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Tryk på en anden app for at bruge opdelt skærm"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Vælg en anden app for at bruge opdelt skærm"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller din organisation tillader ikke denne handling"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vil du springe selvstudiet for navigation over?"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 024aba9..c25ef66 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Teilen"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Teilen"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Für „Geteilter Bildschirm“ auf weitere App tippen"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Für geteilten Bildschirm andere App auswählen"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Die App oder deine Organisation lässt diese Aktion nicht zu"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Navigationstutorial überspringen?"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 1ab42b3..9bb4fc6 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Compartir"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
     <string name="action_split" msgid="2098009717623550676">"Pantalla dividida"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Presiona otra app para usar la pantalla dividida"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"La app o tu organización no permiten realizar esta acción"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"¿Omitir el instructivo de navegación?"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 7d5e27b..5a95416 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Compartir"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Hacer captura"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividir"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Toca otra app para usar la pantalla dividida"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"No puedes hacerlo porque la aplicación o tu organización no lo permiten"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"¿Saltar tutorial de navegación?"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index b4ec869..1c14660 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -86,8 +86,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>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Valige jagatud ekraanikuva jaoks muu rakendus"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Rakendus või teie organisatsioon on selle toimingu keelanud"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Kas jätta navigeerimise õpetused vahele?"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index ecd0edc..a920ba5 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Partekatu"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Atera pantaila-argazki bat"</string>
     <string name="action_split" msgid="2098009717623550676">"Zatitu"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Sakatu beste aplikazio bat pantaila zatitzeko"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pantaila zatitua ikusteko, aukeratu beste aplikazio bat"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikazioak edo erakundeak ez du eman ekintza hori gauzatzeko baimena"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Nabigazio-tutoriala saltatu nahi duzu?"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index de177f4..c074720 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"هم‌رسانی"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"نماگرفت"</string>
     <string name="action_split" msgid="2098009717623550676">"دونیمه"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"زدن روی برنامه‌ای دیگر برای استفاده از صفحه دونیمه"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"انتخاب برنامه‌ای دیگر برای استفاده از صفحه دونیمه"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"برنامه یا سازمان شما اجازه نمی‌دهد این کنش انجام شود."</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"آموزش گام‌به‌گام پیمایش رد شود؟"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 71f1148..2aee419 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Partager"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
     <string name="action_split" msgid="2098009717623550676">"Séparé"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Toucher une autre appli pour partager l\'écran"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choisir une autre application pour utiliser l\'écran partagé"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"L\'application ou votre organisation n\'autorise pas cette action"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorer le tutoriel sur la navigation?"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 3e5c715..b67266c 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Partager"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
     <string name="action_split" msgid="2098009717623550676">"Partager"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Appuyez sur autre appli pour utiliser écran partagé"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Sélect. autre appli pour utiliser l\'écran partagé"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Cette action n\'est pas autorisée par l\'application ou par votre organisation"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorer le tutoriel de navigation ?"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 88813f2..e4f5de2 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -86,8 +86,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>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Para usar a pantalla dividida, toca outra app"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolle outra app para usar a pantalla dividida"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"A aplicación ou a túa organización non permite realizar esta acción"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Queres omitir o titorial de navegación?"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 2fb5516..03bbfe9 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"શેર કરો"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"સ્ક્રીનશૉટ"</string>
     <string name="action_split" msgid="2098009717623550676">"વિભાજિત કરો"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"વિભાજિત સ્ક્રીન વાપરવા, કોઈ અન્ય ઍપ પર ટૅપ કરો"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"સ્ક્રીન વિભાજનનો ઉપયોગ કરવા કોઈ અન્ય ઍપ પસંદ કરો"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ઍપ કે તમારી સંસ્થા દ્વારા આ ક્રિયા કરવાની મંજૂરી નથી"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"નૅવિગેશન ટ્યૂટૉરિઅલ છોડી દઈએ?"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 8b66b4d..4c67c5d 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Bagikan"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Pisahkan"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Ketuk apl lain untuk menggunakan layar terpisah"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pilih aplikasi lain untuk memakai layar terpisah"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak diizinkan oleh aplikasi atau organisasi Anda"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Lewati tutorial gestur?"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 1f83c3d..d5a04be 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Deila"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Skjámynd"</string>
     <string name="action_split" msgid="2098009717623550676">"Skipta"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Ýttu á annað forrit til að nota skjáskiptingu"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Veldu annað forrit til að nota skjáskiptingu"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Forritið eða fyrirtækið leyfir ekki þessa aðgerð"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Sleppa flettileiðsögn?"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 8dfe52a..fb54446 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"共有"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"スクリーンショット"</string>
     <string name="action_split" msgid="2098009717623550676">"分割"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"分割画面を使用するには、他のアプリをタップします"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"分割画面にするには、別のアプリを選択してください"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"この操作はアプリまたは組織で許可されていません"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"操作チュートリアルをスキップしますか?"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 1a0f693..f5a59bc 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Бөлісу"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
     <string name="action_split" msgid="2098009717623550676">"Бөлу"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлу режимін пайдалану үшін басқа қолданбаны түртіңіз."</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлу үшін басқа қолданбаны таңдаңыз."</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Бұл әрекетке қолданба не ұйым рұқсат етпейді."</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Қимылдар оқулығын өткізіп жіберу керек пе?"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 0af23b1..8881134 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"ចែករំលែក"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"រូបថតអេក្រង់"</string>
     <string name="action_split" msgid="2098009717623550676">"បំបែក"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"ចុចកម្មវិធី​ផ្សេងទៀត ដើម្បីប្រើ​មុខងារបំបែកអេក្រង់"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ជ្រើសរើសកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារ​បំបែកអេក្រង់"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"សកម្មភាពនេះ​មិនត្រូវបានអនុញ្ញាតដោយកម្មវិធី​ ឬ​ស្ថាប័ន​របស់អ្នកទេ"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"រំលង​មេរៀន​អំពី​ការរុករក​ឬ?"</string>
diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml
index 30983c4..ee594c8 100644
--- a/quickstep/res/values-land/dimens.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -82,4 +82,6 @@
     <dimen name="taskbar_suw_frame">96dp</dimen>
     <dimen name="taskbar_suw_insets">24dp</dimen>
 
-</resources>
\ No newline at end of file
+    <dimen name="keyboard_quick_switch_taskview_width">205dp</dimen>
+    <dimen name="keyboard_quick_switch_taskview_height">119dp</dimen>
+</resources>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 4573db4..8cf5e12 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Kopīgot"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Veikt ekrānuzņēmumu"</string>
     <string name="action_split" msgid="2098009717623550676">"Sadalīt"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Lai sadalītu ekrānu, pieskarieties citai lietotnei"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Izvēlieties citu lietotni, lai sadalītu ekrānu"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Lietotne vai jūsu organizācija neatļauj veikt šo darbību."</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vai izlaist navigācijas mācības?"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 7bd9a4d..20c462c 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Сподели"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Слика од екранот"</string>
     <string name="action_split" msgid="2098009717623550676">"Раздели"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Допрете друга аплик. за да користите поделен екран"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Изберете друга апликација за да користите поделен екран"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Апликацијата или вашата организација не го дозволува дејствово"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Да се прескокне упатството за навигација?"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 9050963..47d840a 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Хуваалцах"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Дэлгэцийн агшин дарах"</string>
     <string name="action_split" msgid="2098009717623550676">"Хуваах"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Дэлгэцийг хуваахыг ашиглахын тулд өөр аппыг товш"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Дэлгэцийг хуваах горим ашиглах өөр апп сонгоно уу"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Энэ үйлдлийг апп эсвэл танай байгууллага зөвшөөрдөггүй"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Навигацын практик хичээлийг алгасах уу?"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index a763da1..8d77bd1 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"शेअर करा"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट"</string>
     <string name="action_split" msgid="2098009717623550676">"स्प्लिट"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन वापरण्यासाठी दुसऱ्या ॲपवर टॅप करा"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"स्प्लिट स्क्रीन वापरण्यासाठी दुसरे ॲप निवडा"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"अ‍ॅप किंवा तुमच्या संस्थेद्वारे ही क्रिया करण्याची अनुमती नाही"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"नेव्हिगेशन ट्यूटोरियल वगळायचे आहे का?"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 2242e69..f75171f 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Del"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Skjermdump"</string>
     <string name="action_split" msgid="2098009717623550676">"Del opp"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Trykk på en annen app for å bruke delt skjerm"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Velg en annen app for å bruke delt skjerm"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisasjonen din tillater ikke denne handlingen"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vil du hoppe over navigeringsveiledningen?"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 36c91a8..1f15b28 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"ସେୟାର୍ କରନ୍ତୁ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ସ୍କ୍ରିନସଟ୍"</string>
     <string name="action_split" msgid="2098009717623550676">"ସ୍ପ୍ଲିଟ୍"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"ସ୍ପ୍ଲିଟସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପରେ ଟାପ କର"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପ ବାଛନ୍ତୁ"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ଆପ୍ କିମ୍ବା ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ଏହି କାର୍ଯ୍ୟକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ନାଭିଗେସନ୍ ଟ୍ୟୁଟୋରିଆଲକୁ ବାଦ୍ ଦେବେ?"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 121eaa7..fb809cd 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"ਸਾਂਝਾ ਕਰੋ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
     <string name="action_split" msgid="2098009717623550676">"ਸਪਲਿਟ"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਨੂੰ ਚੁਣੋ"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਇਸ ਕਾਰਵਾਈ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ਕੀ ਨੈਵੀਗੇਸ਼ਨ ਟਿਊਟੋਰੀਅਲ ਨੂੰ ਛੱਡਣਾ ਹੈ?"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 7f60555..dca735c 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Distribuie"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Captură de ecran"</string>
     <string name="action_split" msgid="2098009717623550676">"Împărțit"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Atinge altă aplicație pentru ecranul împărțit"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Alege altă aplicație pentru ecranul împărțit"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Această acțiune nu este permisă de aplicație sau de organizația ta"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Omiți tutorialul de navigare?"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 65adf5f..4cb1adf 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"බෙදා ගන්න"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"තිර රුව"</string>
     <string name="action_split" msgid="2098009717623550676">"බෙදන්න"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"බෙදුම් තිරය භාවිතා කිරීමට තවත් යෙදුමක් තට්ටු කරන්න"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"බෙදීම් තිරය භාවිතා කිරීමට වෙනත් යෙදුමක් තෝරා ගන්න"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"මෙම ක්‍රියාව යෙදුම හෝ ඔබේ සංවිධානය මගින් ඉඩ නොදේ"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"නිබන්ධනය සංචාලනය මඟ හරින්නද?"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index b4ffcdd..56cc6ff 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Дели"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Снимак екрана"</string>
     <string name="action_split" msgid="2098009717623550676">"Подели"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Додирните другу апликацију за подељени екран"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Одаберите другу апликацију за подељени екран"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Апликација или организација не дозвољавају ову радњу"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Желите да прескочите водич за кретање?"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index b2258b0..0200c50 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -86,8 +86,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>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <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_split_app_unsupported" msgid="2360229567007828914">"Välj en annan app för att använda delad skärm"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisationen tillåter inte den här åtgärden"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vill du hoppa över självstudierna?"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index bf68a17..a4d4b28 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Shiriki"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Picha ya skrini"</string>
     <string name="action_split" msgid="2098009717623550676">"Iliyogawanywa"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Gusa programu nyingine ili utumie kipengele cha kugawa skrini"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Chagua programu nyingine ili utumie hali ya kugawa skrini"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Kitendo hiki hakiruhusiwi na programu au shirika lako"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ungependa kuruka mafunzo ya usogezaji?"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 0abe1a5..cdc0312 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"பகிர்"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ஸ்கிரீன்ஷாட்"</string>
     <string name="action_split" msgid="2098009717623550676">"பிரி"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"திரைப் பிரிப்பைப் பயன்படுத்த வேறு ஆப்ஸைத் தட்டவும்"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"திரைப் பிரிப்பை பயன்படுத்த வேறு ஆப்ஸை தேர்வுசெய்க"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ஆப்ஸோ உங்கள் நிறுவனமோ இந்த செயலை அனுமதிப்பதில்லை"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"வழிகாட்டுதல் பயிற்சியைத் தவிர்க்கவா?"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index f062c4b..bec2d17 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Ibahagi"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Split"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Mag-tap ng ibang app para gamitin ang split screen"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pumili ng ibang app para gamitin ang split screen"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Hindi pinapayagan ng app o ng iyong organisasyon ang pagkilos na ito"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Laktawan ang tutorial sa pag-navigate?"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index a287128..9d422e9 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Paylaş"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Ekran görüntüsü"</string>
     <string name="action_split" msgid="2098009717623550676">"Böl"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran için başka bir uygulamaya dokunun"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Bölünmüş ekran kullanmak için başka bir uygulama seçin"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Uygulamanız veya kuruluşunuz bu işleme izin vermiyor"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Gezinme eğitimi atlansın mı?"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 949749a..70c0e1b 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Поділитися"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Знімок екрана"</string>
     <string name="action_split" msgid="2098009717623550676">"Розділити"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Щоб розділити екран, виберіть ще один додаток"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Щоб розділити екран, виберіть ще один додаток"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Ця дія заборонена додатком або адміністратором організації"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропустити посібник із навігації?"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index af33222..8382890 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"اشتراک کریں"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"اسکرین شاٹ"</string>
     <string name="action_split" msgid="2098009717623550676">"اسپلٹ"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"اسپلٹ اسکرین کا استعمال کرنے کیلئے دوسری ایپ پر تھپتھپائیں"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"اسپلٹ اسکرین کے استعمال کیلئے دوسری ایپ منتخب کریں"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ایپ یا آپ کی تنظیم کی جانب سے اس کارروائی کی اجازت نہیں ہے"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"نیویگیشن کا ٹیوٹوریل نظر انداز کریں؟"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index fab7254..a946d1b 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -86,8 +86,7 @@
     <string name="action_share" msgid="2648470652637092375">"Chia sẻ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Chụp ảnh màn hình"</string>
     <string name="action_split" msgid="2098009717623550676">"Chia đôi màn hình"</string>
-    <!-- no translation found for toast_split_select_app (8464310533320556058) -->
-    <skip />
+    <string name="toast_split_select_app" msgid="8464310533320556058">"Nhấn vào ứng dụng khác để chia đôi màn hình"</string>
     <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Chọn một ứng dụng khác để dùng chế độ chia đôi màn hình"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Ứng dụng hoặc tổ chức của bạn không cho phép thực hiện hành động này"</string>
     <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Bỏ qua phần hướng dẫn thao tác?"</string>
diff --git a/quickstep/res/values/attrs.xml b/quickstep/res/values/attrs.xml
index 336fb57..f1d4dab 100644
--- a/quickstep/res/values/attrs.xml
+++ b/quickstep/res/values/attrs.xml
@@ -19,4 +19,13 @@
         <attr name="android:textSize"/>
         <attr name="android:fontFamily"/>
     </declare-styleable>
+
+    <!--
+         TaskView specific attributes. These attributes are used to customize a TaskView view in
+         XML files.
+     -->
+    <declare-styleable name="TaskView">
+        <!-- Border color for a keyboard quick switch task views -->
+        <attr name="borderColor" format="color" />
+    </declare-styleable>
 </resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 3846a9c..d5e8351 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -328,4 +328,16 @@
     <!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
     <!--     starting_surface_exit_animation_window_shift_length -->
     <dimen name="starting_surface_exit_animation_window_shift_length">20dp</dimen>
+
+    <!-- Keyboard Quick Switch -->
+    <dimen name="keyboard_quick_switch_border_width">4dp</dimen>
+    <dimen name="keyboard_quick_switch_taskview_width">104dp</dimen>
+    <dimen name="keyboard_quick_switch_taskview_height">134dp</dimen>
+    <dimen name="keyboard_quick_switch_recents_icon_size">20dp</dimen>
+    <dimen name="keyboard_quick_switch_margin_top">56dp</dimen>
+    <dimen name="keyboard_quick_switch_margin_ends">16dp</dimen>
+    <dimen name="keyboard_quick_switch_view_spacing">16dp</dimen>
+    <dimen name="keyboard_quick_switch_split_view_spacing">2dp</dimen>
+    <dimen name="keyboard_quick_switch_view_radius">28dp</dimen>
+    <dimen name="keyboard_quick_switch_task_view_radius">16dp</dimen>
 </resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index d2f5802..01d92d1 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -282,4 +282,12 @@
     <string name="move_drop_target_top_or_left">Move to top&#47;left</string>
     <!-- Label for moving drop target to the bottom or right side of the screen, depending on orientation (from the Taskbar only). -->
     <string name="move_drop_target_bottom_or_right">Move to bottom&#47;right</string>
+
+    <!-- Label for quick switch tile showing how many more apps are available [CHAR LIMIT=NONE] -->
+    <string name="quick_switch_overflow">{count, plural,
+            =1{Show # more app.}
+            other{Show # more apps.}
+        }</string>
+    <!-- Accessibility label for quick switch tiles showing split tasks [CHAR LIMIT=NONE] -->
+    <string name="quick_switch_split_task"><xliff:g id="app_name_1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app_name_2" example="Gmail">%2$s</xliff:g></string>
 </resources>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 6119eb6..4417407 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -223,4 +223,11 @@
         <item name="android:fontFamily">google-sans-text</item>
         <item name="android:textSize">14sp</item>
     </style>
-</resources>
\ No newline at end of file
+
+    <style name="KeyboardQuickSwitchOverview">
+        <item name="fontFamily">google-sans-text</item>
+        <item name="android:textSize">14sp</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+        <item name="lineHeight">20sp</item>
+    </style>
+</resources>
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index ad6ce7d..2e1318b 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -112,10 +112,23 @@
     }
 
     @Override
-    @WorkerThread
-    public void loadItems(UserManagerState ums, Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
+    public void loadHotseatItems(UserManagerState ums,
+            Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
         // TODO: Implement caching and preloading
-        super.loadItems(ums, pinnedShortcuts);
+        super.loadHotseatItems(ums, pinnedShortcuts);
+
+        WorkspaceItemFactory hotseatFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts,
+                mIDP.numDatabaseHotseatIcons, mHotseatState.containerId);
+        FixedContainerItems hotseatItems = new FixedContainerItems(mHotseatState.containerId,
+                mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get));
+        mDataModel.extraItems.put(mHotseatState.containerId, hotseatItems);
+    }
+
+    @Override
+    public void loadAllAppsItems(UserManagerState ums,
+            Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
+        // TODO: Implement caching and preloading
+        super.loadAllAppsItems(ums, pinnedShortcuts);
 
         WorkspaceItemFactory allAppsFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts,
                 mIDP.numDatabaseAllAppsColumns, mAllAppsState.containerId);
@@ -123,17 +136,22 @@
                 mAllAppsState.containerId, mAllAppsState.storage.read(mApp.getContext(),
                 allAppsFactory, ums.allUsers::get));
         mDataModel.extraItems.put(mAllAppsState.containerId, allAppsPredictionItems);
+    }
 
-        WorkspaceItemFactory hotseatFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts,
-                mIDP.numDatabaseHotseatIcons, mHotseatState.containerId);
-        FixedContainerItems hotseatItems = new FixedContainerItems(mHotseatState.containerId,
-                mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get));
-        mDataModel.extraItems.put(mHotseatState.containerId, hotseatItems);
+    @Override
+    public void loadWidgetsRecommendationItems() {
+        // TODO: Implement caching and preloading
+        super.loadWidgetsRecommendationItems();
 
         // Widgets prediction isn't used frequently. And thus, it is not persisted on disk.
         mDataModel.extraItems.put(mWidgetsRecommendationState.containerId,
                 new FixedContainerItems(mWidgetsRecommendationState.containerId,
                         new ArrayList<>()));
+    }
+
+    @Override
+    public void markActive() {
+        super.markActive();
         mActive = true;
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
new file mode 100644
index 0000000..c4962cd
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.R;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
+import com.android.quickstep.RecentsModel;
+import com.android.quickstep.util.GroupTask;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+/**
+ * Handles initialization of the {@link KeyboardQuickSwitchViewController}.
+ */
+public final class KeyboardQuickSwitchController implements
+        TaskbarControllers.LoggableTaskbarController {
+
+    static final int MAX_TASKS = 6;
+
+    @NonNull private final ControllerCallbacks mControllerCallbacks = new ControllerCallbacks();
+
+    // Initialized on init
+    @Nullable private RecentsModel mModel;
+
+    // Used to keep track of the last requested task list id, so that we do not request to load the
+    // tasks again if we have already requested it and the task list has not changed
+    private int mTaskListChangeId = -1;
+    // Only empty before the recent tasks list has been loaded the first time
+    @NonNull private List<GroupTask> mTasks = new ArrayList<>();
+    private int mNumHiddenTasks = 0;
+
+    // Initialized in init
+    private TaskbarControllers mControllers;
+
+    @Nullable private KeyboardQuickSwitchViewController mQuickSwitchViewController;
+
+    /** Initialize the controller. */
+    public void init(@NonNull TaskbarControllers controllers) {
+        mControllers = controllers;
+        mModel = RecentsModel.INSTANCE.get(controllers.taskbarActivityContext);
+    }
+
+    void onConfigurationChanged(@ActivityInfo.Config int configChanges) {
+        if (mQuickSwitchViewController == null) {
+            return;
+        }
+        if ((configChanges & (ActivityInfo.CONFIG_KEYBOARD
+                | ActivityInfo.CONFIG_KEYBOARD_HIDDEN)) != 0) {
+            mQuickSwitchViewController.closeQuickSwitchView(true);
+            return;
+        }
+        int currentFocusedIndex = mQuickSwitchViewController.getCurrentFocusedIndex();
+        onDestroy();
+        if (currentFocusedIndex != -1) {
+            mControllers.taskbarActivityContext.getMainThreadHandler().post(
+                    () -> openQuickSwitchView(currentFocusedIndex));
+        }
+    }
+
+    void openQuickSwitchView() {
+        openQuickSwitchView(-1);
+    }
+
+    private void openQuickSwitchView(int currentFocusedIndex) {
+        if (mQuickSwitchViewController != null) {
+            return;
+        }
+        TaskbarOverlayContext overlayContext =
+                mControllers.taskbarOverlayController.requestWindow();
+        KeyboardQuickSwitchView keyboardQuickSwitchView =
+                (KeyboardQuickSwitchView) overlayContext.getLayoutInflater()
+                        .inflate(
+                                R.layout.keyboard_quick_switch_view,
+                                overlayContext.getDragLayer(),
+                                /* attachToRoot= */ false);
+        mQuickSwitchViewController = new KeyboardQuickSwitchViewController(
+                mControllers, overlayContext, keyboardQuickSwitchView, mControllerCallbacks);
+
+        if (mModel.isTaskListValid(mTaskListChangeId)) {
+            mQuickSwitchViewController.openQuickSwitchView(
+                    mTasks, mNumHiddenTasks, /* updateTasks= */ false, currentFocusedIndex);
+            return;
+        }
+        mTaskListChangeId = mModel.getTasks((tasks) -> {
+            // Only store MAX_TASK tasks, from most to least recent
+            Collections.reverse(tasks);
+            mTasks = tasks.stream().limit(MAX_TASKS).collect(Collectors.toList());
+            mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS);
+            mQuickSwitchViewController.openQuickSwitchView(
+                    mTasks, mNumHiddenTasks, /* updateTasks= */ true, currentFocusedIndex);
+        });
+    }
+
+    void closeQuickSwitchView() {
+        if (mQuickSwitchViewController == null) {
+            return;
+        }
+        mQuickSwitchViewController.closeQuickSwitchView(true);
+    }
+
+    /**
+     * See {@link TaskbarUIController#launchFocusedTask()}
+     */
+    int launchFocusedTask() {
+        // Return -1 so that the RecentsView is not incorrectly opened when the user closes the
+        // quick switch view by tapping the screen.
+        return mQuickSwitchViewController == null
+                ? -1 : mQuickSwitchViewController.launchFocusedTask();
+    }
+
+    void onDestroy() {
+        if (mQuickSwitchViewController != null) {
+            mQuickSwitchViewController.onDestroy();
+        }
+    }
+
+    @Override
+    public void dumpLogs(String prefix, PrintWriter pw) {
+        pw.println(prefix + "KeyboardQuickSwitchController:");
+
+        pw.println(prefix + "\tisOpen=" + (mQuickSwitchViewController != null));
+        pw.println(prefix + "\tmNumHiddenTasks=" + mNumHiddenTasks);
+        pw.println(prefix + "\tmTaskListChangeId=" + mTaskListChangeId);
+        pw.println(prefix + "\tmTasks=[");
+        for (GroupTask task : mTasks) {
+            Task task1 = task.task1;
+            Task task2 = task.task2;
+            ComponentName cn1 = task1.getTopComponent();
+            ComponentName cn2 = task2 != null ? task2.getTopComponent() : null;
+            pw.println(prefix + "\t\tt1: (id=" + task1.key.id
+                    + "; package=" + (cn1 != null ? cn1.getPackageName() + ")" : "no package)")
+                    + " t2: (id=" + (task2 != null ? task2.key.id : "-1")
+                    + "; package=" + (cn2 != null ? cn2.getPackageName() + ")"
+                    : "no package)"));
+        }
+        pw.println(prefix + "\t]");
+
+        if (mQuickSwitchViewController != null) {
+            mQuickSwitchViewController.dumpLogs(prefix + '\t', pw);
+        }
+    }
+
+    class ControllerCallbacks {
+
+        int getTaskCount() {
+            return mNumHiddenTasks == 0 ? mTasks.size() : MAX_TASKS + 1;
+        }
+
+        @Nullable
+        GroupTask getTaskAt(int index) {
+            return index < 0 || index >= mTasks.size() ? null : mTasks.get(index);
+        }
+
+        void updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback) {
+            mModel.getThumbnailCache().updateThumbnailInBackground(task, callback);
+        }
+
+        void updateTitleInBackground(Task task, Consumer<Task> callback) {
+            mModel.getIconCache().updateIconInBackground(task, callback);
+        }
+
+        void onCloseComplete() {
+            mQuickSwitchViewController = null;
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
new file mode 100644
index 0000000..84129fd
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
@@ -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.taskbar;
+
+import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
+
+import android.animation.Animator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.launcher3.R;
+import com.android.quickstep.util.BorderAnimator;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.util.function.Consumer;
+
+/**
+ * A view that displays a recent task during a keyboard quick switch.
+ */
+public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
+
+    @NonNull private final BorderAnimator mBorderAnimator;
+
+    @Nullable private ImageView mThumbnailView1;
+    @Nullable private ImageView mThumbnailView2;
+
+    public KeyboardQuickSwitchTaskView(@NonNull Context context) {
+        this(context, null);
+    }
+
+    public KeyboardQuickSwitchTaskView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyboardQuickSwitchTaskView(
+            @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public KeyboardQuickSwitchTaskView(
+            @NonNull Context context,
+            @Nullable AttributeSet attrs,
+            int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        setWillNotDraw(false);
+        Resources resources = context.getResources();
+        mBorderAnimator = new BorderAnimator(
+                /* borderBoundsBuilder= */ bounds -> bounds.set(0, 0, getWidth(), getHeight()),
+                /* borderWidthPx= */ resources.getDimensionPixelSize(
+                        R.dimen.keyboard_quick_switch_border_width),
+                /* borderRadiusPx= */ resources.getDimensionPixelSize(
+                        R.dimen.keyboard_quick_switch_task_view_radius),
+                /* borderColor= */ attrs == null
+                        ? DEFAULT_BORDER_COLOR
+                        : context.getTheme()
+                                .obtainStyledAttributes(
+                                        attrs,
+                                        R.styleable.TaskView,
+                                        defStyleAttr,
+                                        defStyleRes)
+                                .getColor(
+                                        R.styleable.TaskView_borderColor,
+                                        DEFAULT_BORDER_COLOR),
+                /* invalidateViewCallback= */ KeyboardQuickSwitchTaskView.this::invalidate);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mThumbnailView1 = findViewById(R.id.thumbnail1);
+        mThumbnailView2 = findViewById(R.id.thumbnail2);
+    }
+
+    @NonNull
+    protected Animator getFocusAnimator(boolean focused) {
+        return mBorderAnimator.buildAnimator(focused);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+        mBorderAnimator.drawBorder(canvas);
+    }
+
+    protected void setThumbnails(
+            @NonNull Task task1,
+            @Nullable Task task2,
+            @Nullable ThumbnailUpdateFunction thumbnailUpdateFunction,
+            @Nullable TitleUpdateFunction titleUpdateFunction) {
+        applyThumbnail(mThumbnailView1, task1, thumbnailUpdateFunction);
+        applyThumbnail(mThumbnailView2, task2, thumbnailUpdateFunction);
+
+        if (titleUpdateFunction == null) {
+            setContentDescription(task2 == null
+                    ? task1.titleDescription
+                    : getContext().getString(
+                            R.string.quick_switch_split_task,
+                            task1.titleDescription,
+                            task2.titleDescription));
+            return;
+        }
+        titleUpdateFunction.updateTitleInBackground(task1, t ->
+                setContentDescription(task1.titleDescription));
+        if (task2 == null) {
+            return;
+        }
+        titleUpdateFunction.updateTitleInBackground(task2, t ->
+                setContentDescription(getContext().getString(
+                        R.string.quick_switch_split_task,
+                        task1.titleDescription,
+                        task2.titleDescription)));
+    }
+
+    private void applyThumbnail(
+            @Nullable ImageView thumbnailView,
+            @Nullable Task task,
+            @Nullable ThumbnailUpdateFunction updateFunction) {
+        if (thumbnailView == null) {
+            return;
+        }
+        if (task == null) {
+            return;
+        }
+        if (updateFunction == null) {
+            applyThumbnail(thumbnailView, task.thumbnail);
+            return;
+        }
+        updateFunction.updateThumbnailInBackground(
+                task, thumbnailData -> applyThumbnail(thumbnailView, thumbnailData));
+    }
+
+    private void applyThumbnail(
+            @NonNull ImageView thumbnailView, ThumbnailData thumbnailData) {
+        Bitmap bm = thumbnailData == null ? null : thumbnailData.thumbnail;
+
+        thumbnailView.setVisibility(VISIBLE);
+        thumbnailView.setImageBitmap(bm);
+    }
+
+    protected interface ThumbnailUpdateFunction {
+
+        void updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback);
+    }
+
+    protected interface TitleUpdateFunction {
+
+        void updateTitleInBackground(Task task, Consumer<Task> callback);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
new file mode 100644
index 0000000..94d62b2
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -0,0 +1,497 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID;
+
+import static com.android.launcher3.taskbar.KeyboardQuickSwitchController.MAX_TASKS;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Outline;
+import android.graphics.Rect;
+import android.icu.text.MessageFormat;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.view.ViewTreeObserver;
+import android.view.animation.Interpolator;
+import android.widget.HorizontalScrollView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.Interpolators;
+import com.android.quickstep.util.GroupTask;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * View that allows quick switching between recent tasks through keyboard alt-tab and alt-shift-tab
+ * commands.
+ */
+public class KeyboardQuickSwitchView extends ConstraintLayout {
+
+    private static final long OUTLINE_ANIMATION_DURATION_MS = 333;
+    private static final float OUTLINE_START_HEIGHT_FACTOR = 0.45f;
+    private static final float OUTLINE_START_RADIUS_FACTOR = 0.25f;
+    private static final Interpolator OPEN_OUTLINE_INTERPOLATOR =
+            Interpolators.EMPHASIZED_DECELERATE;
+    private static final Interpolator CLOSE_OUTLINE_INTERPOLATOR =
+            Interpolators.EMPHASIZED_ACCELERATE;
+
+    private static final long ALPHA_ANIMATION_DURATION_MS = 83;
+    private static final long ALPHA_ANIMATION_START_DELAY_MS = 67;
+
+    private static final long CONTENT_TRANSLATION_X_ANIMATION_DURATION_MS = 500;
+    private static final long CONTENT_TRANSLATION_Y_ANIMATION_DURATION_MS = 333;
+    private static final float CONTENT_START_TRANSLATION_X_DP = 32;
+    private static final float CONTENT_START_TRANSLATION_Y_DP = 40;
+    private static final Interpolator OPEN_TRANSLATION_X_INTERPOLATOR = Interpolators.EMPHASIZED;
+    private static final Interpolator OPEN_TRANSLATION_Y_INTERPOLATOR =
+            Interpolators.EMPHASIZED_DECELERATE;
+    private static final Interpolator CLOSE_TRANSLATION_Y_INTERPOLATOR =
+            Interpolators.EMPHASIZED_ACCELERATE;
+
+    private static final long CONTENT_ALPHA_ANIMATION_DURATION_MS = 83;
+    private static final long CONTENT_ALPHA_ANIMATION_START_DELAY_MS = 83;
+
+    private final AnimatedFloat mOutlineAnimationProgress = new AnimatedFloat(
+            this::invalidateOutline);
+
+    private HorizontalScrollView mScrollView;
+    private ConstraintLayout mContent;
+
+    private int mTaskViewHeight;
+    private int mSpacing;
+    private int mOutlineRadius;
+    private boolean mIsRtl;
+
+    @Nullable private AnimatorSet mOpenAnimation;
+
+    @Nullable private KeyboardQuickSwitchViewController.ViewCallbacks mViewCallbacks;
+
+    public KeyboardQuickSwitchView(@NonNull Context context) {
+        this(context, null);
+    }
+
+    public KeyboardQuickSwitchView(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public KeyboardQuickSwitchView(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public KeyboardQuickSwitchView(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mScrollView = findViewById(R.id.scroll_view);
+        mContent = findViewById(R.id.content);
+
+        Resources resources = getResources();
+        mTaskViewHeight = resources.getDimensionPixelSize(
+                R.dimen.keyboard_quick_switch_taskview_height);
+        mSpacing = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_spacing);
+        mOutlineRadius = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_view_radius);
+        mIsRtl = Utilities.isRtl(resources);
+    }
+
+    @NonNull
+    private KeyboardQuickSwitchTaskView createAndAddTaskView(
+            int index,
+            int width,
+            boolean isFinalView,
+            boolean updateTasks,
+            @NonNull LayoutInflater layoutInflater,
+            @Nullable View previousView,
+            @NonNull List<GroupTask> groupTasks) {
+        KeyboardQuickSwitchTaskView taskView = (KeyboardQuickSwitchTaskView) layoutInflater.inflate(
+                R.layout.keyboard_quick_switch_taskview, mContent, false);
+        taskView.setId(View.generateViewId());
+        taskView.setOnClickListener(v -> mViewCallbacks.launchTappedTask(index));
+
+        LayoutParams lp = new LayoutParams(width, mTaskViewHeight);
+        // Create a right-to-left ordering of views (or left-to-right in RTL locales)
+        if (previousView != null) {
+            lp.endToStart = previousView.getId();
+        } else {
+            lp.endToEnd = PARENT_ID;
+        }
+        lp.topToTop = PARENT_ID;
+        lp.bottomToBottom = PARENT_ID;
+        // Add spacing between views
+        lp.setMarginEnd(mSpacing);
+        if (isFinalView) {
+            // Add spacing to the start of the final view so that scrolling ends with some padding.
+            lp.startToStart = PARENT_ID;
+            lp.setMarginStart(mSpacing);
+            lp.horizontalBias = 1f;
+        }
+
+        GroupTask groupTask = groupTasks.get(index);
+        taskView.setThumbnails(
+                groupTask.task1,
+                groupTask.task2,
+                updateTasks ? mViewCallbacks::updateThumbnailInBackground : null,
+                updateTasks ? mViewCallbacks::updateTitleInBackground : null);
+
+        mContent.addView(taskView, lp);
+        return taskView;
+    }
+
+    private void createAndAddOverviewButton(
+            int width,
+            @NonNull LayoutInflater layoutInflater,
+            @Nullable View previousView,
+            @NonNull String overflowString) {
+        KeyboardQuickSwitchTaskView overviewButton =
+                (KeyboardQuickSwitchTaskView) layoutInflater.inflate(
+                        R.layout.keyboard_quick_switch_overview, this, false);
+        overviewButton.setOnClickListener(v -> mViewCallbacks.launchTappedTask(MAX_TASKS));
+
+        overviewButton.<TextView>findViewById(R.id.text).setText(overflowString);
+
+        ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
+                width, mTaskViewHeight);
+        lp.startToStart = PARENT_ID;
+        lp.endToStart = previousView.getId();
+        lp.topToTop = PARENT_ID;
+        lp.bottomToBottom = PARENT_ID;
+        lp.setMarginEnd(mSpacing);
+        lp.setMarginStart(mSpacing);
+
+        mContent.addView(overviewButton, lp);
+    }
+
+    protected void applyLoadPlan(
+            @NonNull Context context,
+            @NonNull List<GroupTask> groupTasks,
+            int numHiddenTasks,
+            boolean updateTasks,
+            int currentFocusIndexOverride,
+            @NonNull KeyboardQuickSwitchViewController.ViewCallbacks viewCallbacks) {
+        if (groupTasks.isEmpty()) {
+            // Do not show the quick switch view.
+            return;
+        }
+        mViewCallbacks = viewCallbacks;
+        Resources resources = context.getResources();
+        int width = resources.getDimensionPixelSize(R.dimen.keyboard_quick_switch_taskview_width);
+        View previousView = null;
+
+        LayoutInflater layoutInflater = LayoutInflater.from(context);
+        int tasksToDisplay = Math.min(MAX_TASKS, groupTasks.size());
+        for (int i = 0; i < tasksToDisplay; i++) {
+            previousView = createAndAddTaskView(
+                    i,
+                    width,
+                    /* isFinalView= */ i == tasksToDisplay - 1 && numHiddenTasks == 0,
+                    updateTasks,
+                    layoutInflater,
+                    previousView,
+                    groupTasks);
+        }
+
+        if (numHiddenTasks > 0) {
+            HashMap<String, Integer> args = new HashMap<>();
+            args.put("count", numHiddenTasks);
+            createAndAddOverviewButton(
+                    width,
+                    layoutInflater,
+                    previousView,
+                    new MessageFormat(
+                            resources.getString(R.string.quick_switch_overflow),
+                            Locale.getDefault()).format(args));
+        }
+
+        getViewTreeObserver().addOnGlobalLayoutListener(
+                new ViewTreeObserver.OnGlobalLayoutListener() {
+                    @Override
+                    public void onGlobalLayout() {
+                        animateOpen(currentFocusIndexOverride);
+
+                        getViewTreeObserver().removeOnGlobalLayoutListener(this);
+                    }
+                });
+    }
+
+    protected Animator getCloseAnimation() {
+        AnimatorSet closeAnimation = new AnimatorSet();
+
+        Animator outlineAnimation = mOutlineAnimationProgress.animateToValue(0f);
+        outlineAnimation.setDuration(OUTLINE_ANIMATION_DURATION_MS);
+        outlineAnimation.setInterpolator(CLOSE_OUTLINE_INTERPOLATOR);
+        closeAnimation.play(outlineAnimation);
+
+        Animator alphaAnimation = ObjectAnimator.ofFloat(this, ALPHA, 1f, 0f);
+        alphaAnimation.setStartDelay(ALPHA_ANIMATION_START_DELAY_MS);
+        alphaAnimation.setDuration(ALPHA_ANIMATION_DURATION_MS);
+        closeAnimation.play(alphaAnimation);
+
+        Animator translationYAnimation = ObjectAnimator.ofFloat(
+                mScrollView, TRANSLATION_Y, 0, -Utilities.dpToPx(CONTENT_START_TRANSLATION_Y_DP));
+        translationYAnimation.setDuration(CONTENT_TRANSLATION_Y_ANIMATION_DURATION_MS);
+        translationYAnimation.setInterpolator(CLOSE_TRANSLATION_Y_INTERPOLATOR);
+        closeAnimation.play(translationYAnimation);
+
+        Animator contentAlphaAnimation = ObjectAnimator.ofFloat(mScrollView, ALPHA, 1f, 0f);
+        contentAlphaAnimation.setDuration(CONTENT_ALPHA_ANIMATION_DURATION_MS);
+        closeAnimation.play(contentAlphaAnimation);
+
+        closeAnimation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                if (mOpenAnimation != null) {
+                    mOpenAnimation.cancel();
+                }
+            }
+        });
+
+        return closeAnimation;
+    }
+
+    private void animateOpen(int currentFocusIndexOverride) {
+        if (mOpenAnimation != null) {
+            // Restart animation since currentFocusIndexOverride can change the initial scroll.
+            mOpenAnimation.cancel();
+        }
+        mOpenAnimation = new AnimatorSet();
+
+        Animator outlineAnimation = mOutlineAnimationProgress.animateToValue(1f);
+        outlineAnimation.setDuration(OUTLINE_ANIMATION_DURATION_MS);
+        mOpenAnimation.play(outlineAnimation);
+
+        Animator alphaAnimation = ObjectAnimator.ofFloat(this, ALPHA, 0f, 1f);
+        alphaAnimation.setDuration(ALPHA_ANIMATION_DURATION_MS);
+        mOpenAnimation.play(alphaAnimation);
+
+        Animator translationXAnimation = ObjectAnimator.ofFloat(
+                mScrollView, TRANSLATION_X, -Utilities.dpToPx(CONTENT_START_TRANSLATION_X_DP), 0);
+        translationXAnimation.setDuration(CONTENT_TRANSLATION_X_ANIMATION_DURATION_MS);
+        translationXAnimation.setInterpolator(OPEN_TRANSLATION_X_INTERPOLATOR);
+        mOpenAnimation.play(translationXAnimation);
+
+        Animator translationYAnimation = ObjectAnimator.ofFloat(
+                mScrollView, TRANSLATION_Y, -Utilities.dpToPx(CONTENT_START_TRANSLATION_Y_DP), 0);
+        translationYAnimation.setDuration(CONTENT_TRANSLATION_Y_ANIMATION_DURATION_MS);
+        translationYAnimation.setInterpolator(OPEN_TRANSLATION_Y_INTERPOLATOR);
+        mOpenAnimation.play(translationYAnimation);
+
+        Animator contentAlphaAnimation = ObjectAnimator.ofFloat(mScrollView, ALPHA, 0f, 1f);
+        contentAlphaAnimation.setStartDelay(CONTENT_ALPHA_ANIMATION_START_DELAY_MS);
+        contentAlphaAnimation.setDuration(CONTENT_ALPHA_ANIMATION_DURATION_MS);
+        mOpenAnimation.play(contentAlphaAnimation);
+
+        ViewOutlineProvider outlineProvider = getOutlineProvider();
+        mOpenAnimation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                setClipToPadding(false);
+                setOutlineProvider(new ViewOutlineProvider() {
+                    @Override
+                    public void getOutline(View view, Outline outline) {
+                        outline.setRoundRect(
+                                /* rect= */ new Rect(
+                                        /* left= */ 0,
+                                        /* top= */ 0,
+                                        /* right= */ getWidth(),
+                                        /* bottom= */
+                                        (int) (getHeight() * Utilities.mapBoundToRange(
+                                                mOutlineAnimationProgress.value,
+                                                /* lowerBound= */ 0f,
+                                                /* upperBound= */ 1f,
+                                                /* toMin= */ OUTLINE_START_HEIGHT_FACTOR,
+                                                /* toMax= */ 1f,
+                                                OPEN_OUTLINE_INTERPOLATOR))),
+                                /* radius= */ mOutlineRadius * Utilities.mapBoundToRange(
+                                        mOutlineAnimationProgress.value,
+                                        /* lowerBound= */ 0f,
+                                        /* upperBound= */ 1f,
+                                        /* toMin= */ OUTLINE_START_RADIUS_FACTOR,
+                                        /* toMax= */ 1f,
+                                        OPEN_OUTLINE_INTERPOLATOR));
+                    }
+                });
+                if (currentFocusIndexOverride == -1) {
+                    initializeScroll(/* index= */ 0, /* shouldTruncateTarget= */ false);
+                } else {
+                    animateFocusMove(-1, currentFocusIndexOverride);
+                }
+                mScrollView.setVisibility(VISIBLE);
+                setVisibility(VISIBLE);
+                requestFocus();
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                setClipToPadding(true);
+                setOutlineProvider(outlineProvider);
+                invalidateOutline();
+                mOpenAnimation = null;
+            }
+        });
+
+        mOpenAnimation.start();
+    }
+
+    protected void animateFocusMove(int fromIndex, int toIndex) {
+        KeyboardQuickSwitchTaskView focusedTask = getTaskAt(toIndex);
+        if (focusedTask == null) {
+            return;
+        }
+        AnimatorSet focusAnimation = new AnimatorSet();
+        focusAnimation.play(focusedTask.getFocusAnimator(true));
+
+        KeyboardQuickSwitchTaskView previouslyFocusedTask = getTaskAt(fromIndex);
+        if (previouslyFocusedTask != null) {
+            focusAnimation.play(previouslyFocusedTask.getFocusAnimator(false));
+        }
+
+        focusAnimation.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                super.onAnimationStart(animation);
+                focusedTask.requestAccessibilityFocus();
+                if (fromIndex == -1) {
+                    int firstVisibleTaskIndex = toIndex == 0
+                            ? toIndex
+                            : getTaskAt(toIndex - 1) == null
+                                    ? toIndex : toIndex - 1;
+                    // Scroll so that the previous task view is truncated as a visual hint that
+                    // there are more tasks
+                    initializeScroll(
+                            firstVisibleTaskIndex,
+                            /* shouldTruncateTarget= */ firstVisibleTaskIndex != toIndex);
+                } else if (toIndex > fromIndex || toIndex == 0) {
+                    // Scrolling to next task view
+                    if (mIsRtl) {
+                        scrollRightTo(focusedTask);
+                    } else {
+                        scrollLeftTo(focusedTask);
+                    }
+                } else {
+                    // Scrolling to previous task view
+                    if (mIsRtl) {
+                        scrollLeftTo(focusedTask);
+                    } else {
+                        scrollRightTo(focusedTask);
+                    }
+                }
+                if (mViewCallbacks != null) {
+                    mViewCallbacks.updateCurrentFocusIndex(toIndex);
+                }
+            }
+        });
+
+        focusAnimation.start();
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        return (mViewCallbacks != null && mViewCallbacks.onKeyUp(keyCode, event))
+                || super.onKeyUp(keyCode, event);
+    }
+
+    private void initializeScroll(int index, boolean shouldTruncateTarget) {
+        View task = getTaskAt(index);
+        if (task == null) {
+            return;
+        }
+        if (mIsRtl) {
+            scrollRightTo(
+                    task, shouldTruncateTarget, /* smoothScroll= */ false);
+        } else {
+            scrollLeftTo(
+                    task, shouldTruncateTarget, /* smoothScroll= */ false);
+        }
+    }
+
+    private void scrollRightTo(@NonNull View targetTask) {
+        scrollRightTo(targetTask, /* shouldTruncateTarget= */ false, /* smoothScroll= */ true);
+    }
+
+    private void scrollRightTo(
+            @NonNull View targetTask, boolean shouldTruncateTarget, boolean smoothScroll) {
+        if (smoothScroll && !shouldScroll(targetTask, shouldTruncateTarget)) {
+            return;
+        }
+        int scrollTo = targetTask.getLeft() - mSpacing
+                + (shouldTruncateTarget ? targetTask.getWidth() / 2 : 0);
+        // Scroll so that the focused task is to the left of the list
+        if (smoothScroll) {
+            mScrollView.smoothScrollTo(scrollTo, 0);
+        } else {
+            mScrollView.scrollTo(scrollTo, 0);
+        }
+    }
+
+    private void scrollLeftTo(@NonNull View targetTask) {
+        scrollLeftTo(targetTask, /* shouldTruncateTarget= */ false, /* smoothScroll= */ true);
+    }
+
+    private void scrollLeftTo(
+            @NonNull View targetTask, boolean shouldTruncateTarget, boolean smoothScroll) {
+        if (smoothScroll && !shouldScroll(targetTask, shouldTruncateTarget)) {
+            return;
+        }
+        int scrollTo = targetTask.getRight() + mSpacing - mScrollView.getWidth()
+                - (shouldTruncateTarget ? targetTask.getWidth() / 2 : 0);
+        // Scroll so that the focused task is to the right of the list
+        if (smoothScroll) {
+            mScrollView.smoothScrollTo(scrollTo, 0);
+        } else {
+            mScrollView.scrollTo(scrollTo, 0);
+        }
+    }
+
+    private boolean shouldScroll(@NonNull View targetTask, boolean shouldTruncateTarget) {
+        boolean isTargetTruncated =
+                targetTask.getRight() + mSpacing > mScrollView.getScrollX() + mScrollView.getWidth()
+                        || Math.max(0, targetTask.getLeft() - mSpacing) < mScrollView.getScrollX();
+
+        return isTargetTruncated && !shouldTruncateTarget;
+    }
+
+    @Nullable
+    protected KeyboardQuickSwitchTaskView getTaskAt(int index) {
+        return index < 0 || index >= mContent.getChildCount()
+                ? null : (KeyboardQuickSwitchTaskView) mContent.getChildAt(index);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
new file mode 100644
index 0000000..f0f361e
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.animation.Animator;
+import android.view.KeyEvent;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer;
+import com.android.quickstep.util.GroupTask;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * Handles initialization of the {@link KeyboardQuickSwitchView} and supplies it with the list of
+ * tasks.
+ */
+public class KeyboardQuickSwitchViewController {
+
+    @NonNull private final ViewCallbacks mViewCallbacks = new ViewCallbacks();
+    @NonNull private final TaskbarControllers mControllers;
+    @NonNull private final TaskbarOverlayContext mOverlayContext;
+    @NonNull private final KeyboardQuickSwitchView mKeyboardQuickSwitchView;
+    @NonNull private final KeyboardQuickSwitchController.ControllerCallbacks mControllerCallbacks;
+
+    @Nullable private Animator mCloseAnimation;
+
+    private int mCurrentFocusIndex = -1;
+
+    protected KeyboardQuickSwitchViewController(
+            @NonNull TaskbarControllers controllers,
+            @NonNull TaskbarOverlayContext overlayContext,
+            @NonNull KeyboardQuickSwitchView keyboardQuickSwitchView,
+            @NonNull KeyboardQuickSwitchController.ControllerCallbacks controllerCallbacks) {
+        mControllers = controllers;
+        mOverlayContext = overlayContext;
+        mKeyboardQuickSwitchView = keyboardQuickSwitchView;
+        mControllerCallbacks = controllerCallbacks;
+    }
+
+    protected int getCurrentFocusedIndex() {
+        return mCurrentFocusIndex;
+    }
+
+    protected void openQuickSwitchView(
+            @NonNull List<GroupTask> tasks,
+            int numHiddenTasks,
+            boolean updateTasks,
+            int currentFocusIndexOverride) {
+        TaskbarOverlayDragLayer dragLayer = mOverlayContext.getDragLayer();
+        dragLayer.addView(mKeyboardQuickSwitchView);
+        dragLayer.runOnClickOnce(v -> closeQuickSwitchView(true));
+
+        mKeyboardQuickSwitchView.applyLoadPlan(
+                mOverlayContext,
+                tasks,
+                numHiddenTasks,
+                updateTasks,
+                currentFocusIndexOverride,
+                mViewCallbacks);
+    }
+
+    protected void closeQuickSwitchView(boolean animate) {
+        if (mCloseAnimation != null) {
+            if (animate) {
+                // Let currently-running animation finish.
+                return;
+            } else {
+                mCloseAnimation.cancel();
+            }
+        }
+        if (!animate) {
+            mCloseAnimation = null;
+            onCloseComplete();
+            return;
+        }
+        mCloseAnimation = mKeyboardQuickSwitchView.getCloseAnimation();
+
+        mCloseAnimation.addListener(new AnimationSuccessListener() {
+            @Override
+            public void onAnimationSuccess(Animator animator) {
+                mCloseAnimation = null;
+                onCloseComplete();
+            }
+        });
+        mCloseAnimation.start();
+    }
+
+    /**
+     * Launched the currently-focused task.
+     *
+     * Returns index -1 iff the RecentsView shouldn't be opened.
+     *
+     * If the index is not -1, then the {@link com.android.quickstep.views.TaskView} at the returned
+     * index will be focused.
+     */
+    protected int launchFocusedTask() {
+        // Launch the second-most recent task if the user quick switches too quickly, if possible.
+        return launchTaskAt(mCurrentFocusIndex == -1
+                ? (mControllerCallbacks.getTaskCount() > 1 ? 1 : 0) : mCurrentFocusIndex);
+    }
+
+    private int launchTaskAt(int index) {
+        KeyboardQuickSwitchTaskView taskView = mKeyboardQuickSwitchView.getTaskAt(index);
+        GroupTask task = mControllerCallbacks.getTaskAt(index);
+        if (taskView == null || task == null) {
+            return Math.max(0, index);
+        } else if (task.task2 == null) {
+            UI_HELPER_EXECUTOR.execute(() ->
+                    ActivityManagerWrapper.getInstance().startActivityFromRecents(
+                            task.task1.key,
+                            mControllers.taskbarActivityContext.getActivityLaunchOptions(
+                                    taskView, null).options));
+        } else {
+            mControllers.uiController.launchSplitTasks(taskView, task);
+        }
+        return -1;
+    }
+
+    private void onCloseComplete() {
+        mOverlayContext.getDragLayer().removeView(mKeyboardQuickSwitchView);
+        mControllerCallbacks.onCloseComplete();
+    }
+
+    protected void onDestroy() {
+        closeQuickSwitchView(false);
+    }
+
+    public void dumpLogs(String prefix, PrintWriter pw) {
+        pw.println(prefix + "KeyboardQuickSwitchViewController:");
+
+        pw.println(prefix + "\thasFocus=" + mKeyboardQuickSwitchView.hasFocus());
+        pw.println(prefix + "\tcloseAnimationRunning=" + (mCloseAnimation != null));
+        pw.println(prefix + "\tmCurrentFocusIndex=" + mCurrentFocusIndex);
+    }
+
+    class ViewCallbacks {
+
+        boolean onKeyUp(int keyCode, KeyEvent event) {
+            if (keyCode != KeyEvent.KEYCODE_TAB) {
+                return false;
+            }
+            int taskCount = mControllerCallbacks.getTaskCount();
+            int toIndex = mCurrentFocusIndex == -1
+                    // Focus the second-most recent app if possible
+                    ? (taskCount > 1 ? 1 : 0)
+                    : (event.isShiftPressed()
+                            // focus a more recent task or loop back to the opposite end
+                            ? Math.max(0, mCurrentFocusIndex == 0
+                                    ? taskCount - 1 : mCurrentFocusIndex - 1)
+                            // focus a less recent app or loop back to the opposite end
+                            : ((mCurrentFocusIndex + 1) % taskCount));
+
+            mKeyboardQuickSwitchView.animateFocusMove(mCurrentFocusIndex, toIndex);
+
+            return true;
+        }
+
+        void updateCurrentFocusIndex(int index) {
+            mCurrentFocusIndex = index;
+        }
+
+        void launchTappedTask(int index) {
+            KeyboardQuickSwitchViewController.this.launchTaskAt(index);
+            closeQuickSwitchView(true);
+        }
+
+        void updateThumbnailInBackground(Task task, Consumer<ThumbnailData> callback) {
+            mControllerCallbacks.updateThumbnailInBackground(task, callback);
+        }
+
+        void updateTitleInBackground(Task task, Consumer<Task> callback) {
+            mControllerCallbacks.updateTitleInBackground(task, callback);
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 335482c..ac584bf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -29,6 +29,7 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.TaskTransitionSpec;
+import android.view.View;
 import android.view.WindowManagerGlobal;
 
 import androidx.annotation.NonNull;
@@ -49,6 +50,7 @@
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.OnboardingPrefs;
 import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.views.RecentsView;
 
 import java.io.PrintWriter;
@@ -310,6 +312,7 @@
 
     @Override
     public void onTaskbarIconLaunched(ItemInfo item) {
+        super.onTaskbarIconLaunched(item);
         InstanceId instanceId = new InstanceIdSequence().newInstanceId();
         mLauncher.logAppLaunch(mControllers.taskbarActivityContext.getStatsLogManager(), item,
                 instanceId);
@@ -380,6 +383,17 @@
     }
 
     @Override
+    public RecentsView getRecentsView() {
+        return mLauncher.getOverviewPanel();
+    }
+
+    @Override
+    public void launchSplitTasks(View taskView, GroupTask groupTask) {
+        super.launchSplitTasks(taskView, groupTask);
+        mLauncher.launchSplitTasks(taskView, groupTask);
+    }
+
+    @Override
     public void dumpLogs(String prefix, PrintWriter pw) {
         super.dumpLogs(prefix, pw);
 
@@ -399,9 +413,4 @@
 
         mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw);
     }
-
-    @Override
-    public RecentsView getRecentsView() {
-        return mLauncher.getOverviewPanel();
-    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 74e7375..0f25ba1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
@@ -36,6 +38,7 @@
 import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
+import com.android.systemui.shared.system.QuickStepContract;
 
 import java.io.PrintWriter;
 
@@ -78,6 +81,10 @@
     private float mStartProgressForNextRevealAnim;
     private boolean mWasLastRevealAnimReversed;
 
+    // States that affect whether region sampling is enabled or not
+    private boolean mIsStashed;
+    private boolean mTaskbarHidden;
+
     public StashedHandleViewController(TaskbarActivityContext activity,
             StashedHandleView stashedHandleView) {
         mActivity = activity;
@@ -218,7 +225,8 @@
 
     /** Called when taskbar is stashed or unstashed. */
     public void onIsStashedChanged(boolean isStashed) {
-        mRegionSamplingHelper.setWindowVisible(isStashed);
+        mIsStashed = isStashed;
+        updateRegionSamplingWindowVisibility();
         if (isStashed) {
             mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
             mRegionSamplingHelper.start(mStashedHandleView.getSampledRegion());
@@ -247,6 +255,15 @@
                 homeDisabled ? 0 : 1);
     }
 
+    public void updateStateForSysuiFlags(int systemUiStateFlags) {
+        mTaskbarHidden = (systemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0;
+        updateRegionSamplingWindowVisibility();
+    }
+
+    private void updateRegionSamplingWindowVisibility() {
+        mRegionSamplingHelper.setWindowVisible(mIsStashed && !mTaskbarHidden);
+    }
+
     public boolean isStashedHandleVisible() {
         return mStashedHandleView.getVisibility() == View.VISIBLE;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index c6d8fce..9b0f8c4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -15,7 +15,6 @@
  */
 package com.android.launcher3.taskbar;
 
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.content.pm.PackageManager.FEATURE_PC;
 import static android.os.Trace.TRACE_TAG_APP;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -236,7 +235,8 @@
                 isDesktopMode
                         ? new DesktopTaskbarRecentAppsController(this)
                         : TaskbarRecentAppsController.DEFAULT,
-                new TaskbarEduTooltipController(this));
+                new TaskbarEduTooltipController(this),
+                new KeyboardQuickSwitchController());
     }
 
     public void init(@NonNull TaskbarSharedState sharedState) {
@@ -247,6 +247,12 @@
         // Initialize controllers after all are constructed.
         mControllers.init(sharedState);
         updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
+        disableNavBarElements(sharedState.disableNavBarDisplayId, sharedState.disableNavBarState1,
+                sharedState.disableNavBarState2, false /* animate */);
+        onSystemBarAttributesChanged(sharedState.systemBarAttrsDisplayId,
+                sharedState.systemBarAttrsBehavior);
+        onNavButtonsDarkIntensityChanged(sharedState.navButtonsDarkIntensity);
+
 
         if (!mAddedWindow) {
             mWindowManager.addView(mDragLayer, mWindowLayoutParams);
@@ -564,6 +570,7 @@
                         || isNavBarKidsModeActive());
         mControllers.stashedHandleViewController.setIsHomeButtonDisabled(
                 mControllers.navbarButtonsViewController.isHomeDisabled());
+        mControllers.stashedHandleViewController.updateStateForSysuiFlags(systemUiStateFlags);
         mControllers.taskbarKeyguardController.updateStateForSysuiFlags(systemUiStateFlags);
         mControllers.taskbarStashController.updateStateForSysuiFlags(
                 systemUiStateFlags, fromInit || !isUserSetupComplete());
@@ -829,15 +836,17 @@
                             launchFromTaskbarPreservingSplitIfVisible(recents, info);
                         }
 
-                        mControllers.uiController.onTaskbarIconLaunched(info);
                     } catch (NullPointerException
                             | ActivityNotFoundException
                             | SecurityException e) {
                         Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
                                 .show();
                         Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e);
+                        return;
                     }
+
                 }
+                mControllers.uiController.onTaskbarIconLaunched(info);
                 mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
             }
         } else if (tag instanceof AppInfo) {
@@ -851,8 +860,8 @@
                 taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
             } else {
                 launchFromTaskbarPreservingSplitIfVisible(recents, info);
-                mControllers.uiController.onTaskbarIconLaunched(info);
             }
+            mControllers.uiController.onTaskbarIconLaunched(info);
             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
         } else if (tag instanceof ItemClickProxy) {
             ((ItemClickProxy) tag).onItemClicked(view);
@@ -1061,6 +1070,12 @@
         mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
     }
 
+    void notifyUpdateLayoutParams() {
+        if (mDragLayer.isAttachedToWindow()) {
+            mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
+        }
+    }
+
     public void showPopupMenuForIcon(BubbleTextView btv) {
         setTaskbarWindowFullscreen(true);
         btv.post(() -> mControllers.taskbarPopupController.showForIcon(btv));
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index ea70de4..931d79f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -59,6 +59,7 @@
     public final TaskbarTranslationController taskbarTranslationController;
     public final TaskbarOverlayController taskbarOverlayController;
     public final TaskbarEduTooltipController taskbarEduTooltipController;
+    public final KeyboardQuickSwitchController keyboardQuickSwitchController;
 
     @Nullable private LoggableTaskbarController[] mControllersToLog = null;
     @Nullable private BackgroundRendererController[] mBackgroundRendererControllers = null;
@@ -103,7 +104,8 @@
             VoiceInteractionWindowController voiceInteractionWindowController,
             TaskbarTranslationController taskbarTranslationController,
             TaskbarRecentAppsController taskbarRecentAppsController,
-            TaskbarEduTooltipController taskbarEduTooltipController) {
+            TaskbarEduTooltipController taskbarEduTooltipController,
+            KeyboardQuickSwitchController keyboardQuickSwitchController) {
         this.taskbarActivityContext = taskbarActivityContext;
         this.taskbarDragController = taskbarDragController;
         this.navButtonController = navButtonController;
@@ -127,6 +129,7 @@
         this.taskbarTranslationController = taskbarTranslationController;
         this.taskbarRecentAppsController = taskbarRecentAppsController;
         this.taskbarEduTooltipController = taskbarEduTooltipController;
+        this.keyboardQuickSwitchController = keyboardQuickSwitchController;
     }
 
     /**
@@ -159,6 +162,7 @@
         taskbarRecentAppsController.init(this);
         taskbarTranslationController.init(this);
         taskbarEduTooltipController.init(this);
+        keyboardQuickSwitchController.init(this);
 
         mControllersToLog = new LoggableTaskbarController[] {
                 taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -167,7 +171,7 @@
                 stashedHandleViewController, taskbarStashController, taskbarEduController,
                 taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController,
                 voiceInteractionWindowController, taskbarTranslationController,
-                taskbarEduTooltipController
+                taskbarEduTooltipController, keyboardQuickSwitchController
         };
         mBackgroundRendererControllers = new BackgroundRendererController[] {
                 taskbarDragLayerController, taskbarScrimViewController,
@@ -191,6 +195,7 @@
     public void onConfigurationChanged(@Config int configChanges) {
         navbarButtonsViewController.onConfigurationChanged(configChanges);
         taskbarDragLayerController.onConfigurationChanged();
+        keyboardQuickSwitchController.onConfigurationChanged(configChanges);
     }
 
     /**
@@ -216,6 +221,7 @@
         taskbarInsetsController.onDestroy();
         voiceInteractionWindowController.onDestroy();
         taskbarRecentAppsController.onDestroy();
+        keyboardQuickSwitchController.onDestroy();
 
         mControllersToLog = null;
         mBackgroundRendererControllers = null;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 9f24565..571d443 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -18,16 +18,21 @@
 import android.graphics.Insets
 import android.graphics.Region
 import android.view.InsetsFrameProvider
+import android.view.InsetsFrameProvider.SOURCE_DISPLAY
+import android.view.InsetsFrameProvider.SOURCE_FRAME
 import android.view.InsetsState
 import android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES
 import android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT
 import android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR
+import android.view.InsetsState.ITYPE_LEFT_GESTURES
+import android.view.InsetsState.ITYPE_RIGHT_GESTURES
 import android.view.ViewTreeObserver
 import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME
 import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
 import android.view.WindowManager
 import android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD
 import android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION
+import com.android.internal.policy.GestureNavigationSettingsObserver
 import com.android.launcher3.AbstractFloatingView
 import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY
 import com.android.launcher3.DeviceProfile
@@ -45,6 +50,9 @@
     private val deviceProfileChangeListener = { _: DeviceProfile ->
         onTaskbarWindowHeightOrInsetsChanged()
     }
+    private val gestureNavSettingsObserver =
+        GestureNavigationSettingsObserver(context.mainThreadHandler, context,
+            this::onTaskbarWindowHeightOrInsetsChanged)
 
     // Initialized in init.
     private lateinit var controllers: TaskbarControllers
@@ -59,7 +67,16 @@
             intArrayOf(
                 ITYPE_EXTRA_NAVIGATION_BAR,
                 ITYPE_BOTTOM_TAPPABLE_ELEMENT,
-                ITYPE_BOTTOM_MANDATORY_GESTURES
+                ITYPE_BOTTOM_MANDATORY_GESTURES,
+                ITYPE_LEFT_GESTURES,
+                ITYPE_RIGHT_GESTURES,
+            ),
+            intArrayOf(
+                SOURCE_FRAME,
+                SOURCE_FRAME,
+                SOURCE_FRAME,
+                SOURCE_DISPLAY,
+                SOURCE_DISPLAY
             )
         )
 
@@ -67,10 +84,12 @@
 
         windowLayoutParams.insetsRoundedCornerFrame = true
         context.addOnDeviceProfileChangeListener(deviceProfileChangeListener)
+        gestureNavSettingsObserver.registerForCurrentUser()
     }
 
     fun onDestroy() {
         context.removeOnDeviceProfileChangeListener(deviceProfileChangeListener)
+        gestureNavSettingsObserver.unregister()
     }
 
     fun onTaskbarWindowHeightOrInsetsChanged() {
@@ -91,6 +110,22 @@
                 provider.insetsSize = getInsetsByNavMode(contentHeight)
             } else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) {
                 provider.insetsSize = getInsetsByNavMode(tappableHeight)
+            } else if (provider.type == ITYPE_LEFT_GESTURES) {
+                provider.insetsSize =
+                    Insets.of(
+                        gestureNavSettingsObserver.getLeftSensitivity(context.resources),
+                        0,
+                        0,
+                        0
+                    )
+            } else if (provider.type == ITYPE_RIGHT_GESTURES) {
+                provider.insetsSize =
+                    Insets.of(
+                        0,
+                        0,
+                        gestureNavSettingsObserver.getRightSensitivity(context.resources),
+                        0
+                    )
             }
         }
 
@@ -116,6 +151,7 @@
                 provider.insetsSizeOverrides = insetsSizeOverride
             }
         }
+        context.notifyUpdateLayoutParams()
     }
 
     /**
@@ -140,10 +176,12 @@
      * @param params The window layout params.
      * @param providesInsetsTypes The inset types we would like this layout params to provide.
      */
-    fun setProvidesInsetsTypes(params: WindowManager.LayoutParams, providesInsetsTypes: IntArray) {
+    fun setProvidesInsetsTypes(params: WindowManager.LayoutParams, providesInsetsTypes: IntArray,
+            providesInsetsSources: IntArray) {
         params.providedInsets = arrayOfNulls<InsetsFrameProvider>(providesInsetsTypes.size)
         for (i in providesInsetsTypes.indices) {
-            params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i])
+            params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i],
+                    providesInsetsSources[i], null, null)
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index a58906f..4110822 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -362,18 +362,24 @@
     }
 
     public void disableNavBarElements(int displayId, int state1, int state2, boolean animate) {
+        mSharedState.disableNavBarDisplayId = displayId;
+        mSharedState.disableNavBarState1 = state1;
+        mSharedState.disableNavBarState2 = state2;
         if (mTaskbarActivityContext != null) {
             mTaskbarActivityContext.disableNavBarElements(displayId, state1, state2, animate);
         }
     }
 
     public void onSystemBarAttributesChanged(int displayId, int behavior) {
+        mSharedState.systemBarAttrsDisplayId = displayId;
+        mSharedState.systemBarAttrsBehavior = behavior;
         if (mTaskbarActivityContext != null) {
             mTaskbarActivityContext.onSystemBarAttributesChanged(displayId, behavior);
         }
     }
 
     public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
+        mSharedState.navButtonsDarkIntensity = darkIntensity;
         if (mTaskbarActivityContext != null) {
             mTaskbarActivityContext.onNavButtonsDarkIntensityChanged(darkIntensity);
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 30d6eb4..115b99e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.taskbar;
 
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
 import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
 
 import android.content.Intent;
@@ -56,6 +57,7 @@
 
 import java.io.PrintWriter;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Objects;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
@@ -152,9 +154,28 @@
             return null;
         }
 
-        final PopupContainerWithArrow<BaseTaskbarContext> container =
-                (PopupContainerWithArrow<BaseTaskbarContext>) context.getLayoutInflater().inflate(
-                        R.layout.popup_container, context.getDragLayer(), false);
+        PopupContainerWithArrow<BaseTaskbarContext> container;
+        int deepShortcutCount = mPopupDataProvider.getShortcutCountForItem(item);
+        // TODO(b/198438631): add support for INSTALL shortcut factory
+        List<SystemShortcut> systemShortcuts = getSystemShortcuts()
+                .map(s -> s.getShortcut(context, item, icon))
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        if (ENABLE_MATERIAL_U_POPUP.get()) {
+            container = (PopupContainerWithArrow) context.getLayoutInflater().inflate(
+                    R.layout.popup_container_material_u, context.getDragLayer(), false);
+            container.populateAndShowRowsMaterialU(icon, deepShortcutCount, systemShortcuts);
+        } else {
+            container = (PopupContainerWithArrow) context.getLayoutInflater().inflate(
+                    R.layout.popup_container, context.getDragLayer(), false);
+            container.populateAndShow(
+                    icon,
+                    deepShortcutCount,
+                    mPopupDataProvider.getNotificationKeysForItem(item),
+                    systemShortcuts);
+        }
+
         container.addOnAttachStateChangeListener(
                 new PopupLiveUpdateHandler<BaseTaskbarContext>(context, container) {
                     @Override
@@ -165,15 +186,6 @@
         // TODO (b/198438631): configure for taskbar/context
         container.setPopupItemDragHandler(new TaskbarPopupItemDragHandler());
         mControllers.taskbarDragController.addDragListener(container);
-
-        container.populateAndShow(icon,
-                mPopupDataProvider.getShortcutCountForItem(item),
-                mPopupDataProvider.getNotificationKeysForItem(item),
-                // TODO (b/198438631): add support for INSTALL shortcut factory
-                getSystemShortcuts()
-                        .map(s -> s.getShortcut(context, item, icon))
-                        .filter(Objects::nonNull)
-                        .collect(Collectors.toList()));
         container.requestFocus();
 
         // Make focusable to receive back events
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index 87b3789..026eff7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -20,8 +20,21 @@
  */
 public class TaskbarSharedState {
 
+    // TaskbarManager#onSystemUiFlagsChanged
     public int sysuiStateFlags;
 
+    // TaskbarManager#disableNavBarElements()
+    public int disableNavBarDisplayId;
+    public int disableNavBarState1;
+    public int disableNavBarState2;
+
+    // TaskbarManager#onSystemBarAttributesChanged()
+    public int systemBarAttrsDisplayId;
+    public int systemBarAttrsBehavior;
+
+    // TaskbarManager#onNavButtonsDarkIntensityChanged()
+    public float navButtonsDarkIntensity;
+
     public boolean setupUIVisible = false;
 
     public boolean allAppsVisible = false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index bfdf156..76b8b6d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -17,6 +17,8 @@
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 
+import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
+
 import android.content.Intent;
 import android.graphics.drawable.BitmapDrawable;
 import android.view.MotionEvent;
@@ -29,6 +31,7 @@
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.SplitConfigurationOptions;
+import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer;
@@ -73,7 +76,13 @@
     protected void onStashedInAppChanged() { }
 
     /** Called when an icon is launched. */
-    public void onTaskbarIconLaunched(ItemInfo item) { }
+    @CallSuper
+    public void onTaskbarIconLaunched(ItemInfo item) {
+        // When launching from Taskbar, e.g. from Overview, set FLAG_IN_APP immediately instead of
+        // waiting for onPause, to reduce potential visual noise during the app open transition.
+        mControllers.taskbarStashController.updateStateForFlag(FLAG_IN_APP, true);
+        mControllers.taskbarStashController.applyState();
+    }
 
     public View getRootView() {
         return mControllers.taskbarActivityContext.getDragLayer();
@@ -103,7 +112,7 @@
     public void onExpandPip() {
         if (mControllers != null) {
             final TaskbarStashController stashController = mControllers.taskbarStashController;
-            stashController.updateStateForFlag(TaskbarStashController.FLAG_IN_APP, true);
+            stashController.updateStateForFlag(FLAG_IN_APP, true);
             stashController.applyState();
         }
     }
@@ -228,4 +237,43 @@
                 }
         );
     }
+
+    /**
+     * Opens the Keyboard Quick Switch View.
+     *
+     * This will set the focus to the first task from the right (from the left in RTL)
+     */
+    public void openQuickSwitchView() {
+        mControllers.keyboardQuickSwitchController.openQuickSwitchView();
+    }
+
+    /**
+     * Closes the Keyboard Quick Switch View.
+     *
+     * No-op if the view is already closed
+     */
+    public void closeQuickSwitchView() {
+        mControllers.keyboardQuickSwitchController.closeQuickSwitchView();
+    }
+
+    /**
+     * Launches the focused task and closes the Keyboard Quick Switch View.
+     *
+     * If the overlay or view are closed, or the overview task is focused, then Overview is
+     * launched. If the overview task is launched, then the first hidden task is focused.
+     *
+     * @return the index of what task should be focused in ; -1 iff Overview shouldn't be launched
+     */
+    public int launchFocusedTask() {
+        int focusedTaskIndex = mControllers.keyboardQuickSwitchController.launchFocusedTask();
+        mControllers.keyboardQuickSwitchController.closeQuickSwitchView();
+        return focusedTaskIndex;
+    }
+
+    /**
+     * Launches the focused task in splitscreen.
+     *
+     * No-op if the view is not yet open.
+     */
+    public void launchSplitTasks(View taskview, GroupTask groupTask) { }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
index d91b650..ec64128 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -27,17 +27,45 @@
 import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
 
+import androidx.annotation.NonNull;
+
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
 
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
 /** Root drag layer for the Taskbar overlay window. */
 public class TaskbarOverlayDragLayer extends
         BaseDragLayer<TaskbarOverlayContext> implements
         ViewTreeObserver.OnComputeInternalInsetsListener {
 
+    private final List<OnClickListener> mOnClickListeners = new CopyOnWriteArrayList<>();
+    private final TouchController mClickListenerTouchController = new TouchController() {
+        @Override
+        public boolean onControllerTouchEvent(MotionEvent ev) {
+            if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
+                for (OnClickListener listener : mOnClickListeners) {
+                    listener.onClick(TaskbarOverlayDragLayer.this);
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+            for (int i = 0; i < getChildCount(); i++) {
+                if (isEventOverView(getChildAt(i), ev)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    };
+
     TaskbarOverlayDragLayer(Context context) {
         super(context, null, 1);
         setClipChildren(false);
@@ -58,7 +86,10 @@
 
     @Override
     public void recreateControllers() {
-        mControllers = new TouchController[]{mActivity.getDragController()};
+        mControllers = mOnClickListeners.isEmpty()
+                ? new TouchController[]{mActivity.getDragController()}
+                : new TouchController[] {
+                        mActivity.getDragController(), mClickListenerTouchController};
     }
 
     @Override
@@ -99,6 +130,51 @@
     }
 
     /**
+     * Adds the given callback to clicks to this drag layer.
+     * <p>
+     * Clicks are only accepted on this drag layer if they fall within this drag layer's bounds and
+     * outside the bounds of all child views.
+     * <p>
+     * If the click falls within the bounds of a child view, then this callback does not run and
+     * that child can optionally handle it.
+     */
+    private void addOnClickListener(@NonNull OnClickListener listener) {
+        boolean wasEmpty = mOnClickListeners.isEmpty();
+        mOnClickListeners.add(listener);
+        if (wasEmpty) {
+            recreateControllers();
+        }
+    }
+
+    /**
+     * Removes the given on click callback.
+     * <p>
+     * No-op if the callback was never added.
+     */
+    private void removeOnClickListener(@NonNull OnClickListener listener) {
+        boolean wasEmpty = mOnClickListeners.isEmpty();
+        mOnClickListeners.remove(listener);
+        if (!wasEmpty && mOnClickListeners.isEmpty()) {
+            recreateControllers();
+        }
+    }
+
+    /**
+     * Queues the given callback on the next click on this drag layer.
+     * <p>
+     * Once run, this callback is immediately removed.
+     */
+    public void runOnClickOnce(@NonNull OnClickListener listener) {
+        addOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                listener.onClick(v);
+                removeOnClickListener(this);
+            }
+        });
+    }
+
+    /**
      * Taskbar automatically stashes when opening all apps, but we don't report the insets as
      * changing to avoid moving the underlying app. But internally, the apps view should still
      * layout according to the stashed insets rather than the unstashed insets. So this method
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index fd986e6..80ce369 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -50,6 +50,7 @@
 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
 import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
 
@@ -143,6 +144,7 @@
 import com.android.launcher3.util.PendingRequestArgs;
 import com.android.launcher3.util.PendingSplitSelectInfo;
 import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
 import com.android.launcher3.util.TouchController;
@@ -152,6 +154,7 @@
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.TouchInteractionService.TISBinder;
+import com.android.quickstep.util.GroupTask;
 import com.android.quickstep.util.LauncherUnfoldAnimationController;
 import com.android.quickstep.util.ProxyScreenStatusProvider;
 import com.android.quickstep.util.QuickstepOnboardingPrefs;
@@ -1206,6 +1209,32 @@
                 getDeviceProfile().toSmallString());
     }
 
+    /**
+     * Launches the given {@link GroupTask} in splitscreen.
+     *
+     * If the second split task is missing, launches the first task normally.
+     */
+    public void launchSplitTasks(View taskView, GroupTask groupTask) {
+        if (groupTask.task2 == null) {
+            UI_HELPER_EXECUTOR.execute(() ->
+                    ActivityManagerWrapper.getInstance().startActivityFromRecents(
+                            groupTask.task1.key,
+                            getActivityLaunchOptions(taskView, null).options));
+            return;
+        }
+        mSplitSelectStateController.launchTasks(
+                groupTask.task1.key.id,
+                groupTask.task2.key.id,
+                SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
+                /* callback= */ success -> {},
+                /* freezeTaskList= */ true,
+                groupTask.mSplitBounds == null
+                        ? DEFAULT_SPLIT_RATIO
+                        : groupTask.mSplitBounds.appsStackedVertically
+                                ? groupTask.mSplitBounds.topTaskPercent
+                                : groupTask.mSplitBounds.leftTaskPercent);
+    }
+
     private static final class LauncherTaskViewController extends
             TaskViewTouchController<Launcher> {
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
index a8edd51..278a45a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
@@ -32,6 +32,7 @@
 
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -41,13 +42,21 @@
 import java.util.List;
 import java.util.Map;
 import java.util.WeakHashMap;
-import java.util.function.Consumer;
+import java.util.function.BiConsumer;
 import java.util.function.IntConsumer;
 
 /**
  * {@link LauncherWidgetHolder} that puts the app widget host in the background
  */
 public final class QuickstepWidgetHolder extends LauncherWidgetHolder {
+
+    private static final UpdateKey<AppWidgetProviderInfo> KEY_PROVIDER_UPDATE =
+            AppWidgetHostView::onUpdateProviderInfo;
+    private static final UpdateKey<RemoteViews> KEY_VIEWS_UPDATE =
+            AppWidgetHostView::updateAppWidget;
+    private static final UpdateKey<Integer> KEY_VIEW_DATA_CHANGED =
+            AppWidgetHostView::onViewDataChanged;
+
     private static final List<QuickstepWidgetHolder> sHolders = new ArrayList<>();
     private static final SparseArray<QuickstepWidgetHolderListener> sListeners =
             new SparseArray<>();
@@ -59,6 +68,8 @@
     private final @NonNull IntConsumer mAppWidgetRemovedCallback;
 
     private final ArrayList<ProviderChangedListener> mProviderChangedListeners = new ArrayList<>();
+    // Map to all pending updated keyed with appWidgetId;
+    private final SparseArray<PendingUpdate> mPendingUpdateMap = new SparseArray<>();
 
     @Thunk
     QuickstepWidgetHolder(@NonNull Context context,
@@ -90,6 +101,57 @@
         return sWidgetHost;
     }
 
+    @Override
+    protected void updateDeferredView() {
+        super.updateDeferredView();
+        int count = mPendingUpdateMap.size();
+        for (int i = 0; i < count; i++) {
+            int widgetId = mPendingUpdateMap.keyAt(i);
+            QuickstepWidgetHolderListener listener = sListeners.get(widgetId);
+            if (listener == null) {
+                continue;
+            }
+            AppWidgetHostView view = listener.mView.get(this);
+            if (view == null) {
+                continue;
+            }
+            PendingUpdate pendingUpdate = mPendingUpdateMap.valueAt(i);
+            if (pendingUpdate == null) {
+                continue;
+            }
+            if (pendingUpdate.providerInfo != null) {
+                KEY_PROVIDER_UPDATE.accept(view, pendingUpdate.providerInfo);
+            }
+            if (pendingUpdate.remoteViews != null) {
+                KEY_VIEWS_UPDATE.accept(view, pendingUpdate.remoteViews);
+            }
+            pendingUpdate.changedViews.forEach(
+                    viewId -> KEY_VIEW_DATA_CHANGED.accept(view, viewId));
+        }
+        mPendingUpdateMap.clear();
+    }
+
+    private <T> void addPendingAction(int widgetId, UpdateKey<T> key, T data) {
+        PendingUpdate pendingUpdate = mPendingUpdateMap.get(widgetId);
+        if (pendingUpdate == null) {
+            pendingUpdate = new PendingUpdate();
+            mPendingUpdateMap.put(widgetId, pendingUpdate);
+        }
+
+        if (KEY_PROVIDER_UPDATE.equals(key)) {
+            // For provider change, remove all updates
+            pendingUpdate.providerInfo = (AppWidgetProviderInfo) data;
+            pendingUpdate.remoteViews = null;
+            pendingUpdate.changedViews.clear();
+        } else if (KEY_VIEWS_UPDATE.equals(key)) {
+            // For views update, remove all previous updates, except the provider
+            pendingUpdate.remoteViews = (RemoteViews) data;
+            pendingUpdate.changedViews.clear();
+        } else if (KEY_VIEW_DATA_CHANGED.equals(key)) {
+            pendingUpdate.changedViews.add((Integer) data);
+        }
+    }
+
     /**
      * Delete the specified app widget from the host
      * @param appWidgetId The ID of the app widget to be deleted
@@ -108,6 +170,12 @@
         sHolders.remove(this);
     }
 
+    @Override
+    protected boolean shouldListen(int flags) {
+        return (flags & (FLAG_STATE_IS_NORMAL | FLAG_ACTIVITY_STARTED))
+                == (FLAG_STATE_IS_NORMAL | FLAG_ACTIVITY_STARTED);
+    }
+
     /**
      * Add a listener that is triggered when the providers of the widgets are changed
      * @param listener The listener that notifies when the providers changed
@@ -163,7 +231,7 @@
 
         QuickstepWidgetHolderListener listener = sListeners.get(appWidgetId);
         if (listener == null) {
-            listener = new QuickstepWidgetHolderListener(this, widgetView);
+            listener = new QuickstepWidgetHolderListener(appWidgetId, this, widgetView);
             sWidgetHost.setListener(appWidgetId, listener);
             sListeners.put(appWidgetId, listener);
         } else {
@@ -185,14 +253,17 @@
 
     private static class QuickstepWidgetHolderListener
             implements AppWidgetHost.AppWidgetHostListener {
+
         @NonNull
         private final Map<QuickstepWidgetHolder, AppWidgetHostView> mView = new WeakHashMap<>();
 
-        @Nullable
-        private RemoteViews mRemoteViews = null;
+        private final int mWidgetId;
 
-        QuickstepWidgetHolderListener(@NonNull QuickstepWidgetHolder holder,
+        @Nullable private RemoteViews mRemoteViews = null;
+
+        QuickstepWidgetHolderListener(int widgetId, @NonNull QuickstepWidgetHolder holder,
                 @NonNull LauncherAppWidgetHostView view) {
+            mWidgetId = widgetId;
             mView.put(holder, view);
         }
 
@@ -207,24 +278,30 @@
         @WorkerThread
         public void onUpdateProviderInfo(@Nullable AppWidgetProviderInfo info) {
             mRemoteViews = null;
-            executeOnMainExecutor(v -> v.onUpdateProviderInfo(info));
+            executeOnMainExecutor(KEY_PROVIDER_UPDATE, info);
         }
 
         @Override
         @WorkerThread
         public void updateAppWidget(@Nullable RemoteViews views) {
             mRemoteViews = views;
-            executeOnMainExecutor(v -> v.updateAppWidget(mRemoteViews));
+            executeOnMainExecutor(KEY_VIEWS_UPDATE, mRemoteViews);
         }
 
         @Override
         @WorkerThread
         public void onViewDataChanged(int viewId) {
-            executeOnMainExecutor(v -> v.onViewDataChanged(viewId));
+            executeOnMainExecutor(KEY_VIEW_DATA_CHANGED, viewId);
         }
 
-        private void executeOnMainExecutor(Consumer<AppWidgetHostView> consumer) {
-            MAIN_EXECUTOR.execute(() -> mView.values().forEach(consumer));
+        private <T> void executeOnMainExecutor(UpdateKey<T> key, T data) {
+            MAIN_EXECUTOR.execute(() -> mView.forEach((holder, view) -> {
+                if (holder.isListening()) {
+                    key.accept(view, data);
+                } else {
+                    holder.addPendingAction(mWidgetId, key, data);
+                }
+            }));
         }
     }
 
@@ -267,4 +344,12 @@
             return new QuickstepWidgetHolder(context, appWidgetRemovedCallback, interactionHandler);
         }
     }
+
+    private static class PendingUpdate {
+        public final IntSet changedViews = new IntSet();
+        public AppWidgetProviderInfo providerInfo;
+        public RemoteViews remoteViews;
+    }
+
+    private interface UpdateKey<T> extends BiConsumer<AppWidgetHostView, T> { }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index f78d9cf..847114a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -76,6 +76,7 @@
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.WorkspaceRevealAnim;
+import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.LauncherRecentsView;
 import com.android.quickstep.views.RecentsView;
 
@@ -164,6 +165,10 @@
         if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) {
             return false;
         }
+        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+            // TODO(b/268075592): add support for quickswitch to/from desktop
+            return false;
+        }
         return true;
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index c5383c3..f941b02 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -48,6 +48,7 @@
 import com.android.launcher3.util.NavigationMode;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskUtils;
+import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 
@@ -78,6 +79,10 @@
         if ((ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0) {
             return false;
         }
+        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED) {
+            // TODO(b/268075592): add support for quickswitch to/from desktop
+            return false;
+        }
         return true;
     }
 
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 3f6eb94..1122e00 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1167,6 +1167,11 @@
             return LAST_TASK;
         }
 
+        if (DesktopTaskView.DESKTOP_MODE_SUPPORTED && endTarget == NEW_TASK) {
+            // TODO(b/268075592): add support for quickswitch to/from desktop
+            return LAST_TASK;
+        }
+
         return endTarget;
     }
 
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 5a09e02..d0fd65f 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -24,12 +24,17 @@
 import android.os.Build;
 import android.os.SystemClock;
 import android.os.Trace;
+import android.view.View;
 
 import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.taskbar.TaskbarUIController;
 import com.android.launcher3.util.RunnableList;
 import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
 import com.android.quickstep.views.RecentsView;
@@ -48,7 +53,7 @@
 public class OverviewCommandHelper {
 
     public static final int TYPE_SHOW = 1;
-    public static final int TYPE_SHOW_NEXT_FOCUS = 2;
+    public static final int TYPE_KEYBOARD_INPUT = 2;
     public static final int TYPE_HIDE = 3;
     public static final int TYPE_TOGGLE = 4;
     public static final int TYPE_HOME = 5;
@@ -66,6 +71,13 @@
     private final TaskAnimationManager mTaskAnimationManager;
     private final ArrayList<CommandInfo> mPendingCommands = new ArrayList<>();
 
+    /**
+     * Index of the TaskView that should be focused when launching Overview. Persisted so that we
+     * do not lose the focus across multiple calls of
+     * {@link OverviewCommandHelper#executeCommand(CommandInfo)} for the same command
+     */
+    private int mTaskFocusIndexOverride = -1;
+
     public OverviewCommandHelper(TouchInteractionService service,
             OverviewComponentObserver observer,
             TaskAnimationManager taskAnimationManager) {
@@ -165,8 +177,25 @@
                 mOverviewComponentObserver.getActivityInterface();
         RecentsView recents = activityInterface.getVisibleRecentsView();
         if (recents == null) {
+            T activity = activityInterface.getCreatedActivity();
+            DeviceProfile dp = activity == null ? null : activity.getDeviceProfile();
+            TaskbarUIController uiController = activityInterface.getTaskbarController();
+            boolean allowQuickSwitch = FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
+                    && uiController != null
+                    && dp != null
+                    && (dp.isTablet || dp.isTwoPanels);
+
             if (cmd.type == TYPE_HIDE) {
-                // already hidden
+                if (!allowQuickSwitch) {
+                    return true;
+                }
+                mTaskFocusIndexOverride = uiController.launchFocusedTask();
+                if (mTaskFocusIndexOverride == -1) {
+                    return true;
+                }
+            }
+            if (cmd.type == TYPE_KEYBOARD_INPUT && allowQuickSwitch) {
+                uiController.openQuickSwitchView();
                 return true;
             }
             if (cmd.type == TYPE_HOME) {
@@ -179,6 +208,7 @@
                     // already visible
                     return true;
                 case TYPE_HIDE: {
+                    mTaskFocusIndexOverride = -1;
                     int currentPage = recents.getNextPage();
                     TaskView tv = (currentPage >= 0 && currentPage < recents.getTaskViewCount())
                             ? (TaskView) recents.getPageAt(currentPage)
@@ -194,15 +224,9 @@
         }
 
         final Runnable completeCallback = () -> {
-            if (cmd.type == TYPE_SHOW_NEXT_FOCUS) {
-                RecentsView rv = activityInterface.getVisibleRecentsView();
-                // When the overview is launched via alt tab (cmd type is TYPE_SHOW_NEXT_FOCUS),
-                // the touch mode somehow is not change to false by the Android framework.
-                // The subsequent tab to go through tasks in overview can only be dispatched to
-                // focuses views, while focus can only be requested in
-                // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
-                // here we launch overview from home.
-                rv.getViewRootImpl().touchModeChanged(false);
+            RecentsView rv = activityInterface.getVisibleRecentsView();
+            if (rv != null && (cmd.type == TYPE_KEYBOARD_INPUT || cmd.type == TYPE_HIDE)) {
+                updateRecentsViewFocus(rv);
             }
             scheduleNextTask(cmd);
         };
@@ -280,40 +304,55 @@
         cmd.removeListener(handler);
         Trace.endAsyncSection(TRANSITION_NAME, 0);
 
-        if (cmd.type == TYPE_SHOW_NEXT_FOCUS) {
-            RecentsView rv =
-                    mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
-            if (rv != null) {
-                // When the overview is launched via alt tab (cmd type is TYPE_SHOW_NEXT_FOCUS),
-                // the touch mode somehow is not change to false by the Android framework.
-                // The subsequent tab to go through tasks in overview can only be dispatched to
-                // focuses views, while focus can only be requested in
-                // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
-                // here we launch overview with live tile.
-                rv.getViewRootImpl().touchModeChanged(false);
-                // Ensure that recents view has focus so that it receives the followup key inputs
-                TaskView taskView = rv.getNextTaskView();
-                if (taskView == null) {
-                    taskView = rv.getTaskViewAt(0);
-                    if (taskView != null) {
-                        taskView.requestFocus();
-                    } else {
-                        rv.requestFocus();
-                    }
-                } else {
-                    taskView.requestFocus();
-                }
-            }
+        RecentsView rv =
+                mOverviewComponentObserver.getActivityInterface().getVisibleRecentsView();
+        if (rv != null && (cmd.type == TYPE_KEYBOARD_INPUT || cmd.type == TYPE_HIDE)) {
+            updateRecentsViewFocus(rv);
         }
         scheduleNextTask(cmd);
     }
 
+    private void updateRecentsViewFocus(@NonNull RecentsView rv) {
+        // When the overview is launched via alt tab (cmd type is TYPE_KEYBOARD_INPUT),
+        // the touch mode somehow is not change to false by the Android framework.
+        // The subsequent tab to go through tasks in overview can only be dispatched to
+        // focuses views, while focus can only be requested in
+        // {@link View#requestFocusNoSearch(int, Rect)} when touch mode is false. To note,
+        // here we launch overview with live tile.
+        rv.getViewRootImpl().touchModeChanged(false);
+        // Ensure that recents view has focus so that it receives the followup key inputs
+        TaskView taskView = rv.getTaskViewAt(mTaskFocusIndexOverride);
+        if (taskView != null) {
+            requestFocus(taskView);
+            return;
+        }
+        taskView = rv.getNextTaskView();
+        if (taskView != null) {
+            requestFocus(taskView);
+            return;
+        }
+        taskView = rv.getTaskViewAt(0);
+        if (taskView != null) {
+            requestFocus(taskView);
+            return;
+        }
+        requestFocus(rv);
+    }
+
+    private void requestFocus(@NonNull View view) {
+        view.post(() -> {
+            view.requestFocus();
+            view.requestAccessibilityFocus();
+        });
+    }
+
     public void dump(PrintWriter pw) {
         pw.println("OverviewCommandHelper:");
         pw.println("  mPendingCommands=" + mPendingCommands.size());
         if (!mPendingCommands.isEmpty()) {
             pw.println("    pendingCommandType=" + mPendingCommands.get(0).type);
         }
+        pw.println("  mTaskFocusIndexOverride=" + mTaskFocusIndexOverride);
     }
 
     private static class CommandInfo {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 287b468..1b8a93c 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -205,7 +205,7 @@
         public void onOverviewShown(boolean triggeredFromAltTab) {
             if (triggeredFromAltTab) {
                 TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
-                mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW_NEXT_FOCUS);
+                mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_KEYBOARD_INPUT);
             } else {
                 mOverviewCommandHelper.addCommand(OverviewCommandHelper.TYPE_SHOW);
             }
diff --git a/quickstep/src/com/android/quickstep/util/BorderAnimator.java b/quickstep/src/com/android/quickstep/util/BorderAnimator.java
new file mode 100644
index 0000000..1f1c15b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/BorderAnimator.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.animation.Animator;
+import android.annotation.ColorInt;
+import android.annotation.Nullable;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.view.animation.Interpolator;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Px;
+
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.anim.Interpolators;
+
+/**
+ * Utility class for drawing a rounded-rect border around a view.
+ * <p>
+ * To use this class:
+ * 1. Create an instance in the target view.
+ * 2. Override the target view's {@link android.view.View#draw(Canvas)} method and call
+ *      {@link BorderAnimator#drawBorder(Canvas)} after {@code super.draw(canvas)}.
+ * 3. Call {@link BorderAnimator#buildAnimator(boolean)} and start the animation or call
+ *      {@link BorderAnimator#setBorderVisible(boolean)} where appropriate.
+ */
+public final class BorderAnimator {
+
+    public static final int DEFAULT_BORDER_COLOR = 0xffffffff;
+
+    private static final long DEFAULT_APPEARANCE_ANIMATION_DURATION_MS = 300;
+    private static final long DEFAULT_DISAPPEARANCE_ANIMATION_DURATION_MS = 133;
+    private static final Interpolator DEFAULT_INTERPOLATOR = Interpolators.EMPHASIZED_DECELERATE;
+
+    @NonNull private final AnimatedFloat mBorderAnimationProgress = new AnimatedFloat(
+            this::updateOutline);
+    @NonNull private final Rect mBorderBounds = new Rect();
+    @NonNull private final BorderBoundsBuilder mBorderBoundsBuilder;
+    @Px private final int mBorderWidthPx;
+    @Px private final int mBorderRadiusPx;
+    @NonNull private final Runnable mInvalidateViewCallback;
+    private final long mAppearanceDurationMs;
+    private final long mDisappearanceDurationMs;
+    @NonNull private final Interpolator mInterpolator;
+    @NonNull private final Paint mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+    private int mAlignmentAdjustment;
+
+    @Nullable private Animator mRunningBorderAnimation;
+
+    public BorderAnimator(
+            @NonNull BorderBoundsBuilder borderBoundsBuilder,
+            int borderWidthPx,
+            int borderRadiusPx,
+            @ColorInt int borderColor,
+            @NonNull Runnable invalidateViewCallback) {
+        this(borderBoundsBuilder,
+                borderWidthPx,
+                borderRadiusPx,
+                borderColor,
+                invalidateViewCallback,
+                DEFAULT_APPEARANCE_ANIMATION_DURATION_MS,
+                DEFAULT_DISAPPEARANCE_ANIMATION_DURATION_MS,
+                DEFAULT_INTERPOLATOR);
+    }
+
+    public BorderAnimator(
+            @NonNull BorderBoundsBuilder borderBoundsBuilder,
+            int borderWidthPx,
+            int borderRadiusPx,
+            @ColorInt int borderColor,
+            @NonNull Runnable invalidateViewCallback,
+            long appearanceDurationMs,
+            long disappearanceDurationMs,
+            @NonNull Interpolator interpolator) {
+        mBorderBoundsBuilder = borderBoundsBuilder;
+        mBorderWidthPx = borderWidthPx;
+        mBorderRadiusPx = borderRadiusPx;
+        mInvalidateViewCallback = invalidateViewCallback;
+        mAppearanceDurationMs = appearanceDurationMs;
+        mDisappearanceDurationMs = disappearanceDurationMs;
+        mInterpolator = interpolator;
+
+        mBorderPaint.setColor(borderColor);
+        mBorderPaint.setStyle(Paint.Style.STROKE);
+        mBorderPaint.setAlpha(0);
+    }
+
+    private void updateOutline() {
+        float interpolatedProgress = mInterpolator.getInterpolation(
+                mBorderAnimationProgress.value);
+        mAlignmentAdjustment = (int) Utilities.mapBoundToRange(
+                mBorderAnimationProgress.value,
+                /* lowerBound= */ 0f,
+                /* upperBound= */ 1f,
+                /* toMin= */ 0f,
+                /* toMax= */ (float) (mBorderWidthPx / 2f),
+                mInterpolator);
+
+        mBorderPaint.setAlpha(Math.round(255 * interpolatedProgress));
+        mBorderPaint.setStrokeWidth(Math.round(mBorderWidthPx * interpolatedProgress));
+        mInvalidateViewCallback.run();
+    }
+
+    /**
+     * Draws the border on the given canvas.
+     * <p>
+     * Call this method in the target view's {@link android.view.View#draw(Canvas)} method after
+     * calling super.
+     */
+    public void drawBorder(Canvas canvas) {
+        canvas.drawRoundRect(
+                /* left= */ mBorderBounds.left + mAlignmentAdjustment,
+                /* top= */ mBorderBounds.top + mAlignmentAdjustment,
+                /* right= */ mBorderBounds.right - mAlignmentAdjustment,
+                /* bottom= */ mBorderBounds.bottom - mAlignmentAdjustment,
+                /* rx= */ mBorderRadiusPx - mAlignmentAdjustment,
+                /* ry= */ mBorderRadiusPx - mAlignmentAdjustment,
+                /* paint= */ mBorderPaint);
+    }
+
+    /**
+     * Builds the border appearance/disappearance animation.
+     */
+    @NonNull
+    public Animator buildAnimator(boolean isAppearing) {
+        mBorderBoundsBuilder.updateBorderBounds(mBorderBounds);
+        mRunningBorderAnimation = mBorderAnimationProgress.animateToValue(isAppearing ? 1f : 0f);
+        mRunningBorderAnimation.setDuration(
+                isAppearing ? mAppearanceDurationMs : mDisappearanceDurationMs);
+
+        mRunningBorderAnimation.addListener(
+                AnimatorListeners.forEndCallback(() -> mRunningBorderAnimation = null));
+
+        return mRunningBorderAnimation;
+    }
+
+    /**
+     * Immediately shows/hides the border without an animation.
+     *
+     * To animate the appearance/disappearance, see {@link BorderAnimator#buildAnimator(boolean)}
+     */
+    public void setBorderVisible(boolean visible) {
+        if (mRunningBorderAnimation != null) {
+            mRunningBorderAnimation.end();
+        }
+        mBorderAnimationProgress.updateValue(visible ? 1f : 0f);
+    }
+
+    /**
+     * Callback to update the border bounds when building this animation.
+     */
+    public interface BorderBoundsBuilder {
+
+        /**
+         * Sets the given rect to the most up-to-date bounds.
+         */
+        void updateBorderBounds(Rect rect);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 0ac682f..2770049 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -133,6 +133,12 @@
     }
 
     @Override
+    protected void updateBorderBounds(Rect bounds) {
+        bounds.set(mBackgroundView.getLeft(), mBackgroundView.getTop(), mBackgroundView.getRight(),
+                mBackgroundView.getBottom());
+    }
+
+    @Override
     public void bind(Task task, RecentsOrientedState orientedState) {
         bind(Collections.singletonList(task), orientedState);
     }
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 5cf79ea..e9498fd 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -5,6 +5,7 @@
 
 import android.content.Context;
 import android.graphics.PointF;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -72,6 +73,23 @@
     }
 
     @Override
+    protected void updateBorderBounds(Rect bounds) {
+        if (mSplitBoundsConfig == null) {
+            super.updateBorderBounds(bounds);
+            return;
+        }
+        bounds.set(
+                Math.min(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
+                        mSnapshotView2.getLeft() + Math.round(mSnapshotView2.getTranslationX())),
+                Math.min(mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
+                        mSnapshotView2.getTop() + Math.round(mSnapshotView2.getTranslationY())),
+                Math.max(mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
+                        mSnapshotView2.getRight() + Math.round(mSnapshotView2.getTranslationX())),
+                Math.max(mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()),
+                        mSnapshotView2.getBottom() + Math.round(mSnapshotView2.getTranslationY())));
+    }
+
+    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         mSnapshotView2 = findViewById(R.id.bottomright_snapshot);
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index d3c7778..0e2f020 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -31,6 +31,7 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
 import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
+import static com.android.quickstep.util.BorderAnimator.DEFAULT_BORDER_COLOR;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
 
@@ -42,6 +43,7 @@
 import android.app.ActivityOptions;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Canvas;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -94,6 +96,7 @@
 import com.android.quickstep.TaskThumbnailCache;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.TaskViewUtils;
+import com.android.quickstep.util.BorderAnimator;
 import com.android.quickstep.util.CancellableTask;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.util.SplitSelectStateController;
@@ -405,6 +408,8 @@
 
     private boolean mIsClickableAsLiveTile = true;
 
+    @Nullable private final BorderAnimator mBorderAnimator;
+
     public TaskView(Context context) {
         this(context, null);
     }
@@ -414,12 +419,46 @@
     }
 
     public TaskView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public TaskView(
+            Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
         mActivity = StatefulActivity.fromContext(context);
         setOnClickListener(this::onClick);
 
         mCurrentFullscreenParams = new FullscreenDrawParams(context);
         mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
+
+        setWillNotDraw(!FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get());
+
+        mBorderAnimator = !FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get()
+                ? null
+                : new BorderAnimator(
+                        /* borderBoundsBuilder= */ this::updateBorderBounds,
+                        /* borderWidthPx= */ context.getResources().getDimensionPixelSize(
+                                R.dimen.keyboard_quick_switch_border_width),
+                        /* borderRadiusPx= */ (int) mCurrentFullscreenParams.mCornerRadius,
+                        /* borderColor= */ attrs == null
+                        ? DEFAULT_BORDER_COLOR
+                        : context.getTheme()
+                                .obtainStyledAttributes(
+                                        attrs,
+                                        R.styleable.TaskView,
+                                        defStyleAttr,
+                                        defStyleRes)
+                                .getColor(
+                                        R.styleable.TaskView_borderColor,
+                                        DEFAULT_BORDER_COLOR),
+                        /* invalidateViewCallback= */ TaskView.this::invalidate);
+    }
+
+    protected void updateBorderBounds(Rect bounds) {
+        bounds.set(mSnapshotView.getLeft() + Math.round(mSnapshotView.getTranslationX()),
+                mSnapshotView.getTop() + Math.round(mSnapshotView.getTranslationY()),
+                mSnapshotView.getRight() + Math.round(mSnapshotView.getTranslationX()),
+                mSnapshotView.getBottom() + Math.round(mSnapshotView.getTranslationY()));
     }
 
     public void setTaskViewId(int id) {
@@ -463,6 +502,22 @@
         mIconTouchDelegate = new TransformingTouchDelegate(mIconView);
     }
 
+    @Override
+    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        if (mBorderAnimator != null) {
+            mBorderAnimator.buildAnimator(gainFocus).start();
+        }
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+        if (mBorderAnimator != null) {
+            mBorderAnimator.drawBorder(canvas);
+        }
+    }
+
     /**
      * Whether the taskview should take the touch event from parent. Events passed to children
      * that might require special handling.
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
index c5e0398..4cca24e 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
@@ -52,6 +52,7 @@
     @Mock lateinit var taskbarTranslationController: TaskbarTranslationController
     @Mock lateinit var taskbarOverlayController: TaskbarOverlayController
     @Mock lateinit var taskbarEduTooltipController: TaskbarEduTooltipController
+    @Mock lateinit var keyboardQuickSwitchController: KeyboardQuickSwitchController
 
     lateinit var taskbarControllers: TaskbarControllers
 
@@ -90,6 +91,7 @@
                 taskbarTranslationController,
                 taskbarRecentAppsController,
                 taskbarEduTooltipController,
+                keyboardQuickSwitchController
             )
     }
 }
diff --git a/res/drawable/popup_background_material_u.xml b/res/drawable/popup_background_material_u.xml
new file mode 100644
index 0000000..4d40ba8
--- /dev/null
+++ b/res/drawable/popup_background_material_u.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="?attr/popupColorPrimary"/>
+    <corners android:radius="@dimen/dialogCornerRadius"/>
+</shape>
\ No newline at end of file
diff --git a/res/layout/deep_shortcut_container.xml b/res/layout/deep_shortcut_container.xml
new file mode 100644
index 0000000..b6c3f56
--- /dev/null
+++ b/res/layout/deep_shortcut_container.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/deep_shortcuts_container"
+    android:background="@drawable/popup_background_material_u"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:tag="@string/popup_container_iterate_children"
+    android:elevation="@dimen/deep_shortcuts_elevation"
+    android:orientation="vertical"/>
\ No newline at end of file
diff --git a/res/layout/deep_shortcut_material_u.xml b/res/layout/deep_shortcut_material_u.xml
new file mode 100644
index 0000000..fc019e9
--- /dev/null
+++ b/res/layout/deep_shortcut_material_u.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.shortcuts.DeepShortcutView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/deep_shortcut_material"
+    android:layout_width="@dimen/bg_popup_item_width"
+    android:layout_height="@dimen/bg_popup_item_height"
+    android:elevation="@dimen/deep_shortcuts_elevation"
+    android:background="@drawable/middle_item_primary"
+    android:theme="@style/PopupItem" >
+
+    <com.android.launcher3.shortcuts.DeepShortcutTextView
+        style="@style/BaseIcon"
+        android:id="@+id/bubble_text"
+        android:background="?android:attr/selectableItemBackground"
+        android:gravity="start|center_vertical"
+        android:textAlignment="viewStart"
+        android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
+        android:paddingEnd="@dimen/popup_padding_end"
+        android:drawablePadding="@dimen/deep_shortcut_drawable_padding"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:textSize="14sp"
+        android:textColor="?android:attr/textColorPrimary"
+        launcher:layoutHorizontal="true"
+        launcher:iconDisplay="shortcut_popup"
+        launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size" />
+
+    <View
+        android:id="@+id/icon"
+        android:layout_width="@dimen/deep_shortcut_icon_size"
+        android:layout_height="@dimen/deep_shortcut_icon_size"
+        android:layout_marginStart="@dimen/popup_padding_start"
+        android:layout_gravity="start|center_vertical"
+        android:background="@drawable/ic_deepshortcut_placeholder"/>
+</com.android.launcher3.shortcuts.DeepShortcutView>
\ No newline at end of file
diff --git a/res/layout/home_settings.xml b/res/layout/home_settings.xml
index 0f2461a..c0f16e2 100644
--- a/res/layout/home_settings.xml
+++ b/res/layout/home_settings.xml
@@ -12,6 +12,9 @@
         android:layout_marginHorizontal="@dimen/developer_options_filter_margins"
         android:hint="@string/developer_options_filter_hint"
         android:visibility="gone"
+        android:inputType="text"
+        android:maxLines="1"
+        android:imeOptions="actionDone"
         />
 
     <FrameLayout
diff --git a/res/layout/popup_container_material_u.xml b/res/layout/popup_container_material_u.xml
new file mode 100644
index 0000000..d3036b6
--- /dev/null
+++ b/res/layout/popup_container_material_u.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.popup.PopupContainerWithArrow
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/popup_container"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"/>
\ No newline at end of file
diff --git a/res/layout/system_shortcut.xml b/res/layout/system_shortcut.xml
index 21d532e..cbd7fa4 100644
--- a/res/layout/system_shortcut.xml
+++ b/res/layout/system_shortcut.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="@dimen/bg_popup_item_width"
     android:layout_height="wrap_content"
+    android:id="@+id/system_shortcut"
     android:minHeight="@dimen/bg_popup_item_height"
     android:elevation="@dimen/deep_shortcuts_elevation"
     android:background="@drawable/middle_item_primary"
diff --git a/res/layout/system_shortcut_icons.xml b/res/layout/system_shortcut_icons_container.xml
similarity index 89%
rename from res/layout/system_shortcut_icons.xml
rename to res/layout/system_shortcut_icons_container.xml
index 775a45f..ee104d9 100644
--- a/res/layout/system_shortcut_icons.xml
+++ b/res/layout/system_shortcut_icons_container.xml
@@ -26,7 +26,7 @@
     android:clipToPadding="true">
 
     <Space android:layout_width="0dp"
-           android:layout_height="match_parent"
-           android:layout_weight="1"
-           android:id="@+id/separator"/>
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:id="@+id/separator"/>
 </LinearLayout>
diff --git a/res/layout/system_shortcut_icons.xml b/res/layout/system_shortcut_icons_container_material_u.xml
similarity index 73%
copy from res/layout/system_shortcut_icons.xml
copy to res/layout/system_shortcut_icons_container_material_u.xml
index 775a45f..afd11e6 100644
--- a/res/layout/system_shortcut_icons.xml
+++ b/res/layout/system_shortcut_icons_container_material_u.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- 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.
@@ -17,16 +17,16 @@
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/system_shortcut_icons"
+    android:tag="@string/popup_container_iterate_children"
     android:layout_width="match_parent"
     android:layout_height="@dimen/system_shortcut_header_height"
     android:orientation="horizontal"
     android:gravity="end|center_vertical"
-    android:background="@drawable/single_item_primary"
-    android:elevation="@dimen/deep_shortcuts_elevation"
-    android:clipToPadding="true">
+    android:background="@drawable/popup_background_material_u"
+    android:elevation="@dimen/deep_shortcuts_elevation">
 
     <Space android:layout_width="0dp"
-           android:layout_height="match_parent"
-           android:layout_weight="1"
-           android:id="@+id/separator"/>
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:id="@+id/separator"/>
 </LinearLayout>
diff --git a/res/layout/system_shortcut_rows_container_material_u.xml b/res/layout/system_shortcut_rows_container_material_u.xml
new file mode 100644
index 0000000..006e280
--- /dev/null
+++ b/res/layout/system_shortcut_rows_container_material_u.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/system_shortcuts_container"
+    android:background="@drawable/popup_background_material_u"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:tag="@string/popup_container_iterate_children"
+    android:elevation="@dimen/deep_shortcuts_elevation"
+    android:orientation="vertical"/>
diff --git a/res/layout/system_shortcut_icons.xml b/res/layout/widget_shortcut_container_material_u.xml
similarity index 71%
copy from res/layout/system_shortcut_icons.xml
copy to res/layout/widget_shortcut_container_material_u.xml
index 775a45f..aab34e3 100644
--- a/res/layout/system_shortcut_icons.xml
+++ b/res/layout/widget_shortcut_container_material_u.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- 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.
@@ -16,17 +16,12 @@
 
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/system_shortcut_icons"
+    android:id="@+id/widget_shortcut_container"
+    android:background="@drawable/popup_background_material_u"
     android:layout_width="match_parent"
     android:layout_height="@dimen/system_shortcut_header_height"
     android:orientation="horizontal"
     android:gravity="end|center_vertical"
-    android:background="@drawable/single_item_primary"
     android:elevation="@dimen/deep_shortcuts_elevation"
-    android:clipToPadding="true">
-
-    <Space android:layout_width="0dp"
-           android:layout_height="match_parent"
-           android:layout_weight="1"
-           android:id="@+id/separator"/>
-</LinearLayout>
+    android:tag="@string/popup_container_iterate_children"
+    android:clipToPadding="true"/>
\ No newline at end of file
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 1794b19..7b97abc 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Raak en hou die legstuk om dit op die tuisskerm rond te beweeg"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Voeg by tuisskerm"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk by tuisskerm gevoeg"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# legstuk}other{# legstukke}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# kortpad}other{# kortpaaie}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index be7a737..6208fb1 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ምግብር}one{# ምግብሮች}other{# ምግብሮች}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# አቋራጭ}one{# አቋራጭ}other{# አቋራጮች}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>፣ <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 1aaa659..a38fe0b 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{تطبيق مصغّر واحد}zero{# تطبيق مصغّر}two{تطبيقان مصغّران}few{# تطبيقات مصغّرة}many{# تطبيقًا مصغّرًا}other{# تطبيق مصغّر}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{اختصار واحد}zero{# اختصار}two{اختصاران}few{# اختصارات}many{# اختصارًا}other{# اختصار}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>، <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 5dd751e..3a67edb 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# টা ৱিজেট}one{# টা ৱিজেট}other{# টা ৱিজেট}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# টা শ্বৰ্টকাট}one{# টা শ্বৰ্টকাট}other{# টা শ্বৰ্টকাট}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 9b3d60c..326ac68 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Əsas ekranda hərəkət etdirmək üçün vidcetə toxunub saxlayın"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Əsas ekrana əlavə edin"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidceti əsas ekrana əlavə edildi"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidcet}other{# vidcet}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# qısayol}other{# qısayol}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 9061ef4..fc656bd 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i zadržite vidžet da biste ga pomerali 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">"Dodali ste vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> na početni ekran"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidžet}one{# vidžet}few{# vidžeta}other{# vidžeta}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečica}one{# prečica}few{# prečice}other{# prečica}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 6bd6450..d5097c3 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# віджэт}one{# віджэт}few{# віджэты}many{# віджэтаў}other{# віджэта}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлык}one{# ярлык}few{# ярлыкі}many{# ярлыкоў}other{# ярлыка}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 68707a8..ff40365 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# приспособление}other{# приспособления}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# пряк път}other{# преки пътя}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 31704bc..509c68a 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{#টি উইজেট}one{#টি উইজেট}other{#টি উইজেট}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{#টি শর্টকাট}one{#টি শর্টকাট}other{#টি শর্টকাট}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 4b197d7..46bac11 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -37,6 +37,7 @@
     <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_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>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidžet}one{# vidžet}few{# vidžeta}other{# vidžeta}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečica}one{# prečica}few{# prečice}other{# prečica}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 275cba2..739bd98 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén premut el widget per moure\'l per la pantalla d\'inici"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Afegeix a la pantalla d\'inici"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"El widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> s\'ha afegit a la pantalla d\'inici"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# drecera}other{# dreceres}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index af1ed17..fac5e9f 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pokud chcete widgetem pohybovat po ploše, podržte ho"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Přidat na plochu"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> byl přidán na plochu"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ # widget}few{# widgety}many{# widgetu}other{# widgetů}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# zkratka}few{# zkratky}many{# zkratky}other{# zkratek}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 2ac056a..2125ed7 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Hold widgetten nede for at flytte den rundt på startskærmen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Føj til startskærm"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widgetten <xliff:g id="WIDGET_NAME">%1$s</xliff:g> blev føjet til startskærmen"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# genvej}one{# genvej}other{# genveje}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index c688916..29a2c5b 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Wenn du das Widget auf dem Startbildschirm verschieben möchtest, halte es gedrückt"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Zum Startbildschirm hinzufügen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-Widget zum Startbildschirm hinzugefügt"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# Widget}other{# Widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# Verknüpfung}other{# Verknüpfungen}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 80307c6..0c64060 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# γραφικό στοιχείο}other{# γραφικά στοιχεία}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# συντόμευση}other{# συντομεύσεις}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 22ab551..ef9dfb3 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -37,6 +37,7 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch and hold the widget to move it around the home screen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
+    <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 22838ea..a623919 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -37,6 +37,7 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch &amp; hold the widget to move it around the home screen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
+    <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 22ab551..ef9dfb3 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -37,6 +37,7 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch and hold the widget to move it around the home screen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
+    <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 22ab551..ef9dfb3 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -37,6 +37,7 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Touch and hold the widget to move it around the home screen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
+    <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index a885f00..da3fea1 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -37,6 +37,7 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‏‏‏‏‏‎‎‎‏‏‏‏‎‎Touch &amp; hold the widget to move it around the home screen‎‏‎‎‏‎"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‏‎‏‏‎‎‏‏‎‏‎‏‏‏‏‎Add to home screen‎‏‎‎‏‎"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‏‎‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="WIDGET_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ widget added to home screen‎‏‎‎‏‎"</string>
+    <string name="suggested_widgets_header_title" msgid="1844314680798145222">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‎‏‎‏‎‎‏‎‎‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎‏‏‏‎‏‎‏‎‏‏‎‎‎‏‏‎‎Suggestions‎‏‎‎‏‎"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎‎# widget‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎‎# widgets‎‏‎‎‏‎}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‏‏‏‏‎‏‎# shortcut‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‏‏‏‏‎‏‎# shortcuts‎‏‎‎‏‎}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>‎‏‎‎‏‏‏‎, ‎‏‎‎‏‏‎<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 3a21f15..b01679f 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén presionado el widget para moverlo por la pantalla principal"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Agregar a pantalla principal"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Se agregó el widget de <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a la pantalla principal"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# acceso directo}other{# accesos directos}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index af9cc27..73dcad5 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén pulsado el widget para moverlo por la pantalla de inicio"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Añadir a pantalla de inicio"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> añadido a la pantalla de inicio"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# acceso directo}other{# accesos directos}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index b8d12a3..efeb853 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Vidina teisaldamiseks avakuval puudutage vidinat ja hoidke seda all"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Lisa avakuvale"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g> lisati avakuvale"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidin}other{# vidinat}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# otsetee}other{# otseteed}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 530a5a0..d0b6f54 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Widgeta hasierako pantailan zehar mugitzeko, eduki ezazu sakatuta"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Gehitu hasierako pantailan"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta hasierako pantailan gehitu da"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# lasterbide}other{# lasterbide}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index cb811f3..5ec5b54 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{‏# ابزارک}one{‏# ابزارک}other{‏# ابزارک}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{‏# میان‌بر}one{‏# میان‌بر}other{‏# میان‌بر}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>،<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 92fe859..1b02c14 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Voit siirtää widgetiä aloitusnäytöllä koskettamalla sitä pitkään"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Lisää aloitusnäytölle"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget lisätty aloitusnäytölle: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgetiä}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pikakuvake}other{# pikakuvaketta}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index db35665..604cb31 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Maintenez le doigt sur le widget pour le déplacer sur l\'écran d\'accueil"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Le widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a été ajouté à l\'écran d\'accueil"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# raccourci}one{# raccourci}other{# raccourcis}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 571a03e..1d22a5f 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Appuyez de manière prolongée sur le widget pour le déplacer sur l\'écran d\'accueil"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ajouté à l\'écran d\'accueil"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# raccourci}one{# raccourci}other{# raccourcis}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 2ed64a1..8e90cbc 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Mantén premido o widget para movelo pola pantalla de inicio"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Engadir á pantalla de inicio"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Engadiuse o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> á pantalla de inicio"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atallo}other{# atallos}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 719f531..487fb9e 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# વિજેટ}one{# વિજેટ}other{# વિજેટ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# શૉર્ટકટ}one{# શૉર્ટકટ}other{# શૉર્ટકટ}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index eacd252..d937288 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}one{# विजेट}other{# विजेट}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# शॉर्टकट}one{# शॉर्टकट}other{# शॉर्टकट}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index eeeade0..66b5ef9 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -37,6 +37,7 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i zadržite widget da biste ga pomicali po početnom zaslonu"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni zaslon"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> dodan je na početni zaslon"</string>
+    <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Prijedlozi"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}few{# widgeta}other{# widgeta}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečac}one{# prečac}few{# prečaca}other{# prečaca}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 330fd69..e25fc8d 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tartsa lenyomva a modult a kezdőképernyőn való mozgatáshoz"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Hozzáadás a kezdőképernyőhöz"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadva a kezdőképernyőhöz"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# modul}other{# modul}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# gyorsparancs}other{# gyorsparancs}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index cf01672..bdb2259 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# վիջեթ}one{# վիջեթ}other{# վիջեթ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# դյուրանցում}one{# դյուրանցում}other{# դյուրանցում}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index fdccae3..ec3531b 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Sentuh lama widget untuk memindahkannya di sekitar layar utama"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Tambahkan ke layar utama"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ditambahkan ke layar utama"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pintasan}other{# pintasan}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 8ddfddc..ee57fbc 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Haltu fingri á græjunni til að hreyfa hana um heimaskjáinn"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Bæta á heimaskjá"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> græju bætt við heimaskjá"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# græja}one{# græja}other{# græjur}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# flýtileið}one{# flýtileið}other{# flýtileiðir}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 1c7cbe1..6a20454 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tocca e tieni premuto il widget per spostarlo nella schermata Home"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Aggiungi alla schermata Home"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> aggiunto alla schermata Home"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# scorciatoia}other{# scorciatoie}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 3bb65b4..191efb8 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ווידג\'ט אחד}one{# ווידג\'טים}two{# ווידג\'טים}other{# ווידג\'טים}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{קיצור דרך אחד}one{# קיצורי דרך}two{# קיצורי דרך}other{# קיצורי דרך}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 02dcba6..117ba4d 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 件のウィジェット}other{# 件のウィジェット}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 件のショートカット}other{# 件のショートカット}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 2e684b2..c563e36 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ვიჯეტი}other{# ვიჯეტი}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# მალსახმობი}other{# მალსახმობი}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 4caffb3..1a28773 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# таңбаша}other{# таңбаша}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 1039a89..fcde08f 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ធាតុ​ក្រាហ្វិក #}other{ធាតុ​ក្រាហ្វិក #}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ផ្លូវកាត់ #}other{ផ្លូវកាត់ #}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index fa97690..e15b94e 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ವಿಜೆಟ್}one{# ವಿಜೆಟ್‌ಗಳು}other{# ವಿಜೆಟ್‌ಗಳು}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ಶಾರ್ಟ್‌ಕಟ್}one{# ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು}other{# ಶಾರ್ಟ್‌ಕಟ್‌ಗಳು}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index b1c9a16..48ca19d 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{위젯 #개}other{위젯 #개}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{바로가기 #개}other{바로가기 #개}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 18672f5..a2a3f0c 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ыкчам баскыч}other{# ыкчам баскыч}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 422240c..d0c26aa 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -23,7 +23,6 @@
 
     <!-- Dynamic grid -->
     <dimen name="dynamic_grid_edge_margin">15.28dp</dimen>
-    <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
     <dimen name="dynamic_grid_drop_target_size">36dp</dimen>
     <dimen name="cell_layout_padding">20dp</dimen>
 
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 5a773ae..2de7cc1 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ວິດເຈັດ}other{# ວິດເຈັດ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ທາງລັດ}other{# ທາງລັດ}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index a01c1cd..93f3d3f 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Paliesdami ir palaikydami valdiklį galite judėti pagrindiniame ekrane"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Pridėti prie pagrindinio ekrano"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Valdiklis „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“ pridėtas prie pagrindinio ekrano"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# valdiklis}one{# valdiklis}few{# valdikliai}many{# valdiklio}other{# valdiklių}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# spartusis klavišas}one{# spartusis klavišas}few{# spartieji klavišai}many{# sparčiojo klavišo}other{# sparčiųjų klavišų}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index a5e3ed8..cf6f259 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pieskarieties logrīkam un turiet to, lai to pārvietotu pa sākuma ekrānu."</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Pievienot sākuma ekrānam"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Logrīks “<xliff:g id="WIDGET_NAME">%1$s</xliff:g>” ir pievienots sākuma ekrānam"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# logrīks}zero{# logrīku}one{# logrīks}other{# logrīki}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# saīsne}zero{# saīšņu}one{# saīsne}other{# saīsnes}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 8418ed2..12bd5fd 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виџет}one{# виџет}other{# виџети}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# кратенка}one{# кратенка}other{# кратенки}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 945e5ba..af36000 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# വിജറ്റ്}other{# വിജറ്റുകൾ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# കുറുക്കുവഴി}other{# കുറുക്കുവഴികൾ}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index a3754ce..be82db3 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# товчлол}other{# товчлол}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index ac7a09b..513e608 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}other{# विजेट}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# शॉर्टकट}other{# शॉर्टकट}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 263ef48..c41c70b 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Sentuh &amp; tahan widget untuk menggerakkan widget di sekitar skrin utama"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Tambahkan pada skrin utama"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ditambahkan pada skrin utama"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pintasan}other{# pintasan}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index e62e050..7cccad4 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ဝိဂျက် # ခု}other{ဝိဂျက် # ခု}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ဖြတ်လမ်းလင့်ခ် # ခု}other{ဖြတ်လမ်းလင့်ခ် # ခု}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>၊ <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 2471081..1d8d153 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Trykk og hold på modulen for å bevege den rundt på startskjermen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Legg til på startskjermen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modulen er lagt til på startskjermen"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# modul}other{# moduler}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# snarvei}other{# snarveier}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 0cd7f95..f07f16c 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}other{# वटा विजेट}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# सर्टकट}other{# वटा सर्टकट}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 5e6ed97..5685643 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -37,6 +37,8 @@
     <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_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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# snelkoppeling}other{# snelkoppelingen}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index a0509b1..e4e5877 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{#ଟି ୱିଜେଟ୍}other{#ଟି ୱିଜେଟ୍}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{#ଟି ସର୍ଟକଟ୍}other{#ଟି ସର୍ଟକଟ୍}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 2bb7274..1a78d95 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ਵਿਜੇਟ}one{# ਵਿਜੇਟ}other{# ਵਿਜੇਟ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ਸ਼ਾਰਟਕੱਟ}one{# ਸ਼ਾਰਟਕੱਟ}other{# ਸ਼ਾਰਟਕੱਟ}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index f79d0d2..ea379d2 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Kliknij i przytrzymaj widżet, aby poruszać nim po ekranie głównym"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj do ekranu głównego"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> został dodany do ekranu głównego"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widżet}few{# widżety}many{# widżetów}other{# widżetu}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# skrót}few{# skróty}many{# skrótów}other{# skrótu}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index db86366..b56f857 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -37,6 +37,7 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Toque sem soltar no widget para o mover no ecrã principal"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Adicionar ao ecrã principal"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> adicionado ao ecrã principal"</string>
+    <string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestões"</string>
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atalho}other{# atalhos}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index fea3ca9..b2f420c 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Toque no widget e o pressione para definir a posição dele na tela inicial"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Adicionar à tela inicial"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> adicionado à tela inicial"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atalho}one{# atalho}other{# atalhos}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 242649e..1af20f3 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Atinge lung widgetul pentru a-l muta pe ecranul de pornire"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Adaugă pe ecranul de pornire"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a fost adăugat pe ecranul de pornire"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}few{# widgeturi}other{# de widgeturi}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# comandă rapidă}few{# comenzi rapide}other{# de comenzi rapide}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g> <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index c14e4d1..345eed5 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}one{# виджет}few{# виджета}many{# виджетов}other{# виджета}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлык}one{# ярлык}few{# ярлыка}many{# ярлыков}other{# ярлыка}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 27a81cf..67700a9 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{විජට් #}one{විජට් #}other{විජට් #}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{කෙටි මං #}one{කෙටි මං #}other{කෙටි මං #}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 973ec86..a7c7c58 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pridržaním môžete miniaplikáciu posúvať po ploche"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Pridať na plochu"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Na plochu bola pridaná miniaplikácia <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# miniaplikácia}few{# miniaplikácie}many{# widgets}other{# miniaplikácií}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# odkaz}few{# odkazy}many{# shortcuts}other{# odkazov}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index a2720b6..ff49ffe 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dotaknite se pripomočka in ga pridržite, če ga želite premikati po začetnem zaslonu."</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na začetni zaslon"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Pripomoček »<xliff:g id="WIDGET_NAME">%1$s</xliff:g>« je dodan na začetni zaslon."</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# pripomoček}one{# pripomoček}two{# pripomočka}few{# pripomočki}other{# pripomočkov}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# bližnjica}one{# bližnjica}two{# bližnjici}few{# bližnjice}other{# bližnjic}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index dd25a36..1bba697 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Prek dhe mbaj të shtypur miniaplikacionin për ta lëvizur atë nëpër ekranin bazë"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Shto në ekranin bazë"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Miniaplikacioni <xliff:g id="WIDGET_NAME">%1$s</xliff:g> u shtua në ekranin bazë"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# miniaplikacion}other{# miniaplikacione}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shkurtore}other{# shkurtore}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 14212d7..667eaf5 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виџет}one{# виџет}few{# виџета}other{# виџета}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# пречица}one{# пречица}few{# пречице}other{# пречица}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 05cb231..3ebea21 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tryck länge på widgeten om du vill flytta den på startskärmen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Lägg till på startskärmen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget för <xliff:g id="WIDGET_NAME">%1$s</xliff:g> har lagts till på startskärmen"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgetar}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# genväg}other{# genvägar}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 5624d4a..f4ac880 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Gusa na ushikilie wijeti ili uisogeze kwenye skrini ya kwanza"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Weka kwenye skrini ya kwanza"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Umeongeza wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g> kwenye skrini ya kwanza"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{Wijeti #}other{Wijeti #}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{Njia # ya mkato}other{Njia # za mkato}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 0af0603..cc1f09e 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -35,7 +35,6 @@
 
 <!-- Dynamic grid -->
     <dimen name="dynamic_grid_edge_margin">9dp</dimen>
-    <dimen name="dynamic_grid_icon_drawable_padding">7dp</dimen>
     <dimen name="cell_layout_padding">9dp</dimen>
 
 <!-- Hotseat -->
diff --git a/res/values-sw600dp/styles.xml b/res/values-sw600dp/styles.xml
new file mode 100644
index 0000000..63bd46b
--- /dev/null
+++ b/res/values-sw600dp/styles.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <style name="CellStyleDefault">
+        <item name="iconDrawablePadding">7dp</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 4213ea4..e0c44c8 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# விட்ஜெட்}other{# விட்ஜெட்டுகள்}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ஷார்ட்கட்}other{# ஷார்ட்கட்கள்}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index e8ef4fa..8617a28 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"విడ్జెట్‌ను మొదటి స్క్రీన్ చుట్టూ తిప్పడానికి దాన్ని తాకి, &amp; నొక్కి ఉంచండి"</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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# విడ్జెట్}other{# విడ్జెట్‌లు}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# షార్ట్‌కట్}other{# షార్ట్‌కట్‌లు}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 85289e4..24ed95d 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{วิดเจ็ต # รายการ}other{วิดเจ็ต # รายการ}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ทางลัด # รายการ}other{ทางลัด # รายการ}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index ec6bc5f..7567bbb 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Pindutin nang matagal ang widget para ilipat-lipat ito sa home screen"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Idagdag sa home screen"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Idinagdag sa home screen ang widget na <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# na widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}one{# shortcut}other{# na shortcut}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index c485994..df6a7e7 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Ana ekranda taşımak için widget\'a dokunup basılı tutun"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Ana ekrana ekle"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ana ekrana eklendi"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# kısayol}other{# kısayol}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index d375756..5ef5b65 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# віджет}one{# віджет}few{# віджети}many{# віджетів}other{# віджета}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлик}one{# ярлик}few{# ярлики}many{# ярликів}other{# ярлика}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 13a0962..e3c10c6 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ویجیٹ}other{# ویجیٹس}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# شارٹ کٹ}other{# شارٹ کٹس}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>، <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index a3859fd..79860f3 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Bosh ekranda surish uchun vidjet ustiga bosib turing"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Bosh ekranga chiqarish"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjeti bosh ekranga qoʻshildi"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ta vidjet}other{# ta vidjet}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ta yorliq}other{# ta yorliq}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 6924aed..e128e2c 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Chạm và giữ tiện ích để di chuyển tiện ích đó xung quanh màn hình chính"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Thêm vào màn hình chính"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Đã thêm tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g> vào màn hình chính"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# tiện ích}other{# tiện ích}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# lối tắt}other{# lối tắt}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 5011df8..860dbe4 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 个微件}other{# 个微件}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 个快捷方式}other{# 个快捷方式}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>,<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index d14ce53..e3ba417 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 個小工具}other{# 個小工具}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 個捷徑}other{# 個捷徑}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 45cbc7f..fc00cc8 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -37,6 +37,8 @@
     <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>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 項小工具}other{# 項小工具}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 個捷徑}other{# 個捷徑}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index ec4a0d9..0688385 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -37,6 +37,8 @@
     <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Thinta uphinde ubambe iwijethi ukuyihambisa kusikrini sasekhaya"</string>
     <string name="add_to_home_screen" msgid="9168649446635919791">"Faka kusikrini sasekhaya"</string>
     <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Iwijethi ye-<xliff:g id="WIDGET_NAME">%1$s</xliff:g> yengezwe kusikrini sasekhaya"</string>
+    <!-- no translation found for suggested_widgets_header_title (1844314680798145222) -->
+    <skip />
     <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{iwijethi #}one{amawijethi #}other{amawijethi #}}"</string>
     <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{isinqamuleli #}one{izinqamuleli #}other{izinqamuleli #}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9d2aa06..ba6e547 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -21,7 +21,6 @@
     <!-- Dynamic Grid -->
     <dimen name="dynamic_grid_edge_margin">10.77dp</dimen>
     <dimen name="dynamic_grid_left_right_margin">8dp</dimen>
-    <dimen name="dynamic_grid_icon_drawable_padding">7dp</dimen>
     <!-- Minimum amount of next page visible in spring loaded mode -->
     <dimen name="dynamic_grid_spring_loaded_min_next_space_visible">24dp</dimen>
 
@@ -349,7 +348,7 @@
     <dimen name="developer_options_filter_margins">10dp</dimen>
 
     <!-- Theming related -->
-    <dimen name="default_dialog_corner_radius">8dp</dimen>
+    <dimen name="default_dialog_corner_radius">26dp</dimen>
     <dimen name="dialogCornerRadius">@dimen/default_dialog_corner_radius</dimen>
 
     <!-- Onboarding bottomsheet related -->
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 604c1b8..2fb0fa6 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3;
 
+import static com.android.launcher3.LauncherPrefs.GRID_NAME;
 import static com.android.launcher3.Utilities.dpiFromPx;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_DEVICE_PROFILE_LOGGING;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TWO_PANEL_HOME;
@@ -93,8 +94,6 @@
     public static final int TYPE_MULTI_DISPLAY = 1;
     public static final int TYPE_TABLET = 2;
 
-    private static final String KEY_IDP_GRID_NAME = "idp_grid_name";
-
     private static final float ICON_SIZE_DEFINED_IN_APP_DP = 48;
 
     // Constants that affects the interpolation curve between statically defined device profile
@@ -207,8 +206,7 @@
         String gridName = getCurrentGridName(context);
         String newGridName = initGrid(context, gridName);
         if (!newGridName.equals(gridName)) {
-            LauncherPrefs.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName)
-                    .apply();
+            LauncherPrefs.get(context).put(GRID_NAME, newGridName);
         }
         new DeviceGridState(this).writeToPrefs(context);
 
@@ -316,7 +314,7 @@
     }
 
     public static String getCurrentGridName(Context context) {
-        return LauncherPrefs.getPrefs(context).getString(KEY_IDP_GRID_NAME, null);
+        return LauncherPrefs.get(context).get(GRID_NAME);
     }
 
     private String initGrid(Context context, String gridName) {
@@ -458,9 +456,8 @@
 
 
     public void setCurrentGrid(Context context, String gridName) {
-        Context appContext = context.getApplicationContext();
-        LauncherPrefs.getPrefs(appContext).edit().putString(KEY_IDP_GRID_NAME, gridName).apply();
-        MAIN_EXECUTOR.execute(() -> onConfigChanged(appContext));
+        LauncherPrefs.get(context).put(GRID_NAME, gridName);
+        MAIN_EXECUTOR.execute(() -> onConfigChanged(context.getApplicationContext()));
     }
 
     private Object[] toModelState() {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 41632f7..8097fd7 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -3211,7 +3211,7 @@
     }
 
     @Override
-    public boolean shouldUseColorExtractionForPopup() {
+    public boolean canUseMultipleShadesForPopup() {
         return getTopOpenViewWithType(this, TYPE_FOLDER) == null
                 && getStateManager().getState() != LauncherState.ALL_APPS;
     }
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 2e07e30..befaa64 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -4,6 +4,8 @@
 import android.content.SharedPreferences
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener
 import androidx.annotation.VisibleForTesting
+import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
+import com.android.launcher3.LauncherFiles.SHARED_PREFERENCES_KEY
 import com.android.launcher3.allapps.WorkProfileManager
 import com.android.launcher3.model.DeviceGridState
 import com.android.launcher3.pm.InstallSessionHelper
@@ -20,11 +22,10 @@
 class LauncherPrefs(private val context: Context) {
 
     /** Wrapper around `getInner` for a `ContextualItem` */
-    fun <T : Any> get(item: ContextualItem<T>): T =
-        getInner(item, item.defaultValueFromContext(context))
+    fun <T> get(item: ContextualItem<T>): T = getInner(item, item.defaultValueFromContext(context))
 
     /** Wrapper around `getInner` for an `Item` */
-    fun <T : Any> get(item: ConstantItem<T>): T = getInner(item, item.defaultValue)
+    fun <T> get(item: ConstantItem<T>): T = getInner(item, item.defaultValue)
 
     /**
      * Retrieves the value for an [Item] from [SharedPreferences]. It handles method typing via the
@@ -32,11 +33,11 @@
      * `String`, `Boolean`, `Float`, `Int`, `Long`, or `Set<String>`.
      */
     @Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST")
-    private fun <T : Any> getInner(item: Item, default: T): T {
+    private fun <T> getInner(item: Item, default: T): T {
         val sp = context.getSharedPreferences(item.sharedPrefFile, Context.MODE_PRIVATE)
 
-        return when (default::class.java) {
-            String::class.java -> sp.getString(item.sharedPrefKey, default as String)
+        return when (item.type) {
+            String::class.java -> sp.getString(item.sharedPrefKey, default as? String)
             Boolean::class.java,
             java.lang.Boolean::class.java -> sp.getBoolean(item.sharedPrefKey, default as Boolean)
             Int::class.java,
@@ -45,11 +46,10 @@
             java.lang.Float::class.java -> sp.getFloat(item.sharedPrefKey, default as Float)
             Long::class.java,
             java.lang.Long::class.java -> sp.getLong(item.sharedPrefKey, default as Long)
-            Set::class.java -> sp.getStringSet(item.sharedPrefKey, default as Set<String>)
+            Set::class.java -> sp.getStringSet(item.sharedPrefKey, default as? Set<String>)
             else ->
                 throw IllegalArgumentException(
-                    "item type: ${default::class.java}" +
-                        " is not compatible with sharedPref methods"
+                    "item type: ${item.type}" + " is not compatible with sharedPref methods"
                 )
         }
             as T
@@ -224,39 +224,36 @@
             backedUpItem(RestoreDbTask.RESTORED_DEVICE_TYPE, InvariantDeviceProfile.TYPE_PHONE)
         @JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "")
         @JvmField val OLD_APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_OLD_IDS, "")
+        @JvmField val GRID_NAME = ConstantItem("idp_grid_name", true, null, String::class.java)
         @JvmField
         val ALLOW_ROTATION =
-            backedUpItem(RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY) {
+            backedUpItem(RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY, Boolean::class.java) {
                 RotationHelper.getAllowRotationDefaultValue(DisplayController.INSTANCE.get(it).info)
             }
 
         @VisibleForTesting
         @JvmStatic
         fun <T> backedUpItem(sharedPrefKey: String, defaultValue: T): ConstantItem<T> =
-            ConstantItem(sharedPrefKey, LauncherFiles.SHARED_PREFERENCES_KEY, defaultValue)
+            ConstantItem(sharedPrefKey, true, defaultValue)
 
         @JvmStatic
         fun <T> backedUpItem(
             sharedPrefKey: String,
+            type: Class<out T>,
             defaultValueFromContext: (c: Context) -> T
-        ): ContextualItem<T> =
-            ContextualItem(
-                sharedPrefKey,
-                LauncherFiles.SHARED_PREFERENCES_KEY,
-                defaultValueFromContext
-            )
+        ): ContextualItem<T> = ContextualItem(sharedPrefKey, true, defaultValueFromContext, type)
 
         @VisibleForTesting
         @JvmStatic
         fun <T> nonRestorableItem(sharedPrefKey: String, defaultValue: T): ConstantItem<T> =
-            ConstantItem(sharedPrefKey, LauncherFiles.DEVICE_PREFERENCES_KEY, defaultValue)
+            ConstantItem(sharedPrefKey, false, defaultValue)
 
         @Deprecated("Don't use shared preferences directly. Use other LauncherPref methods.")
         @JvmStatic
         fun getPrefs(context: Context): SharedPreferences {
             // Use application context for shared preferences, so we use single cached instance
             return context.applicationContext.getSharedPreferences(
-                LauncherFiles.SHARED_PREFERENCES_KEY,
+                SHARED_PREFERENCES_KEY,
                 Context.MODE_PRIVATE
             )
         }
@@ -266,7 +263,7 @@
         fun getDevicePrefs(context: Context): SharedPreferences {
             // Use application context for shared preferences, so we use a single cached instance
             return context.applicationContext.getSharedPreferences(
-                LauncherFiles.DEVICE_PREFERENCES_KEY,
+                DEVICE_PREFERENCES_KEY,
                 Context.MODE_PRIVATE
             )
         }
@@ -275,21 +272,26 @@
 
 abstract class Item {
     abstract val sharedPrefKey: String
-    abstract val sharedPrefFile: String
+    abstract val isBackedUp: Boolean
+    abstract val type: Class<*>
+    val sharedPrefFile: String = if (isBackedUp) SHARED_PREFERENCES_KEY else DEVICE_PREFERENCES_KEY
 
     fun <T> to(value: T): Pair<Item, T> = Pair(this, value)
 }
 
 data class ConstantItem<T>(
     override val sharedPrefKey: String,
-    override val sharedPrefFile: String,
-    val defaultValue: T
+    override val isBackedUp: Boolean,
+    val defaultValue: T,
+    // The default value can be null. If so, the type needs to be explicitly stated, or else NPE
+    override val type: Class<out T> = defaultValue!!::class.java
 ) : Item()
 
 data class ContextualItem<T>(
     override val sharedPrefKey: String,
-    override val sharedPrefFile: String,
-    private val defaultSupplier: (c: Context) -> T
+    override val isBackedUp: Boolean,
+    private val defaultSupplier: (c: Context) -> T,
+    override val type: Class<out T>
 ) : Item() {
     private var default: T? = null
 
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index dd37bab..7641728 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -439,9 +439,11 @@
             return;
         }
 
-        RecyclerView.ItemDecoration decoration = getMainAdapterProvider().getDecorator();
-        getSearchRecyclerView().removeItemDecoration(decoration);
-        getSearchRecyclerView().addItemDecoration(decoration);
+        if (!FeatureFlags.ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES.get()) {
+            RecyclerView.ItemDecoration decoration = getMainAdapterProvider().getDecorator();
+            getSearchRecyclerView().removeItemDecoration(decoration);
+            getSearchRecyclerView().addItemDecoration(decoration);
+        }
 
         // replaceAppsRVcontainer() needs to use both mUsingTabs value to remove the old view AND
         // showTabs value to create new view. Hence the mUsingTabs new value assignment MUST happen
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 4b0b1ff..7b0033d 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -411,6 +411,10 @@
             "Enables receiving unfold animation events from sysui instead of calculating "
                     + "them in launcher process using hinge sensor values.");
 
+    public static final BooleanFlag ENABLE_KEYBOARD_QUICK_SWITCH = getDebugFlag(
+            "ENABLE_KEYBOARD_QUICK_SWITCH", false,
+            "Enables keyboard quick switching");
+
     public static void initialize(Context context) {
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/graphics/SysUiScrim.java b/src/com/android/launcher3/graphics/SysUiScrim.java
index 11e7dc8..e983a30 100644
--- a/src/com/android/launcher3/graphics/SysUiScrim.java
+++ b/src/com/android/launcher3/graphics/SysUiScrim.java
@@ -32,11 +32,10 @@
 import android.util.DisplayMetrics;
 import android.util.FloatProperty;
 import android.view.View;
-import android.view.WindowInsets;
 
 import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.testing.shared.ResourceUtils;
 import com.android.launcher3.util.DynamicResource;
@@ -185,21 +184,18 @@
 
     /**
      * Determines whether to draw the top and/or bottom scrim based on new insets.
+     *
+     * In order for the bottom scrim to be drawn this 3 condition should be meet at the same time:
+     * the device is in 3 button navigation, the taskbar is not present and the Hotseat is
+     * horizontal
      */
     public void onInsetsChanged(Rect insets) {
+        DeviceProfile dp = mActivity.getDeviceProfile();
         mDrawTopScrim = mTopScrim != null && insets.top > 0;
         mDrawBottomScrim = mBottomMask != null
-                && !mActivity.getDeviceProfile().isVerticalBarLayout()
-                && hasBottomNavButtons();
-    }
-
-    private boolean hasBottomNavButtons() {
-        if (Utilities.ATLEAST_Q && mActivity.getRootView() != null
-                && mActivity.getRootView().getRootWindowInsets() != null) {
-            WindowInsets windowInsets = mActivity.getRootView().getRootWindowInsets();
-            return windowInsets.getTappableElementInsets().bottom > 0;
-        }
-        return true;
+                && !dp.isVerticalBarLayout()
+                && !dp.isGestureMode
+                && !dp.isTaskbarPresent;
     }
 
     @Override
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 6c62b31..0a6a7cd 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -37,7 +37,6 @@
 
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
@@ -72,24 +71,32 @@
     private final IconCache mIconCache;
     private final InvariantDeviceProfile mIDP;
 
-    private final IntArray itemsToRemove = new IntArray();
-    private final IntArray restoredRows = new IntArray();
-    private final IntSparseArrayMap<GridOccupancy> occupied = new IntSparseArrayMap<>();
+    private final IntArray mItemsToRemove = new IntArray();
+    private final IntArray mRestoredRows = new IntArray();
+    private final IntSparseArrayMap<GridOccupancy> mOccupied = new IntSparseArrayMap<>();
 
-    private final int iconPackageIndex;
-    private final int iconResourceIndex;
-    private final int iconIndex;
-    public final int titleIndex;
+    private final int mIconPackageIndex;
+    private final int mIconResourceIndex;
+    private final int mIconIndex;
+    public final int mTitleIndex;
 
-    private final int idIndex;
-    private final int containerIndex;
-    private final int itemTypeIndex;
-    private final int screenIndex;
-    private final int cellXIndex;
-    private final int cellYIndex;
-    private final int profileIdIndex;
-    private final int restoredIndex;
-    private final int intentIndex;
+    private final int mIdIndex;
+    private final int mContainerIndex;
+    private final int mItemTypeIndex;
+    private final int mScreenIndex;
+    private final int mCellXIndex;
+    private final int mCellYIndex;
+    private final int mProfileIdIndex;
+    private final int mRestoredIndex;
+    private final int mIntentIndex;
+
+    private final int mAppWidgetIdIndex;
+    private final int mAppWidgetProviderIndex;
+    private final int mSpanXIndex;
+    private final int mSpanYIndex;
+    private final int mRankIndex;
+    private final int mOptionsIndex;
+    private final int mAppWidgetSourceIndex;
 
     @Nullable
     private LauncherActivityInfo mActivityInfo;
@@ -114,20 +121,28 @@
         mPM = mContext.getPackageManager();
 
         // Init column indices
-        iconIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
-        iconPackageIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
-        iconResourceIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
-        titleIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
+        mIconIndex = getColumnIndexOrThrow(Favorites.ICON);
+        mIconPackageIndex = getColumnIndexOrThrow(Favorites.ICON_PACKAGE);
+        mIconResourceIndex = getColumnIndexOrThrow(Favorites.ICON_RESOURCE);
+        mTitleIndex = getColumnIndexOrThrow(Favorites.TITLE);
 
-        idIndex = getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
-        containerIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
-        itemTypeIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
-        screenIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
-        cellXIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
-        cellYIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
-        profileIdIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE_ID);
-        restoredIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.RESTORED);
-        intentIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
+        mIdIndex = getColumnIndexOrThrow(Favorites._ID);
+        mContainerIndex = getColumnIndexOrThrow(Favorites.CONTAINER);
+        mItemTypeIndex = getColumnIndexOrThrow(Favorites.ITEM_TYPE);
+        mScreenIndex = getColumnIndexOrThrow(Favorites.SCREEN);
+        mCellXIndex = getColumnIndexOrThrow(Favorites.CELLX);
+        mCellYIndex = getColumnIndexOrThrow(Favorites.CELLY);
+        mProfileIdIndex = getColumnIndexOrThrow(Favorites.PROFILE_ID);
+        mRestoredIndex = getColumnIndexOrThrow(Favorites.RESTORED);
+        mIntentIndex = getColumnIndexOrThrow(Favorites.INTENT);
+
+        mAppWidgetIdIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_ID);
+        mAppWidgetProviderIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER);
+        mSpanXIndex = getColumnIndexOrThrow(Favorites.SPANX);
+        mSpanYIndex = getColumnIndexOrThrow(Favorites.SPANY);
+        mRankIndex = getColumnIndexOrThrow(Favorites.RANK);
+        mOptionsIndex = getColumnIndexOrThrow(Favorites.OPTIONS);
+        mAppWidgetSourceIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_SOURCE);
     }
 
     @Override
@@ -137,18 +152,18 @@
             mActivityInfo = null;
 
             // Load common properties.
-            itemType = getInt(itemTypeIndex);
-            container = getInt(containerIndex);
-            id = getInt(idIndex);
-            serialNumber = getInt(profileIdIndex);
+            itemType = getInt(mItemTypeIndex);
+            container = getInt(mContainerIndex);
+            id = getInt(mIdIndex);
+            serialNumber = getInt(mProfileIdIndex);
             user = allUsers.get(serialNumber);
-            restoreFlag = getInt(restoredIndex);
+            restoreFlag = getInt(mRestoredIndex);
         }
         return result;
     }
 
     public Intent parseIntent() {
-        String intentDescription = getString(intentIndex);
+        String intentDescription = getString(mIntentIndex);
         try {
             return TextUtils.isEmpty(intentDescription) ?
                     null : Intent.parseUri(intentDescription, 0);
@@ -185,14 +200,14 @@
 
     public IconRequestInfo<WorkspaceItemInfo> createIconRequestInfo(
             WorkspaceItemInfo wai, boolean useLowResIcon) {
-        String packageName = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
-                ? getString(iconPackageIndex) : null;
-        String resourceName = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
-                ? getString(iconResourceIndex) : null;
-        byte[] iconBlob = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
+        String packageName = itemType == Favorites.ITEM_TYPE_SHORTCUT
+                ? getString(mIconPackageIndex) : null;
+        String resourceName = itemType == Favorites.ITEM_TYPE_SHORTCUT
+                ? getString(mIconResourceIndex) : null;
+        byte[] iconBlob = itemType == Favorites.ITEM_TYPE_SHORTCUT
                 || itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
                 || restoreFlag != 0
-                ? getBlob(iconIndex) : null;
+                ? getBlob(mIconIndex) : null;
 
         return new IconRequestInfo<>(
                 wai, mActivityInfo, packageName, resourceName, iconBlob, useLowResIcon);
@@ -202,7 +217,70 @@
      * Returns the title or empty string
      */
     private String getTitle() {
-        return Utilities.trim(getString(titleIndex));
+        return Utilities.trim(getString(mTitleIndex));
+    }
+
+    /**
+     * When loading an app widget for the workspace, returns it's app widget id
+     */
+    public int getAppWidgetId() {
+        return getInt(mAppWidgetIdIndex);
+    }
+
+    /**
+     * When loading an app widget for the workspace, returns the widget provider
+     */
+    public String getAppWidgetProvider() {
+        return getString(mAppWidgetProviderIndex);
+    }
+
+    /**
+     * Returns the x position for the item in the cell layout's grid
+     */
+    public int getSpanX() {
+        return getInt(mSpanXIndex);
+    }
+
+    /**
+     * Returns the y position for the item in the cell layout's grid
+     */
+    public int getSpanY() {
+        return getInt(mSpanYIndex);
+    }
+
+    /**
+     * Returns the rank for the item
+     */
+    public int getRank() {
+        return getInt(mRankIndex);
+    }
+
+    /**
+     * Returns the options for the item
+     */
+    public int getOptions() {
+        return getInt(mOptionsIndex);
+    }
+
+    /**
+     * When loading an app widget for the workspace, returns it's app widget source
+     */
+    public int getAppWidgetSource() {
+        return getInt(mAppWidgetSourceIndex);
+    }
+
+    /**
+     * Returns the screen that the item is on
+     */
+    public int getScreen() {
+        return getInt(mScreenIndex);
+    }
+
+    /**
+     * Returns the UX container that the item is in
+     */
+    public int getContainer() {
+        return getInt(mContainerIndex);
     }
 
     /**
@@ -320,7 +398,7 @@
      */
     public void markDeleted(String reason) {
         FileLog.e(TAG, reason);
-        itemsToRemove.add(id);
+        mItemsToRemove.add(id);
     }
 
     /**
@@ -328,10 +406,10 @@
      * @return true is any item was removed.
      */
     public boolean commitDeleted() {
-        if (itemsToRemove.size() > 0) {
+        if (mItemsToRemove.size() > 0) {
             // Remove dead items
             mContext.getContentResolver().delete(mContentUri, Utilities.createDbSelectionQuery(
-                    LauncherSettings.Favorites._ID, itemsToRemove), null);
+                    Favorites._ID, mItemsToRemove), null);
             return true;
         }
         return false;
@@ -342,7 +420,7 @@
      */
     public void markRestored() {
         if (restoreFlag != 0) {
-            restoredRows.add(id);
+            mRestoredRows.add(id);
             restoreFlag = 0;
         }
     }
@@ -352,13 +430,13 @@
     }
 
     public void commitRestoredItems() {
-        if (restoredRows.size() > 0) {
+        if (mRestoredRows.size() > 0) {
             // Update restored items that no longer require special handling
             ContentValues values = new ContentValues();
-            values.put(LauncherSettings.Favorites.RESTORED, 0);
+            values.put(Favorites.RESTORED, 0);
             mContext.getContentResolver().update(mContentUri, values,
                     Utilities.createDbSelectionQuery(
-                            LauncherSettings.Favorites._ID, restoredRows), null);
+                            Favorites._ID, mRestoredRows), null);
         }
     }
 
@@ -366,8 +444,7 @@
      * Returns true is the item is on workspace or hotseat
      */
     public boolean isOnWorkspaceOrHotseat() {
-        return container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
-                container == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+        return container == Favorites.CONTAINER_DESKTOP || container == Favorites.CONTAINER_HOTSEAT;
     }
 
     /**
@@ -381,9 +458,9 @@
     public void applyCommonProperties(ItemInfo info) {
         info.id = id;
         info.container = container;
-        info.screenId = getInt(screenIndex);
-        info.cellX = getInt(cellXIndex);
-        info.cellY = getInt(cellYIndex);
+        info.screenId = getInt(mScreenIndex);
+        info.cellX = getInt(mCellXIndex);
+        info.cellY = getInt(mCellYIndex);
     }
 
     public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) {
@@ -396,7 +473,7 @@
      */
     public void checkAndAddItem(
             ItemInfo info, BgDataModel dataModel, LoaderMemoryLogger logger) {
-        if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+        if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
             // Ensure that it is a valid intent. An exception here will
             // cause the item loading to get skipped
             ShortcutKey.fromItemInfo(info);
@@ -413,9 +490,9 @@
      */
     protected boolean checkItemPlacement(ItemInfo item) {
         int containerIndex = item.screenId;
-        if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+        if (item.container == Favorites.CONTAINER_HOTSEAT) {
             final GridOccupancy hotseatOccupancy =
-                    occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT);
+                    mOccupied.get(Favorites.CONTAINER_HOTSEAT);
 
             if (item.screenId >= mIDP.numDatabaseHotseatIcons) {
                 Log.e(TAG, "Error loading shortcut " + item
@@ -438,19 +515,18 @@
             } else {
                 final GridOccupancy occupancy = new GridOccupancy(mIDP.numDatabaseHotseatIcons, 1);
                 occupancy.cells[item.screenId][0] = true;
-                occupied.put(LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy);
+                mOccupied.put(Favorites.CONTAINER_HOTSEAT, occupancy);
                 return true;
             }
-        } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+        } else if (item.container != Favorites.CONTAINER_DESKTOP) {
             // Skip further checking if it is not the hotseat or workspace container
             return true;
         }
 
         final int countX = mIDP.numColumns;
         final int countY = mIDP.numRows;
-        if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
-                item.cellX < 0 || item.cellY < 0 ||
-                item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {
+        if (item.container == Favorites.CONTAINER_DESKTOP && item.cellX < 0 || item.cellY < 0
+                || item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {
             Log.e(TAG, "Error loading shortcut " + item
                     + " into cell (" + containerIndex + "-" + item.screenId + ":"
                     + item.cellX + "," + item.cellY
@@ -458,7 +534,7 @@
             return false;
         }
 
-        if (!occupied.containsKey(item.screenId)) {
+        if (!mOccupied.containsKey(item.screenId)) {
             GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
             if (item.screenId == Workspace.FIRST_SCREEN_ID && FeatureFlags.QSB_ON_FIRST_SCREEN) {
                 // Mark the first X columns (X is width of the search container) in the first row as
@@ -468,9 +544,9 @@
                 int spanY = 1;
                 screen.markCells(0, 0, spanX, spanY, true);
             }
-            occupied.put(item.screenId, screen);
+            mOccupied.put(item.screenId, screen);
         }
-        final GridOccupancy occupancy = occupied.get(item.screenId);
+        final GridOccupancy occupancy = mOccupied.get(item.screenId);
 
         // Check if any workspace icons overlap with each other
         if (occupancy.isRegionVacant(item.cellX, item.cellY, item.spanX, item.spanY)) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 46a6a66..da9be49 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -58,7 +58,8 @@
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.LauncherSettings.Settings;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.Folder;
@@ -198,7 +199,7 @@
         }
 
         Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
-        TimingLogger logger = new TimingLogger(TAG, "run");
+        TimingLogger timingLogger = new TimingLogger(TAG, "run");
         LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
         try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
             List<ShortcutInfo> allShortcuts = new ArrayList<>();
@@ -208,7 +209,7 @@
             } finally {
                 Trace.endSection();
             }
-            logASplit(logger, "loadWorkspace");
+            logASplit(timingLogger, "loadWorkspace");
 
             // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db.
             // sanitizeData should not be invoked if the workspace is loaded from a db different
@@ -216,22 +217,23 @@
             // (e.g. both grid preview and minimal device mode uses a different db)
             if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) {
                 verifyNotStopped();
-                sanitizeData();
-                logASplit(logger, "sanitizeData");
+                sanitizeFolders(mItemsDeleted);
+                sanitizeWidgetsShortcutsAndPackages();
+                logASplit(timingLogger, "sanitizeData");
             }
 
             verifyNotStopped();
             mLauncherBinder.bindWorkspace(true /* incrementBindId */);
-            logASplit(logger, "bindWorkspace");
+            logASplit(timingLogger, "bindWorkspace");
 
             mModelDelegate.workspaceLoadComplete();
             // Notify the installer packages of packages with active installs on the first screen.
             sendFirstScreenActiveInstallsBroadcast();
-            logASplit(logger, "sendFirstScreenActiveInstallsBroadcast");
+            logASplit(timingLogger, "sendFirstScreenActiveInstallsBroadcast");
 
             // Take a break
             waitForIdle();
-            logASplit(logger, "step 1 complete");
+            logASplit(timingLogger, "step 1 complete");
             verifyNotStopped();
 
             // second step
@@ -242,11 +244,11 @@
             } finally {
                 Trace.endSection();
             }
-            logASplit(logger, "loadAllApps");
+            logASplit(timingLogger, "loadAllApps");
 
             verifyNotStopped();
             mLauncherBinder.bindAllApps();
-            logASplit(logger, "bindAllApps");
+            logASplit(timingLogger, "bindAllApps");
 
             verifyNotStopped();
             IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
@@ -254,69 +256,69 @@
             updateHandler.updateIcons(allActivityList,
                     LauncherActivityCachingLogic.newInstance(mApp.getContext()),
                     mApp.getModel()::onPackageIconsUpdated);
-            logASplit(logger, "update icon cache");
+            logASplit(timingLogger, "update icon cache");
 
             verifyNotStopped();
-            logASplit(logger, "save shortcuts in icon cache");
+            logASplit(timingLogger, "save shortcuts in icon cache");
             updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(),
                     mApp.getModel()::onPackageIconsUpdated);
 
             // Take a break
             waitForIdle();
-            logASplit(logger, "step 2 complete");
+            logASplit(timingLogger, "step 2 complete");
             verifyNotStopped();
 
             // third step
             List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
-            logASplit(logger, "loadDeepShortcuts");
+            logASplit(timingLogger, "loadDeepShortcuts");
 
             verifyNotStopped();
             mLauncherBinder.bindDeepShortcuts();
-            logASplit(logger, "bindDeepShortcuts");
+            logASplit(timingLogger, "bindDeepShortcuts");
 
             verifyNotStopped();
-            logASplit(logger, "save deep shortcuts in icon cache");
+            logASplit(timingLogger, "save deep shortcuts in icon cache");
             updateHandler.updateIcons(allDeepShortcuts,
                     new ShortcutCachingLogic(), (pkgs, user) -> { });
 
             // Take a break
             waitForIdle();
-            logASplit(logger, "step 3 complete");
+            logASplit(timingLogger, "step 3 complete");
             verifyNotStopped();
 
             // fourth step
             List<ComponentWithLabelAndIcon> allWidgetsList =
                     mBgDataModel.widgetsModel.update(mApp, null);
-            logASplit(logger, "load widgets");
+            logASplit(timingLogger, "load widgets");
 
             verifyNotStopped();
             mLauncherBinder.bindWidgets();
-            logASplit(logger, "bindWidgets");
+            logASplit(timingLogger, "bindWidgets");
             verifyNotStopped();
 
             updateHandler.updateIcons(allWidgetsList,
                     new ComponentWithIconCachingLogic(mApp.getContext(), true),
                     mApp.getModel()::onWidgetLabelsUpdated);
-            logASplit(logger, "save widgets in icon cache");
+            logASplit(timingLogger, "save widgets in icon cache");
 
             // fifth step
             loadFolderNames();
 
             verifyNotStopped();
             updateHandler.finish();
-            logASplit(logger, "finish icon update");
+            logASplit(timingLogger, "finish icon update");
 
             mModelDelegate.modelLoadComplete();
             transaction.commit();
             memoryLogger.clearLogs();
         } catch (CancellationException e) {
             // Loader stopped, ignore
-            logASplit(logger, "Cancelled");
+            logASplit(timingLogger, "Cancelled");
         } catch (Exception e) {
             memoryLogger.printLogs();
             throw e;
         } finally {
-            logger.dumpToLog();
+            timingLogger.dumpToLog();
         }
         TraceHelper.INSTANCE.endSection(traceToken);
     }
@@ -326,9 +328,10 @@
         this.notify();
     }
 
-    private void loadWorkspace(List<ShortcutInfo> allDeepShortcuts, LoaderMemoryLogger logger) {
-        loadWorkspace(allDeepShortcuts, LauncherSettings.Favorites.CONTENT_URI,
-                null /* selection */, logger);
+    private void loadWorkspace(
+            List<ShortcutInfo> allDeepShortcuts, LoaderMemoryLogger memoryLogger) {
+        loadWorkspace(allDeepShortcuts, Favorites.CONTENT_URI,
+                null /* selection */, memoryLogger);
     }
 
     protected void loadWorkspace(
@@ -340,7 +343,7 @@
             List<ShortcutInfo> allDeepShortcuts,
             Uri contentUri,
             String selection,
-            @Nullable LoaderMemoryLogger logger) {
+            @Nullable LoaderMemoryLogger memoryLogger) {
         final Context context = mApp.getContext();
         final ContentResolver contentResolver = context.getContentResolver();
         final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
@@ -356,13 +359,11 @@
 
         if (clearDb) {
             Log.d(TAG, "loadWorkspace: resetting launcher database");
-            LauncherSettings.Settings.call(contentResolver,
-                    LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
+            Settings.call(contentResolver, Settings.METHOD_CREATE_EMPTY_DB);
         }
 
         Log.d(TAG, "loadWorkspace: loading default favorites");
-        LauncherSettings.Settings.call(contentResolver,
-                LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES);
+        Settings.call(contentResolver, Settings.METHOD_LOAD_DEFAULT_FAVORITES);
 
         synchronized (mBgDataModel) {
             mBgDataModel.clear();
@@ -380,24 +381,8 @@
                     contentResolver.query(contentUri, null, selection, null, null), contentUri,
                     mApp, mUserManagerState);
             final Bundle extras = c.getExtras();
-            mDbName = extras == null
-                    ? null : extras.getString(LauncherSettings.Settings.EXTRA_DB_NAME);
+            mDbName = extras == null ? null : extras.getString(Settings.EXTRA_DB_NAME);
             try {
-                final int appWidgetIdIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.APPWIDGET_ID);
-                final int appWidgetProviderIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.APPWIDGET_PROVIDER);
-                final int spanXIndex = c.getColumnIndexOrThrow
-                        (LauncherSettings.Favorites.SPANX);
-                final int spanYIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.SPANY);
-                final int rankIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.RANK);
-                final int optionsIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.OPTIONS);
-                final int sourceContainerIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.APPWIDGET_SOURCE);
-
                 final LongSparseArray<Boolean> unlockedUsers = new LongSparseArray<>();
 
                 mUserManagerState.init(mUserCache, mUserManager);
@@ -425,437 +410,23 @@
                     unlockedUsers.put(serialNo, userUnlocked);
                 }
 
-                WorkspaceItemInfo info;
-                LauncherAppWidgetInfo appWidgetInfo;
-                LauncherAppWidgetProviderInfo widgetProviderInfo;
-                Intent intent;
-                String targetPkg;
                 List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos = new ArrayList<>();
 
                 while (!mStopped && c.moveToNext()) {
-                    try {
-                        if (c.user == null) {
-                            // User has been deleted, remove the item.
-                            c.markDeleted("User has been deleted");
-                            continue;
-                        }
-
-                        boolean allowMissingTarget = false;
-                        switch (c.itemType) {
-                        case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                        case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
-                        case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
-                            intent = c.parseIntent();
-                            if (intent == null) {
-                                c.markDeleted("Invalid or null intent");
-                                continue;
-                            }
-
-                            int disabledState = mUserManagerState.isUserQuiet(c.serialNumber)
-                                    ? WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0;
-                            ComponentName cn = intent.getComponent();
-                            targetPkg = cn == null ? intent.getPackage() : cn.getPackageName();
-
-                            if (TextUtils.isEmpty(targetPkg) &&
-                                    c.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
-                                c.markDeleted("Only legacy shortcuts can have null package");
-                                continue;
-                            }
-
-                            // If there is no target package, its an implicit intent
-                            // (legacy shortcut) which is always valid
-                            boolean validTarget = TextUtils.isEmpty(targetPkg) ||
-                                    mLauncherApps.isPackageEnabled(targetPkg, c.user);
-
-                            // If it's a deep shortcut, we'll use pinned shortcuts to restore it
-                            if (cn != null && validTarget && c.itemType
-                                    != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                                // If the apk is present and the shortcut points to a specific
-                                // component.
-
-                                // If the component is already present
-                                if (mLauncherApps.isActivityEnabled(cn, c.user)) {
-                                    // no special handling necessary for this item
-                                    c.markRestored();
-                                } else {
-                                    // Gracefully try to find a fallback activity.
-                                    intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
-                                    if (intent != null) {
-                                        c.restoreFlag = 0;
-                                        c.updater().put(
-                                                LauncherSettings.Favorites.INTENT,
-                                                intent.toUri(0)).commit();
-                                        cn = intent.getComponent();
-                                    } else {
-                                        c.markDeleted("Unable to find a launch target");
-                                        continue;
-                                    }
-                                }
-                            }
-                            // else if cn == null => can't infer much, leave it
-                            // else if !validPkg => could be restored icon or missing sd-card
-
-                            if (!TextUtils.isEmpty(targetPkg) && !validTarget) {
-                                // Points to a valid app (superset of cn != null) but the apk
-                                // is not available.
-
-                                if (c.restoreFlag != 0) {
-                                    // Package is not yet available but might be
-                                    // installed later.
-                                    FileLog.d(TAG, "package not yet restored: " + targetPkg);
-
-                                    tempPackageKey.update(targetPkg, c.user);
-                                    if (c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED)) {
-                                        // Restore has started once.
-                                    } else if (installingPkgs.containsKey(tempPackageKey)) {
-                                        // App restore has started. Update the flag
-                                        c.restoreFlag |= WorkspaceItemInfo.FLAG_RESTORE_STARTED;
-                                        c.updater().put(LauncherSettings.Favorites.RESTORED,
-                                                c.restoreFlag).commit();
-                                    } else {
-                                        c.markDeleted("Unrestored app removed: " + targetPkg);
-                                        continue;
-                                    }
-                                } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
-                                    // Package is present but not available.
-                                    disabledState |= WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE;
-                                    // Add the icon on the workspace anyway.
-                                    allowMissingTarget = true;
-                                } else if (!isSdCardReady) {
-                                    // SdCard is not ready yet. Package might get available,
-                                    // once it is ready.
-                                    Log.d(TAG, "Missing pkg, will check later: " + targetPkg);
-                                    mPendingPackages.add(new PackageUserKey(targetPkg, c.user));
-                                    // Add the icon on the workspace anyway.
-                                    allowMissingTarget = true;
-                                } else {
-                                    // Do not wait for external media load anymore.
-                                    c.markDeleted("Invalid package removed: " + targetPkg);
-                                    continue;
-                                }
-                            }
-
-                            if ((c.restoreFlag & WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI) != 0) {
-                                validTarget = false;
-                            }
-
-                            if (validTarget) {
-                                // The shortcut points to a valid target (either no target
-                                // or something which is ready to be used)
-                                c.markRestored();
-                            }
-
-                            boolean useLowResIcon = !c.isOnWorkspaceOrHotseat();
-
-                            if (c.restoreFlag != 0) {
-                                // Already verified above that user is same as default user
-                                info = c.getRestoredItemInfo(intent);
-                            } else if (c.itemType ==
-                                    LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
-                                info = c.getAppShortcutInfo(
-                                        intent,
-                                        allowMissingTarget,
-                                        useLowResIcon,
-                                        !FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get());
-                            } else if (c.itemType ==
-                                    LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-
-                                ShortcutKey key = ShortcutKey.fromIntent(intent, c.user);
-                                if (unlockedUsers.get(c.serialNumber)) {
-                                    ShortcutInfo pinnedShortcut =
-                                            shortcutKeyToPinnedShortcuts.get(key);
-                                    if (pinnedShortcut == null) {
-                                        // The shortcut is no longer valid.
-                                        c.markDeleted("Pinned shortcut not found");
-                                        continue;
-                                    }
-                                    info = new WorkspaceItemInfo(pinnedShortcut, context);
-                                    // If the pinned deep shortcut is no longer published,
-                                    // use the last saved icon instead of the default.
-                                    mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon);
-
-                                    if (pmHelper.isAppSuspended(
-                                            pinnedShortcut.getPackage(), info.user)) {
-                                        info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
-                                    }
-                                    intent = info.getIntent();
-                                    allDeepShortcuts.add(pinnedShortcut);
-                                } else {
-                                    // Create a shortcut info in disabled mode for now.
-                                    info = c.loadSimpleWorkspaceItem();
-                                    info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
-                                }
-                            } else { // item type == ITEM_TYPE_SHORTCUT
-                                info = c.loadSimpleWorkspaceItem();
-
-                                // Shortcuts are only available on the primary profile
-                                if (!TextUtils.isEmpty(targetPkg)
-                                        && pmHelper.isAppSuspended(targetPkg, c.user)) {
-                                    disabledState |= FLAG_DISABLED_SUSPENDED;
-                                }
-                                info.options = c.getInt(optionsIndex);
-
-                                // App shortcuts that used to be automatically added to Launcher
-                                // didn't always have the correct intent flags set, so do that
-                                // here
-                                if (intent.getAction() != null &&
-                                    intent.getCategories() != null &&
-                                    intent.getAction().equals(Intent.ACTION_MAIN) &&
-                                    intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
-                                    intent.addFlags(
-                                        Intent.FLAG_ACTIVITY_NEW_TASK |
-                                        Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-                                }
-                            }
-
-                            if (info != null) {
-                                if (info.itemType
-                                        != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                                    // Skip deep shortcuts; their title and icons have already been
-                                    // loaded above.
-                                    iconRequestInfos.add(
-                                            c.createIconRequestInfo(info, useLowResIcon));
-                                }
-
-                                c.applyCommonProperties(info);
-
-                                info.intent = intent;
-                                info.rank = c.getInt(rankIndex);
-                                info.spanX = 1;
-                                info.spanY = 1;
-                                info.runtimeStatusFlags |= disabledState;
-                                if (isSafeMode && !isSystemApp(context, intent)) {
-                                    info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;
-                                }
-                                    LauncherActivityInfo activityInfo = c.getLauncherActivityInfo();
-                                    if (activityInfo != null) {
-                                        info.setProgressLevel(
-                                                PackageManagerHelper
-                                                    .getLoadingProgress(activityInfo),
-                                                PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
-                                    }
-
-                                if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
-                                    tempPackageKey.update(targetPkg, c.user);
-                                    SessionInfo si = installingPkgs.get(tempPackageKey);
-                                        if (si == null) {
-                                            info.runtimeStatusFlags &=
-                                                ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
-                                        } else if (activityInfo == null) {
-                                            int installProgress = (int) (si.getProgress() * 100);
-
-                                            info.setProgressLevel(
-                                                    installProgress,
-                                                    PackageInstallInfo.STATUS_INSTALLING);
-                                        }
-                                }
-
-                                c.checkAndAddItem(info, mBgDataModel, logger);
-                            } else {
-                                throw new RuntimeException("Unexpected null WorkspaceItemInfo");
-                            }
-                            break;
-
-                        case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
-                            FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id);
-                            c.applyCommonProperties(folderInfo);
-
-                            // Do not trim the folder label, as is was set by the user.
-                            folderInfo.title = c.getString(c.titleIndex);
-                            folderInfo.spanX = 1;
-                            folderInfo.spanY = 1;
-                            folderInfo.options = c.getInt(optionsIndex);
-
-                            // no special handling required for restored folders
-                            c.markRestored();
-
-                            c.checkAndAddItem(folderInfo, mBgDataModel, logger);
-                            break;
-
-                        case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                            if (WidgetsModel.GO_DISABLE_WIDGETS) {
-                                c.markDeleted("Only legacy shortcuts can have null package");
-                                continue;
-                            }
-                            // Follow through
-                        case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
-                            // Read all Launcher-specific widget details
-                            boolean customWidget = c.itemType ==
-                                LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
-
-                            int appWidgetId = c.getInt(appWidgetIdIndex);
-                            String savedProvider = c.getString(appWidgetProviderIndex);
-                            final ComponentName component;
-
-                            boolean isSearchWidget = (c.getInt(optionsIndex)
-                                    & LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET) != 0;
-                            if (isSearchWidget) {
-                                component  = QsbContainerView.getSearchComponentName(context);
-                                if (component == null) {
-                                    c.markDeleted("Discarding SearchWidget without packagename ");
-                                    continue;
-                                }
-                            } else {
-                                component = ComponentName.unflattenFromString(savedProvider);
-                            }
-                            final boolean isIdValid = !c.hasRestoreFlag(
-                                    LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
-                            final boolean wasProviderReady = !c.hasRestoreFlag(
-                                    LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY);
-
-                            ComponentKey providerKey = new ComponentKey(component, c.user);
-                            if (!mWidgetProvidersMap.containsKey(providerKey)) {
-                                mWidgetProvidersMap.put(providerKey,
-                                        widgetHelper.findProvider(component, c.user));
-                            }
-                            final AppWidgetProviderInfo provider =
-                                    mWidgetProvidersMap.get(providerKey);
-
-                            final boolean isProviderReady = isValidProvider(provider);
-                            if (!isSafeMode && !customWidget &&
-                                    wasProviderReady && !isProviderReady) {
-                                c.markDeleted(
-                                        "Deleting widget that isn't installed anymore: "
-                                        + provider);
-                            } else {
-                                if (isProviderReady) {
-                                    appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
-                                            provider.provider);
-
-                                    // The provider is available. So the widget is either
-                                    // available or not available. We do not need to track
-                                    // any future restore updates.
-                                    int status = c.restoreFlag &
-                                            ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED &
-                                            ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
-                                    if (!wasProviderReady) {
-                                        // If provider was not previously ready, update the
-                                        // status and UI flag.
-
-                                        // Id would be valid only if the widget restore broadcast was received.
-                                        if (isIdValid) {
-                                            status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
-                                        }
-                                    }
-                                    appWidgetInfo.restoreStatus = status;
-                                } else {
-                                    Log.v(TAG, "Widget restore pending id=" + c.id
-                                            + " appWidgetId=" + appWidgetId
-                                            + " status =" + c.restoreFlag);
-                                    appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
-                                            component);
-                                    appWidgetInfo.restoreStatus = c.restoreFlag;
-
-                                    tempPackageKey.update(component.getPackageName(), c.user);
-                                    SessionInfo si =
-                                            installingPkgs.get(tempPackageKey);
-                                    Integer installProgress = si == null
-                                            ? null
-                                            : (int) (si.getProgress() * 100);
-
-                                    if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
-                                        // Restore has started once.
-                                    } else if (installProgress != null) {
-                                        // App restore has started. Update the flag
-                                        appWidgetInfo.restoreStatus |=
-                                                LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
-                                    } else if (!isSafeMode) {
-                                        c.markDeleted("Unrestored widget removed: " + component);
-                                        continue;
-                                    }
-
-                                    appWidgetInfo.installProgress =
-                                            installProgress == null ? 0 : installProgress;
-                                }
-                                if (appWidgetInfo.hasRestoreFlag(
-                                        LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
-                                    appWidgetInfo.bindOptions = c.parseIntent();
-                                }
-
-                                c.applyCommonProperties(appWidgetInfo);
-                                appWidgetInfo.spanX = c.getInt(spanXIndex);
-                                appWidgetInfo.spanY = c.getInt(spanYIndex);
-                                appWidgetInfo.options = c.getInt(optionsIndex);
-                                appWidgetInfo.user = c.user;
-                                appWidgetInfo.sourceContainer = c.getInt(sourceContainerIndex);
-
-                                if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) {
-                                    c.markDeleted("Widget has invalid size: "
-                                            + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY);
-                                    continue;
-                                }
-                                widgetProviderInfo =
-                                        widgetHelper.getLauncherAppWidgetInfo(appWidgetId);
-                                if (widgetProviderInfo != null
-                                        && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
-                                        || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
-                                    FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent()
-                                            + " minSizes not meet: span=" + appWidgetInfo.spanX
-                                            + "x" + appWidgetInfo.spanY + " minSpan="
-                                            + widgetProviderInfo.minSpanX + "x"
-                                            + widgetProviderInfo.minSpanY);
-                                    logWidgetInfo(mApp.getInvariantDeviceProfile(),
-                                            widgetProviderInfo);
-                                }
-                                if (!c.isOnWorkspaceOrHotseat()) {
-                                    c.markDeleted("Widget found where container != " +
-                                            "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
-                                    continue;
-                                }
-
-                                if (!customWidget) {
-                                    String providerName =
-                                            appWidgetInfo.providerName.flattenToString();
-                                    if (!providerName.equals(savedProvider) ||
-                                            (appWidgetInfo.restoreStatus != c.restoreFlag)) {
-                                        c.updater()
-                                                .put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
-                                                        providerName)
-                                                .put(LauncherSettings.Favorites.RESTORED,
-                                                        appWidgetInfo.restoreStatus)
-                                                .commit();
-                                    }
-                                }
-
-                                if (appWidgetInfo.restoreStatus !=
-                                        LauncherAppWidgetInfo.RESTORE_COMPLETED) {
-                                    appWidgetInfo.pendingItemInfo = WidgetsModel.newPendingItemInfo(
-                                            mApp.getContext(),
-                                            appWidgetInfo.providerName,
-                                            appWidgetInfo.user);
-                                    mIconCache.getTitleAndIconForApp(
-                                            appWidgetInfo.pendingItemInfo, false);
-                                }
-
-                                c.checkAndAddItem(appWidgetInfo, mBgDataModel);
-                            }
-                            break;
-                        }
-                    } catch (Exception e) {
-                        Log.e(TAG, "Desktop items loading interrupted", e);
-                    }
+                    processWorkspaceItem(c, memoryLogger, installingPkgs, isSdCardReady,
+                            tempPackageKey, widgetHelper, pmHelper, shortcutKeyToPinnedShortcuts,
+                            iconRequestInfos, unlockedUsers, isSafeMode, allDeepShortcuts);
                 }
-                if (FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get()) {
-                    Trace.beginSection("LoadWorkspaceIconsInBulk");
-                    try {
-                        mIconCache.getTitlesAndIconsInBulk(iconRequestInfos);
-                        for (IconRequestInfo<WorkspaceItemInfo> iconRequestInfo :
-                                iconRequestInfos) {
-                            WorkspaceItemInfo wai = iconRequestInfo.itemInfo;
-                            if (mIconCache.isDefaultIcon(wai.bitmap, wai.user)) {
-                                iconRequestInfo.loadWorkspaceIcon(mApp.getContext());
-                            }
-                        }
-                    } finally {
-                        Trace.endSection();
-                    }
-                }
+                maybeLoadWorkspaceIconsInBulk(iconRequestInfos);
             } finally {
                 IOUtils.closeSilently(c);
             }
 
             // Load delegate items
-            mModelDelegate.loadItems(mUserManagerState, shortcutKeyToPinnedShortcuts);
+            mModelDelegate.loadHotseatItems(mUserManagerState, shortcutKeyToPinnedShortcuts);
+            mModelDelegate.loadAllAppsItems(mUserManagerState, shortcutKeyToPinnedShortcuts);
+            mModelDelegate.loadWidgetsRecommendationItems();
+            mModelDelegate.markActive();
 
             // Load string cache
             mModelDelegate.loadStringCache(mBgDataModel.stringCache);
@@ -885,7 +456,7 @@
                     info.rank = rank;
 
                     if (info.usingLowResIcon()
-                            && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+                            && info.itemType == Favorites.ITEM_TYPE_APPLICATION
                             && verifier.isItemInPreview(info.rank)) {
                         mIconCache.getTitleAndIcon(info, false);
                     }
@@ -896,6 +467,418 @@
         }
     }
 
+    private void processWorkspaceItem(LoaderCursor c,
+            LoaderMemoryLogger memoryLogger,
+            HashMap<PackageUserKey, SessionInfo> installingPkgs,
+            boolean isSdCardReady,
+            PackageUserKey tempPackageKey,
+            WidgetManagerHelper widgetHelper,
+            PackageManagerHelper pmHelper,
+            Map<ShortcutKey, ShortcutInfo> shortcutKeyToPinnedShortcuts,
+            List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos,
+            LongSparseArray<Boolean> unlockedUsers,
+            boolean isSafeMode,
+            List<ShortcutInfo> allDeepShortcuts) {
+
+        try {
+            if (c.user == null) {
+                // User has been deleted, remove the item.
+                c.markDeleted("User has been deleted");
+                return;
+            }
+
+            boolean allowMissingTarget = false;
+            switch (c.itemType) {
+                case Favorites.ITEM_TYPE_SHORTCUT:
+                case Favorites.ITEM_TYPE_APPLICATION:
+                case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
+                    Intent intent = c.parseIntent();
+                    if (intent == null) {
+                        c.markDeleted("Invalid or null intent");
+                        return;
+                    }
+
+                    int disabledState = mUserManagerState.isUserQuiet(c.serialNumber)
+                            ? WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0;
+                    ComponentName cn = intent.getComponent();
+                    String targetPkg = cn == null ? intent.getPackage() : cn.getPackageName();
+
+                    if (TextUtils.isEmpty(targetPkg)
+                            && c.itemType != Favorites.ITEM_TYPE_SHORTCUT) {
+                        c.markDeleted("Only legacy shortcuts can have null package");
+                        return;
+                    }
+
+                    // If there is no target package, it's an implicit intent
+                    // (legacy shortcut) which is always valid
+                    boolean validTarget = TextUtils.isEmpty(targetPkg)
+                            || mLauncherApps.isPackageEnabled(targetPkg, c.user);
+
+                    // If it's a deep shortcut, we'll use pinned shortcuts to restore it
+                    if (cn != null && validTarget && c.itemType
+                            != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+                        // If the apk is present and the shortcut points to a specific component.
+
+                        // If the component is already present
+                        if (mLauncherApps.isActivityEnabled(cn, c.user)) {
+                            // no special handling necessary for this item
+                            c.markRestored();
+                        } else {
+                            // Gracefully try to find a fallback activity.
+                            intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
+                            if (intent != null) {
+                                c.restoreFlag = 0;
+                                c.updater().put(
+                                        Favorites.INTENT,
+                                        intent.toUri(0)).commit();
+                                cn = intent.getComponent();
+                            } else {
+                                c.markDeleted("Unable to find a launch target");
+                                return;
+                            }
+                        }
+                    }
+                    // else if cn == null => can't infer much, leave it
+                    // else if !validPkg => could be restored icon or missing sd-card
+
+                    if (!TextUtils.isEmpty(targetPkg) && !validTarget) {
+                        // Points to a valid app (superset of cn != null) but the apk
+                        // is not available.
+
+                        if (c.restoreFlag != 0) {
+                            // Package is not yet available but might be
+                            // installed later.
+                            FileLog.d(TAG, "package not yet restored: " + targetPkg);
+
+                            tempPackageKey.update(targetPkg, c.user);
+                            if (c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED)) {
+                                // Restore has started once.
+                            } else if (installingPkgs.containsKey(tempPackageKey)) {
+                                // App restore has started. Update the flag
+                                c.restoreFlag |= WorkspaceItemInfo.FLAG_RESTORE_STARTED;
+                                c.updater().put(Favorites.RESTORED,
+                                        c.restoreFlag).commit();
+                            } else {
+                                c.markDeleted("Unrestored app removed: " + targetPkg);
+                                return;
+                            }
+                        } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
+                            // Package is present but not available.
+                            disabledState |= WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE;
+                            // Add the icon on the workspace anyway.
+                            allowMissingTarget = true;
+                        } else if (!isSdCardReady) {
+                            // SdCard is not ready yet. Package might get available,
+                            // once it is ready.
+                            Log.d(TAG, "Missing pkg, will check later: " + targetPkg);
+                            mPendingPackages.add(new PackageUserKey(targetPkg, c.user));
+                            // Add the icon on the workspace anyway.
+                            allowMissingTarget = true;
+                        } else {
+                            // Do not wait for external media load anymore.
+                            c.markDeleted("Invalid package removed: " + targetPkg);
+                            return;
+                        }
+                    }
+
+                    if ((c.restoreFlag & WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI) != 0) {
+                        validTarget = false;
+                    }
+
+                    if (validTarget) {
+                        // The shortcut points to a valid target (either no target
+                        // or something which is ready to be used)
+                        c.markRestored();
+                    }
+
+                    boolean useLowResIcon = !c.isOnWorkspaceOrHotseat();
+
+                    WorkspaceItemInfo info;
+                    if (c.restoreFlag != 0) {
+                        // Already verified above that user is same as default user
+                        info = c.getRestoredItemInfo(intent);
+                    } else if (c.itemType == Favorites.ITEM_TYPE_APPLICATION) {
+                        info = c.getAppShortcutInfo(intent, allowMissingTarget, useLowResIcon,
+                                !FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get());
+                    } else if (c.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+                        ShortcutKey key = ShortcutKey.fromIntent(intent, c.user);
+                        if (unlockedUsers.get(c.serialNumber)) {
+                            ShortcutInfo pinnedShortcut = shortcutKeyToPinnedShortcuts.get(key);
+                            if (pinnedShortcut == null) {
+                                // The shortcut is no longer valid.
+                                c.markDeleted("Pinned shortcut not found");
+                                return;
+                            }
+                            info = new WorkspaceItemInfo(pinnedShortcut, mApp.getContext());
+                            // If the pinned deep shortcut is no longer published,
+                            // use the last saved icon instead of the default.
+                            mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon);
+
+                            if (pmHelper.isAppSuspended(
+                                    pinnedShortcut.getPackage(), info.user)) {
+                                info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
+                            }
+                            intent = info.getIntent();
+                            allDeepShortcuts.add(pinnedShortcut);
+                        } else {
+                            // Create a shortcut info in disabled mode for now.
+                            info = c.loadSimpleWorkspaceItem();
+                            info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
+                        }
+                    } else { // item type == ITEM_TYPE_SHORTCUT
+                        info = c.loadSimpleWorkspaceItem();
+
+                        // Shortcuts are only available on the primary profile
+                        if (!TextUtils.isEmpty(targetPkg)
+                                && pmHelper.isAppSuspended(targetPkg, c.user)) {
+                            disabledState |= FLAG_DISABLED_SUSPENDED;
+                        }
+                        info.options = c.getOptions();
+
+                        // App shortcuts that used to be automatically added to Launcher
+                        // didn't always have the correct intent flags set, so do that here
+                        if (intent.getAction() != null
+                                && intent.getCategories() != null
+                                && intent.getAction().equals(Intent.ACTION_MAIN)
+                                && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
+                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+                        }
+                    }
+
+                    if (info != null) {
+                        if (info.itemType != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+                            // Skip deep shortcuts; their title and icons have already been
+                            // loaded above.
+                            iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon));
+                        }
+
+                        c.applyCommonProperties(info);
+
+                        info.intent = intent;
+                        info.rank = c.getRank();
+                        info.spanX = 1;
+                        info.spanY = 1;
+                        info.runtimeStatusFlags |= disabledState;
+                        if (isSafeMode && !isSystemApp(mApp.getContext(), intent)) {
+                            info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;
+                        }
+                        LauncherActivityInfo activityInfo = c.getLauncherActivityInfo();
+                        if (activityInfo != null) {
+                            info.setProgressLevel(
+                                    PackageManagerHelper.getLoadingProgress(activityInfo),
+                                    PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
+                        }
+
+                        if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
+                            tempPackageKey.update(targetPkg, c.user);
+                            SessionInfo si = installingPkgs.get(tempPackageKey);
+                            if (si == null) {
+                                info.runtimeStatusFlags
+                                        &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
+                            } else if (activityInfo == null) {
+                                int installProgress = (int) (si.getProgress() * 100);
+
+                                info.setProgressLevel(installProgress,
+                                        PackageInstallInfo.STATUS_INSTALLING);
+                            }
+                        }
+
+                        c.checkAndAddItem(info, mBgDataModel, memoryLogger);
+                    } else {
+                        throw new RuntimeException("Unexpected null WorkspaceItemInfo");
+                    }
+                    break;
+
+                case Favorites.ITEM_TYPE_FOLDER:
+                    FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id);
+                    c.applyCommonProperties(folderInfo);
+
+                    // Do not trim the folder label, as is was set by the user.
+                    folderInfo.title = c.getString(c.mTitleIndex);
+                    folderInfo.spanX = 1;
+                    folderInfo.spanY = 1;
+                    folderInfo.options = c.getOptions();
+
+                    // no special handling required for restored folders
+                    c.markRestored();
+
+                    c.checkAndAddItem(folderInfo, mBgDataModel, memoryLogger);
+                    break;
+
+                case Favorites.ITEM_TYPE_APPWIDGET:
+                    if (WidgetsModel.GO_DISABLE_WIDGETS) {
+                        c.markDeleted("Only legacy shortcuts can have null package");
+                        return;
+                    }
+                    // Follow through
+                case Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
+                    // Read all Launcher-specific widget details
+                    boolean customWidget = c.itemType
+                            == Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+
+                    int appWidgetId = c.getAppWidgetId();
+                    String savedProvider = c.getAppWidgetProvider();
+                    final ComponentName component;
+
+                    if ((c.getOptions() & LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET) != 0) {
+                        component  = QsbContainerView.getSearchComponentName(mApp.getContext());
+                        if (component == null) {
+                            c.markDeleted("Discarding SearchWidget without packagename ");
+                            return;
+                        }
+                    } else {
+                        component = ComponentName.unflattenFromString(savedProvider);
+                    }
+                    final boolean isIdValid =
+                            !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
+                    final boolean wasProviderReady =
+                            !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY);
+
+                    ComponentKey providerKey = new ComponentKey(component, c.user);
+                    if (!mWidgetProvidersMap.containsKey(providerKey)) {
+                        mWidgetProvidersMap.put(providerKey,
+                                widgetHelper.findProvider(component, c.user));
+                    }
+                    final AppWidgetProviderInfo provider = mWidgetProvidersMap.get(providerKey);
+
+                    final boolean isProviderReady = isValidProvider(provider);
+                    if (!isSafeMode && !customWidget && wasProviderReady && !isProviderReady) {
+                        c.markDeleted("Deleting widget that isn't installed anymore: " + provider);
+                    } else {
+                        LauncherAppWidgetInfo appWidgetInfo;
+                        if (isProviderReady) {
+                            appWidgetInfo =
+                                    new LauncherAppWidgetInfo(appWidgetId, provider.provider);
+
+                            // The provider is available. So the widget is either
+                            // available or not available. We do not need to track
+                            // any future restore updates.
+                            int status = c.restoreFlag
+                                    & ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
+                                    & ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
+                            if (!wasProviderReady) {
+                                // If provider was not previously ready, update status and UI flag.
+
+                                // Id would be valid only if the widget restore broadcast received.
+                                if (isIdValid) {
+                                    status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
+                                }
+                            }
+                            appWidgetInfo.restoreStatus = status;
+                        } else {
+                            Log.v(TAG, "Widget restore pending id=" + c.id
+                                    + " appWidgetId=" + appWidgetId
+                                    + " status =" + c.restoreFlag);
+                            appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, component);
+                            appWidgetInfo.restoreStatus = c.restoreFlag;
+
+                            tempPackageKey.update(component.getPackageName(), c.user);
+                            SessionInfo si = installingPkgs.get(tempPackageKey);
+                            Integer installProgress = si == null
+                                    ? null
+                                    : (int) (si.getProgress() * 100);
+
+                            if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
+                                // Restore has started once.
+                            } else if (installProgress != null) {
+                                // App restore has started. Update the flag
+                                appWidgetInfo.restoreStatus
+                                        |= LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
+                            } else if (!isSafeMode) {
+                                c.markDeleted("Unrestored widget removed: " + component);
+                                return;
+                            }
+
+                            appWidgetInfo.installProgress =
+                                    installProgress == null ? 0 : installProgress;
+                        }
+                        if (appWidgetInfo.hasRestoreFlag(
+                                LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
+                            appWidgetInfo.bindOptions = c.parseIntent();
+                        }
+
+                        c.applyCommonProperties(appWidgetInfo);
+                        appWidgetInfo.spanX = c.getSpanX();
+                        appWidgetInfo.spanY = c.getSpanY();
+                        appWidgetInfo.options = c.getOptions();
+                        appWidgetInfo.user = c.user;
+                        appWidgetInfo.sourceContainer = c.getAppWidgetSource();
+
+                        if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) {
+                            c.markDeleted("Widget has invalid size: "
+                                    + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY);
+                            return;
+                        }
+                        LauncherAppWidgetProviderInfo widgetProviderInfo =
+                                widgetHelper.getLauncherAppWidgetInfo(appWidgetId);
+                        if (widgetProviderInfo != null
+                                && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
+                                || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
+                            FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent()
+                                    + " minSizes not meet: span=" + appWidgetInfo.spanX
+                                    + "x" + appWidgetInfo.spanY + " minSpan="
+                                    + widgetProviderInfo.minSpanX + "x"
+                                    + widgetProviderInfo.minSpanY);
+                            logWidgetInfo(mApp.getInvariantDeviceProfile(),
+                                    widgetProviderInfo);
+                        }
+                        if (!c.isOnWorkspaceOrHotseat()) {
+                            c.markDeleted("Widget found where container != CONTAINER_DESKTOP"
+                                    + "nor CONTAINER_HOTSEAT - ignoring!");
+                            return;
+                        }
+
+                        if (!customWidget) {
+                            String providerName = appWidgetInfo.providerName.flattenToString();
+                            if (!providerName.equals(savedProvider)
+                                    || (appWidgetInfo.restoreStatus != c.restoreFlag)) {
+                                c.updater()
+                                        .put(Favorites.APPWIDGET_PROVIDER,
+                                                providerName)
+                                        .put(Favorites.RESTORED,
+                                                appWidgetInfo.restoreStatus)
+                                        .commit();
+                            }
+                        }
+
+                        if (appWidgetInfo.restoreStatus
+                                != LauncherAppWidgetInfo.RESTORE_COMPLETED) {
+                            appWidgetInfo.pendingItemInfo = WidgetsModel.newPendingItemInfo(
+                                    mApp.getContext(),
+                                    appWidgetInfo.providerName,
+                                    appWidgetInfo.user);
+                            mIconCache.getTitleAndIconForApp(
+                                    appWidgetInfo.pendingItemInfo, false);
+                        }
+
+                        c.checkAndAddItem(appWidgetInfo, mBgDataModel);
+                    }
+                    break;
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Desktop items loading interrupted", e);
+        }
+    }
+
+    private void maybeLoadWorkspaceIconsInBulk(
+            List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos) {
+        if (FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get()) {
+            Trace.beginSection("LoadWorkspaceIconsInBulk");
+            try {
+                mIconCache.getTitlesAndIconsInBulk(iconRequestInfos);
+                for (IconRequestInfo<WorkspaceItemInfo> iconRequestInfo : iconRequestInfos) {
+                    WorkspaceItemInfo wai = iconRequestInfo.itemInfo;
+                    if (mIconCache.isDefaultIcon(wai.bitmap, wai.user)) {
+                        iconRequestInfo.loadWorkspaceIcon(mApp.getContext());
+                    }
+                }
+            } finally {
+                Trace.endSection();
+            }
+        }
+    }
+
     private void setIgnorePackages(IconCacheUpdateHandler updateHandler) {
         // Ignore packages which have a promise icon.
         synchronized (mBgDataModel) {
@@ -917,15 +900,12 @@
         }
     }
 
-    private void sanitizeData() {
-        Context context = mApp.getContext();
-        ContentResolver contentResolver = context.getContentResolver();
-        if (mItemsDeleted) {
+    private void sanitizeFolders(boolean itemsDeleted) {
+        if (itemsDeleted) {
             // Remove any empty folder
-            int[] deletedFolderIds = LauncherSettings.Settings
-                    .call(contentResolver,
-                            LauncherSettings.Settings.METHOD_DELETE_EMPTY_FOLDERS)
-                    .getIntArray(LauncherSettings.Settings.EXTRA_VALUE);
+            int[] deletedFolderIds = Settings.call(mApp.getContext().getContentResolver(),
+                            Settings.METHOD_DELETE_EMPTY_FOLDERS)
+                    .getIntArray(Settings.EXTRA_VALUE);
             synchronized (mBgDataModel) {
                 for (int folderId : deletedFolderIds) {
                     mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId));
@@ -933,11 +913,16 @@
                     mBgDataModel.itemsIdMap.remove(folderId);
                 }
             }
-
         }
+    }
+
+    private void sanitizeWidgetsShortcutsAndPackages() {
+        Context context = mApp.getContext();
+        ContentResolver contentResolver = context.getContentResolver();
+
         // Remove any ghost widgets
-        LauncherSettings.Settings.call(contentResolver,
-                LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS);
+        Settings.call(contentResolver,
+                Settings.METHOD_REMOVE_GHOST_WIDGETS);
 
         // Update pinned state of model shortcuts
         mBgDataModel.updateShortcutPinnedState(context);
@@ -1107,10 +1092,12 @@
         FileLog.d(TAG, widgetDimension.toString());
     }
 
-    private static void logASplit(final TimingLogger logger, final String label) {
-        logger.addSplit(label);
-        if (DEBUG) {
-            Log.d(TAG, label);
+    private static void logASplit(@Nullable TimingLogger timingLogger, String label) {
+        if (timingLogger != null) {
+            timingLogger.addSplit(label);
+            if (DEBUG) {
+                Log.d(TAG, label);
+            }
         }
     }
 }
diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java
index 3bd9470..0639a6c 100644
--- a/src/com/android/launcher3/model/ModelDelegate.java
+++ b/src/com/android/launcher3/model/ModelDelegate.java
@@ -80,10 +80,29 @@
     }
 
     /**
-     * Load delegate items if any in the data model
+     * Load hot seat items if any in the data model
      */
     @WorkerThread
-    public void loadItems(UserManagerState ums, Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
+    public void loadHotseatItems(UserManagerState ums,
+            Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
+
+    /**
+     * Load all apps items if any in the data model
+     */
+    @WorkerThread
+    public void loadAllAppsItems(UserManagerState ums,
+            Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
+
+    /**
+     * Load widget recommendation items if any in the data model
+     */
+    @WorkerThread
+    public void loadWidgetsRecommendationItems() { }
+
+    /**
+     * Marks the ModelDelegate as active
+     */
+    public void markActive() { }
 
     /**
      * Load String cache
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 9a745ab..c23ea8a 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -21,6 +21,7 @@
 import static com.android.launcher3.anim.Interpolators.ACCELERATED_EASE;
 import static com.android.launcher3.anim.Interpolators.DECELERATED_EASE;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -116,7 +117,7 @@
 
     private final String mIterateChildrenTag;
 
-    private final int[] mColorIds;
+    protected final int[] mColorIds;
 
     public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
@@ -125,8 +126,8 @@
         mActivityContext = ActivityContext.lookupContext(context);
         mIsRtl = Utilities.isRtl(getResources());
 
-        int backgroundColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
-        mArrowColor = backgroundColor;
+        int popupPrimaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
+        mArrowColor = popupPrimaryColor;
         mElevation = getResources().getDimension(R.dimen.deep_shortcuts_elevation);
 
         // Initialize arrow view
@@ -143,18 +144,18 @@
 
         int smallerRadius = resources.getDimensionPixelSize(R.dimen.popup_smaller_radius);
         mRoundedTop = new GradientDrawable();
-        mRoundedTop.setColor(backgroundColor);
+        mRoundedTop.setColor(popupPrimaryColor);
         mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius,
                 mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius});
 
         mRoundedBottom = new GradientDrawable();
-        mRoundedBottom.setColor(backgroundColor);
+        mRoundedBottom.setColor(popupPrimaryColor);
         mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius,
                 smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius});
 
         mIterateChildrenTag = getContext().getString(R.string.popup_container_iterate_children);
 
-        if (mActivityContext.shouldUseColorExtractionForPopup()) {
+        if (!ENABLE_MATERIAL_U_POPUP.get() && mActivityContext.canUseMultipleShadesForPopup()) {
             mColorIds = new int[]{R.color.popup_shade_first, R.color.popup_shade_second,
                     R.color.popup_shade_third};
         } else {
@@ -241,15 +242,23 @@
                 mlp.bottomMargin = 0;
 
                 if (colors != null) {
-                    backgroundColor = colors[numVisibleChild % colors.length];
+                    if (!ENABLE_MATERIAL_U_POPUP.get()) {
+                        backgroundColor = colors[numVisibleChild % colors.length];
+                    }
+
+                    if (ENABLE_MATERIAL_U_POPUP.get() && isShortcutContainer(view)) {
+                        setChildColor(view, colors[0], colorAnimator);
+                        mArrowColor = colors[0];
+                    }
                 }
 
                 // Arrow color matches the first child or the last child.
-                if (mIsAboveIcon || (numVisibleChild == 0 && viewGroup == this)) {
+                if (!ENABLE_MATERIAL_U_POPUP.get()
+                        && (mIsAboveIcon || (numVisibleChild == 0 && viewGroup == this))) {
                     mArrowColor = backgroundColor;
                 }
 
-                if (view instanceof ViewGroup && mIterateChildrenTag.equals(view.getTag())) {
+                if (view instanceof ViewGroup && isShortcutContainer(view)) {
                     assignMarginsAndBackgrounds((ViewGroup) view, backgroundColor);
                     numVisibleChild++;
                     continue;
@@ -287,6 +296,13 @@
     }
 
     /**
+     * Returns {@code true} if view is a layout container of shortcuts
+     */
+    boolean isShortcutContainer(View view) {
+        return mIterateChildrenTag.equals(view.getTag());
+    }
+
+    /**
      * Sets the background color of the child.
      */
     protected void setChildColor(View view, int color, AnimatorSet animatorSetOut) {
@@ -308,7 +324,7 @@
      */
     protected void reorderAndShow(int viewsToFlip) {
         setupForDisplay();
-        boolean reverseOrder = mIsAboveIcon;
+        boolean reverseOrder = !ENABLE_MATERIAL_U_POPUP.get() && mIsAboveIcon;
         if (reverseOrder) {
             reverseOrder(viewsToFlip);
         }
@@ -634,7 +650,7 @@
         for (int i = group.getChildCount() - 1; i >= 0; --i) {
             View view = group.getChildAt(i);
             if (view.getVisibility() == VISIBLE && view instanceof ViewGroup) {
-                if (mIterateChildrenTag.equals(view.getTag())) {
+                if (isShortcutContainer(view)) {
                     fadeInChildViews((ViewGroup) view, alphaValues, startDelay, duration, out);
                     continue;
                 }
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 4da588e..8fef5c6 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -17,12 +17,16 @@
 package com.android.launcher3.popup;
 
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
+import static com.android.launcher3.Utilities.ATLEAST_P;
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.Utilities.squaredTouchSlop;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
 import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
 import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
+import static java.util.Collections.emptyList;
+
 import android.animation.AnimatorSet;
 import android.animation.LayoutTransition;
 import android.annotation.TargetApi;
@@ -39,6 +43,8 @@
 import android.view.ViewGroup;
 import android.widget.ImageView;
 
+import androidx.annotation.LayoutRes;
+
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.BubbleTextView;
@@ -82,20 +88,20 @@
 public class PopupContainerWithArrow<T extends Context & ActivityContext>
         extends ArrowPopup<T> implements DragSource, DragController.DragListener {
 
-    private final List<DeepShortcutView> mShortcuts = new ArrayList<>();
+    private final List<DeepShortcutView> mDeepShortcuts = new ArrayList<>();
     private final PointF mInterceptTouchDown = new PointF();
 
     private final int mStartDragThreshold;
 
+    private static final int SHORTCUT_COLLAPSE_THRESHOLD = 6;
+
     private BubbleTextView mOriginalIcon;
     private int mNumNotifications;
     private NotificationContainer mNotificationContainer;
     private int mContainerWidth;
 
     private ViewGroup mWidgetContainer;
-
     private ViewGroup mDeepShortcutContainer;
-
     private ViewGroup mSystemShortcutContainer;
 
     protected PopupItemDragHandler mPopupItemDragHandler;
@@ -211,19 +217,27 @@
             return null;
         }
 
-        final PopupContainerWithArrow<Launcher> container =
-                (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
-                        R.layout.popup_container, launcher.getDragLayer(), false);
-        container.configureForLauncher(launcher);
-
+        PopupContainerWithArrow<Launcher> container;
         PopupDataProvider popupDataProvider = launcher.getPopupDataProvider();
-        container.populateAndShow(icon,
-                popupDataProvider.getShortcutCountForItem(item),
-                popupDataProvider.getNotificationKeysForItem(item),
-                launcher.getSupportedShortcuts()
-                        .map(s -> s.getShortcut(launcher, item, icon))
-                        .filter(Objects::nonNull)
-                        .collect(Collectors.toList()));
+        int deepShortcutCount = popupDataProvider.getShortcutCountForItem(item);
+        List<SystemShortcut> systemShortcuts = launcher.getSupportedShortcuts()
+                .map(s -> s.getShortcut(launcher, item, icon))
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+        if (ENABLE_MATERIAL_U_POPUP.get()) {
+            container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
+                    R.layout.popup_container_material_u, launcher.getDragLayer(), false);
+            container.populateAndShowRowsMaterialU(icon, deepShortcutCount, systemShortcuts);
+        } else {
+            container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
+                    R.layout.popup_container, launcher.getDragLayer(), false);
+            container.populateAndShow(
+                    icon,
+                    deepShortcutCount,
+                    popupDataProvider.getNotificationKeysForItem(item),
+                    systemShortcuts);
+        }
+        container.configureForLauncher(launcher);
         launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
         container.requestFocus();
         return container;
@@ -246,7 +260,7 @@
             initializeSystemShortcut(R.layout.system_shortcut, this, shortcuts.get(0));
             return;
         }
-        mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this);
+        mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons_container, this);
         for (SystemShortcut shortcut : shortcuts) {
             initializeSystemShortcut(
                     R.layout.system_shortcut_icon_only, mSystemShortcutContainer,
@@ -281,17 +295,7 @@
             mDeepShortcutContainer = findViewById(R.id.deep_shortcuts_container);
         }
         if (hasDeepShortcuts) {
-            // Remove the widget shortcut fom the list
-            List<SystemShortcut> systemShortcuts = shortcuts
-                    .stream()
-                    .filter(shortcut -> !(shortcut instanceof SystemShortcut.Widgets))
-                    .collect(Collectors.toList());
-            Optional<SystemShortcut.Widgets> widgetShortcutOpt = shortcuts
-                    .stream()
-                    .filter(shortcut -> shortcut instanceof SystemShortcut.Widgets)
-                    .map(SystemShortcut.Widgets.class::cast)
-                    .findFirst();
-
+            List<SystemShortcut> systemShortcuts = getNonWidgetSystemShortcuts(shortcuts);
             // if there are deep shortcuts, we might want to increase the width of shortcuts to fit
             // horizontally laid out system shortcuts.
             mContainerWidth = Math.max(mContainerWidth,
@@ -304,10 +308,10 @@
             for (int i = shortcutCount; i > 0; i--) {
                 DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut, mDeepShortcutContainer);
                 v.getLayoutParams().width = mContainerWidth;
-                mShortcuts.add(v);
+                mDeepShortcuts.add(v);
             }
             updateHiddenShortcuts();
-
+            Optional<SystemShortcut.Widgets> widgetShortcutOpt = getWidgetShortcut(shortcuts);
             if (widgetShortcutOpt.isPresent()) {
                 if (mWidgetContainer == null) {
                     mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container,
@@ -327,21 +331,151 @@
         }
 
         reorderAndShow(viewsToFlip);
+        showPopupContainer((ItemInfo) originalIcon.getTag(), notificationKeys);
+    }
 
-        ItemInfo originalItemInfo = (ItemInfo) originalIcon.getTag();
-        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-            setAccessibilityPaneTitle(getTitleForAccessibility());
+    /**
+     * Populate and show shortcuts for the Launcher U app shortcut design.
+     * Will inflate the container and shortcut View instances for the popup container.
+     * @param originalIcon App icon that the popup is shown for
+     * @param deepShortcutCount Number of DeepShortcutView instances to add to container
+     * @param systemShortcuts List of SystemShortcuts to add to container
+     */
+    public void populateAndShowRowsMaterialU(final BubbleTextView originalIcon,
+            int deepShortcutCount, List<SystemShortcut> systemShortcuts) {
+
+        mOriginalIcon = originalIcon;
+        mContainerWidth = getResources().getDimensionPixelSize(R.dimen.bg_popup_item_width);
+
+        if (deepShortcutCount > 0) {
+            addAllShortcutsMaterialU(deepShortcutCount, systemShortcuts);
+        } else if (!systemShortcuts.isEmpty()) {
+            addSystemShortcutsMaterialU(systemShortcuts,
+                    R.layout.system_shortcut_rows_container_material_u,
+                    R.layout.system_shortcut);
         }
 
-        mOriginalIcon.setForceHideDot(true);
+        // no reversing needed for U design
+        reorderAndShow(0);
+        showPopupContainer((ItemInfo) originalIcon.getTag(), /* notificationKeys= */ emptyList());
+    }
 
+    /**
+     * Animates and loads shortcuts on background thread for this popup container
+     */
+    private void showPopupContainer(ItemInfo originalItemInfo,
+            List<NotificationKeyData> notificationKeys) {
+
+        if (ATLEAST_P) {
+            setAccessibilityPaneTitle(getTitleForAccessibility());
+        }
+        mOriginalIcon.setForceHideDot(true);
         // All views are added. Animate layout from now on.
         setLayoutTransition(new LayoutTransition());
-
         // Load the shortcuts on a background thread and update the container as it animates.
         MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(PopupPopulator.createUpdateRunnable(
                 mActivityContext, originalItemInfo, new Handler(Looper.getMainLooper()),
-                this, mShortcuts, notificationKeys));
+                this, mDeepShortcuts, notificationKeys));
+    }
+
+    /**
+     * Adds any Deep Shortcuts, System Shortcuts and the Widget Shortcut to their respective
+     * containers
+     * @param deepShortcutCount number of DeepShortcutView instances
+     * @param systemShortcuts List of SystemShortcuts
+     */
+    private void addAllShortcutsMaterialU(int deepShortcutCount,
+            List<SystemShortcut> systemShortcuts) {
+
+        if (deepShortcutCount + systemShortcuts.size() <= SHORTCUT_COLLAPSE_THRESHOLD) {
+            // add all system shortcuts including widgets shortcut to same container
+            addSystemShortcutsMaterialU(systemShortcuts,
+                    R.layout.system_shortcut_rows_container_material_u,
+                    R.layout.system_shortcut);
+            addDeepShortcutsMaterialU(deepShortcutCount);
+            return;
+        }
+
+        List<SystemShortcut> nonWidgetSystemShortcuts =
+                getNonWidgetSystemShortcuts(systemShortcuts);
+        // If total shortcuts over threshold, collapse system shortcuts to single row
+        addSystemShortcutsMaterialU(nonWidgetSystemShortcuts,
+                R.layout.system_shortcut_icons_container_material_u,
+                R.layout.system_shortcut_icon_only);
+        // May need to recalculate row width
+        mContainerWidth = Math.max(mContainerWidth,
+                nonWidgetSystemShortcuts.size() * getResources()
+                        .getDimensionPixelSize(R.dimen.system_shortcut_header_icon_touch_size));
+        // Add widget shortcut to separate container
+        Optional<SystemShortcut.Widgets> widgetShortcutOpt = getWidgetShortcut(systemShortcuts);
+        if (widgetShortcutOpt.isPresent()) {
+            mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container_material_u,
+                    this);
+            initializeWidgetShortcut(mWidgetContainer, widgetShortcutOpt.get());
+        }
+        addDeepShortcutsMaterialU(deepShortcutCount);
+    }
+
+    /**
+     * Finds the first instance of the Widgets Shortcut from the SystemShortcut List
+     * @param systemShortcuts List of SystemShortcut instances to search
+     * @return Optional Widgets SystemShortcut
+     */
+    private static Optional<SystemShortcut.Widgets> getWidgetShortcut(
+            List<SystemShortcut> systemShortcuts) {
+        return systemShortcuts
+                .stream()
+                .filter(shortcut -> shortcut instanceof SystemShortcut.Widgets)
+                .map(SystemShortcut.Widgets.class::cast)
+                .findFirst();
+    }
+
+    /**
+     * Returns list of [systemShortcuts] without the Widgets shortcut instance if found
+     * @param systemShortcuts list of SystemShortcuts to filter from
+     * @return systemShortcuts without the Widgets Shortcut
+     */
+    private static List<SystemShortcut> getNonWidgetSystemShortcuts(
+            List<SystemShortcut> systemShortcuts) {
+
+        return systemShortcuts
+                .stream()
+                .filter(shortcut -> !(shortcut instanceof SystemShortcut.Widgets))
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Inflates the given systemShortcutContainerLayout as a container, and populates with
+     * the systemShortcuts as views using the systemShortcutLayout
+     * @param systemShortcuts List of SystemShortcut to inflate as Views
+     * @param systemShortcutContainerLayout Layout Resource for the Container of shortcut Views
+     * @param systemShortcutLayout Layout Resource for the individual shortcut Views
+     */
+    private void addSystemShortcutsMaterialU(List<SystemShortcut> systemShortcuts,
+            @LayoutRes int systemShortcutContainerLayout, @LayoutRes int systemShortcutLayout) {
+
+        if (systemShortcuts.size() == 0) {
+            return;
+        }
+        mSystemShortcutContainer = inflateAndAdd(systemShortcutContainerLayout, this);
+        for (SystemShortcut shortcut : systemShortcuts) {
+            initializeSystemShortcut(systemShortcutLayout, mSystemShortcutContainer, shortcut);
+        }
+    }
+
+    /**
+     * Inflates and adds [deepShortcutCount] number of DeepShortcutView for the  to a new container
+     * @param deepShortcutCount number of DeepShortcutView instances to add
+     */
+    private void addDeepShortcutsMaterialU(int deepShortcutCount) {
+        mDeepShortcutContainer = inflateAndAdd(R.layout.deep_shortcut_container, this);
+        for (int i = deepShortcutCount; i > 0; i--) {
+            DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut_material_u,
+                    mDeepShortcutContainer);
+            v.getLayoutParams().width = mContainerWidth;
+            mDeepShortcuts.add(v);
+        }
+        updateHiddenShortcuts();
     }
 
     protected NotificationContainer getNotificationContainer() {
@@ -391,9 +525,9 @@
         int allowedCount = mNotificationContainer != null
                 ? MAX_SHORTCUTS_IF_NOTIFICATIONS : MAX_SHORTCUTS;
 
-        int total = mShortcuts.size();
+        int total = mDeepShortcuts.size();
         for (int i = 0; i < total; i++) {
-            DeepShortcutView view = mShortcuts.get(i);
+            DeepShortcutView view = mDeepShortcuts.get(i);
             view.setVisibility(i >= allowedCount ? GONE : VISIBLE);
         }
     }
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index 69c96ff..44e3dd6 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -242,7 +242,7 @@
     public WidgetsListContentEntry getSelectedAppWidgets(PackageUserKey packageUserKey) {
         return (WidgetsListContentEntry) mAllWidgets.stream()
                 .filter(row -> row instanceof WidgetsListContentEntry
-                        && row.mPkgItem.packageName.equals(packageUserKey.mPackageName))
+                        && PackageUserKey.fromPackageItemInfo(row.mPkgItem).equals(packageUserKey))
                 .findAny()
                 .orElse(null);
     }
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
index c8455b8..2ffe34f 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
@@ -18,6 +18,7 @@
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.makeMeasureSpec;
 
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
 import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
 
 import android.content.Context;
@@ -203,14 +204,22 @@
             systemShortcuts.add(mPinnedAppsAdapter.getSystemShortcut(item, v));
         }
         systemShortcuts.add(APP_INFO.getShortcut(mActivity, item, v));
-
-        final PopupContainerWithArrow container =
-                (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
-                        R.layout.popup_container, mActivity.getDragLayer(), false);
-
-        container.populateAndShow((BubbleTextView) v,
-                popupDataProvider.getShortcutCountForItem(item),
-                Collections.emptyList(), systemShortcuts);
+        int deepShortcutCount = popupDataProvider.getShortcutCountForItem(item);
+        final PopupContainerWithArrow<SecondaryDisplayLauncher> container;
+        if (ENABLE_MATERIAL_U_POPUP.get()) {
+            container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
+                    R.layout.popup_container_material_u, mActivity.getDragLayer(), false);
+            container.populateAndShowRowsMaterialU((BubbleTextView) v, deepShortcutCount,
+                    systemShortcuts);
+        } else {
+            container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
+                    R.layout.popup_container, mActivity.getDragLayer(), false);
+            container.populateAndShow(
+                    (BubbleTextView) v,
+                    deepShortcutCount,
+                    Collections.emptyList(),
+                    systemShortcuts);
+        }
         container.requestFocus();
 
         if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index d31a646..0b756b6 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -208,6 +208,11 @@
                 );
             }
 
+            case TestProtocol.REQUEST_WORKSPACE_CURRENT_PAGE_INDEX: {
+                return getLauncherUIProperty(Bundle::putInt,
+                        launcher -> launcher.getWorkspace().getCurrentPage());
+            }
+
             case TestProtocol.REQUEST_HOTSEAT_CELL_CENTER: {
                 final HotseatCellCenterRequest request = extra.getParcelable(
                         TestProtocol.TEST_INFO_REQUEST_FIELD);
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 2ab4601..f7837f5 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -199,9 +199,9 @@
     }
 
     /**
-     * Returns {@code true} if popups should use color extraction.
+     * Returns {@code true} if popups can use a range of color shades instead of a singular color.
      */
-    default boolean shouldUseColorExtractionForPopup() {
+    default boolean canUseMultipleShadesForPopup() {
         return true;
     }
 
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 5b57e22..315cbad 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -15,12 +15,16 @@
  */
 package com.android.launcher3.views;
 
+import static androidx.core.content.ContextCompat.getColorStateList;
+
+import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS;
 
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
@@ -31,6 +35,7 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnLongClickListener;
+import android.view.ViewGroup;
 import android.widget.Toast;
 
 import androidx.annotation.Nullable;
@@ -139,6 +144,16 @@
         mTargetRect.roundOut(outPos);
     }
 
+    @Override
+    public void assignMarginsAndBackgrounds(ViewGroup viewGroup) {
+        if (ENABLE_MATERIAL_U_POPUP.get()) {
+            assignMarginsAndBackgrounds(viewGroup,
+                    getColorStateList(getContext(), mColorIds[0]).getDefaultColor());
+        } else {
+            assignMarginsAndBackgrounds(viewGroup, Color.TRANSPARENT);
+        }
+    }
+
     public static OptionsPopupView show(ActivityContext launcher, RectF targetRect,
             List<OptionItem> items, boolean shouldAddArrow) {
         return show(launcher, targetRect, items, shouldAddArrow, 0 /* width */);
diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
index d7235ad..bea7517 100644
--- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java
+++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
@@ -55,10 +55,10 @@
 public class LauncherWidgetHolder {
     public static final int APPWIDGET_HOST_ID = 1024;
 
-    private static final int FLAG_LISTENING = 1;
-    private static final int FLAG_STATE_IS_NORMAL = 1 << 1;
-    private static final int FLAG_ACTIVITY_STARTED = 1 << 2;
-    private static final int FLAG_ACTIVITY_RESUMED = 1 << 3;
+    protected static final int FLAG_LISTENING = 1;
+    protected static final int FLAG_STATE_IS_NORMAL = 1 << 1;
+    protected static final int FLAG_ACTIVITY_STARTED = 1 << 2;
+    protected static final int FLAG_ACTIVITY_RESUMED = 1 << 3;
     private static final int FLAGS_SHOULD_LISTEN =
             FLAG_STATE_IS_NORMAL | FLAG_ACTIVITY_STARTED | FLAG_ACTIVITY_RESUMED;
 
@@ -77,7 +77,7 @@
     @NonNull
     private final SparseArray<RemoteViews> mCachedRemoteViews = new SparseArray<>();
 
-    private int mFlags = FLAG_STATE_IS_NORMAL;
+    protected int mFlags = FLAG_STATE_IS_NORMAL;
 
     // TODO(b/191735836): Replace with ActivityOptions.KEY_SPLASH_SCREEN_STYLE when un-hidden
     private static final String KEY_SPLASH_SCREEN_STYLE = "android.activity.splashScreenStyle";
@@ -115,6 +115,13 @@
             // widgets upon bind anyway. See issue 14255011 for more context.
         }
 
+        updateDeferredView();
+    }
+
+    /**
+     * Update any views which have been deferred because the host was not listening.
+     */
+    protected void updateDeferredView() {
         // We go in reverse order and inflate any deferred or cached widget
         for (int i = mViews.size() - 1; i >= 0; i--) {
             LauncherAppWidgetHostView view = mViews.valueAt(i);
@@ -464,7 +471,7 @@
         }
 
         final boolean listening = isListening();
-        if (!listening && (mFlags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN) {
+        if (!listening && shouldListen(mFlags)) {
             // Postpone starting listening until all flags are on.
             startListening();
         } else if (listening && (mFlags & FLAG_ACTIVITY_STARTED) == 0) {
@@ -474,6 +481,14 @@
     }
 
     /**
+     * Returns true if the holder should be listening for widget updates based
+     * on the provided state flags.
+     */
+    protected boolean shouldListen(int flags) {
+        return (flags & FLAGS_SHOULD_LISTEN) == FLAGS_SHOULD_LISTEN;
+    }
+
+    /**
      * Returns the new LauncherWidgetHolder instance
      */
     public static LauncherWidgetHolder newInstance(Context context) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderHolder.java b/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderHolder.java
deleted file mode 100644
index 9562af3..0000000
--- a/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderHolder.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.widget.picker;
-
-import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-
-/**
- * A {@link ViewHolder} for {@link WidgetsListHeader} of an app, which renders the app icon, the app
- * name, label and a button for showing / hiding widgets.
- */
-public final class WidgetsListSearchHeaderHolder extends ViewHolder {
-    final WidgetsListHeader mWidgetsListHeader;
-
-    public WidgetsListSearchHeaderHolder(WidgetsListHeader view) {
-        super(view);
-
-        mWidgetsListHeader = view;
-    }
-}
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 11363a2..65873f1 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -126,6 +126,9 @@
     public static final String REQUEST_WORKSPACE_CELL_CENTER = "workspace-cell-center";
     public static final String REQUEST_WORKSPACE_COLUMNS_ROWS = "workspace-columns-rows";
 
+    public static final String REQUEST_WORKSPACE_CURRENT_PAGE_INDEX =
+            "workspace-current-page-index";
+
     public static final String REQUEST_HOTSEAT_CELL_CENTER = "hotseat-cell-center";
 
     public static final String REQUEST_GET_FOCUSED_TASK_HEIGHT_FOR_TABLET =
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index dcc669b..0fe8bee 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -93,6 +93,24 @@
                     gesturePx = 0,
                     cutoutPx = 0
                 ),
+            "twopanel-phone" to
+                DeviceSpec(
+                    Pair(1080, 2092),
+                    densityDpi = 420,
+                    statusBarNaturalPx = 133,
+                    statusBarRotatedPx = 110,
+                    gesturePx = 63,
+                    cutoutPx = 133
+                ),
+            "twopanel-tablet" to
+                DeviceSpec(
+                    Pair(2208, 1840),
+                    densityDpi = 420,
+                    statusBarNaturalPx = 110,
+                    statusBarRotatedPx = 133,
+                    gesturePx = 0,
+                    cutoutPx = 0
+                )
         )
 
     protected fun initializeVarsForPhone(
diff --git a/tests/src/com/android/launcher3/LauncherPrefsTest.kt b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
index 31e8d30..d40a7bc 100644
--- a/tests/src/com/android/launcher3/LauncherPrefsTest.kt
+++ b/tests/src/com/android/launcher3/LauncherPrefsTest.kt
@@ -13,7 +13,7 @@
 private val TEST_BOOLEAN_ITEM = LauncherPrefs.nonRestorableItem("1", false)
 private val TEST_STRING_ITEM = LauncherPrefs.nonRestorableItem("2", "( ͡❛ ͜ʖ ͡❛)")
 private val TEST_INT_ITEM = LauncherPrefs.nonRestorableItem("3", -1)
-private val TEST_CONTEXTUAL_ITEM = LauncherPrefs.backedUpItem("4") { true }
+private val TEST_CONTEXTUAL_ITEM = ContextualItem("4", true, { true }, Boolean::class.java)
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
index 3443fd9..77fca96 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
@@ -114,6 +114,10 @@
                 new FavoriteItemsTransaction(mTargetContext, this);
         transaction = buildWorkspaceFromBoards(testCase.mStart, transaction);
         transaction.commit();
+        // resetLoaderState triggers the launcher to start loading the workspace which allows
+        // waitForLauncherCondition to wait for that condition, otherwise the condition would
+        // always be true and it wouldn't wait for the changes to be applied.
+        resetLoaderState();
         waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading());
         Widget widget = mLauncher.getWorkspace().getWidgetAtCell(mainWidgetCellPos.getCellX(),
                 mainWidgetCellPos.getCellY());
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index 6444ef6..7ab86ad 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -18,6 +18,9 @@
 
 import static androidx.test.InstrumentationRegistry.getContext;
 
+import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_ID;
+import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_PROVIDER;
+import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_SOURCE;
 import static com.android.launcher3.LauncherSettings.Favorites.CELLX;
 import static com.android.launcher3.LauncherSettings.Favorites.CELLY;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER;
@@ -30,9 +33,13 @@
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.OPTIONS;
 import static com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID;
+import static com.android.launcher3.LauncherSettings.Favorites.RANK;
 import static com.android.launcher3.LauncherSettings.Favorites.RESTORED;
 import static com.android.launcher3.LauncherSettings.Favorites.SCREEN;
+import static com.android.launcher3.LauncherSettings.Favorites.SPANX;
+import static com.android.launcher3.LauncherSettings.Favorites.SPANY;
 import static com.android.launcher3.LauncherSettings.Favorites.TITLE;
 import static com.android.launcher3.LauncherSettings.Favorites._ID;
 import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY;
@@ -92,7 +99,9 @@
         mCursor = new MatrixCursor(new String[] {
                 ICON, ICON_PACKAGE, ICON_RESOURCE, TITLE,
                 _ID, CONTAINER, ITEM_TYPE, PROFILE_ID,
-                SCREEN, CELLX, CELLY, RESTORED, INTENT
+                SCREEN, CELLX, CELLY, RESTORED, INTENT,
+                APPWIDGET_ID, APPWIDGET_PROVIDER, SPANX,
+                SPANY, RANK, OPTIONS, APPWIDGET_SOURCE
         });
 
         UserManagerState ums = new UserManagerState();
diff --git a/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
new file mode 100644
index 0000000..d981267
--- /dev/null
+++ b/tests/src/com/android/launcher3/nonquickstep/DeviceProfileDumpTest.kt
@@ -0,0 +1,1626 @@
+/*
+ * 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.nonquickstep
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.AbstractDeviceProfileTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.InvariantDeviceProfile
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests for DeviceProfile. */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceProfileDumpTest : AbstractDeviceProfileTest() {
+
+    @Test
+    fun phonePortrait3Button() {
+        initializeVarsForPhone(deviceSpecs["phone"]!!, isGestureMode = false)
+        val dp = getDeviceProfileForGrid("5_by_5")
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.625 px\n" +
+                    "\tisTablet:false\n" +
+                    "\tisPhone:true\n" +
+                    "\ttransposeLayoutWithOrientation:true\n" +
+                    "\tisGestureMode:false\n" +
+                    "\tisLandscape:false\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:false\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 1080.0px (411.42856dp)\n" +
+                    "\theightPx: 2400.0px (914.2857dp)\n" +
+                    "\tavailableWidthPx: 1080.0px (411.42856dp)\n" +
+                    "\tavailableHeightPx: 2156.0px (821.3333dp)\n" +
+                    "\tmInsets.left: 0.0px (0.0dp)\n" +
+                    "\tmInsets.top: 118.0px (44.95238dp)\n" +
+                    "\tmInsets.right: 0.0px (0.0dp)\n" +
+                    "\tmInsets.bottom: 126.0px (48.0dp)\n" +
+                    "\taspectRatio:2.2222223\n" +
+                    "\tisScalableGrid:false\n" +
+                    "\tinv.numRows: 5\n" +
+                    "\tinv.numColumns: 5\n" +
+                    "\tinv.numSearchContainerColumns: 5\n" +
+                    "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+                    "\tcellWidthPx: 165.0px (62.857143dp)\n" +
+                    "\tcellHeightPx: 235.0px (89.52381dp)\n" +
+                    "\tgetCellSize().x: 207.0px (78.85714dp)\n" +
+                    "\tgetCellSize().y: 379.0px (144.38095dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 21.0px (8.0dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 28.0px (10.666667dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 21.0px (8.0dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 28.0px (10.666667dp)\n" +
+                    "\ticonSizePx: 147.0px (56.0dp)\n" +
+                    "\ticonTextSizePx: 38.0px (14.476191dp)\n" +
+                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tfolderCellWidthPx: 195.0px (74.28571dp)\n" +
+                    "\tfolderCellHeightPx: 230.0px (87.61905dp)\n" +
+                    "\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
+                    "\tfolderChildTextSizePx: 38.0px (14.476191dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+                    "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+                    "\tbottomSheetTopPadding: 146.0px (55.61905dp)\n" +
+                    "\tbottomSheetOpenDuration: 267\n" +
+                    "\tbottomSheetCloseDuration: 267\n" +
+                    "\tbottomSheetWorkspaceScale: 1.0\n" +
+                    "\tbottomSheetDepth: 0.0\n" +
+                    "\tallAppsShiftRange: 788.0px (300.1905dp)\n" +
+                    "\tallAppsTopPadding: 0.0px (0.0dp)\n" +
+                    "\tallAppsOpenDuration: 600\n" +
+                    "\tallAppsCloseDuration: 300\n" +
+                    "\tallAppsIconSizePx: 147.0px (56.0dp)\n" +
+                    "\tallAppsIconTextSizePx: 38.0px (14.476191dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+                    "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+                    "\tallAppsCellWidthPx: 189.0px (72.0dp)\n" +
+                    "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 5\n" +
+                    "\tallAppsLeftRightPadding: 21.0px (8.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSizePx: 294.0px (112.0dp)\n" +
+                    "\tinv.hotseatColumnSpan: 5\n" +
+                    "\thotseatCellHeightPx: 166.0px (63.238094dp)\n" +
+                    "\thotseatBarBottomSpacePx: 147.0px (56.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 200.0px (76.190475dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 128.0px (48.761906dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 21.0px (8.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 21.0px (8.0dp)\n" +
+                    "\tnumShownHotseatIcons: 5\n" +
+                    "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:false\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.left: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.right: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.bottom: 203.0px (77.333336dp)\n" +
+                    "\ticonScale: 1.0px (0.3809524dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+                    "\textraSpace: 722.0px (275.0476dp)\n" +
+                    "\tunscaled extraSpace: 722.0px (275.0476dp)\n" +
+                    "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+                    "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+                    "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 126.0px (48.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 84.0px (32.0dp)\n" +
+                    "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 391.0px (148.95238dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 1906.0px (726.0952dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.77572966px (0.29551607dp)\n" +
+                    "\tgetCellLayoutHeight(): 1953.0px (744.0dp)\n" +
+                    "\tgetCellLayoutWidth(): 1080.0px (411.42856dp)\n"
+            )
+    }
+
+    @Test
+    fun phonePortrait() {
+        initializeVarsForPhone(deviceSpecs["phone"]!!)
+        val dp = getDeviceProfileForGrid("5_by_5")
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.625 px\n" +
+                    "\tisTablet:false\n" +
+                    "\tisPhone:true\n" +
+                    "\ttransposeLayoutWithOrientation:true\n" +
+                    "\tisGestureMode:true\n" +
+                    "\tisLandscape:false\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:false\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 1080.0px (411.42856dp)\n" +
+                    "\theightPx: 2400.0px (914.2857dp)\n" +
+                    "\tavailableWidthPx: 1080.0px (411.42856dp)\n" +
+                    "\tavailableHeightPx: 2219.0px (845.3333dp)\n" +
+                    "\tmInsets.left: 0.0px (0.0dp)\n" +
+                    "\tmInsets.top: 118.0px (44.95238dp)\n" +
+                    "\tmInsets.right: 0.0px (0.0dp)\n" +
+                    "\tmInsets.bottom: 63.0px (24.0dp)\n" +
+                    "\taspectRatio:2.2222223\n" +
+                    "\tisScalableGrid:false\n" +
+                    "\tinv.numRows: 5\n" +
+                    "\tinv.numColumns: 5\n" +
+                    "\tinv.numSearchContainerColumns: 5\n" +
+                    "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+                    "\tcellWidthPx: 165.0px (62.857143dp)\n" +
+                    "\tcellHeightPx: 235.0px (89.52381dp)\n" +
+                    "\tgetCellSize().x: 207.0px (78.85714dp)\n" +
+                    "\tgetCellSize().y: 383.0px (145.90475dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 21.0px (8.0dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 28.0px (10.666667dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 21.0px (8.0dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 28.0px (10.666667dp)\n" +
+                    "\ticonSizePx: 147.0px (56.0dp)\n" +
+                    "\ticonTextSizePx: 38.0px (14.476191dp)\n" +
+                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tfolderCellWidthPx: 195.0px (74.28571dp)\n" +
+                    "\tfolderCellHeightPx: 230.0px (87.61905dp)\n" +
+                    "\tfolderChildIconSizePx: 147.0px (56.0dp)\n" +
+                    "\tfolderChildTextSizePx: 38.0px (14.476191dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+                    "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+                    "\tbottomSheetTopPadding: 146.0px (55.61905dp)\n" +
+                    "\tbottomSheetOpenDuration: 267\n" +
+                    "\tbottomSheetCloseDuration: 267\n" +
+                    "\tbottomSheetWorkspaceScale: 1.0\n" +
+                    "\tbottomSheetDepth: 0.0\n" +
+                    "\tallAppsShiftRange: 788.0px (300.1905dp)\n" +
+                    "\tallAppsTopPadding: 0.0px (0.0dp)\n" +
+                    "\tallAppsOpenDuration: 600\n" +
+                    "\tallAppsCloseDuration: 300\n" +
+                    "\tallAppsIconSizePx: 147.0px (56.0dp)\n" +
+                    "\tallAppsIconTextSizePx: 38.0px (14.476191dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+                    "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+                    "\tallAppsCellWidthPx: 189.0px (72.0dp)\n" +
+                    "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 5\n" +
+                    "\tallAppsLeftRightPadding: 21.0px (8.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSizePx: 273.0px (104.0dp)\n" +
+                    "\tinv.hotseatColumnSpan: 5\n" +
+                    "\thotseatCellHeightPx: 166.0px (63.238094dp)\n" +
+                    "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 200.0px (76.190475dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 107.0px (40.761906dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 21.0px (8.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 21.0px (8.0dp)\n" +
+                    "\tnumShownHotseatIcons: 5\n" +
+                    "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:false\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.left: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.right: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.bottom: 245.0px (93.333336dp)\n" +
+                    "\ticonScale: 1.0px (0.3809524dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+                    "\textraSpace: 743.0px (283.0476dp)\n" +
+                    "\tunscaled extraSpace: 743.0px (283.0476dp)\n" +
+                    "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+                    "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+                    "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 63.0px (24.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 84.0px (32.0dp)\n" +
+                    "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 391.0px (148.95238dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 1927.0px (734.0952dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.7781155px (0.29642496dp)\n" +
+                    "\tgetCellLayoutHeight(): 1974.0px (752.0dp)\n" +
+                    "\tgetCellLayoutWidth(): 1080.0px (411.42856dp)\n"
+            )
+    }
+
+    @Test
+    fun phoneVerticalBar3Button() {
+        initializeVarsForPhone(deviceSpecs["phone"]!!, isVerticalBar = true, isGestureMode = false)
+        val dp = getDeviceProfileForGrid("5_by_5")
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.625 px\n" +
+                    "\tisTablet:false\n" +
+                    "\tisPhone:true\n" +
+                    "\ttransposeLayoutWithOrientation:true\n" +
+                    "\tisGestureMode:false\n" +
+                    "\tisLandscape:true\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:false\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 2400.0px (914.2857dp)\n" +
+                    "\theightPx: 1080.0px (411.42856dp)\n" +
+                    "\tavailableWidthPx: 2156.0px (821.3333dp)\n" +
+                    "\tavailableHeightPx: 1006.0px (383.2381dp)\n" +
+                    "\tmInsets.left: 118.0px (44.95238dp)\n" +
+                    "\tmInsets.top: 74.0px (28.190475dp)\n" +
+                    "\tmInsets.right: 126.0px (48.0dp)\n" +
+                    "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+                    "\taspectRatio:2.2222223\n" +
+                    "\tisScalableGrid:false\n" +
+                    "\tinv.numRows: 5\n" +
+                    "\tinv.numColumns: 5\n" +
+                    "\tinv.numSearchContainerColumns: 5\n" +
+                    "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+                    "\tcellWidthPx: 158.0px (60.190475dp)\n" +
+                    "\tcellHeightPx: 166.0px (63.238094dp)\n" +
+                    "\tgetCellSize().x: 368.0px (140.19048dp)\n" +
+                    "\tgetCellSize().y: 193.0px (73.52381dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 53.0px (20.190475dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 53.0px (20.190475dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 40.0px (15.238095dp)\n" +
+                    "\ticonSizePx: 147.0px (56.0dp)\n" +
+                    "\ticonTextSizePx: 0.0px (0.0dp)\n" +
+                    "\ticonDrawablePaddingPx: 0.0px (0.0dp)\n" +
+                    "\tfolderCellWidthPx: 142.0px (54.095238dp)\n" +
+                    "\tfolderCellHeightPx: 168.0px (64.0dp)\n" +
+                    "\tfolderChildIconSizePx: 108.0px (41.142857dp)\n" +
+                    "\tfolderChildTextSizePx: 28.0px (10.666667dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 7.0px (2.6666667dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+                    "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+                    "\tbottomSheetTopPadding: 114.0px (43.42857dp)\n" +
+                    "\tbottomSheetOpenDuration: 267\n" +
+                    "\tbottomSheetCloseDuration: 267\n" +
+                    "\tbottomSheetWorkspaceScale: 1.0\n" +
+                    "\tbottomSheetDepth: 0.0\n" +
+                    "\tallAppsShiftRange: 788.0px (300.1905dp)\n" +
+                    "\tallAppsTopPadding: 0.0px (0.0dp)\n" +
+                    "\tallAppsOpenDuration: 600\n" +
+                    "\tallAppsCloseDuration: 300\n" +
+                    "\tallAppsIconSizePx: 147.0px (56.0dp)\n" +
+                    "\tallAppsIconTextSizePx: 38.0px (14.476191dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+                    "\tallAppsCellHeightPx: 321.0px (122.28571dp)\n" +
+                    "\tallAppsCellWidthPx: 189.0px (72.0dp)\n" +
+                    "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 5\n" +
+                    "\tallAppsLeftRightPadding: 0.0px (0.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSizePx: 252.0px (96.0dp)\n" +
+                    "\tinv.hotseatColumnSpan: 5\n" +
+                    "\thotseatCellHeightPx: 166.0px (63.238094dp)\n" +
+                    "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 63.0px (24.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 42.0px (16.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 118.0px (44.95238dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 64.0px (24.380953dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 49.0px (18.666666dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 42.0px (16.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 189.0px (72.0dp)\n" +
+                    "\tnumShownHotseatIcons: 5\n" +
+                    "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:false\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.left: 10.0px (3.8095238dp)\n" +
+                    "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.right: 199.0px (75.809525dp)\n" +
+                    "\tworkspacePadding.bottom: 0.0px (0.0dp)\n" +
+                    "\ticonScale: 1.0px (0.3809524dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+                    "\textraSpace: 136.0px (51.809525dp)\n" +
+                    "\tunscaled extraSpace: 136.0px (51.809525dp)\n" +
+                    "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+                    "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+                    "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 16.0px (6.095238dp)\n" +
+                    "\tdropTargetBarSizePx: 95.0px (36.190475dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 16.0px (6.095238dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 201.0px (76.57143dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 1008.0px (384.0dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.8021869px (0.305595dp)\n" +
+                    "\tgetCellLayoutHeight(): 1006.0px (383.2381dp)\n" +
+                    "\tgetCellLayoutWidth(): 1947.0px (741.7143dp)\n"
+            )
+    }
+
+    @Test
+    fun phoneVerticalBar() {
+        initializeVarsForPhone(deviceSpecs["phone"]!!, isVerticalBar = true)
+        val dp = getDeviceProfileForGrid("5_by_5")
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.625 px\n" +
+                    "\tisTablet:false\n" +
+                    "\tisPhone:true\n" +
+                    "\ttransposeLayoutWithOrientation:true\n" +
+                    "\tisGestureMode:true\n" +
+                    "\tisLandscape:true\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:false\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 2400.0px (914.2857dp)\n" +
+                    "\theightPx: 1080.0px (411.42856dp)\n" +
+                    "\tavailableWidthPx: 2282.0px (869.3333dp)\n" +
+                    "\tavailableHeightPx: 943.0px (359.2381dp)\n" +
+                    "\tmInsets.left: 118.0px (44.95238dp)\n" +
+                    "\tmInsets.top: 74.0px (28.190475dp)\n" +
+                    "\tmInsets.right: 0.0px (0.0dp)\n" +
+                    "\tmInsets.bottom: 63.0px (24.0dp)\n" +
+                    "\taspectRatio:2.2222223\n" +
+                    "\tisScalableGrid:false\n" +
+                    "\tinv.numRows: 5\n" +
+                    "\tinv.numColumns: 5\n" +
+                    "\tinv.numSearchContainerColumns: 5\n" +
+                    "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+                    "\tcellWidthPx: 158.0px (60.190475dp)\n" +
+                    "\tcellHeightPx: 166.0px (63.238094dp)\n" +
+                    "\tgetCellSize().x: 393.0px (149.71428dp)\n" +
+                    "\tgetCellSize().y: 180.0px (68.57143dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 53.0px (20.190475dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 53.0px (20.190475dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 40.0px (15.238095dp)\n" +
+                    "\ticonSizePx: 147.0px (56.0dp)\n" +
+                    "\ticonTextSizePx: 0.0px (0.0dp)\n" +
+                    "\ticonDrawablePaddingPx: 0.0px (0.0dp)\n" +
+                    "\tfolderCellWidthPx: 128.0px (48.761906dp)\n" +
+                    "\tfolderCellHeightPx: 152.0px (57.904762dp)\n" +
+                    "\tfolderChildIconSizePx: 98.0px (37.333332dp)\n" +
+                    "\tfolderChildTextSizePx: 25.0px (9.523809dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 6.0px (2.2857144dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+                    "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+                    "\tbottomSheetTopPadding: 114.0px (43.42857dp)\n" +
+                    "\tbottomSheetOpenDuration: 267\n" +
+                    "\tbottomSheetCloseDuration: 267\n" +
+                    "\tbottomSheetWorkspaceScale: 1.0\n" +
+                    "\tbottomSheetDepth: 0.0\n" +
+                    "\tallAppsShiftRange: 788.0px (300.1905dp)\n" +
+                    "\tallAppsTopPadding: 0.0px (0.0dp)\n" +
+                    "\tallAppsOpenDuration: 600\n" +
+                    "\tallAppsCloseDuration: 300\n" +
+                    "\tallAppsIconSizePx: 147.0px (56.0dp)\n" +
+                    "\tallAppsIconTextSizePx: 38.0px (14.476191dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+                    "\tallAppsCellHeightPx: 321.0px (122.28571dp)\n" +
+                    "\tallAppsCellWidthPx: 189.0px (72.0dp)\n" +
+                    "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 5\n" +
+                    "\tallAppsLeftRightPadding: 0.0px (0.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSizePx: 252.0px (96.0dp)\n" +
+                    "\tinv.hotseatColumnSpan: 5\n" +
+                    "\thotseatCellHeightPx: 166.0px (63.238094dp)\n" +
+                    "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 63.0px (24.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 42.0px (16.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 118.0px (44.95238dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 64.0px (24.380953dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 112.0px (42.666668dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 42.0px (16.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 63.0px (24.0dp)\n" +
+                    "\tnumShownHotseatIcons: 5\n" +
+                    "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:false\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.left: 10.0px (3.8095238dp)\n" +
+                    "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.right: 199.0px (75.809525dp)\n" +
+                    "\tworkspacePadding.bottom: 0.0px (0.0dp)\n" +
+                    "\ticonScale: 1.0px (0.3809524dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+                    "\textraSpace: 73.0px (27.809525dp)\n" +
+                    "\tunscaled extraSpace: 73.0px (27.809525dp)\n" +
+                    "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+                    "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+                    "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 63.0px (24.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 16.0px (6.095238dp)\n" +
+                    "\tdropTargetBarSizePx: 95.0px (36.190475dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 16.0px (6.095238dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 201.0px (76.57143dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 952.0px (362.66666dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.79639447px (0.30338836dp)\n" +
+                    "\tgetCellLayoutHeight(): 943.0px (359.2381dp)\n" +
+                    "\tgetCellLayoutWidth(): 2073.0px (789.7143dp)\n"
+            )
+    }
+
+    @Test
+    fun tabletLandscape3Button() {
+        initializeVarsForTablet(deviceSpecs["tablet"]!!, isLandscape = true, isGestureMode = false)
+        val dp = getDeviceProfileForGrid("6_by_5")
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.0 px\n" +
+                    "\tisTablet:true\n" +
+                    "\tisPhone:false\n" +
+                    "\ttransposeLayoutWithOrientation:false\n" +
+                    "\tisGestureMode:false\n" +
+                    "\tisLandscape:true\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:false\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 2560.0px (1280.0dp)\n" +
+                    "\theightPx: 1600.0px (800.0dp)\n" +
+                    "\tavailableWidthPx: 2560.0px (1280.0dp)\n" +
+                    "\tavailableHeightPx: 1496.0px (748.0dp)\n" +
+                    "\tmInsets.left: 0.0px (0.0dp)\n" +
+                    "\tmInsets.top: 104.0px (52.0dp)\n" +
+                    "\tmInsets.right: 0.0px (0.0dp)\n" +
+                    "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+                    "\taspectRatio:1.6\n" +
+                    "\tisScalableGrid:true\n" +
+                    "\tinv.numRows: 5\n" +
+                    "\tinv.numColumns: 6\n" +
+                    "\tinv.numSearchContainerColumns: 3\n" +
+                    "\tminCellSize: PointF(120.0, 104.0)dp\n" +
+                    "\tcellWidthPx: 240.0px (120.0dp)\n" +
+                    "\tcellHeightPx: 208.0px (104.0dp)\n" +
+                    "\tgetCellSize().x: 240.0px (120.0dp)\n" +
+                    "\tgetCellSize().y: 208.0px (104.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 128.0px (64.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 32.0px (16.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 59.0px (29.5dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 25.0px (12.5dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 59.0px (29.5dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 59.0px (29.5dp)\n" +
+                    "\ticonSizePx: 120.0px (60.0dp)\n" +
+                    "\ticonTextSizePx: 28.0px (14.0dp)\n" +
+                    "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tfolderCellWidthPx: 397.0px (198.5dp)\n" +
+                    "\tfolderCellHeightPx: 371.0px (185.5dp)\n" +
+                    "\tfolderChildIconSizePx: 99.0px (49.5dp)\n" +
+                    "\tfolderChildTextSizePx: 23.0px (11.5dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 80.0px (40.0dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
+                    "\tfolderTopPadding: 48.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 0.0px (0.0dp)\n" +
+                    "\tbottomSheetTopPadding: 104.0px (52.0dp)\n" +
+                    "\tbottomSheetOpenDuration: 500\n" +
+                    "\tbottomSheetCloseDuration: 500\n" +
+                    "\tbottomSheetWorkspaceScale: 0.97\n" +
+                    "\tbottomSheetDepth: 0.0\n" +
+                    "\tallAppsShiftRange: 1496.0px (748.0dp)\n" +
+                    "\tallAppsTopPadding: 104.0px (52.0dp)\n" +
+                    "\tallAppsOpenDuration: 500\n" +
+                    "\tallAppsCloseDuration: 500\n" +
+                    "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
+                    "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tallAppsCellHeightPx: 284.0px (142.0dp)\n" +
+                    "\tallAppsCellWidthPx: 252.0px (126.0dp)\n" +
+                    "\tallAppsBorderSpacePxX: 32.0px (16.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 32.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 6\n" +
+                    "\tallAppsLeftRightPadding: 32.0px (16.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 412.0px (206.0dp)\n" +
+                    "\thotseatBarSizePx: 200.0px (100.0dp)\n" +
+                    "\tinv.hotseatColumnSpan: 4\n" +
+                    "\thotseatCellHeightPx: 135.0px (67.5dp)\n" +
+                    "\thotseatBarBottomSpacePx: 80.0px (40.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 128.0px (64.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 65.0px (32.5dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 668.0px (334.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 668.0px (334.0dp)\n" +
+                    "\tnumShownHotseatIcons: 6\n" +
+                    "\thotseatBorderSpace: 100.0px (50.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 1224.0px (612.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:true\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 240.0px (120.0dp)\n" +
+                    "\tworkspacePadding.left: 181.0px (90.5dp)\n" +
+                    "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.right: 181.0px (90.5dp)\n" +
+                    "\tworkspacePadding.bottom: 244.0px (122.0dp)\n" +
+                    "\ticonScale: 1.0px (0.5dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.5dp)\n" +
+                    "\textraSpace: 80.0px (40.0dp)\n" +
+                    "\tunscaled extraSpace: 80.0px (40.0dp)\n" +
+                    "\tmaxEmptySpace: 200.0px (100.0dp)\n" +
+                    "\tworkspaceTopPadding: 25.0px (12.5dp)\n" +
+                    "\tworkspaceBottomPadding: 55.0px (27.5dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarSizePx: 144.0px (72.0dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 64.0px (32.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 312.0px (156.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 1272.0px (636.0dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.76677316px (0.38338658dp)\n" +
+                    "\tgetCellLayoutHeight(): 1252.0px (626.0dp)\n" +
+                    "\tgetCellLayoutWidth(): 2198.0px (1099.0dp)\n"
+            )
+    }
+
+    @Test
+    fun tabletLandscape() {
+        initializeVarsForTablet(deviceSpecs["tablet"]!!, isLandscape = true)
+        val dp = getDeviceProfileForGrid("6_by_5")
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.0 px\n" +
+                    "\tisTablet:true\n" +
+                    "\tisPhone:false\n" +
+                    "\ttransposeLayoutWithOrientation:false\n" +
+                    "\tisGestureMode:true\n" +
+                    "\tisLandscape:true\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:false\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 2560.0px (1280.0dp)\n" +
+                    "\theightPx: 1600.0px (800.0dp)\n" +
+                    "\tavailableWidthPx: 2560.0px (1280.0dp)\n" +
+                    "\tavailableHeightPx: 1496.0px (748.0dp)\n" +
+                    "\tmInsets.left: 0.0px (0.0dp)\n" +
+                    "\tmInsets.top: 104.0px (52.0dp)\n" +
+                    "\tmInsets.right: 0.0px (0.0dp)\n" +
+                    "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+                    "\taspectRatio:1.6\n" +
+                    "\tisScalableGrid:true\n" +
+                    "\tinv.numRows: 5\n" +
+                    "\tinv.numColumns: 6\n" +
+                    "\tinv.numSearchContainerColumns: 3\n" +
+                    "\tminCellSize: PointF(120.0, 104.0)dp\n" +
+                    "\tcellWidthPx: 240.0px (120.0dp)\n" +
+                    "\tcellHeightPx: 208.0px (104.0dp)\n" +
+                    "\tgetCellSize().x: 240.0px (120.0dp)\n" +
+                    "\tgetCellSize().y: 208.0px (104.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 128.0px (64.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 32.0px (16.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 59.0px (29.5dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 25.0px (12.5dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 59.0px (29.5dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 59.0px (29.5dp)\n" +
+                    "\ticonSizePx: 120.0px (60.0dp)\n" +
+                    "\ticonTextSizePx: 28.0px (14.0dp)\n" +
+                    "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tfolderCellWidthPx: 397.0px (198.5dp)\n" +
+                    "\tfolderCellHeightPx: 371.0px (185.5dp)\n" +
+                    "\tfolderChildIconSizePx: 99.0px (49.5dp)\n" +
+                    "\tfolderChildTextSizePx: 23.0px (11.5dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 80.0px (40.0dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
+                    "\tfolderTopPadding: 48.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 0.0px (0.0dp)\n" +
+                    "\tbottomSheetTopPadding: 104.0px (52.0dp)\n" +
+                    "\tbottomSheetOpenDuration: 500\n" +
+                    "\tbottomSheetCloseDuration: 500\n" +
+                    "\tbottomSheetWorkspaceScale: 0.97\n" +
+                    "\tbottomSheetDepth: 0.0\n" +
+                    "\tallAppsShiftRange: 1496.0px (748.0dp)\n" +
+                    "\tallAppsTopPadding: 104.0px (52.0dp)\n" +
+                    "\tallAppsOpenDuration: 500\n" +
+                    "\tallAppsCloseDuration: 500\n" +
+                    "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
+                    "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tallAppsCellHeightPx: 284.0px (142.0dp)\n" +
+                    "\tallAppsCellWidthPx: 252.0px (126.0dp)\n" +
+                    "\tallAppsBorderSpacePxX: 32.0px (16.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 32.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 6\n" +
+                    "\tallAppsLeftRightPadding: 32.0px (16.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 412.0px (206.0dp)\n" +
+                    "\thotseatBarSizePx: 200.0px (100.0dp)\n" +
+                    "\tinv.hotseatColumnSpan: 4\n" +
+                    "\thotseatCellHeightPx: 135.0px (67.5dp)\n" +
+                    "\thotseatBarBottomSpacePx: 80.0px (40.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 128.0px (64.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 65.0px (32.5dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 668.0px (334.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 668.0px (334.0dp)\n" +
+                    "\tnumShownHotseatIcons: 6\n" +
+                    "\thotseatBorderSpace: 100.0px (50.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 1224.0px (612.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:true\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 240.0px (120.0dp)\n" +
+                    "\tworkspacePadding.left: 181.0px (90.5dp)\n" +
+                    "\tworkspacePadding.top: 0.0px (0.0dp)\n" +
+                    "\tworkspacePadding.right: 181.0px (90.5dp)\n" +
+                    "\tworkspacePadding.bottom: 244.0px (122.0dp)\n" +
+                    "\ticonScale: 1.0px (0.5dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.5dp)\n" +
+                    "\textraSpace: 80.0px (40.0dp)\n" +
+                    "\tunscaled extraSpace: 80.0px (40.0dp)\n" +
+                    "\tmaxEmptySpace: 200.0px (100.0dp)\n" +
+                    "\tworkspaceTopPadding: 25.0px (12.5dp)\n" +
+                    "\tworkspaceBottomPadding: 55.0px (27.5dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarSizePx: 144.0px (72.0dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 64.0px (32.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 312.0px (156.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 1272.0px (636.0dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.76677316px (0.38338658dp)\n" +
+                    "\tgetCellLayoutHeight(): 1252.0px (626.0dp)\n" +
+                    "\tgetCellLayoutWidth(): 2198.0px (1099.0dp)\n"
+            )
+    }
+
+    @Test
+    fun tabletPortrait3Button() {
+        initializeVarsForTablet(deviceSpecs["tablet"]!!, isGestureMode = false)
+        val dp = getDeviceProfileForGrid("6_by_5")
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.0 px\n" +
+                    "\tisTablet:true\n" +
+                    "\tisPhone:false\n" +
+                    "\ttransposeLayoutWithOrientation:false\n" +
+                    "\tisGestureMode:false\n" +
+                    "\tisLandscape:false\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:false\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 1600.0px (800.0dp)\n" +
+                    "\theightPx: 2560.0px (1280.0dp)\n" +
+                    "\tavailableWidthPx: 1600.0px (800.0dp)\n" +
+                    "\tavailableHeightPx: 2456.0px (1228.0dp)\n" +
+                    "\tmInsets.left: 0.0px (0.0dp)\n" +
+                    "\tmInsets.top: 104.0px (52.0dp)\n" +
+                    "\tmInsets.right: 0.0px (0.0dp)\n" +
+                    "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+                    "\taspectRatio:1.6\n" +
+                    "\tisScalableGrid:true\n" +
+                    "\tinv.numRows: 5\n" +
+                    "\tinv.numColumns: 6\n" +
+                    "\tinv.numSearchContainerColumns: 3\n" +
+                    "\tminCellSize: PointF(102.0, 120.0)dp\n" +
+                    "\tcellWidthPx: 204.0px (102.0dp)\n" +
+                    "\tcellHeightPx: 240.0px (120.0dp)\n" +
+                    "\tgetCellSize().x: 204.0px (102.0dp)\n" +
+                    "\tgetCellSize().y: 240.0px (120.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 32.0px (16.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 128.0px (64.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 72.0px (36.0dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 72.0px (36.0dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 72.0px (36.0dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 72.0px (36.0dp)\n" +
+                    "\ticonSizePx: 120.0px (60.0dp)\n" +
+                    "\ticonTextSizePx: 28.0px (14.0dp)\n" +
+                    "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tfolderCellWidthPx: 408.0px (204.0dp)\n" +
+                    "\tfolderCellHeightPx: 648.0px (324.0dp)\n" +
+                    "\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
+                    "\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 163.0px (81.5dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
+                    "\tfolderTopPadding: 48.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 0.0px (0.0dp)\n" +
+                    "\tbottomSheetTopPadding: 704.0px (352.0dp)\n" +
+                    "\tbottomSheetOpenDuration: 500\n" +
+                    "\tbottomSheetCloseDuration: 500\n" +
+                    "\tbottomSheetWorkspaceScale: 0.97\n" +
+                    "\tbottomSheetDepth: 0.0\n" +
+                    "\tallAppsShiftRange: 1810.0px (905.0dp)\n" +
+                    "\tallAppsTopPadding: 750.0px (375.0dp)\n" +
+                    "\tallAppsOpenDuration: 500\n" +
+                    "\tallAppsCloseDuration: 500\n" +
+                    "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
+                    "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tallAppsCellHeightPx: 316.0px (158.0dp)\n" +
+                    "\tallAppsCellWidthPx: 192.0px (96.0dp)\n" +
+                    "\tallAppsBorderSpacePxX: 16.0px (8.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 32.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 6\n" +
+                    "\tallAppsLeftRightPadding: 32.0px (16.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 152.0px (76.0dp)\n" +
+                    "\thotseatBarSizePx: 272.0px (136.0dp)\n" +
+                    "\tinv.hotseatColumnSpan: 6\n" +
+                    "\thotseatCellHeightPx: 135.0px (67.5dp)\n" +
+                    "\thotseatBarBottomSpacePx: 152.0px (76.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 216.0px (108.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 137.0px (68.5dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 150.0px (75.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 150.0px (75.0dp)\n" +
+                    "\tnumShownHotseatIcons: 6\n" +
+                    "\thotseatBorderSpace: 116.0px (58.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 1300.0px (650.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:true\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 108.0px (54.0dp)\n" +
+                    "\tworkspacePadding.left: 36.0px (18.0dp)\n" +
+                    "\tworkspacePadding.top: 132.0px (66.0dp)\n" +
+                    "\tworkspacePadding.right: 36.0px (18.0dp)\n" +
+                    "\tworkspacePadding.bottom: 468.0px (234.0dp)\n" +
+                    "\ticonScale: 1.0px (0.5dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.5dp)\n" +
+                    "\textraSpace: 424.0px (212.0dp)\n" +
+                    "\tunscaled extraSpace: 424.0px (212.0dp)\n" +
+                    "\tmaxEmptySpace: 19998.0px (9999.0dp)\n" +
+                    "\tworkspaceTopPadding: 204.0px (102.0dp)\n" +
+                    "\tworkspaceBottomPadding: 220.0px (110.0dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 220.0px (110.0dp)\n" +
+                    "\tdropTargetBarSizePx: 144.0px (72.0dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 96.0px (48.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 564.0px (282.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 2072.0px (1036.0dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.8125px (0.40625dp)\n" +
+                    "\tgetCellLayoutHeight(): 1856.0px (928.0dp)\n" +
+                    "\tgetCellLayoutWidth(): 1528.0px (764.0dp)\n"
+            )
+    }
+
+    @Test
+    fun tabletPortrait() {
+        initializeVarsForTablet(deviceSpecs["tablet"]!!)
+        val dp = getDeviceProfileForGrid("6_by_5")
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.0 px\n" +
+                    "\tisTablet:true\n" +
+                    "\tisPhone:false\n" +
+                    "\ttransposeLayoutWithOrientation:false\n" +
+                    "\tisGestureMode:true\n" +
+                    "\tisLandscape:false\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:false\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 1600.0px (800.0dp)\n" +
+                    "\theightPx: 2560.0px (1280.0dp)\n" +
+                    "\tavailableWidthPx: 1600.0px (800.0dp)\n" +
+                    "\tavailableHeightPx: 2456.0px (1228.0dp)\n" +
+                    "\tmInsets.left: 0.0px (0.0dp)\n" +
+                    "\tmInsets.top: 104.0px (52.0dp)\n" +
+                    "\tmInsets.right: 0.0px (0.0dp)\n" +
+                    "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+                    "\taspectRatio:1.6\n" +
+                    "\tisScalableGrid:true\n" +
+                    "\tinv.numRows: 5\n" +
+                    "\tinv.numColumns: 6\n" +
+                    "\tinv.numSearchContainerColumns: 3\n" +
+                    "\tminCellSize: PointF(102.0, 120.0)dp\n" +
+                    "\tcellWidthPx: 204.0px (102.0dp)\n" +
+                    "\tcellHeightPx: 240.0px (120.0dp)\n" +
+                    "\tgetCellSize().x: 204.0px (102.0dp)\n" +
+                    "\tgetCellSize().y: 240.0px (120.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 32.0px (16.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 128.0px (64.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 72.0px (36.0dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 72.0px (36.0dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 72.0px (36.0dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 72.0px (36.0dp)\n" +
+                    "\ticonSizePx: 120.0px (60.0dp)\n" +
+                    "\ticonTextSizePx: 28.0px (14.0dp)\n" +
+                    "\ticonDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tfolderCellWidthPx: 408.0px (204.0dp)\n" +
+                    "\tfolderCellHeightPx: 648.0px (324.0dp)\n" +
+                    "\tfolderChildIconSizePx: 120.0px (60.0dp)\n" +
+                    "\tfolderChildTextSizePx: 28.0px (14.0dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 163.0px (81.5dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 0.0px (0.0dp)\n" +
+                    "\tfolderTopPadding: 48.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 0.0px (0.0dp)\n" +
+                    "\tbottomSheetTopPadding: 704.0px (352.0dp)\n" +
+                    "\tbottomSheetOpenDuration: 500\n" +
+                    "\tbottomSheetCloseDuration: 500\n" +
+                    "\tbottomSheetWorkspaceScale: 0.97\n" +
+                    "\tbottomSheetDepth: 0.0\n" +
+                    "\tallAppsShiftRange: 1810.0px (905.0dp)\n" +
+                    "\tallAppsTopPadding: 750.0px (375.0dp)\n" +
+                    "\tallAppsOpenDuration: 500\n" +
+                    "\tallAppsCloseDuration: 500\n" +
+                    "\tallAppsIconSizePx: 120.0px (60.0dp)\n" +
+                    "\tallAppsIconTextSizePx: 28.0px (14.0dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 14.0px (7.0dp)\n" +
+                    "\tallAppsCellHeightPx: 316.0px (158.0dp)\n" +
+                    "\tallAppsCellWidthPx: 192.0px (96.0dp)\n" +
+                    "\tallAppsBorderSpacePxX: 16.0px (8.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 32.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 6\n" +
+                    "\tallAppsLeftRightPadding: 32.0px (16.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 152.0px (76.0dp)\n" +
+                    "\thotseatBarSizePx: 272.0px (136.0dp)\n" +
+                    "\tinv.hotseatColumnSpan: 6\n" +
+                    "\thotseatCellHeightPx: 135.0px (67.5dp)\n" +
+                    "\thotseatBarBottomSpacePx: 152.0px (76.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 216.0px (108.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 137.0px (68.5dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 150.0px (75.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 150.0px (75.0dp)\n" +
+                    "\tnumShownHotseatIcons: 6\n" +
+                    "\thotseatBorderSpace: 116.0px (58.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 1300.0px (650.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:true\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 108.0px (54.0dp)\n" +
+                    "\tworkspacePadding.left: 36.0px (18.0dp)\n" +
+                    "\tworkspacePadding.top: 132.0px (66.0dp)\n" +
+                    "\tworkspacePadding.right: 36.0px (18.0dp)\n" +
+                    "\tworkspacePadding.bottom: 468.0px (234.0dp)\n" +
+                    "\ticonScale: 1.0px (0.5dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.5dp)\n" +
+                    "\textraSpace: 424.0px (212.0dp)\n" +
+                    "\tunscaled extraSpace: 424.0px (212.0dp)\n" +
+                    "\tmaxEmptySpace: 19998.0px (9999.0dp)\n" +
+                    "\tworkspaceTopPadding: 204.0px (102.0dp)\n" +
+                    "\tworkspaceBottomPadding: 220.0px (110.0dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 220.0px (110.0dp)\n" +
+                    "\tdropTargetBarSizePx: 144.0px (72.0dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 96.0px (48.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 564.0px (282.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 2072.0px (1036.0dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.8125px (0.40625dp)\n" +
+                    "\tgetCellLayoutHeight(): 1856.0px (928.0dp)\n" +
+                    "\tgetCellLayoutWidth(): 1528.0px (764.0dp)\n"
+            )
+    }
+
+    @Test
+    fun twoPanelLandscape3Button() {
+        initializeVarsForTwoPanel(
+            deviceSpecs["twopanel-tablet"]!!,
+            deviceSpecs["twopanel-phone"]!!,
+            isLandscape = true,
+            isGestureMode = false
+        )
+        val dp = getDeviceProfileForGrid("4_by_4")
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.625 px\n" +
+                    "\tisTablet:true\n" +
+                    "\tisPhone:false\n" +
+                    "\ttransposeLayoutWithOrientation:false\n" +
+                    "\tisGestureMode:false\n" +
+                    "\tisLandscape:true\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:true\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 2208.0px (841.1429dp)\n" +
+                    "\theightPx: 1840.0px (700.9524dp)\n" +
+                    "\tavailableWidthPx: 2208.0px (841.1429dp)\n" +
+                    "\tavailableHeightPx: 1730.0px (659.0476dp)\n" +
+                    "\tmInsets.left: 0.0px (0.0dp)\n" +
+                    "\tmInsets.top: 110.0px (41.904762dp)\n" +
+                    "\tmInsets.right: 0.0px (0.0dp)\n" +
+                    "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+                    "\taspectRatio:1.2\n" +
+                    "\tisScalableGrid:false\n" +
+                    "\tinv.numRows: 4\n" +
+                    "\tinv.numColumns: 4\n" +
+                    "\tinv.numSearchContainerColumns: 4\n" +
+                    "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+                    "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+                    "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+                    "\tgetCellSize().x: 270.0px (102.85714dp)\n" +
+                    "\tgetCellSize().y: 342.0px (130.28572dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
+                    "\ticonSizePx: 141.0px (53.714287dp)\n" +
+                    "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
+                    "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
+                    "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
+                    "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+                    "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+                    "\tbottomSheetTopPadding: 110.0px (41.904762dp)\n" +
+                    "\tbottomSheetOpenDuration: 500\n" +
+                    "\tbottomSheetCloseDuration: 500\n" +
+                    "\tbottomSheetWorkspaceScale: 0.97\n" +
+                    "\tbottomSheetDepth: 1.0\n" +
+                    "\tallAppsShiftRange: 1730.0px (659.0476dp)\n" +
+                    "\tallAppsTopPadding: 110.0px (41.904762dp)\n" +
+                    "\tallAppsOpenDuration: 500\n" +
+                    "\tallAppsCloseDuration: 500\n" +
+                    "\tallAppsIconSizePx: 141.0px (53.714287dp)\n" +
+                    "\tallAppsIconTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+                    "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+                    "\tallAppsCellWidthPx: 183.0px (69.71429dp)\n" +
+                    "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 8\n" +
+                    "\tallAppsLeftRightPadding: 42.0px (16.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 183.0px (69.71429dp)\n" +
+                    "\thotseatBarSizePx: 267.0px (101.71429dp)\n" +
+                    "\tinv.hotseatColumnSpan: 4\n" +
+                    "\thotseatCellHeightPx: 159.0px (60.57143dp)\n" +
+                    "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 116.0px (44.190475dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 108.0px (41.142857dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 113.0px (43.04762dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 113.0px (43.04762dp)\n" +
+                    "\tnumShownHotseatIcons: 6\n" +
+                    "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:true\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.left: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.top: 30.0px (11.428572dp)\n" +
+                    "\tworkspacePadding.right: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
+                    "\ticonScale: 1.0px (0.3809524dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+                    "\textraSpace: 478.0px (182.09525dp)\n" +
+                    "\tunscaled extraSpace: 478.0px (182.09525dp)\n" +
+                    "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+                    "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+                    "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 299.0px (113.90476dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 1457.0px (555.0476dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.8452555px (0.32200208dp)\n" +
+                    "\tgetCellLayoutHeight(): 1370.0px (521.9048dp)\n" +
+                    "\tgetCellLayoutWidth(): 1083.0px (412.57144dp)\n"
+            )
+    }
+
+    @Test
+    fun twoPanelLandscape() {
+        initializeVarsForTwoPanel(
+            deviceSpecs["twopanel-tablet"]!!,
+            deviceSpecs["twopanel-phone"]!!,
+            isLandscape = true
+        )
+        val dp = getDeviceProfileForGrid("4_by_4")
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.625 px\n" +
+                    "\tisTablet:true\n" +
+                    "\tisPhone:false\n" +
+                    "\ttransposeLayoutWithOrientation:false\n" +
+                    "\tisGestureMode:true\n" +
+                    "\tisLandscape:true\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:true\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 2208.0px (841.1429dp)\n" +
+                    "\theightPx: 1840.0px (700.9524dp)\n" +
+                    "\tavailableWidthPx: 2208.0px (841.1429dp)\n" +
+                    "\tavailableHeightPx: 1730.0px (659.0476dp)\n" +
+                    "\tmInsets.left: 0.0px (0.0dp)\n" +
+                    "\tmInsets.top: 110.0px (41.904762dp)\n" +
+                    "\tmInsets.right: 0.0px (0.0dp)\n" +
+                    "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+                    "\taspectRatio:1.2\n" +
+                    "\tisScalableGrid:false\n" +
+                    "\tinv.numRows: 4\n" +
+                    "\tinv.numColumns: 4\n" +
+                    "\tinv.numSearchContainerColumns: 4\n" +
+                    "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+                    "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+                    "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+                    "\tgetCellSize().x: 270.0px (102.85714dp)\n" +
+                    "\tgetCellSize().y: 342.0px (130.28572dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
+                    "\ticonSizePx: 141.0px (53.714287dp)\n" +
+                    "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
+                    "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
+                    "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
+                    "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+                    "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+                    "\tbottomSheetTopPadding: 110.0px (41.904762dp)\n" +
+                    "\tbottomSheetOpenDuration: 500\n" +
+                    "\tbottomSheetCloseDuration: 500\n" +
+                    "\tbottomSheetWorkspaceScale: 0.97\n" +
+                    "\tbottomSheetDepth: 1.0\n" +
+                    "\tallAppsShiftRange: 1730.0px (659.0476dp)\n" +
+                    "\tallAppsTopPadding: 110.0px (41.904762dp)\n" +
+                    "\tallAppsOpenDuration: 500\n" +
+                    "\tallAppsCloseDuration: 500\n" +
+                    "\tallAppsIconSizePx: 141.0px (53.714287dp)\n" +
+                    "\tallAppsIconTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+                    "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+                    "\tallAppsCellWidthPx: 183.0px (69.71429dp)\n" +
+                    "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 8\n" +
+                    "\tallAppsLeftRightPadding: 42.0px (16.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 183.0px (69.71429dp)\n" +
+                    "\thotseatBarSizePx: 267.0px (101.71429dp)\n" +
+                    "\tinv.hotseatColumnSpan: 4\n" +
+                    "\thotseatCellHeightPx: 159.0px (60.57143dp)\n" +
+                    "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 116.0px (44.190475dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 108.0px (41.142857dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 113.0px (43.04762dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 113.0px (43.04762dp)\n" +
+                    "\tnumShownHotseatIcons: 6\n" +
+                    "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:true\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.left: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.top: 30.0px (11.428572dp)\n" +
+                    "\tworkspacePadding.right: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
+                    "\ticonScale: 1.0px (0.3809524dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+                    "\textraSpace: 478.0px (182.09525dp)\n" +
+                    "\tunscaled extraSpace: 478.0px (182.09525dp)\n" +
+                    "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+                    "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+                    "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 299.0px (113.90476dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 1457.0px (555.0476dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.8452555px (0.32200208dp)\n" +
+                    "\tgetCellLayoutHeight(): 1370.0px (521.9048dp)\n" +
+                    "\tgetCellLayoutWidth(): 1083.0px (412.57144dp)\n"
+            )
+    }
+
+    @Test
+    fun twoPanelPortrait3Button() {
+        initializeVarsForTwoPanel(
+            deviceSpecs["twopanel-tablet"]!!,
+            deviceSpecs["twopanel-phone"]!!,
+            isGestureMode = false
+        )
+        val dp = getDeviceProfileForGrid("4_by_4")
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.625 px\n" +
+                    "\tisTablet:true\n" +
+                    "\tisPhone:false\n" +
+                    "\ttransposeLayoutWithOrientation:false\n" +
+                    "\tisGestureMode:false\n" +
+                    "\tisLandscape:false\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:true\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 1840.0px (700.9524dp)\n" +
+                    "\theightPx: 2208.0px (841.1429dp)\n" +
+                    "\tavailableWidthPx: 1840.0px (700.9524dp)\n" +
+                    "\tavailableHeightPx: 2075.0px (790.4762dp)\n" +
+                    "\tmInsets.left: 0.0px (0.0dp)\n" +
+                    "\tmInsets.top: 133.0px (50.666668dp)\n" +
+                    "\tmInsets.right: 0.0px (0.0dp)\n" +
+                    "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+                    "\taspectRatio:1.2\n" +
+                    "\tisScalableGrid:false\n" +
+                    "\tinv.numRows: 4\n" +
+                    "\tinv.numColumns: 4\n" +
+                    "\tinv.numSearchContainerColumns: 4\n" +
+                    "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+                    "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+                    "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+                    "\tgetCellSize().x: 224.0px (85.333336dp)\n" +
+                    "\tgetCellSize().y: 430.0px (163.80952dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
+                    "\ticonSizePx: 141.0px (53.714287dp)\n" +
+                    "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
+                    "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
+                    "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
+                    "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+                    "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+                    "\tbottomSheetTopPadding: 133.0px (50.666668dp)\n" +
+                    "\tbottomSheetOpenDuration: 500\n" +
+                    "\tbottomSheetCloseDuration: 500\n" +
+                    "\tbottomSheetWorkspaceScale: 0.97\n" +
+                    "\tbottomSheetDepth: 1.0\n" +
+                    "\tallAppsShiftRange: 1826.0px (695.619dp)\n" +
+                    "\tallAppsTopPadding: 382.0px (145.5238dp)\n" +
+                    "\tallAppsOpenDuration: 500\n" +
+                    "\tallAppsCloseDuration: 500\n" +
+                    "\tallAppsIconSizePx: 141.0px (53.714287dp)\n" +
+                    "\tallAppsIconTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+                    "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+                    "\tallAppsCellWidthPx: 183.0px (69.71429dp)\n" +
+                    "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 8\n" +
+                    "\tallAppsLeftRightPadding: 42.0px (16.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 1.0px (0.3809524dp)\n" +
+                    "\thotseatBarSizePx: 267.0px (101.71429dp)\n" +
+                    "\tinv.hotseatColumnSpan: 4\n" +
+                    "\thotseatCellHeightPx: 159.0px (60.57143dp)\n" +
+                    "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 171.0px (65.14286dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 108.0px (41.142857dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 98.0px (37.333332dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 98.0px (37.333332dp)\n" +
+                    "\tnumShownHotseatIcons: 6\n" +
+                    "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:true\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.left: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.top: 24.0px (9.142858dp)\n" +
+                    "\tworkspacePadding.right: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
+                    "\ticonScale: 1.0px (0.3809524dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+                    "\textraSpace: 829.0px (315.8095dp)\n" +
+                    "\tunscaled extraSpace: 829.0px (315.8095dp)\n" +
+                    "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+                    "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+                    "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 168.0px (64.0dp)\n" +
+                    "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 490.0px (186.66667dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 1770.0px (674.2857dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.7437536px (0.2833347dp)\n" +
+                    "\tgetCellLayoutHeight(): 1721.0px (655.619dp)\n" +
+                    "\tgetCellLayoutWidth(): 899.0px (342.4762dp)\n"
+            )
+    }
+
+    @Test
+    fun twoPanelPortrait() {
+        initializeVarsForTwoPanel(deviceSpecs["twopanel-tablet"]!!, deviceSpecs["twopanel-phone"]!!)
+        val dp = getDeviceProfileForGrid("4_by_4")
+        dp.isTaskbarPresentInApps = true
+
+        assertThat(dump(dp))
+            .isEqualTo(
+                "DeviceProfile:\n" +
+                    "\t1 dp = 2.625 px\n" +
+                    "\tisTablet:true\n" +
+                    "\tisPhone:false\n" +
+                    "\ttransposeLayoutWithOrientation:false\n" +
+                    "\tisGestureMode:true\n" +
+                    "\tisLandscape:false\n" +
+                    "\tisMultiWindowMode:false\n" +
+                    "\tisTwoPanels:true\n" +
+                    "\twindowX: 0.0px (0.0dp)\n" +
+                    "\twindowY: 0.0px (0.0dp)\n" +
+                    "\twidthPx: 1840.0px (700.9524dp)\n" +
+                    "\theightPx: 2208.0px (841.1429dp)\n" +
+                    "\tavailableWidthPx: 1840.0px (700.9524dp)\n" +
+                    "\tavailableHeightPx: 2075.0px (790.4762dp)\n" +
+                    "\tmInsets.left: 0.0px (0.0dp)\n" +
+                    "\tmInsets.top: 133.0px (50.666668dp)\n" +
+                    "\tmInsets.right: 0.0px (0.0dp)\n" +
+                    "\tmInsets.bottom: 0.0px (0.0dp)\n" +
+                    "\taspectRatio:1.2\n" +
+                    "\tisScalableGrid:false\n" +
+                    "\tinv.numRows: 4\n" +
+                    "\tinv.numColumns: 4\n" +
+                    "\tinv.numSearchContainerColumns: 4\n" +
+                    "\tminCellSize: PointF(0.0, 0.0)dp\n" +
+                    "\tcellWidthPx: 159.0px (60.57143dp)\n" +
+                    "\tcellHeightPx: 223.0px (84.95238dp)\n" +
+                    "\tgetCellSize().x: 224.0px (85.333336dp)\n" +
+                    "\tgetCellSize().y: 430.0px (163.80952dp)\n" +
+                    "\tcellLayoutBorderSpacePx Horizontal: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutBorderSpacePx Vertical: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.left: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.top: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.right: 0.0px (0.0dp)\n" +
+                    "\tcellLayoutPaddingPx.bottom: 0.0px (0.0dp)\n" +
+                    "\ticonSizePx: 141.0px (53.714287dp)\n" +
+                    "\ticonTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\ticonDrawablePaddingPx: 18.0px (6.857143dp)\n" +
+                    "\tfolderCellWidthPx: 189.0px (72.0dp)\n" +
+                    "\tfolderCellHeightPx: 219.0px (83.42857dp)\n" +
+                    "\tfolderChildIconSizePx: 141.0px (53.714287dp)\n" +
+                    "\tfolderChildTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\tfolderChildDrawablePaddingPx: 10.0px (3.8095238dp)\n" +
+                    "\tfolderCellLayoutBorderSpacePx: 0.0px (0.0dp)\n" +
+                    "\tfolderContentPaddingLeftRight: 21.0px (8.0dp)\n" +
+                    "\tfolderTopPadding: 63.0px (24.0dp)\n" +
+                    "\tfolderFooterHeight: 147.0px (56.0dp)\n" +
+                    "\tbottomSheetTopPadding: 133.0px (50.666668dp)\n" +
+                    "\tbottomSheetOpenDuration: 500\n" +
+                    "\tbottomSheetCloseDuration: 500\n" +
+                    "\tbottomSheetWorkspaceScale: 0.97\n" +
+                    "\tbottomSheetDepth: 1.0\n" +
+                    "\tallAppsShiftRange: 1826.0px (695.619dp)\n" +
+                    "\tallAppsTopPadding: 382.0px (145.5238dp)\n" +
+                    "\tallAppsOpenDuration: 500\n" +
+                    "\tallAppsCloseDuration: 500\n" +
+                    "\tallAppsIconSizePx: 141.0px (53.714287dp)\n" +
+                    "\tallAppsIconTextSizePx: 34.0px (12.952381dp)\n" +
+                    "\tallAppsIconDrawablePaddingPx: 21.0px (8.0dp)\n" +
+                    "\tallAppsCellHeightPx: 315.0px (120.0dp)\n" +
+                    "\tallAppsCellWidthPx: 183.0px (69.71429dp)\n" +
+                    "\tallAppsBorderSpacePxX: 42.0px (16.0dp)\n" +
+                    "\tallAppsBorderSpacePxY: 42.0px (16.0dp)\n" +
+                    "\tnumShownAllAppsColumns: 8\n" +
+                    "\tallAppsLeftRightPadding: 42.0px (16.0dp)\n" +
+                    "\tallAppsLeftRightMargin: 1.0px (0.3809524dp)\n" +
+                    "\thotseatBarSizePx: 267.0px (101.71429dp)\n" +
+                    "\tinv.hotseatColumnSpan: 4\n" +
+                    "\thotseatCellHeightPx: 159.0px (60.57143dp)\n" +
+                    "\thotseatBarBottomSpacePx: 126.0px (48.0dp)\n" +
+                    "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" +
+                    "\thotseatBarEndOffset: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbSpace: 0.0px (0.0dp)\n" +
+                    "\thotseatQsbHeight: 0.0px (0.0dp)\n" +
+                    "\tspringLoadedHotseatBarTopMarginPx: 171.0px (65.14286dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).top: 0.0px (0.0dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).bottom: 108.0px (41.142857dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).left: 98.0px (37.333332dp)\n" +
+                    "\tgetHotseatLayoutPadding(context).right: 98.0px (37.333332dp)\n" +
+                    "\tnumShownHotseatIcons: 6\n" +
+                    "\thotseatBorderSpace: 0.0px (0.0dp)\n" +
+                    "\tisQsbInline: false\n" +
+                    "\thotseatQsbWidth: 0.0px (0.0dp)\n" +
+                    "\tisTaskbarPresent:false\n" +
+                    "\tisTaskbarPresentInApps:true\n" +
+                    "\ttaskbarSize: 0.0px (0.0dp)\n" +
+                    "\tdesiredWorkspaceHorizontalMarginPx: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.left: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.top: 24.0px (9.142858dp)\n" +
+                    "\tworkspacePadding.right: 21.0px (8.0dp)\n" +
+                    "\tworkspacePadding.bottom: 330.0px (125.71429dp)\n" +
+                    "\ticonScale: 1.0px (0.3809524dp)\n" +
+                    "\tcellScaleToFit : 1.0px (0.3809524dp)\n" +
+                    "\textraSpace: 829.0px (315.8095dp)\n" +
+                    "\tunscaled extraSpace: 829.0px (315.8095dp)\n" +
+                    "\tmaxEmptySpace: 0.0px (0.0dp)\n" +
+                    "\tworkspaceTopPadding: 0.0px (0.0dp)\n" +
+                    "\tworkspaceBottomPadding: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizePx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskIconDrawableSizeGridPx: 0.0px (0.0dp)\n" +
+                    "\toverviewTaskThumbnailTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsTopMarginPx: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsHeight: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsClaimedSpaceBelow: 0.0px (0.0dp)\n" +
+                    "\toverviewActionsButtonSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewPageSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewRowSpacing: 0.0px (0.0dp)\n" +
+                    "\toverviewGridSideMargin: 0.0px (0.0dp)\n" +
+                    "\tdropTargetBarTopMarginPx: 168.0px (64.0dp)\n" +
+                    "\tdropTargetBarSizePx: 147.0px (56.0dp)\n" +
+                    "\tdropTargetBarBottomMarginPx: 42.0px (16.0dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkTop(): 490.0px (186.66667dp)\n" +
+                    "\tgetCellLayoutSpringLoadShrunkBottom(): 1770.0px (674.2857dp)\n" +
+                    "\tworkspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)\n" +
+                    "\tgetWorkspaceSpringLoadScale(): 0.7437536px (0.2833347dp)\n" +
+                    "\tgetCellLayoutHeight(): 1721.0px (655.619dp)\n" +
+                    "\tgetCellLayoutWidth(): 899.0px (342.4762dp)\n"
+            )
+    }
+
+    private fun getDeviceProfileForGrid(gridName: String): DeviceProfile {
+        return InvariantDeviceProfile(context, gridName).getDeviceProfile(context)
+    }
+
+    private fun dump(dp: DeviceProfile): String {
+        val stringWriter = StringWriter()
+        val printWriter = PrintWriter(stringWriter)
+        dp.dump(context, "", printWriter)
+        printWriter.flush()
+        return stringWriter.toString()
+    }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 473cfb9..0197a11 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -67,6 +67,7 @@
             "Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_W"
                     + ".*?metaState=META_CTRL_ON");
     static final Pattern LONG_CLICK_EVENT = Pattern.compile("onWorkspaceItemLongClick");
+    public static final int MAX_WORKSPACE_DRAG_TRIES = 100;
 
     private final UiObject2 mHotseat;
 
@@ -430,6 +431,12 @@
                 TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
+    /** Returns the index of the current page */
+    static int geCurrentPage(LauncherInstrumentation launcher) {
+        return launcher.getTestInfo(TestProtocol.REQUEST_WORKSPACE_CURRENT_PAGE_INDEX).getInt(
+                TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
     /**
      * Finds folder icons in the current workspace.
      *
@@ -569,21 +576,10 @@
                     expectLongClickEvents,
                     /* runToSpringLoadedState= */ true);
             Point targetDest = getCellCenter(launcher, cellX, cellY, spanX, spanY);
-            int displayX = launcher.getRealDisplaySize().x;
-
             // Since the destination can be on another page, we need to drag to the edge first
             // until we reach the target page
-            for (int i = 0; i < destinationWorkspace; i++) {
-                // Don't drag all the way to the edge to prevent touch events from getting out of
-                //screen bounds.
-                Point screenEdge = new Point(displayX - 1, targetDest.y);
-                Point finalDragStart = dragStart;
-                executeAndWaitForPageScroll(launcher,
-                        () -> launcher.movePointer(finalDragStart, screenEdge, DEFAULT_DRAG_STEPS,
-                                true, downTime, downTime, true,
-                                LauncherInstrumentation.GestureScope.INSIDE));
-                dragStart = screenEdge;
-            }
+            dragStart = dragToGivenWorkspace(launcher, dragStart, destinationWorkspace,
+                    targetDest.y);
 
             // targetDest.x is now between 0 and displayX so we found the target page,
             // we just have to put move the icon to the destination and drop it
@@ -595,6 +591,45 @@
         }
     }
 
+    /**
+     * Given a drag that already started at currentPosition, drag the item to the given destination
+     * index defined by destinationWorkspaceIndex.
+     *
+     * @param launcher
+     * @param currentPosition
+     * @param destinationWorkspaceIndex
+     * @param y
+     * @return the finishing position of the drag.
+     */
+    static Point dragToGivenWorkspace(LauncherInstrumentation launcher, Point currentPosition,
+            int destinationWorkspaceIndex, int y) {
+        final long downTime = SystemClock.uptimeMillis();
+        int displayX = launcher.getRealDisplaySize().x;
+        int currentPage = Workspace.geCurrentPage(launcher);
+        int counter = 0;
+        while (currentPage != destinationWorkspaceIndex) {
+            counter++;
+            if (counter > MAX_WORKSPACE_DRAG_TRIES) {
+                throw new RuntimeException(
+                        "Wrong destination workspace index " + destinationWorkspaceIndex
+                                + ", desired workspace was never reached");
+            }
+            // if the destination is greater than current page, set the display edge to be the
+            // right edge. Don't drag all the way to the edge to prevent touch events from
+            // getting out of screen bounds.
+            int displayEdge = destinationWorkspaceIndex > currentPage ? displayX - 1 : 1;
+            Point screenEdge = new Point(displayEdge, y);
+            Point finalDragStart = currentPosition;
+            executeAndWaitForPageScroll(launcher,
+                    () -> launcher.movePointer(finalDragStart, screenEdge, DEFAULT_DRAG_STEPS,
+                            true, downTime, downTime, true,
+                            LauncherInstrumentation.GestureScope.INSIDE));
+            currentPage = Workspace.geCurrentPage(launcher);
+            currentPosition = screenEdge;
+        }
+        return currentPosition;
+    }
+
     private static void executeAndWaitForPageScroll(LauncherInstrumentation launcher,
             Runnable command) {
         launcher.executeAndWaitForEvent(command,