Merge "Convert px to dp for determining minWidth and minHeight for each row count, and add breakpoints" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 4ff976d..bc49146 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -536,4 +536,11 @@
     namespace: "launcher"
     description: "Add options to pin/unpin to taskbar to app context menus."
     bug: "375648361"
+}
+
+flag {
+  name: "enable_launcher_icon_shapes"
+  namespace: "launcher"
+  description: "Enable launcher icon shape customizations"
+  bug: "348708061"
 }
\ No newline at end of file
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index 823c821..ce99348 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -33,6 +33,7 @@
     FolderIcon folder_icon = 9;
     Slice slice = 10;
     SearchActionItem search_action_item = 11;
+    TaskView task_view = 15;
   }
   // When used for launch event, stores the global predictive rank
   optional int32 rank = 5;
@@ -262,6 +263,21 @@
   optional int32 index = 3;
 }
 
+// TaskView in RecentsView.
+message TaskView {
+  // TaskViewType.
+  optional int32 type = 1;
+
+  // Index of TaskView in RecentsView.
+  optional int32 index = 2;
+
+  // ComponentName of the Task.
+  optional string component_name = 3;
+
+  // Number of tasks in the TaskView.
+  optional int32 cardinality = 4;
+}
+
 // Represents folder in a closed state.
 message FolderIcon {
   // Number of items inside folder.
diff --git a/quickstep/res/color/all_set_bg_primary.xml b/quickstep/res/color/all_set_bg_primary.xml
index 013de7a..ce4fb47 100644
--- a/quickstep/res/color/all_set_bg_primary.xml
+++ b/quickstep/res/color/all_set_bg_primary.xml
@@ -15,5 +15,5 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?attr/materialColorPrimaryContainer"/>
+    <item android:color="@color/materialColorPrimaryContainer"/>
 </selector>
diff --git a/quickstep/res/color/all_set_bg_tertiary.xml b/quickstep/res/color/all_set_bg_tertiary.xml
index b58d61c..de4bab1 100644
--- a/quickstep/res/color/all_set_bg_tertiary.xml
+++ b/quickstep/res/color/all_set_bg_tertiary.xml
@@ -15,5 +15,5 @@
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:color="?attr/materialColorTertiary"/>
+    <item android:color="@color/materialColorTertiary"/>
 </selector>
diff --git a/quickstep/res/color/bubblebar_drop_target_bg_color.xml b/quickstep/res/color/bubblebar_drop_target_bg_color.xml
index bae8c4e..a91465f 100644
--- a/quickstep/res/color/bubblebar_drop_target_bg_color.xml
+++ b/quickstep/res/color/bubblebar_drop_target_bg_color.xml
@@ -15,5 +15,5 @@
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:alpha="0.35" android:color="?attr/materialColorPrimaryContainer" />
+    <item android:alpha="0.35" android:color="@color/materialColorPrimaryContainer" />
 </selector>
\ No newline at end of file
diff --git a/quickstep/res/color/menu_item_hover_state_color.xml b/quickstep/res/color/menu_item_hover_state_color.xml
index 3c68789..eb35769 100644
--- a/quickstep/res/color/menu_item_hover_state_color.xml
+++ b/quickstep/res/color/menu_item_hover_state_color.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <selector xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
-    <item android:state_hovered="false" android:color="?attr/materialColorSurfaceBright" />
-    <item android:state_hovered="true" android:color="?attr/materialColorSurfaceVariant" />
+    <item android:state_hovered="false" android:color="@color/materialColorSurfaceBright" />
+    <item android:state_hovered="true" android:color="@color/materialColorSurfaceVariant" />
 </selector>
\ No newline at end of file
diff --git a/quickstep/res/color/taskbar_minimized_app_indicator_color.xml b/quickstep/res/color/taskbar_minimized_app_indicator_color.xml
index 1596fe1..2703787 100644
--- a/quickstep/res/color/taskbar_minimized_app_indicator_color.xml
+++ b/quickstep/res/color/taskbar_minimized_app_indicator_color.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/materialColorOutline"/>
+    <item android:color="@color/materialColorOutline"/>
 </selector>
diff --git a/quickstep/res/color/taskbar_running_app_indicator_color.xml b/quickstep/res/color/taskbar_running_app_indicator_color.xml
index 5dc9781..7f2d12d 100644
--- a/quickstep/res/color/taskbar_running_app_indicator_color.xml
+++ b/quickstep/res/color/taskbar_running_app_indicator_color.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License.
   -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/materialColorTertiary"/>
+    <item android:color="@color/materialColorTertiary"/>
 </selector>
diff --git a/quickstep/res/drawable/bg_bubble_bar_drop_target.xml b/quickstep/res/drawable/bg_bubble_bar_drop_target.xml
index f597cb5..bf86a7f 100644
--- a/quickstep/res/drawable/bg_bubble_bar_drop_target.xml
+++ b/quickstep/res/drawable/bg_bubble_bar_drop_target.xml
@@ -20,5 +20,5 @@
     <solid android:color="@color/bubblebar_drop_target_bg_color" />
     <stroke
         android:width="1dp"
-        android:color="?attr/materialColorPrimaryContainer" />
+        android:color="@color/materialColorPrimaryContainer" />
 </shape>
diff --git a/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml b/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml
index 169e396..8fb5587 100644
--- a/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml
+++ b/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml
@@ -22,6 +22,6 @@
         <solid android:color="@color/bubblebar_drop_target_bg_color" />
         <stroke
             android:width="1dp"
-            android:color="?attr/materialColorPrimaryContainer" />
+            android:color="@color/materialColorPrimaryContainer" />
     </shape>
 </inset>
diff --git a/quickstep/res/drawable/bg_floating_desktop_select.xml b/quickstep/res/drawable/bg_floating_desktop_select.xml
index 6481be4..a707aab 100644
--- a/quickstep/res/drawable/bg_floating_desktop_select.xml
+++ b/quickstep/res/drawable/bg_floating_desktop_select.xml
@@ -19,5 +19,5 @@
     android:shape="rectangle">
 
     <corners android:radius="@dimen/rounded_button_radius" />
-    <solid android:color="?attr/materialColorPrimaryContainer" />
+    <solid android:color="@color/materialColorPrimaryContainer" />
 </shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/bg_overview_clear_all_button.xml b/quickstep/res/drawable/bg_overview_clear_all_button.xml
index 0d12274..7f58cf8 100644
--- a/quickstep/res/drawable/bg_overview_clear_all_button.xml
+++ b/quickstep/res/drawable/bg_overview_clear_all_button.xml
@@ -21,7 +21,7 @@
         <shape android:shape="rectangle"
             android:tint="?colorButtonNormal">
             <corners android:radius="@dimen/recents_clear_all_outline_radius" />
-            <solid android:color="?attr/materialColorSurfaceBright"/>
+            <solid android:color="@color/materialColorSurfaceBright"/>
         </shape>
     </item>
 </ripple>
\ No newline at end of file
diff --git a/quickstep/res/drawable/bg_taskbar_edu_tooltip.xml b/quickstep/res/drawable/bg_taskbar_edu_tooltip.xml
index 9e9bb2b..e2fe4c0 100644
--- a/quickstep/res/drawable/bg_taskbar_edu_tooltip.xml
+++ b/quickstep/res/drawable/bg_taskbar_edu_tooltip.xml
@@ -18,5 +18,5 @@
     android:shape="rectangle">
 
     <corners android:radius="@dimen/dialogCornerRadius" />
-    <solid android:color="?attr/materialColorSurfaceBright"/>
+    <solid android:color="@color/materialColorSurfaceBright"/>
 </shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/bg_wellbeing_toast.xml b/quickstep/res/drawable/bg_wellbeing_toast.xml
index 418caae..bb45bb3 100644
--- a/quickstep/res/drawable/bg_wellbeing_toast.xml
+++ b/quickstep/res/drawable/bg_wellbeing_toast.xml
@@ -16,6 +16,6 @@
 <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="?attr/materialColorSecondaryFixed" />
+    <solid android:color="@color/materialColorSecondaryFixed" />
     <corners android:radius="?android:attr/dialogCornerRadius" />
 </shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_chevron_down.xml b/quickstep/res/drawable/ic_chevron_down.xml
index b586e50..15f7fc8 100644
--- a/quickstep/res/drawable/ic_chevron_down.xml
+++ b/quickstep/res/drawable/ic_chevron_down.xml
@@ -19,7 +19,7 @@
     android:width="48dp"
     android:height="48dp"
     android:autoMirrored="true"
-    android:tint="?attr/materialColorOnSurface"
+    android:tint="@color/materialColorOnSurface"
     android:viewportHeight="48"
     android:viewportWidth="48">
     <group
diff --git a/quickstep/res/drawable/rotate_tutorial_warning.xml b/quickstep/res/drawable/rotate_tutorial_warning.xml
index 90b7d64..2d0c8d2 100644
--- a/quickstep/res/drawable/rotate_tutorial_warning.xml
+++ b/quickstep/res/drawable/rotate_tutorial_warning.xml
@@ -21,6 +21,6 @@
     android:viewportHeight="960"
     android:viewportWidth="960">
     <path
-        android:fillColor="?attr/materialColorOnSurface"
+        android:fillColor="@color/materialColorOnSurface"
         android:pathData="M40,840L480,80L920,840L40,840ZM178,760L782,760L480,240L178,760ZM480,720Q497,720 508.5,708.5Q520,697 520,680Q520,663 508.5,651.5Q497,640 480,640Q463,640 451.5,651.5Q440,663 440,680Q440,697 451.5,708.5Q463,720 480,720ZM440,600L520,600L520,400L440,400L440,600ZM480,500L480,500L480,500L480,500Z" />
 </vector>
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
index d1e5667..b44510d 100644
--- a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
@@ -23,7 +23,7 @@
     android:importantForAccessibility="yes"
     android:background="@drawable/keyboard_quick_switch_task_view_background"
     android:clipToOutline="true"
-    launcher:focusBorderColor="?attr/materialColorOutline">
+    launcher:focusBorderColor="@color/materialColorOutline">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
index 0eccd8e..56b1adf 100644
--- a/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview_square.xml
@@ -23,7 +23,7 @@
     android:importantForAccessibility="yes"
     android:background="@drawable/keyboard_quick_switch_task_view_background"
     android:clipToOutline="true"
-    launcher:focusBorderColor="?androidprv:attr/materialColorOutline">
+    launcher:focusBorderColor="@androidprv:color/materialColorOutline">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
diff --git a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
index 40d2322..0767aa5 100644
--- a/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout-sw600dp-land/gesture_tutorial_step_menu.xml
@@ -20,7 +20,7 @@
     android:theme="@style/GestureTutorialActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="?attr/materialColorSurfaceContainer"
+    android:background="@color/materialColorSurfaceContainer"
     android:fitsSystemWindows="true">
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -163,7 +163,7 @@
             android:layout_marginVertical="16dp"
             android:text="@string/gesture_tutorial_action_button_label"
             android:background="@drawable/gesture_tutorial_action_button_background"
-            android:backgroundTint="?attr/materialColorPrimary"
+            android:backgroundTint="@color/materialColorPrimary"
             android:stateListAnimator="@null"
 
             app:layout_constraintTop_toBottomOf="@id/guideline"
diff --git a/quickstep/res/layout/digital_wellbeing_toast.xml b/quickstep/res/layout/digital_wellbeing_toast.xml
index 0551c12..25676ac 100644
--- a/quickstep/res/layout/digital_wellbeing_toast.xml
+++ b/quickstep/res/layout/digital_wellbeing_toast.xml
@@ -24,7 +24,7 @@
     android:forceHasOverlappingRendering="false"
     android:gravity="center"
     android:importantForAccessibility="noHideDescendants"
-    android:textColor="?attr/materialColorOnSecondaryFixed"
+    android:textColor="@color/materialColorOnSecondaryFixed"
     android:textSize="14sp"
     android:autoSizeTextType="uniform"
     android:autoSizeMaxTextSize="14sp"
diff --git a/quickstep/res/layout/gesture_tutorial_step_menu.xml b/quickstep/res/layout/gesture_tutorial_step_menu.xml
index 7feb882..b4493c2 100644
--- a/quickstep/res/layout/gesture_tutorial_step_menu.xml
+++ b/quickstep/res/layout/gesture_tutorial_step_menu.xml
@@ -20,7 +20,7 @@
     android:theme="@style/GestureTutorialActivity"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="?attr/materialColorSurfaceContainer"
+    android:background="@color/materialColorSurfaceContainer"
     android:fitsSystemWindows="true">
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -161,7 +161,7 @@
             android:layout_marginVertical="16dp"
             android:text="@string/gesture_tutorial_action_button_label"
             android:background="@drawable/gesture_tutorial_action_button_background"
-            android:backgroundTint="?attr/materialColorPrimary"
+            android:backgroundTint="@color/materialColorPrimary"
             android:stateListAnimator="@null"
 
             app:layout_constraintTop_toBottomOf="@id/guideline"
diff --git a/quickstep/res/layout/icon_app_chip_view.xml b/quickstep/res/layout/icon_app_chip_view.xml
index 36ece2a..00b5392 100644
--- a/quickstep/res/layout/icon_app_chip_view.xml
+++ b/quickstep/res/layout/icon_app_chip_view.xml
@@ -26,7 +26,7 @@
     android:importantForAccessibility="no"
     android:autoMirrored="true"
     android:elevation="@dimen/task_thumbnail_icon_menu_elevation"
-    android:background="?attr/materialColorSurfaceBright">
+    android:background="@color/materialColorSurfaceBright">
 
     <!-- ignoring warning because the user of the anchor is a Rect where RTL is not needed -->
     <!-- This anchor's bounds is in the expected location after rotations and translations are
diff --git a/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
index c3f9e54..71c782d 100644
--- a/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_desktop_taskview.xml
@@ -22,7 +22,7 @@
     android:layout_height="wrap_content"
     android:clipToOutline="true"
     android:importantForAccessibility="yes"
-    launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
+    launcher:focusBorderColor="@androidprv:color/materialColorOutline"
     launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius">
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -30,7 +30,7 @@
         android:layout_width="@dimen/keyboard_quick_switch_text_button_width"
         android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
         android:background="@drawable/keyboard_quick_switch_text_button_background"
-        android:backgroundTint="?androidprv:attr/materialColorSurfaceContainer"
+        android:backgroundTint="@androidprv:color/materialColorSurfaceContainer"
         android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding"
 
         app:layout_constraintTop_toTopOf="parent"
@@ -43,7 +43,7 @@
             android:layout_width="@dimen/keyboard_quick_switch_desktop_icon_size"
             android:layout_height="@dimen/keyboard_quick_switch_desktop_icon_size"
             android:layout_marginBottom="4dp"
-            android:tint="?androidprv:attr/materialColorOnSurface"
+            android:tint="@androidprv:color/materialColorOnSurface"
             android:src="@drawable/ic_desktop"
 
             app:layout_constraintVertical_chainStyle="packed"
diff --git a/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
index 0b44a2a..5a3ee83 100644
--- a/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_overview_taskview.xml
@@ -22,7 +22,7 @@
     android:layout_height="wrap_content"
     android:clipToOutline="true"
     android:importantForAccessibility="yes"
-    launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
+    launcher:focusBorderColor="@androidprv:color/materialColorOutline"
     launcher:focusBorderRadius="@dimen/keyboard_quick_switch_text_button_radius">
 
     <androidx.constraintlayout.widget.ConstraintLayout
@@ -30,7 +30,7 @@
         android:layout_width="@dimen/keyboard_quick_switch_text_button_width"
         android:layout_height="@dimen/keyboard_quick_switch_taskview_height"
         android:background="@drawable/keyboard_quick_switch_text_button_background"
-        android:backgroundTint="?androidprv:attr/materialColorSurfaceBright"
+        android:backgroundTint="@androidprv:color/materialColorSurfaceBright"
         android:paddingHorizontal="@dimen/keyboard_quick_switch_text_button_horizontal_padding"
 
         app:layout_constraintTop_toTopOf="parent"
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
index 41eb623..37bb027 100644
--- a/quickstep/res/layout/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
@@ -23,7 +23,7 @@
     android:importantForAccessibility="yes"
     android:background="@drawable/keyboard_quick_switch_task_view_background"
     android:clipToOutline="true"
-    launcher:focusBorderColor="?attr/materialColorOutline">
+    launcher:focusBorderColor="@color/materialColorOutline">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
index 1474949..33d8c16 100644
--- a/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview_square.xml
@@ -23,7 +23,7 @@
     android:importantForAccessibility="yes"
     android:background="@drawable/keyboard_quick_switch_task_view_background"
     android:clipToOutline="true"
-    launcher:focusBorderColor="?androidprv:attr/materialColorOutline">
+    launcher:focusBorderColor="@androidprv:color/materialColorOutline">
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/content"
diff --git a/quickstep/res/layout/keyboard_quick_switch_view.xml b/quickstep/res/layout/keyboard_quick_switch_view.xml
index 4118500..345b97c 100644
--- a/quickstep/res/layout/keyboard_quick_switch_view.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_view.xml
@@ -44,7 +44,7 @@
             android:layout_height="@dimen/keyboard_quick_switch_no_recent_items_icon_size"
             android:layout_marginBottom="@dimen/keyboard_quick_switch_no_recent_items_icon_margin"
             android:src="@drawable/view_carousel"
-            android:tint="?attr/materialColorOnSurface"
+            android:tint="@color/materialColorOnSurface"
             android:importantForAccessibility="no"
 
             app:layout_constraintVertical_chainStyle="packed"
diff --git a/quickstep/res/layout/overview_clear_all_button.xml b/quickstep/res/layout/overview_clear_all_button.xml
index 40f38f4..18a6240 100644
--- a/quickstep/res/layout/overview_clear_all_button.xml
+++ b/quickstep/res/layout/overview_clear_all_button.xml
@@ -23,6 +23,6 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:text="@string/recents_clear_all"
-    android:textColor="?attr/materialColorOnSurface"
-    launcher:focusBorderColor="?attr/materialColorOutline"
+    android:textColor="@color/materialColorOnSurface"
+    launcher:focusBorderColor="@color/materialColorOutline"
     android:textSize="14sp" />
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 760bcdb..a7f6b36 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -25,8 +25,8 @@
     android:clipChildren="false"
     android:defaultFocusHighlightEnabled="false"
     android:focusable="true"
-    launcher:focusBorderColor="?attr/materialColorOutline"
-    launcher:hoverBorderColor="?attr/materialColorPrimary">
+    launcher:focusBorderColor="@color/materialColorOutline"
+    launcher:hoverBorderColor="@color/materialColorPrimary">
 
     <include layout="@layout/task_thumbnail_deprecated" />
 
diff --git a/quickstep/res/layout/task_desktop.xml b/quickstep/res/layout/task_desktop.xml
index 5270284..fb515be 100644
--- a/quickstep/res/layout/task_desktop.xml
+++ b/quickstep/res/layout/task_desktop.xml
@@ -22,8 +22,8 @@
     android:contentDescription="@string/recent_task_desktop"
     android:defaultFocusHighlightEnabled="false"
     android:focusable="true"
-    launcher:focusBorderColor="?attr/materialColorOutline"
-    launcher:hoverBorderColor="?attr/materialColorPrimary">
+    launcher:focusBorderColor="@color/materialColorOutline"
+    launcher:hoverBorderColor="@color/materialColorPrimary">
 
     <ViewStub
         android:id="@+id/icon"
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index c36a45e..4c650b9 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -30,8 +30,8 @@
     android:clipChildren="false"
     android:defaultFocusHighlightEnabled="false"
     android:focusable="true"
-    launcher:focusBorderColor="?attr/materialColorOutline"
-    launcher:hoverBorderColor="?attr/materialColorPrimary">
+    launcher:focusBorderColor="@color/materialColorOutline"
+    launcher:hoverBorderColor="@color/materialColorPrimary">
 
     <include layout="@layout/task_thumbnail_deprecated"/>
 
diff --git a/quickstep/res/layout/task_view_menu_option.xml b/quickstep/res/layout/task_view_menu_option.xml
index 5218de0..91051f0 100644
--- a/quickstep/res/layout/task_view_menu_option.xml
+++ b/quickstep/res/layout/task_view_menu_option.xml
@@ -31,7 +31,7 @@
       android:layout_height="@dimen/system_shortcut_icon_size"
       android:layout_marginStart="@dimen/task_menu_option_start_margin"
       android:layout_gravity="center_horizontal"
-      android:backgroundTint="?attr/materialColorOnSurface"/>
+      android:backgroundTint="@color/materialColorOnSurface"/>
 
     <TextView
         style="@style/BaseIcon"
@@ -40,7 +40,7 @@
         android:layout_height="wrap_content"
         android:layout_marginStart="@dimen/task_menu_option_text_start_margin"
         android:textSize="14sp"
-        android:textColor="?attr/materialColorOnSurface"
+        android:textColor="@color/materialColorOnSurface"
         android:focusable="false"
         android:gravity="start"
         android:ellipsize="end" />
diff --git a/quickstep/res/values-night/colors.xml b/quickstep/res/values-night/colors.xml
index a1e9c70..7cb85bc 100644
--- a/quickstep/res/values-night/colors.xml
+++ b/quickstep/res/values-night/colors.xml
@@ -25,5 +25,5 @@
     <color name="all_set_page_background">@android:color/system_neutral1_900</color>
 
     <!-- Turn on work apps button -->
-    <color name="work_turn_on_stroke">?attr/materialColorPrimary</color>
+    <color name="work_turn_on_stroke">@color/materialColorPrimary</color>
 </resources>
\ No newline at end of file
diff --git a/quickstep/res/values-night/styles.xml b/quickstep/res/values-night/styles.xml
index eb88310..0a5e0af 100644
--- a/quickstep/res/values-night/styles.xml
+++ b/quickstep/res/values-night/styles.xml
@@ -73,16 +73,16 @@
     <style name="GestureTutorialActivity" parent="@style/AppTheme">
         <item name="background">@android:color/transparent</item>
         <item name="tutorialSubtitle">@android:color/white</item>
-        <item name="surfaceContainer">?attr/materialColorSurfaceContainer</item>
-        <item name="onSurfaceHome">?attr/materialColorPrimaryFixedDim</item>
-        <item name="surfaceHome">?attr/materialColorOnPrimaryFixedVariant</item>
-        <item name="secondaryHome">?attr/materialColorOnPrimaryFixed</item>
-        <item name="onSurfaceBack">?attr/materialColorTertiaryFixedDim</item>
-        <item name="surfaceBack">?attr/materialColorOnTertiaryFixedVariant</item>
-        <item name="secondaryBack">?attr/materialColorOnTertiaryFixed</item>
-        <item name="onSurfaceOverview">?attr/materialColorPrimaryFixed</item>
-        <item name="surfaceOverview">?attr/materialColorOnSecondaryFixedVariant</item>
-        <item name="secondaryOverview">?attr/materialColorOnSecondaryFixed</item>
+        <item name="surfaceContainer">@color/materialColorSurfaceContainer</item>
+        <item name="onSurfaceHome">@color/materialColorPrimaryFixedDim</item>
+        <item name="surfaceHome">@color/materialColorOnPrimaryFixedVariant</item>
+        <item name="secondaryHome">@color/materialColorOnPrimaryFixed</item>
+        <item name="onSurfaceBack">@color/materialColorTertiaryFixedDim</item>
+        <item name="surfaceBack">@color/materialColorOnTertiaryFixedVariant</item>
+        <item name="secondaryBack">@color/materialColorOnTertiaryFixed</item>
+        <item name="onSurfaceOverview">@color/materialColorPrimaryFixed</item>
+        <item name="surfaceOverview">@color/materialColorOnSecondaryFixedVariant</item>
+        <item name="secondaryOverview">@color/materialColorOnSecondaryFixed</item>
     </style>
 
 </resources>
\ No newline at end of file
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 668bce7..42c0478 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -13,7 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+<resources>
 
     <color name="chip_hint_foreground_color">#fff</color>
     <color name="chip_scrim_start_color">#39000000</color>
@@ -93,5 +93,5 @@
     <color name="lottie_yellow600">#f9ab00</color>
 
     <!-- Turn on work apps button -->
-    <color name="work_turn_on_stroke">?attr/materialColorPrimary</color>
+    <color name="work_turn_on_stroke">@color/materialColorPrimary</color>
 </resources>
\ No newline at end of file
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 6ffcb9b..5f2a63d 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -124,7 +124,7 @@
     <style name="TextAppearance.GestureTutorial.ButtonLabel"
         parent="TextAppearance.GestureTutorial.CallToAction">
         <item name="android:gravity">center</item>
-        <item name="android:textColor">?attr/materialColorOnPrimary</item>
+        <item name="android:textColor">@color/materialColorOnPrimary</item>
         <item name="android:letterSpacing">0.02</item>
         <item name="android:textSize">16sp</item>
         <item name="android:textAllCaps">false</item>
@@ -269,7 +269,7 @@
     <style name="KeyboardQuickSwitchText">
         <item name="fontFamily">google-sans-text</item>
         <item name="android:textSize">14sp</item>
-        <item name="android:textColor">?attr/materialColorOnSurface</item>
+        <item name="android:textColor">@color/materialColorOnSurface</item>
         <item name="lineHeight">20sp</item>
     </style>
 
@@ -278,7 +278,7 @@
     </style>
 
     <style name="KeyboardQuickSwitchText.OnBackground" parent="KeyboardQuickSwitchText">
-        <item name="android:textColor">?attr/materialColorOnSurface</item>
+        <item name="android:textColor">@color/materialColorOnSurface</item>
     </style>
 
     <style name="KeyboardQuickSwitchText.OnTaskView" parent="KeyboardQuickSwitchText">
@@ -292,35 +292,35 @@
     <style name="GestureTutorialActivity" parent="@style/AppTheme">
         <item name="background">@android:color/transparent</item>
         <item name="tutorialSubtitle">@android:color/black</item>
-        <item name="surfaceContainer">?attr/materialColorSurfaceContainer</item>
-        <item name="onSurfaceHome">?attr/materialColorPrimaryFixed</item>
+        <item name="surfaceContainer">@color/materialColorSurfaceContainer</item>
+        <item name="onSurfaceHome">@color/materialColorPrimaryFixed</item>
         <item name="surfaceHome">@android:color/system_accent1_300</item>
-        <item name="secondaryHome">?attr/materialColorOnPrimaryFixedVariant</item>
-        <item name="onSurfaceBack">?attr/materialColorTertiaryFixed</item>
+        <item name="secondaryHome">@color/materialColorOnPrimaryFixedVariant</item>
+        <item name="onSurfaceBack">@color/materialColorTertiaryFixed</item>
         <item name="surfaceBack">@android:color/system_accent3_300</item>
-        <item name="secondaryBack">?attr/materialColorOnTertiaryFixedVariant</item>
-        <item name="onSurfaceOverview">?attr/materialColorPrimaryFixed</item>
+        <item name="secondaryBack">@color/materialColorOnTertiaryFixedVariant</item>
+        <item name="onSurfaceOverview">@color/materialColorPrimaryFixed</item>
         <item name="surfaceOverview">@android:color/system_accent2_300</item>
-        <item name="secondaryOverview">?attr/materialColorOnSecondaryFixedVariant</item>
+        <item name="secondaryOverview">@color/materialColorOnSecondaryFixedVariant</item>
     </style>
 
     <style name="rotate_prompt_title" parent="TextAppearance.GestureTutorial.Dialog.Title">
-        <item name="android:textColor">?attr/materialColorOnSurface</item>
+        <item name="android:textColor">@color/materialColorOnSurface</item>
     </style>
 
     <style name="rotate_prompt_subtitle" parent="TextAppearance.GestureTutorial.Dialog.Subtitle">
-        <item name="android:textColor">?attr/materialColorOnSurfaceVariant</item>
+        <item name="android:textColor">@color/materialColorOnSurfaceVariant</item>
     </style>
 
     <style name="ArrowTipTaskbarStyle">
-        <item name="arrowTipBackground">?attr/materialColorSurfaceContainer</item>
-        <item name="arrowTipTextColor">?attr/materialColorOnSurface</item>
+        <item name="arrowTipBackground">@color/materialColorSurfaceContainer</item>
+        <item name="arrowTipTextColor">@color/materialColorOnSurface</item>
     </style>
 
     <style name="IconAppChipMenuTextStyle">
         <item name="android:fontFamily">google-sans-text-medium</item>
         <item name="android:textSize">@dimen/task_thumbnail_icon_menu_text_size</item>
-        <item name="android:textColor">?attr/materialColorOnSurface</item>
+        <item name="android:textColor">@color/materialColorOnSurface</item>
         <item name="android:letterSpacing">0.025</item>
         <item name="android:lineHeight">20sp</item>
     </style>
diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
index 32fda48..e1e3eec 100644
--- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -37,7 +37,6 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.FloatingHeaderRow;
 import com.android.launcher3.allapps.FloatingHeaderView;
-import com.android.launcher3.util.Themes;
 
 /**
  * A view which shows a horizontal divider
@@ -85,9 +84,9 @@
                 getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height)
         };
 
-        mStrokeColor = Themes.getAttrColor(context, R.attr.materialColorOutlineVariant);
+        mStrokeColor = context.getColor(R.color.materialColorOutlineVariant);
 
-        mAllAppsLabelTextColor = Themes.getAttrColor(context, R.attr.materialColorOnSurfaceVariant);
+        mAllAppsLabelTextColor = context.getColor(R.color.materialColorOnSurfaceVariant);
 
         mAccessibilityManager = AccessibilityManager.getInstance(context);
         setShowAllAppsLabel(!ALL_APPS_VISITED_COUNT.hasReachedMax(context));
diff --git a/quickstep/src/com/android/launcher3/model/data/TaskViewItemInfo.kt b/quickstep/src/com/android/launcher3/model/data/TaskViewItemInfo.kt
new file mode 100644
index 0000000..ee28d7a
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/model/data/TaskViewItemInfo.kt
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model.data
+
+import android.content.Context
+import android.content.Intent
+import androidx.annotation.VisibleForTesting
+import androidx.annotation.VisibleForTesting.Companion.PRIVATE
+import com.android.launcher3.Flags.privateSpaceRestrictAccessibilityDrag
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.logger.LauncherAtom
+import com.android.launcher3.pm.UserCache
+import com.android.quickstep.TaskUtils
+import com.android.quickstep.views.TaskContainer
+
+class TaskViewItemInfo(taskContainer: TaskContainer) : WorkspaceItemInfo() {
+    @VisibleForTesting(otherwise = PRIVATE) val taskViewAtom: LauncherAtom.TaskView
+
+    init {
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_TASK
+        container = LauncherSettings.Favorites.CONTAINER_TASKSWITCHER
+        val componentKey = TaskUtils.getLaunchComponentKeyForTask(taskContainer.task.key)
+        user = componentKey.user
+        intent = Intent().setComponent(componentKey.componentName)
+        title = taskContainer.task.title
+        if (privateSpaceRestrictAccessibilityDrag()) {
+            if (
+                UserCache.getInstance(taskContainer.taskView.context)
+                    .getUserInfo(componentKey.user)
+                    .isPrivate
+            ) {
+                runtimeStatusFlags = runtimeStatusFlags or ItemInfoWithIcon.FLAG_NOT_PINNABLE
+            }
+        }
+
+        taskViewAtom =
+            createTaskViewAtom(
+                type = taskContainer.taskView.type.ordinal,
+                index =
+                    taskContainer.taskView.recentsView?.indexOfChild(taskContainer.taskView) ?: -1,
+                componentName = componentKey.componentName.flattenToShortString(),
+                cardinality = taskContainer.taskView.taskContainers.size,
+            )
+    }
+
+    override fun buildProto(cInfo: CollectionInfo?, context: Context): LauncherAtom.ItemInfo =
+        super.buildProto(cInfo, context).toBuilder().setTaskView(taskViewAtom).build()
+
+    companion object {
+        @VisibleForTesting(otherwise = PRIVATE)
+        fun createTaskViewAtom(
+            type: Int,
+            index: Int,
+            componentName: String,
+            cardinality: Int,
+        ): LauncherAtom.TaskView =
+            LauncherAtom.TaskView.newBuilder()
+                .apply {
+                    this.type = type
+                    this.index = index
+                    this.componentName = componentName
+                    this.cardinality = cardinality
+                }
+                .build()
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt b/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt
index aaa4044..8d1f4f5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt
@@ -164,7 +164,7 @@
     ) :
         ManageWindowsViewContainer(
             originalView.context,
-            Themes.getAttrColor(originalView.context, R.attr.materialColorSurfaceBright),
+            originalView.context.getColor(R.color.materialColorSurfaceBright),
         ),
         TouchController {
         private val taskbarActivityContext = controllers.taskbarActivityContext
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index f346e19..cb4e5e2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -1314,7 +1314,8 @@
             // If the task bar is not start aligned, the navigation bar is located in the center
             // between the taskbar and screen edges, depending on the bubble bar location.
             float navbarWidth = mNavButtonContainer.getWidth();
-            Rect taskbarBounds = mControllers.taskbarViewController.getIconLayoutBounds();
+            Rect taskbarBounds = mControllers.taskbarViewController
+                    .getTransientTaskbarIconLayoutBoundsInParent();
             if (isNavbarOnRight) {
                 if (mNavButtonsView.isLayoutRtl()) {
                     float taskBarEnd = taskbarBounds.right;
@@ -1334,8 +1335,10 @@
     public void onLayoutsUpdated() {
         // no need to do anything if on phone, or if taskbar or navbar views were not placed on
         // screen.
+        Rect transientTaskbarIconLayoutBoundsInParent = mControllers.taskbarViewController
+                .getTransientTaskbarIconLayoutBoundsInParent();
         if (mContext.getDeviceProfile().isPhone
-                || mControllers.taskbarViewController.getIconLayoutBounds().isEmpty()
+                || transientTaskbarIconLayoutBoundsInParent.isEmpty()
                 || mNavButtonsView.getWidth() == 0) {
             return;
         }
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index eb47bb0..b6b090c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -212,7 +212,8 @@
      * morphs into the size of where the taskbar icons will be.
      */
     public Animator createRevealAnimToIsStashed(boolean isStashed) {
-        Rect visualBounds = mControllers.taskbarViewController.getIconLayoutVisualBounds();
+        Rect visualBounds = mControllers.taskbarViewController
+                .getTransientTaskbarIconLayoutBounds();
         float startRadius = mStashedHandleRadius;
 
         if (DisplayController.isTransientTaskbar(mActivity)) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 8149f81..70c61ff 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -301,7 +301,8 @@
             BubbleStashController bubbleStashController = isTransientTaskbar
                     ? new TransientBubbleStashController(dimensionsProvider, this)
                     : new PersistentBubbleStashController(dimensionsProvider);
-            bubbleStashController.setHotseatVerticalCenter(launcherDp.getHotseatVerticalCenter());
+            bubbleStashController.setBubbleBarVerticalCenterForHome(
+                    launcherDp.getBubbleBarVerticalCenterForHome());
             bubbleControllersOptional = Optional.of(new BubbleControllers(
                     new BubbleBarController(this, bubbleBarView),
                     new BubbleBarViewController(this, bubbleBarView, bubbleBarContainer),
@@ -369,8 +370,9 @@
         applyDeviceProfile(launcherDp);
         mControllers.taskbarOverlayController.updateLauncherDeviceProfile(launcherDp);
         mControllers.bubbleControllers.ifPresent(bubbleControllers -> {
-            int hotseatVertCenter = launcherDp.getHotseatVerticalCenter();
-            bubbleControllers.bubbleStashController.setHotseatVerticalCenter(hotseatVertCenter);
+            int bubbleBarVerticalCenter = launcherDp.getBubbleBarVerticalCenterForHome();
+            bubbleControllers.bubbleStashController
+                    .setBubbleBarVerticalCenterForHome(bubbleBarVerticalCenter);
         });
         AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE);
         // Reapply fullscreen to take potential new screen size into account.
@@ -1136,6 +1138,10 @@
             return getSetupWindowSize();
         }
 
+        int bubbleBarTop = mControllers.bubbleControllers.map(bubbleControllers ->
+                bubbleControllers.bubbleBarViewController.getBubbleBarWithFlyoutMaximumHeight()
+        ).orElse(0);
+        int taskbarWindowSize;
         boolean shouldTreatAsTransient = DisplayController.isTransientTaskbar(this)
                 || (enableTaskbarPinning() && !isThreeButtonNav());
 
@@ -1152,16 +1158,18 @@
             DeviceProfile transientTaskbarDp = mDeviceProfile.toBuilder(this)
                     .setIsTransientTaskbar(true).build();
 
-            return transientTaskbarDp.taskbarHeight
+            taskbarWindowSize = transientTaskbarDp.taskbarHeight
                     + (2 * transientTaskbarDp.taskbarBottomMargin)
                     + Math.max(extraHeightForTaskbarTooltips, resources.getDimensionPixelSize(
                     R.dimen.transient_taskbar_shadow_blur));
+            return Math.max(taskbarWindowSize, bubbleBarTop);
         }
 
 
-        return mDeviceProfile.taskbarHeight
+        taskbarWindowSize =  mDeviceProfile.taskbarHeight
                 + getCornerRadius()
                 + extraHeightForTaskbarTooltips;
+        return Math.max(taskbarWindowSize, bubbleBarTop);
     }
 
     public int getSetupWindowSize() {
@@ -1634,15 +1642,6 @@
         mControllers.taskbarEduTooltipController.hide();
     }
 
-    /**
-     * Called when we want to open bubblebar when user performs swipes up gesture.
-     */
-    public void onSwipeToOpenBubblebar() {
-        mControllers.bubbleControllers.ifPresent(controllers -> {
-            controllers.bubbleStashController.showBubbleBar(/* expandBubbles= */ true);
-        });
-    }
-
     /** Returns {@code true} if Taskbar All Apps is open. */
     public boolean isTaskbarAllAppsOpen() {
         return mControllers.taskbarAllAppsController.isOpen();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt
index 19e9872..d85dd50 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt
@@ -45,15 +45,12 @@
 /** Floating tooltip for Taskbar education. */
 class TaskbarEduTooltip
 @JvmOverloads
-constructor(
-    context: Context,
-    attrs: AttributeSet? = null,
-    defStyleAttr: Int = 0,
-) : AbstractFloatingView(context, attrs, defStyleAttr) {
+constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
+    AbstractFloatingView(context, attrs, defStyleAttr) {
 
     private val activityContext: ActivityContext = ActivityContext.lookupContext(context)
 
-    private val backgroundColor = Themes.getAttrColor(context, R.attr.materialColorSurfaceBright)
+    private val backgroundColor = context.getColor(R.color.materialColorSurfaceBright)
 
     private val tooltipCornerRadius = Themes.getDialogCornerRadius(context)
     private val arrowWidth = resources.getDimension(R.dimen.popup_arrow_width)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index f2355b8..130b9b7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -389,6 +389,10 @@
         if (!(view.getTag() instanceof CollectionInfo)) {
             mActivityContext.getViewCache().recycleView(view.getSourceLayoutResId(), view);
         }
+        if (view instanceof FolderIcon fi) {
+            // We should clear FolderInfo's Folder and FolderIcon to avoid memory leak.
+            fi.removeListeners();
+        }
         view.setTag(null);
     }
 
@@ -760,7 +764,7 @@
         ) {
             return 0;
         }
-        Rect iconsBounds = getIconLayoutBounds();
+        Rect iconsBounds = getTransientTaskbarIconLayoutBoundsInParent();
         return getTaskBarIconsEndForBubbleBarLocation(location) - iconsBounds.right;
     }
 
@@ -888,26 +892,46 @@
     }
 
     /**
-     * Returns whether the given MotionEvent, *in screen coorindates*, is within any Taskbar item's
+     * Returns whether the given MotionEvent, *in screen coordinates*, is within any Taskbar item's
      * touch bounds.
      */
     public boolean isEventOverAnyItem(MotionEvent ev) {
         getLocationOnScreen(mTempOutLocation);
-        int xInOurCoordinates = (int) ev.getX() - mTempOutLocation[0];
-        int yInOurCoorindates = (int) ev.getY() - mTempOutLocation[1];
-        return isShown() && mIconLayoutBounds.contains(xInOurCoordinates, yInOurCoorindates);
+        int xInOurCoordinates = (int) ev.getRawX() - mTempOutLocation[0];
+        int yInOurCoordinates = (int) ev.getRawY() - mTempOutLocation[1];
+        return isShown() && getTaskbarIconsActualBounds().contains(xInOurCoordinates,
+                yInOurCoordinates);
+    }
+
+    /**
+     * Returns the current visual taskbar icons bounds (unlike `mIconLayoutBounds` which contains
+     * bounds for transient mode only).
+     */
+    private Rect getTaskbarIconsActualBounds() {
+        View[] iconViews = getIconViews();
+        if (iconViews.length == 0) {
+            return new Rect();
+        }
+
+        int[] firstIconViewLocation = new int[2];
+        int[] lastIconViewLocation = new int[2];
+        iconViews[0].getLocationOnScreen(firstIconViewLocation);
+        iconViews[iconViews.length - 1].getLocationOnScreen(lastIconViewLocation);
+
+        return new Rect(firstIconViewLocation[0], 0, lastIconViewLocation[0] + mIconTouchSize,
+                getHeight());
     }
 
     /**
      * Gets visual bounds of the taskbar view. The visual bounds correspond to the taskbar touch
      * area, rather than layout placement in the parent view.
      */
-    public Rect getIconLayoutVisualBounds() {
+    public Rect getTransientTaskbarIconLayoutBounds() {
         return new Rect(mIconLayoutBounds);
     }
 
     /** Gets taskbar layout bounds in parent view. */
-    public Rect getIconLayoutBounds() {
+    public Rect getTransientTaskbarIconLayoutBoundsInParent() {
         Rect actualBounds = new Rect(mIconLayoutBounds);
         actualBounds.top = getTop();
         actualBounds.bottom = getBottom();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index f65f307..4d77ab2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -91,6 +91,7 @@
     public View.OnTouchListener getTaskbarDividerRightClickListener() {
         return (v, event) -> {
             if (event.isFromSource(InputDevice.SOURCE_MOUSE)
+                    && event.getAction() == MotionEvent.ACTION_DOWN
                     && event.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
                 mControllers.taskbarPinningController.showPinningView(v, getDividerCenterX());
                 return true;
@@ -202,6 +203,10 @@
     private class TaskbarViewGestureListener extends GestureDetector.SimpleOnGestureListener {
         @Override
         public boolean onDown(@NonNull MotionEvent event) {
+            if (event.isFromSource(InputDevice.SOURCE_MOUSE)
+                    && event.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
+                maybeShowPinningView(event);
+            }
             return true;
         }
 
@@ -211,11 +216,16 @@
         }
 
         @Override
-        public void onLongPress(MotionEvent event) {
-            if (DisplayController.isPinnedTaskbar(mActivity)) {
-                mControllers.taskbarPinningController.showPinningView(mTaskbarView,
-                        event.getRawX());
+        public void onLongPress(@NonNull MotionEvent event) {
+            maybeShowPinningView(event);
+        }
+
+        private void maybeShowPinningView(@NonNull MotionEvent event) {
+            if (!DisplayController.isPinnedTaskbar(mActivity) || mTaskbarView.isEventOverAnyItem(
+                    event)) {
+                return;
             }
+            mControllers.taskbarPinningController.showPinningView(mTaskbarView, event.getRawX());
         }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index bc5f9a3..4acf2fe 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -356,12 +356,12 @@
         return mTaskbarView.getMaxNumIconViews();
     }
 
-    public Rect getIconLayoutVisualBounds() {
-        return mTaskbarView.getIconLayoutVisualBounds();
+    public Rect getTransientTaskbarIconLayoutBounds() {
+        return mTaskbarView.getTransientTaskbarIconLayoutBounds();
     }
 
-    public Rect getIconLayoutBounds() {
-        return mTaskbarView.getIconLayoutBounds();
+    public Rect getTransientTaskbarIconLayoutBoundsInParent() {
+        return mTaskbarView.getTransientTaskbarIconLayoutBoundsInParent();
     }
 
     public View[] getIconViews() {
@@ -559,14 +559,14 @@
         if (mControllers.getSharedState().startTaskbarVariantIsTransient) {
             float transY =
                     mTransientTaskbarDp.taskbarBottomMargin + (mTransientTaskbarDp.taskbarHeight
-                            - mTaskbarView.getIconLayoutVisualBounds().bottom)
+                            - mTaskbarView.getTransientTaskbarIconLayoutBounds().bottom)
                             - (mPersistentTaskbarDp.taskbarHeight
                                     - mTransientTaskbarDp.taskbarIconSize) / 2f;
             taskbarIconTranslationYForPinningValue = mapRange(scale, 0f, transY);
         } else {
             float transY =
                     -mTransientTaskbarDp.taskbarBottomMargin + (mPersistentTaskbarDp.taskbarHeight
-                            - mTaskbarView.getIconLayoutVisualBounds().bottom)
+                            - mTaskbarView.getTransientTaskbarIconLayoutBounds().bottom)
                             - (mTransientTaskbarDp.taskbarHeight
                                     - mTransientTaskbarDp.taskbarIconSize) / 2f;
             taskbarIconTranslationYForPinningValue = mapRange(scale, transY, 0f);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarParentViewHeightUpdateNotifier.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarParentViewHeightUpdateNotifier.kt
new file mode 100644
index 0000000..f69ad74
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarParentViewHeightUpdateNotifier.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles
+
+/** Controls the parent view height. */
+interface BubbleBarParentViewHeightUpdateNotifier {
+
+    /** Notify parent that top boundary should be updated. */
+    fun updateTopBoundary()
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeController.kt
index 2d3642b..4b8924c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeController.kt
@@ -91,7 +91,7 @@
         when {
             canUnstash() && swipeState.passedUnstash -> {
                 swipeState.currentState = COLLAPSED
-                bubbleStashController.showBubbleBar(expandBubbles = false)
+                bubbleStashController.showBubbleBar(expandBubbles = false, bubbleBarGesture = true)
             }
             canStash() && !swipeState.passedUnstash -> {
                 swipeState.currentState = STASHED
@@ -103,7 +103,7 @@
     /** Finish tracking swipe gesture. Animate views back to resting state */
     fun finish() {
         if (swipeState.passedUnstash && swipeState.startState in setOf(STASHED, COLLAPSED)) {
-            bubbleStashController.showBubbleBar(expandBubbles = true)
+            bubbleStashController.showBubbleBar(expandBubbles = true, bubbleBarGesture = true)
         }
         if (animatedSwipeTranslation.value == 0f) {
             reset()
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 833be61..219a2b3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -381,6 +381,7 @@
         super.onInitializeAccessibilityNodeInfoInternal(info);
         // Always show only expand action as the menu is only for collapsed bubble bar
         info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_EXPAND);
+        info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
         info.addAction(new AccessibilityNodeInfo.AccessibilityAction(R.id.action_dismiss_all,
                 getResources().getString(R.string.bubble_bar_action_dismiss_all)));
         if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
@@ -395,10 +396,8 @@
     @Override
     public boolean performAccessibilityActionInternal(int action,
             @androidx.annotation.Nullable Bundle arguments) {
-        if (super.performAccessibilityActionInternal(action, arguments)) {
-            return true;
-        }
-        if (action == AccessibilityNodeInfo.ACTION_EXPAND) {
+        if (action == AccessibilityNodeInfo.ACTION_EXPAND
+                || action == AccessibilityNodeInfo.ACTION_CLICK) {
             mController.expandBubbleBar();
             return true;
         }
@@ -416,7 +415,7 @@
                     BubbleBarLocation.UpdateSource.A11Y_ACTION_BAR);
             return true;
         }
-        return false;
+        return super.performAccessibilityActionInternal(action, arguments);
     }
 
     @SuppressLint("RtlHardcoded")
@@ -1307,6 +1306,10 @@
         return getBubbleBarCollapsedHeight() + mPointerSize;
     }
 
+    float getArrowHeight() {
+        return mPointerSize;
+    }
+
     float getBubbleBarCollapsedHeight() {
         // the pointer is invisible when collapsed
         return getScaledIconSize() + mBubbleBarPadding * 2;
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index fd08078..1e0a778 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -95,7 +95,6 @@
     private TaskbarInsetsController mTaskbarInsetsController;
     private TaskbarViewPropertiesProvider mTaskbarViewPropertiesProvider;
     private View.OnClickListener mBubbleClickListener;
-    private View.OnClickListener mBubbleBarClickListener;
     private BubbleView.Controller mBubbleViewController;
     private BubbleBarOverflow mOverflowBubble;
 
@@ -171,20 +170,18 @@
                 mBubbleBarContainer, createFlyoutPositioner(), createFlyoutCallbacks());
         mBubbleBarViewAnimator = new BubbleBarViewAnimator(
                 mBarView, mBubbleStashController, mBubbleBarFlyoutController,
-                mBubbleBarController::showExpandedView);
+                createBubbleBarParentViewController(), mBubbleBarController::showExpandedView);
         mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider;
         onBubbleBarConfigurationChanged(/* animate= */ false);
         mActivity.addOnDeviceProfileChangeListener(
                 dp -> onBubbleBarConfigurationChanged(/* animate= */ true));
         mBubbleBarScaleY.updateValue(1f);
         mBubbleClickListener = v -> onBubbleClicked((BubbleView) v);
-        mBubbleBarClickListener = v -> expandBubbleBar();
         mBubbleDragController.setupBubbleBarView(mBarView);
         mOverflowBubble = bubbleControllers.bubbleCreator.createOverflow(mBarView);
         if (!Flags.enableOptionalBubbleOverflow()) {
             showOverflow(true);
         }
-        mBarView.setOnClickListener(mBubbleBarClickListener);
         mBarView.addOnLayoutChangeListener(
                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
                     mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
@@ -211,7 +208,8 @@
 
             @Override
             public void expandBubbleBar() {
-                BubbleBarViewController.this.expandBubbleBar();
+                BubbleBarViewController.this.setExpanded(
+                        /* isExpanded= */ true, /* maybeShowEdu*/ true);
             }
 
             @Override
@@ -319,20 +317,18 @@
     private FlyoutCallbacks createFlyoutCallbacks() {
         return new FlyoutCallbacks() {
             @Override
-            public void extendTopBoundary(int space) {
-                int defaultSize = mActivity.getDefaultTaskbarWindowSize();
-                mActivity.setTaskbarWindowSize(defaultSize + space);
-            }
-
-            @Override
-            public void resetTopBoundary() {
-                mActivity.setTaskbarWindowSize(mActivity.getDefaultTaskbarWindowSize());
-            }
-
-            @Override
             public void flyoutClicked() {
                 interruptAnimationForTouch();
-                expandBubbleBar();
+                setExpanded(/* isExpanded= */ true, /* maybeShowEdu*/ true);
+            }
+        };
+    }
+
+    private BubbleBarParentViewHeightUpdateNotifier createBubbleBarParentViewController() {
+        return new BubbleBarParentViewHeightUpdateNotifier() {
+            @Override
+            public void updateTopBoundary() {
+                mActivity.setTaskbarWindowSize(mActivity.getDefaultTaskbarWindowSize());
             }
         };
     }
@@ -360,25 +356,6 @@
         mBubbleStashController.onNewBubbleAnimationInterrupted(false, mBarView.getTranslationY());
     }
 
-    private void expandBubbleBar() {
-        if (mShouldShowEducation) {
-            mShouldShowEducation = false;
-            // Get the bubble bar bounds on screen
-            Rect bounds = new Rect();
-            mBarView.getBoundsOnScreen(bounds);
-            // Calculate user education reference position in Screen coordinates
-            Point position = new Point(bounds.centerX(), bounds.top);
-            // Show user education relative to the reference point
-            mSystemUiProxy.showUserEducation(position);
-        } else {
-            // ensure that the bubble bar has the correct translation. we may have just interrupted
-            // the animation by touching the bubble bar.
-            mBubbleBarTranslationY.animateToValue(mBubbleStashController.getBubbleBarTranslationY())
-                    .start();
-            setExpanded(true);
-        }
-    }
-
     private void collapseBubbleBar() {
         setExpanded(false);
         mBubbleStashController.stashBubbleBar();
@@ -391,6 +368,22 @@
         }
     }
 
+    /** Shows the education view if it was previously requested. */
+    private boolean maybeShowEduView() {
+        if (mShouldShowEducation) {
+            mShouldShowEducation = false;
+            // Get the bubble bar bounds on screen
+            Rect bounds = new Rect();
+            mBarView.getBoundsOnScreen(bounds);
+            // Calculate user education reference position in Screen coordinates
+            Point position = new Point(bounds.centerX(), bounds.top);
+            // Show user education relative to the reference point
+            mSystemUiProxy.showUserEducation(position);
+            return true;
+        }
+        return false;
+    }
+
     /** Notifies that the IME became visible. */
     public void onImeVisible() {
         if (isAnimatingNewBubble()) {
@@ -447,6 +440,11 @@
         return mBarView.getBubbleBarCollapsedHeight();
     }
 
+    /** Returns the bubble bar arrow height.*/
+    public float getBubbleBarArrowHeight() {
+        return mBarView.getArrowHeight();
+    }
+
     /**
      * @see BubbleBarView#getRelativePivotX()
      */
@@ -580,6 +578,19 @@
         return mHiddenForNoBubbles;
     }
 
+    /** Returns maximum height of the bubble bar with the flyout view. */
+    public int getBubbleBarWithFlyoutMaximumHeight() {
+        if (!isBubbleBarVisible()) return 0;
+        int bubbleBarTopOnHome = (int) (mBubbleStashController.getBubbleBarVerticalCenterForHome()
+                + mBarView.getBubbleBarCollapsedHeight() / 2);
+        int result = (int) (bubbleBarTopOnHome + mBarView.getArrowHeight());
+        if (isAnimatingNewBubble()) {
+            // when animating new bubble add the maximum height of the flyout view
+            result += mBubbleBarFlyoutController.getMaximumFlyoutHeight();
+        }
+        return result;
+    }
+
     /**
      * Sets whether the bubble bar should be hidden because there are no bubbles.
      */
@@ -946,13 +957,25 @@
         mBarView.setSelectedBubble(newlySelected.getView());
     }
 
+    /** @see #setExpanded(boolean, boolean) */
+    public void setExpanded(boolean isExpanded) {
+        setExpanded(isExpanded, /* maybeShowEdu= */ false);
+    }
+
     /**
      * Sets whether the bubble bar should be expanded (not unstashed, but have the contents
      * within it expanded). This method notifies SystemUI that the bubble bar is expanded and
      * showing a selected bubble. This method should ONLY be called from UI events originating
      * from Launcher.
+     *
+     * @param isExpanded whether the bar should be expanded
+     * @param maybeShowEdu whether we should show the edu view before expanding
      */
-    public void setExpanded(boolean isExpanded) {
+    public void setExpanded(boolean isExpanded, boolean maybeShowEdu) {
+        // if we're trying to expand try showing the edu view instead
+        if (maybeShowEdu && isExpanded && !mBarView.isExpanded() && maybeShowEduView()) {
+            return;
+        }
         if (!mBubbleBarPinning.isAnimating() && isExpanded != mBarView.isExpanded()) {
             mBarView.setExpanded(isExpanded);
             adjustTaskbarAndHotseatToBubbleBarState(isExpanded);
@@ -1012,7 +1035,11 @@
         }
     }
 
-    /** Marks as should show education. */
+    /**
+     * Stores a request to show the education view for later processing when appropriate.
+     *
+     * @see #maybeShowEduView()
+     */
     public void prepareToShowEducation() {
         mShouldShowEducation = true;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
index cb592e6..68917ff 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -102,7 +102,8 @@
                 new TaskbarViewPropertiesProvider() {
                     @Override
                     public Rect getTaskbarViewBounds() {
-                        return taskbarControllers.taskbarViewController.getIconLayoutBounds();
+                        return taskbarControllers.taskbarViewController
+                                .getTransientTaskbarIconLayoutBoundsInParent();
                     }
 
                     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
index c5efe2f..8b344cf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
@@ -30,7 +30,6 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
-import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Matrix;
@@ -217,14 +216,8 @@
     private Bitmap createOverflowBitmap() {
         Drawable iconDrawable = mContext.getDrawable(R.drawable.bubble_ic_overflow_button);
 
-        final TypedArray ta = mContext.obtainStyledAttributes(
-                new int[]{
-                        R.attr.materialColorOnPrimaryFixed,
-                        R.attr.materialColorPrimaryFixed
-                });
-        int overflowIconColor = ta.getColor(0, Color.WHITE);
-        int overflowBackgroundColor = ta.getColor(1, Color.BLACK);
-        ta.recycle();
+        int overflowIconColor = mContext.getColor(R.color.materialColorOnPrimaryFixed);
+        int overflowBackgroundColor = mContext.getColor(R.color.materialColorPrimaryFixed);
 
         iconDrawable.setTint(overflowIconColor);
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
index 447dad1..f5a6655 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -25,6 +25,7 @@
 import androidx.dynamicanimation.animation.SpringForce
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
+import com.android.launcher3.taskbar.bubbles.BubbleBarParentViewHeightUpdateNotifier
 import com.android.launcher3.taskbar.bubbles.BubbleBarView
 import com.android.launcher3.taskbar.bubbles.BubbleView
 import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutController
@@ -39,6 +40,7 @@
     private val bubbleBarView: BubbleBarView,
     private val bubbleStashController: BubbleStashController,
     private val bubbleBarFlyoutController: BubbleBarFlyoutController,
+    private val bubbleBarParentViewHeightUpdateNotifier: BubbleBarParentViewHeightUpdateNotifier,
     private val onExpanded: Runnable,
     private val scheduler: Scheduler = HandlerScheduler(bubbleBarView),
 ) {
@@ -342,7 +344,7 @@
                 scheduler.post(buildHandleToBubbleBarAnimation(initialVelocity = finalVelocity))
                 return@addEndListener
             }
-            animatingBubble = null
+            clearAnimatingBubble()
             if (!canceled) bubbleStashController.stashBubbleBarImmediate()
             bubbleBarView.relativePivotY = 1f
             bubbleBarView.scaleY = 1f
@@ -378,7 +380,7 @@
                     moveToState(AnimatingBubble.State.ANIMATING_OUT)
                     bubbleBarFlyoutController.collapseFlyout {
                         onFlyoutRemoved()
-                        animatingBubble = null
+                        clearAnimatingBubble()
                     }
                     bubbleStashController.showBubbleBarImmediate()
                     bubbleStashController.updateTaskbarTouchRegion()
@@ -437,7 +439,7 @@
             moveToState(AnimatingBubble.State.ANIMATING_OUT)
             bubbleBarFlyoutController.collapseFlyout {
                 onFlyoutRemoved()
-                animatingBubble = null
+                clearAnimatingBubble()
             }
             bubbleStashController.showBubbleBarImmediate()
             bubbleStashController.updateTaskbarTouchRegion()
@@ -515,7 +517,7 @@
         val hideAnimation = animatingBubble?.hideAnimation ?: return
         scheduler.cancel(hideAnimation)
         bubbleBarView.relativePivotY = 1f
-        animatingBubble = null
+        clearAnimatingBubble()
     }
 
     /** Notifies the animator that the taskbar area was touched during an animation. */
@@ -523,7 +525,7 @@
         cancelFlyout()
         val hideAnimation = animatingBubble?.hideAnimation ?: return
         scheduler.cancel(hideAnimation)
-        animatingBubble = null
+        clearAnimatingBubble()
         bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
         bubbleBarView.relativePivotY = 1f
         bubbleStashController.onNewBubbleAnimationInterrupted(
@@ -672,7 +674,7 @@
     private fun cancelHideAnimation() {
         val hideAnimation = animatingBubble?.hideAnimation ?: return
         scheduler.cancel(hideAnimation)
-        animatingBubble = null
+        clearAnimatingBubble()
         bubbleBarView.relativePivotY = 1f
         bubbleStashController.showBubbleBarImmediate()
     }
@@ -700,6 +702,14 @@
     private fun moveToState(state: AnimatingBubble.State) {
         val animatingBubble = this.animatingBubble ?: return
         this.animatingBubble = animatingBubble.copy(state = state)
+        if (state == AnimatingBubble.State.ANIMATING_IN) {
+            bubbleBarParentViewHeightUpdateNotifier.updateTopBoundary()
+        }
+    }
+
+    private fun clearAnimatingBubble() {
+        animatingBubble = null
+        bubbleBarParentViewHeightUpdateNotifier.updateTopBoundary()
     }
 
     private fun expandBubbleBar() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
index 908e97c..63db012 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
@@ -35,6 +35,8 @@
     private val flyoutScheduler: FlyoutScheduler = HandlerScheduler(container),
 ) {
 
+    val maximumFlyoutHeight: Int = BubbleBarFlyoutView.getMaximumViewHeight(container.context)
+
     private companion object {
         const val EXPAND_ANIMATION_DURATION_MS = 400L
         const val COLLAPSE_ANIMATION_DURATION_MS = 350L
@@ -61,6 +63,8 @@
             return rect
         }
 
+    fun getFlyoutMaxHeight(): Int = BubbleBarFlyoutView.getMaximumViewHeight(container.context)
+
     fun setUpAndShowFlyout(message: BubbleBarFlyoutMessage, onInit: () -> Unit, onEnd: () -> Unit) {
         flyout?.let(container::removeView)
         val flyout = BubbleBarFlyoutView(container.context, positioner, flyoutScheduler)
@@ -102,11 +106,10 @@
                 }
         }
         animator.addListener(
-            onStart = { extendTopBoundary() },
             onEnd = {
                 endAction()
                 flyout.setOnClickListener { callbacks.flyoutClicked() }
-            },
+            }
         )
         animator.start()
     }
@@ -114,14 +117,13 @@
     fun updateFlyoutFullyExpanded(message: BubbleBarFlyoutMessage, onEnd: () -> Unit) {
         val flyout = flyout ?: return
         hideFlyout(AnimationType.FADE) {
-            callbacks.resetTopBoundary()
             flyout.updateData(message) { showFlyout(AnimationType.FADE, onEnd) }
         }
     }
 
     fun updateFlyoutWhileExpanding(message: BubbleBarFlyoutMessage) {
         val flyout = flyout ?: return
-        flyout.updateData(message) { extendTopBoundary() }
+        flyout.updateData(message) {}
     }
 
     fun updateFlyoutWhileCollapsing(message: BubbleBarFlyoutMessage, onEnd: () -> Unit) {
@@ -131,14 +133,6 @@
         flyout.updateData(message) { showFlyout(AnimationType.MORPH, onEnd) }
     }
 
-    private fun extendTopBoundary() {
-        val flyout = flyout ?: return
-        val flyoutTop = flyout.top + flyout.translationY
-        // If the top position of the flyout is negative, then it's bleeding over the
-        // top boundary of its parent view
-        if (flyoutTop < 0) callbacks.extendTopBoundary(space = -flyoutTop.toInt())
-    }
-
     fun cancelFlyout(endAction: () -> Unit) {
         hideFlyout(AnimationType.FADE) {
             cleanupFlyoutView()
@@ -184,7 +178,6 @@
     private fun cleanupFlyoutView() {
         container.removeView(flyout)
         this@BubbleBarFlyoutController.flyout = null
-        callbacks.resetTopBoundary()
     }
 
     fun hasFlyout() = flyout != null
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
index f9f5a15..75bf937 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.content.res.Configuration
+import android.content.res.Resources
 import android.graphics.Canvas
 import android.graphics.Color
 import android.graphics.Outline
@@ -44,11 +45,27 @@
     scheduler: FlyoutScheduler? = null,
 ) : ConstraintLayout(context) {
 
-    private companion object {
-        // the minimum progress of the expansion animation before the content starts fading in.
-        const val MIN_EXPANSION_PROGRESS_FOR_CONTENT_ALPHA = 0.75f
+    companion object {
         // the rate multiple for the background color animation relative to the morph animation.
         const val BACKGROUND_COLOR_CHANGE_RATE = 5
+        // the minimum progress of the expansion animation before the content starts fading in.
+        private const val MIN_EXPANSION_PROGRESS_FOR_CONTENT_ALPHA = 0.75f
+
+        private const val TEXT_ROW_HEIGHT_SP = 20
+        private const val MAX_ROWS_COUNT = 3
+
+        /** Returns the maximum possible height of the flyout view. */
+        fun getMaximumViewHeight(context: Context): Int {
+            val verticalPaddings = getFlyoutPadding(context) * 2
+            val textSizeSp = TEXT_ROW_HEIGHT_SP * MAX_ROWS_COUNT
+            val textSizePx = textSizeSp * Resources.getSystem().displayMetrics.scaledDensity
+            val triangleHeight =
+                context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_triangle_height)
+            return verticalPaddings + textSizePx.toInt() + triangleHeight
+        }
+
+        private fun getFlyoutPadding(context: Context) =
+            context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding)
     }
 
     private val scheduler: FlyoutScheduler = scheduler ?: HandlerScheduler(this)
@@ -61,10 +78,7 @@
     private val message: TextView by
         lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_text) }
 
-    private val flyoutPadding by
-        lazy(LazyThreadSafetyMode.NONE) {
-            context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding)
-        }
+    private val flyoutPadding by lazy(LazyThreadSafetyMode.NONE) { getFlyoutPadding(context) }
 
     private val triangleHeight by
         lazy(LazyThreadSafetyMode.NONE) {
@@ -402,18 +416,13 @@
         val isNightModeOn = nightModeFlags == Configuration.UI_MODE_NIGHT_YES
         val defaultBackgroundColor = if (isNightModeOn) Color.BLACK else Color.WHITE
         val defaultTextColor = if (isNightModeOn) Color.WHITE else Color.BLACK
-        val ta =
-            context.obtainStyledAttributes(
-                intArrayOf(
-                    com.android.internal.R.attr.materialColorSurfaceContainer,
-                    com.android.internal.R.attr.materialColorOnSurface,
-                    com.android.internal.R.attr.materialColorOnSurfaceVariant,
-                )
-            )
-        backgroundColor = ta.getColor(0, defaultBackgroundColor)
-        title.setTextColor(ta.getColor(1, defaultTextColor))
-        message.setTextColor(ta.getColor(2, defaultTextColor))
-        ta.recycle()
+
+        backgroundColor =
+            context.getColor(com.android.internal.R.color.materialColorSurfaceContainer)
+        title.setTextColor(context.getColor(com.android.internal.R.color.materialColorOnSurface))
+        message.setTextColor(
+            context.getColor(com.android.internal.R.color.materialColorOnSurfaceVariant)
+        )
         backgroundPaint.color = backgroundColor
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/FlyoutCallbacks.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/FlyoutCallbacks.kt
index e2f010a..0804a62 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/FlyoutCallbacks.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/FlyoutCallbacks.kt
@@ -18,11 +18,6 @@
 
 /** Callbacks that the flyout uses to notify of events. */
 interface FlyoutCallbacks {
-    /** Requests to extend the top boundary of the parent to fully include the flyout. */
-    fun extendTopBoundary(space: Int)
-
-    /** Resets the top boundary of the parent. */
-    fun resetTopBoundary()
 
     /** The flyout was clicked. */
     fun flyoutClicked()
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
index d9589bb..595dac3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -74,6 +74,9 @@
     val isBubblesShowingOnOverview: Boolean
         get() = launcherState == BubbleLauncherState.OVERVIEW
 
+    /** Bubble bar vertical center for launcher home. */
+    var bubbleBarVerticalCenterForHome: Int
+
     /** Updated when sysui locked state changes, when locked, bubble bar is not shown. */
     var isSysuiLocked: Boolean
 
@@ -121,9 +124,6 @@
     /** Set a bubble bar location */
     fun setBubbleBarLocation(bubbleBarLocation: BubbleBarLocation)
 
-    /** Set the hotseat vertical center that bubble bar will align with. */
-    fun setHotseatVerticalCenter(hotseatVerticalCenter: Int)
-
     /**
      * Stashes the bubble bar (transform to the handle view), or just shrink width of the expanded
      * bubble bar based on the controller implementation.
@@ -131,7 +131,17 @@
     fun stashBubbleBar()
 
     /** Shows the bubble bar, and expands bubbles depending on [expandBubbles]. */
-    fun showBubbleBar(expandBubbles: Boolean)
+    fun showBubbleBar(expandBubbles: Boolean) {
+        showBubbleBar(expandBubbles = expandBubbles, bubbleBarGesture = false)
+    }
+
+    /**
+     * Shows the bubble bar, and expands bubbles depending on [expandBubbles].
+     *
+     * Set [bubbleBarGesture] to true if this request originates from a touch gesture on the bubble
+     * bar.
+     */
+    fun showBubbleBar(expandBubbles: Boolean, bubbleBarGesture: Boolean)
 
     // TODO(b/354218264): Move to BubbleBarViewAnimator
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
index 45f5568..9d8c0ed 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
@@ -47,7 +47,7 @@
     private lateinit var bubbleBarAlphaAnimator: MultiPropertyFactory<View>.MultiProperty
     private lateinit var bubbleBarScaleAnimator: AnimatedFloat
     private lateinit var controllersAfterInitAction: ControllersAfterInitAction
-    private var hotseatVerticalCenter: Int = 0
+    override var bubbleBarVerticalCenterForHome: Int = 0
 
     override var launcherState: BubbleLauncherState = BubbleLauncherState.IN_APP
         set(state) {
@@ -97,7 +97,7 @@
     override val bubbleBarTranslationYForHotseat: Float
         get() {
             val bubbleBarHeight = bubbleBarViewController.bubbleBarCollapsedHeight
-            return -hotseatVerticalCenter + bubbleBarHeight / 2
+            return -bubbleBarVerticalCenterForHome + bubbleBarHeight / 2
         }
 
     override val bubbleBarTranslationY: Float
@@ -159,10 +159,6 @@
         animatorSet.setDuration(BAR_STASH_DURATION).start()
     }
 
-    override fun setHotseatVerticalCenter(hotseatVerticalCenter: Int) {
-        this.hotseatVerticalCenter = hotseatVerticalCenter
-    }
-
     override fun showBubbleBarImmediate() = showBubbleBarImmediate(bubbleBarTranslationY)
 
     override fun showBubbleBarImmediate(bubbleBarTranslationY: Float) {
@@ -180,8 +176,8 @@
         updateExpandedState(expand = false)
     }
 
-    override fun showBubbleBar(expandBubbles: Boolean) {
-        updateExpandedState(expandBubbles)
+    override fun showBubbleBar(expandBubbles: Boolean, bubbleBarGesture: Boolean) {
+        updateExpandedState(expand = expandBubbles, bubbleBarGesture = bubbleBarGesture)
     }
 
     override fun stashBubbleBarImmediate() {
@@ -235,13 +231,14 @@
         // no op since does not have a handle view
     }
 
-    private fun updateExpandedState(expand: Boolean) {
+    private fun updateExpandedState(expand: Boolean, bubbleBarGesture: Boolean = false) {
         if (bubbleBarViewController.isHiddenForNoBubbles) {
             // If there are no bubbles the bar is invisible, nothing to do here.
             return
         }
         if (bubbleBarViewController.isExpanded != expand) {
-            bubbleBarViewController.isExpanded = expand
+            val maybeShowEdu = expand && bubbleBarGesture
+            bubbleBarViewController.setExpanded(expand, maybeShowEdu)
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 22d504f..df00696 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -78,7 +78,7 @@
         context.resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f
 
     private var animator: AnimatorSet? = null
-    private var hotseatVerticalCenter: Int = 0
+    override var bubbleBarVerticalCenterForHome: Int = 0
 
     override var isStashed: Boolean = false
         @VisibleForTesting set
@@ -124,7 +124,7 @@
     override val bubbleBarTranslationYForHotseat: Float
         get() {
             val bubbleBarHeight = bubbleBarViewController.bubbleBarCollapsedHeight
-            return -hotseatVerticalCenter + bubbleBarHeight / 2
+            return -bubbleBarVerticalCenterForHome + bubbleBarHeight / 2
         }
 
     override val bubbleBarTranslationYForTaskbar: Float =
@@ -182,10 +182,6 @@
             .start()
     }
 
-    override fun setHotseatVerticalCenter(hotseatVerticalCenter: Int) {
-        this.hotseatVerticalCenter = hotseatVerticalCenter
-    }
-
     override fun showBubbleBarImmediate() {
         showBubbleBarImmediate(bubbleBarTranslationY)
     }
@@ -250,8 +246,12 @@
         updateStashedAndExpandedState(stash = true, expand = false)
     }
 
-    override fun showBubbleBar(expandBubbles: Boolean) {
-        updateStashedAndExpandedState(stash = false, expandBubbles)
+    override fun showBubbleBar(expandBubbles: Boolean, bubbleBarGesture: Boolean) {
+        updateStashedAndExpandedState(
+            stash = false,
+            expand = expandBubbles,
+            bubbleBarGesture = bubbleBarGesture,
+        )
     }
 
     override fun getDiffBetweenHandleAndBarCenters(): Float {
@@ -481,7 +481,11 @@
     }
 
     @VisibleForTesting
-    fun updateStashedAndExpandedState(stash: Boolean, expand: Boolean) {
+    fun updateStashedAndExpandedState(
+        stash: Boolean,
+        expand: Boolean,
+        bubbleBarGesture: Boolean = false,
+    ) {
         if (bubbleBarViewController.isHiddenForNoBubbles) {
             // If there are no bubbles the bar and handle are invisible, nothing to do here.
             return
@@ -502,7 +506,8 @@
                 }
         }
         if (bubbleBarViewController.isExpanded != expand) {
-            bubbleBarViewController.isExpanded = expand
+            val maybeShowEdu = expand && bubbleBarGesture
+            bubbleBarViewController.setExpanded(expand, maybeShowEdu)
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
index e552b24..4932654 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt
@@ -26,11 +26,13 @@
 import android.view.ViewConfiguration
 import androidx.annotation.DimenRes
 import androidx.annotation.DrawableRes
+import androidx.core.view.setPadding
 import com.android.launcher3.R
 import com.android.launcher3.Utilities.dpToPx
 import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
 import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.launcher3.taskbar.TaskbarViewCallbacks
+import com.android.launcher3.util.DisplayController
 import com.android.launcher3.util.Executors.MAIN_EXECUTOR
 import com.android.launcher3.views.ActivityContext
 import com.android.launcher3.views.IconButtonView
@@ -67,6 +69,9 @@
             )
         backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
         setIconDrawable(drawable)
+        if (!DisplayController.isTransientTaskbar(context)) {
+            setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
+        }
         setForegroundTint(activityContext.getColor(R.color.all_apps_button_color))
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
index df61d8a..d5f72d5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarDividerContainer.kt
@@ -21,10 +21,12 @@
 import android.content.res.ColorStateList
 import android.graphics.Color.TRANSPARENT
 import android.util.AttributeSet
+import androidx.core.view.setPadding
 import com.android.launcher3.R
 import com.android.launcher3.Utilities.dpToPx
 import com.android.launcher3.taskbar.TaskbarActivityContext
 import com.android.launcher3.taskbar.TaskbarViewCallbacks
+import com.android.launcher3.util.DisplayController
 import com.android.launcher3.views.ActivityContext
 import com.android.launcher3.views.IconButtonView
 
@@ -50,6 +52,9 @@
         backgroundTintList = ColorStateList.valueOf(TRANSPARENT)
         val drawable = resources.getDrawable(R.drawable.taskbar_divider_button)
         setIconDrawable(drawable)
+        if (!DisplayController.isTransientTaskbar(context)) {
+            setPadding(dpToPx(activityContext.taskbarSpecsEvaluator.taskbarIconPadding.toFloat()))
+        }
     }
 
     @SuppressLint("ClickableViewAccessibility")
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index bf8cff6..a006198 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -80,8 +80,6 @@
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.Pair;
-import android.util.TimeUtils;
-import android.view.Choreographer;
 import android.view.MotionEvent;
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
@@ -1736,30 +1734,13 @@
     }
 
     private void handOffAnimation(PointF velocityPxPerMs) {
-        if (!TransitionAnimator.Companion.longLivedReturnAnimationsEnabled()) {
-            return;
-        }
-
-        // This function is not guaranteed to be called inside a frame. We try to access the frame
-        // time immediately, but if we're not inside a frame we must post a callback to be run at
-        // the beginning of the next frame.
-        try  {
-            handOffAnimationInternal(Choreographer.getInstance().getFrameTime(), velocityPxPerMs);
-        } catch (IllegalStateException e) {
-            Choreographer.getInstance().postFrameCallback(
-                    frameTimeNanos -> handOffAnimationInternal(
-                            frameTimeNanos / TimeUtils.NANOS_PER_MS, velocityPxPerMs));
-        }
-    }
-
-    private void handOffAnimationInternal(long timestamp, PointF velocityPxPerMs) {
-        if (mRecentsAnimationController == null) {
+        if (!TransitionAnimator.Companion.longLivedReturnAnimationsEnabled()
+                || mRecentsAnimationController == null) {
             return;
         }
 
         Pair<RemoteAnimationTarget[], WindowAnimationState[]> targetsAndStates =
-                extractTargetsAndStates(
-                        mRemoteTargetHandles, timestamp, velocityPxPerMs);
+                extractTargetsAndStates(mRemoteTargetHandles, velocityPxPerMs);
         mRecentsAnimationController.handOffAnimation(
                 targetsAndStates.first, targetsAndStates.second);
         ActiveGestureProtoLogProxy.logHandOffAnimation();
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index fef4c30..ff9c9f6 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -353,6 +353,9 @@
         /** Sets visibility for the overlay associated elements. */
         public void setVisibility(int visibility) {}
 
+        /** See {@link View#addChildrenForAccessibility(ArrayList)} */
+        public void addChildForAccessibility(ArrayList<View> outChildren) {}
+
         private class ScreenshotSystemShortcut extends SystemShortcut {
 
             private final RecentsViewContainer mContainer;
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 084cede..783c87c 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -795,15 +795,14 @@
      * second applies to the target in the same index of the first.
      *
      * @param handles The handles wrapping each target.
-     * @param timestamp The start time of the current frame.
      * @param velocityPxPerMs The current velocity of the target animations.
      */
     @NonNull
     public static Pair<RemoteAnimationTarget[], WindowAnimationState[]> extractTargetsAndStates(
-            @NonNull RemoteTargetHandle[] handles, long timestamp,
-            @NonNull PointF velocityPxPerMs) {
+            @NonNull RemoteTargetHandle[] handles, @NonNull PointF velocityPxPerMs) {
         RemoteAnimationTarget[] targets = new RemoteAnimationTarget[handles.length];
         WindowAnimationState[] animationStates = new WindowAnimationState[handles.length];
+        long timestamp = System.currentTimeMillis();
 
         for (int i = 0; i < handles.length; i++) {
             targets[i] = handles[i].getTransformParams().getTargetSet().apps[i];
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
index 778c231..6b61298 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
@@ -114,7 +114,8 @@
                 if (isWithinTapTime && !swipeUpOnBubbleHandle && !mPassedTouchSlop
                         && mStashedOrCollapsedOnDown) {
                     // Taps on the handle / collapsed state should open the bar
-                    mBubbleStashController.showBubbleBar(/* expandBubbles= */ true);
+                    mBubbleStashController.showBubbleBar(
+                            /* expandBubbles= */ true, /* bubbleBarGesture= */ true);
                 }
                 break;
         }
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 2daaaf9..9bfe71f 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -733,48 +733,40 @@
                             .getQueryLength() : -1;
                 }
             default:
-                return info.getFolderIcon().getCardinality();
+                return switch (info.getItemCase()) {
+                    case FOLDER_ICON -> info.getFolderIcon().getCardinality();
+                    case TASK_VIEW -> info.getTaskView().getCardinality();
+                    default -> 0;
+                };
         }
     }
 
     private static String getPackageName(LauncherAtom.ItemInfo info) {
-        switch (info.getItemCase()) {
-            case APPLICATION:
-                return info.getApplication().getPackageName();
-            case SHORTCUT:
-                return info.getShortcut().getShortcutName();
-            case WIDGET:
-                return info.getWidget().getPackageName();
-            case TASK:
-                return info.getTask().getPackageName();
-            case SEARCH_ACTION_ITEM:
-                return info.getSearchActionItem().getPackageName();
-            default:
-                return null;
-        }
+        return switch (info.getItemCase()) {
+            case APPLICATION -> info.getApplication().getPackageName();
+            case SHORTCUT -> info.getShortcut().getShortcutName();
+            case WIDGET -> info.getWidget().getPackageName();
+            case TASK -> info.getTask().getPackageName();
+            case SEARCH_ACTION_ITEM -> info.getSearchActionItem().getPackageName();
+            default -> null;
+        };
     }
 
     private static String getComponentName(LauncherAtom.ItemInfo info) {
-        switch (info.getItemCase()) {
-            case APPLICATION:
-                return info.getApplication().getComponentName();
-            case SHORTCUT:
-                return info.getShortcut().getShortcutName();
-            case WIDGET:
-                return info.getWidget().getComponentName();
-            case TASK:
-                return info.getTask().getComponentName();
-            case SEARCH_ACTION_ITEM:
-                return info.getSearchActionItem().getTitle();
-            case SLICE:
-                return info.getSlice().getUri();
-            default:
-                return null;
-        }
+        return switch (info.getItemCase()) {
+            case APPLICATION -> info.getApplication().getComponentName();
+            case SHORTCUT -> info.getShortcut().getShortcutName();
+            case WIDGET -> info.getWidget().getComponentName();
+            case TASK -> info.getTask().getComponentName();
+            case TASK_VIEW -> info.getTaskView().getComponentName();
+            case SEARCH_ACTION_ITEM -> info.getSearchActionItem().getTitle();
+            case SLICE -> info.getSlice().getUri();
+            default -> null;
+        };
     }
 
     private static int getGridX(LauncherAtom.ItemInfo info, boolean parent) {
-        LauncherAtom.ContainerInfo containerInfo = info.getContainerInfo();
+        ContainerInfo containerInfo = info.getContainerInfo();
         if (containerInfo.getContainerCase() == FOLDER) {
             if (parent) {
                 return containerInfo.getFolder().getWorkspace().getGridX();
@@ -802,37 +794,38 @@
     }
 
     private static int getPageId(LauncherAtom.ItemInfo info) {
-        if (info.hasTask()) {
-            return info.getTask().getIndex();
-        }
-        switch (info.getContainerInfo().getContainerCase()) {
-            case FOLDER:
-                return info.getContainerInfo().getFolder().getPageIndex();
-            case HOTSEAT:
-                return info.getContainerInfo().getHotseat().getIndex();
-            case PREDICTED_HOTSEAT_CONTAINER:
-                return info.getContainerInfo().getPredictedHotseatContainer().getIndex();
-            case TASK_BAR_CONTAINER:
-                return info.getContainerInfo().getTaskBarContainer().getIndex();
-            default:
-                return info.getContainerInfo().getWorkspace().getPageIndex();
-        }
+        return switch (info.getItemCase()) {
+            case TASK -> info.getTask().getIndex();
+            case TASK_VIEW -> info.getTaskView().getIndex();
+            default -> getPageIdFromContainerInfo(info.getContainerInfo());
+        };
+    }
+
+    private static int getPageIdFromContainerInfo(LauncherAtom.ContainerInfo containerInfo) {
+        return switch (containerInfo.getContainerCase()) {
+            case FOLDER -> containerInfo.getFolder().getPageIndex();
+            case HOTSEAT -> containerInfo.getHotseat().getIndex();
+            case PREDICTED_HOTSEAT_CONTAINER ->
+                    containerInfo.getPredictedHotseatContainer().getIndex();
+            case TASK_BAR_CONTAINER -> containerInfo.getTaskBarContainer().getIndex();
+            default -> containerInfo.getWorkspace().getPageIndex();
+        };
     }
 
     private static int getParentPageId(LauncherAtom.ItemInfo info) {
-        switch (info.getContainerInfo().getContainerCase()) {
-            case FOLDER:
+        return switch (info.getContainerInfo().getContainerCase()) {
+            case FOLDER -> {
                 if (info.getContainerInfo().getFolder().getParentContainerCase()
                         == ParentContainerCase.HOTSEAT) {
-                    return info.getContainerInfo().getFolder().getHotseat().getIndex();
+                    yield info.getContainerInfo().getFolder().getHotseat().getIndex();
                 }
-                return info.getContainerInfo().getFolder().getWorkspace().getPageIndex();
-            case SEARCH_RESULT_CONTAINER:
-                return info.getContainerInfo().getSearchResultContainer().getWorkspace()
-                        .getPageIndex();
-            default:
-                return info.getContainerInfo().getWorkspace().getPageIndex();
-        }
+                yield info.getContainerInfo().getFolder().getWorkspace().getPageIndex();
+            }
+            case SEARCH_RESULT_CONTAINER ->
+                    info.getContainerInfo().getSearchResultContainer().getWorkspace()
+                            .getPageIndex();
+            default -> info.getContainerInfo().getWorkspace().getPageIndex();
+        };
     }
 
     private static int getHierarchy(LauncherAtom.ItemInfo info) {
@@ -857,25 +850,21 @@
     }
 
     private static String getStateString(int state) {
-        switch (state) {
-            case LAUNCHER_UICHANGED__DST_STATE__BACKGROUND:
-                return "BACKGROUND";
-            case LAUNCHER_UICHANGED__DST_STATE__HOME:
-                return "HOME";
-            case LAUNCHER_UICHANGED__DST_STATE__OVERVIEW:
-                return "OVERVIEW";
-            case LAUNCHER_UICHANGED__DST_STATE__ALLAPPS:
-                return "ALLAPPS";
-            default:
-                return "INVALID";
-        }
+        return switch (state) {
+            case LAUNCHER_UICHANGED__DST_STATE__BACKGROUND -> "BACKGROUND";
+            case LAUNCHER_UICHANGED__DST_STATE__HOME -> "HOME";
+            case LAUNCHER_UICHANGED__DST_STATE__OVERVIEW -> "OVERVIEW";
+            case LAUNCHER_UICHANGED__DST_STATE__ALLAPPS -> "ALLAPPS";
+            default -> "INVALID";
+        };
     }
 
     private static int getFeatures(LauncherAtom.ItemInfo info) {
-        if (info.getItemCase().equals(LauncherAtom.ItemInfo.ItemCase.WIDGET)) {
-            return info.getWidget().getWidgetFeatures();
-        }
-        return 0;
+        return switch (info.getItemCase()) {
+            case WIDGET -> info.getWidget().getWidgetFeatures();
+            case TASK_VIEW -> info.getTaskView().getType();
+            default -> 0;
+        };
     }
 
     private static int getSearchAttributes(LauncherAtom.ItemInfo info) {
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java b/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java
index 90569b4..3a6d9b0 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java
@@ -17,6 +17,7 @@
 package com.android.quickstep.util;
 
 import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.app.animation.Interpolators.STANDARD;
 
 import android.view.animation.Interpolator;
 
@@ -38,6 +39,8 @@
     int TABLET_APP_PAIR_LAUNCH_DURATION = 998;
     /** Total duration (ms) for launching an app pair from its icon on phones. */
     int PHONE_APP_PAIR_LAUNCH_DURATION = 915;
+    /** Total duration (ms) for fading out desktop tasks in split mode. */
+    int DESKTOP_FADE_OUT_DURATION = 200;
 
     // Initialize timing classes so they can be accessed statically
     SplitAnimationTimings TABLET_OVERVIEW_TO_SPLIT = new TabletOverviewToSplitTimings();
@@ -83,6 +86,10 @@
         return (float) getStagedRectSlideEnd() / getDuration();
     }
 
+    default float getDesktopFadeSplitAnimationEndOffset() {
+        return (float) DESKTOP_FADE_OUT_DURATION / getDuration();
+    }
+
     // DEFAULT VALUES: We define default values here so that SplitAnimationTimings can be used
     // flexibly in animation-running functions, e.g. a single function that handles 2 types of split
     // animations. The values are not intended to be used, and can safely be removed if refactoring
@@ -124,5 +131,9 @@
     default float getAppRevealEndOffset() { return 0; }
     default Interpolator getCellSplitInterpolator() { return LINEAR; }
     default Interpolator getIconFadeInterpolator() { return LINEAR; }
+
+    default Interpolator getDesktopTaskScaleInterpolator() {
+        return STANDARD;
+    }
 }
 
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 743fa40..6fc33dc 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -29,7 +29,7 @@
 import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.app.animation.Interpolators.FINAL_FRAME;
 import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.app.animation.Interpolators.OVERSHOOT_0_75;
+import static com.android.app.animation.Interpolators.EMPHASIZED;
 import static com.android.app.animation.Interpolators.clampToProgress;
 import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
 import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
@@ -3647,6 +3647,7 @@
         // Grid specific properties.
         boolean isFocusedTaskDismissed = false;
         boolean isStagingFocusedTask = false;
+        boolean isSlidingTasks = false;
         TaskView nextFocusedTaskView = null;
         boolean nextFocusedTaskFromTop = false;
         float dismissedTaskWidth = 0;
@@ -3702,6 +3703,7 @@
             scrollDiffPerPage = Math.abs(oldScroll[1] - oldScroll[0]);
         }
 
+        isSlidingTasks = isStagingFocusedTask || areAllDesktopTasksDismissed;
         float dismissTranslationInterpolationEnd = 1;
         boolean closeGapBetweenClearAll = false;
         boolean isClearAllHidden = isClearAllHidden();
@@ -3842,14 +3844,14 @@
                 AnimUtils.getDeviceOverviewToSplitTimings(mContainer.getDeviceProfile().isTablet);
 
         int distanceFromDismissedTask = 1;
-        int stagingTranslation = 0;
-        if (isStagingFocusedTask || areAllDesktopTasksDismissed) {
+        int slidingTranslation = 0;
+        if (isSlidingTasks) {
             int nextSnappedPage = isStagingFocusedTask
                     ? indexOfChild(mUtils.getFirstSmallTaskView(getTaskViews()))
                     : mUtils.getDesktopTaskViewCount(getTaskViews());
-            stagingTranslation = getPagedOrientationHandler().getPrimaryScroll(this)
+            slidingTranslation = getPagedOrientationHandler().getPrimaryScroll(this)
                     - getScrollForPage(nextSnappedPage);
-            stagingTranslation += mIsRtl ? newClearAllShortTotalWidthTranslation
+            slidingTranslation += mIsRtl ? newClearAllShortTotalWidthTranslation
                     : -newClearAllShortTotalWidthTranslation;
         }
         mDismissPrimaryTranslations = new int[taskCount];
@@ -3877,12 +3879,12 @@
                 // Animate task with index >= dismissed index and in the same row as the
                 // dismissed index or next focused index. Offset successive task dismissal
                 // durations for a staggered effect.
-                int staggerColumn = isStagingFocusedTask
+                int staggerColumn = isSlidingTasks
                         ? (int) Math.ceil(distanceFromDismissedTask / 2f)
                         : distanceFromDismissedTask;
                 // Set timings based on if user is initiating splitscreen on the focused task,
                 // or splitting/dismissing some other task.
-                float animationStartProgress = isStagingFocusedTask
+                float animationStartProgress = isSlidingTasks
                         ? Utilities.boundToRange(
                         splitTimings.getGridSlideStartOffset()
                                 + (splitTimings.getGridSlideStaggerOffset()
@@ -3893,7 +3895,7 @@
                                 INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
                                         + ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
                                         * staggerColumn, 0f, dismissTranslationInterpolationEnd);
-                float animationEndProgress = isStagingFocusedTask
+                float animationEndProgress = isSlidingTasks
                         ? Utilities.boundToRange(
                         splitTimings.getGridSlideStartOffset()
                                 + (splitTimings.getGridSlideStaggerOffset() * staggerColumn)
@@ -3901,7 +3903,8 @@
                         0f,
                         dismissTranslationInterpolationEnd)
                         : dismissTranslationInterpolationEnd;
-                Interpolator dismissInterpolator = isStagingFocusedTask ? OVERSHOOT_0_75 : LINEAR;
+
+                Interpolator dismissInterpolator = isSlidingTasks ? EMPHASIZED : LINEAR;
 
                 float primaryTranslation = 0;
                 if (taskView == nextFocusedTaskView) {
@@ -3928,14 +3931,30 @@
                     primaryTranslation +=
                             nextFocusedTaskView != null ? nextFocusedTaskWidth : dismissedTaskWidth;
                 }
-                primaryTranslation += mIsRtl ? stagingTranslation : -stagingTranslation;
+                if (!(taskView instanceof DesktopTaskView)) {
+                    primaryTranslation += mIsRtl ? slidingTranslation : -slidingTranslation;
+                }
 
                 if (primaryTranslation != 0) {
                     float finalTranslation = mIsRtl ? primaryTranslation : -primaryTranslation;
-                    anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
-                            finalTranslation,
+                    float startTranslation = 0;
+                    if (!(taskView instanceof DesktopTaskView) && slidingTranslation != 0) {
+                        startTranslation = isTaskViewVisible(taskView) ? 0
+                                : finalTranslation + (mIsRtl ? -mLastComputedTaskSize.right
+                                        : mLastComputedTaskSize.right);
+                        animationStartProgress = Utilities.boundToRange(
+                                animationStartProgress
+                                        + splitTimings.getDesktopFadeSplitAnimationEndOffset(),
+                                0f,
+                                dismissTranslationInterpolationEnd);
+                    }
+                    Animator dismissAnimator = ObjectAnimator.ofFloat(taskView,
+                            taskView.getPrimaryDismissTranslationProperty(),
+                            startTranslation, finalTranslation);
+                    dismissAnimator.setInterpolator(
                             clampToProgress(dismissInterpolator, animationStartProgress,
                                     animationEndProgress));
+                    anim.add(dismissAnimator);
                     mDismissPrimaryTranslations[i] = (int) finalTranslation;
                     distanceFromDismissedTask++;
                 }
@@ -4698,6 +4717,7 @@
             return;
         }
         setContentDescription(isEmpty ? mEmptyMessage : "");
+        setFocusable(isEmpty);
         mShowEmptyMessage = isEmpty;
         updateEmptyStateUi(hasSizeChanged);
         invalidate();
@@ -5112,13 +5132,37 @@
      */
     public void handleDesktopTaskInSplitSelectState(PendingAnimation builder,
             Interpolator deskTopFadeInterPolator) {
+        SplitAnimationTimings timings = AnimUtils.getDeviceOverviewToSplitTimings(
+                mContainer.getDeviceProfile().isTablet);
         if (enableLargeDesktopWindowingTile()) {
-            for (TaskView taskView : getTaskViews()) {
+            for (int i = 0; i < getTaskViewCount(); i++) {
+                TaskView taskView = requireTaskViewAt(i);
                 if (taskView instanceof DesktopTaskView) {
-                    // Correcting the animation for split mode since we hide DW in split.
+                    // Setting pivot to scale down from screen centre.
+                    if (i >= mCurrentPage - 1 && i <= mCurrentPage + 1) {
+                        float pivotX;
+                        if (i == mCurrentPage - 1) {
+                            pivotX = mIsRtl ? taskView.getWidth() / 2f - mPageSpacing
+                                    - taskView.getWidth()
+                                    : taskView.getWidth() / 2f + mPageSpacing + taskView.getWidth();
+                        } else if (i == mCurrentPage) {
+                            pivotX = taskView.getWidth() / 2f;
+                        } else {
+                            pivotX = mIsRtl ? taskView.getWidth() + mPageSpacing
+                                    + taskView.getWidth()
+                                    : taskView.getWidth() - mPageSpacing - taskView.getWidth();
+                        }
+                        taskView.setPivotX(pivotX);
+                        taskView.setPivotY(taskView.getHeight() / 2f);
+                        builder.add(ObjectAnimator
+                                        .ofFloat(taskView, TaskView.DISMISS_SCALE, 0.95f),
+                                clampToProgress(timings.getDesktopTaskScaleInterpolator(), 0f,
+                                        timings.getDesktopFadeSplitAnimationEndOffset()));
+                    }
                     builder.addFloat(taskView.getSplitAlphaProperty(),
                             MULTI_PROPERTY_VALUE, 1f, 0f,
-                            clampToProgress(deskTopFadeInterPolator, 0f, 0.1f));
+                            clampToProgress(deskTopFadeInterPolator, 0f,
+                                    timings.getDesktopFadeSplitAnimationEndOffset()));
                 }
             }
         }
@@ -5278,12 +5322,12 @@
         pendingAnimation.addEndListener(aBoolean -> {
             mSplitSelectStateController.launchSplitTasks(
                     aBoolean1 -> {
+                        InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
                         if (FeatureFlags.enableSplitContextually()) {
                             mSplitSelectStateController.resetState();
                         } else {
                             resetFromSplitSelectionState();
                         }
-                        InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
                     });
         });
 
diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
index c940fb4..5de8d1c 100644
--- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
@@ -16,19 +16,13 @@
 
 package com.android.quickstep.views
 
-import android.content.Intent
 import android.graphics.Bitmap
 import android.view.View
 import com.android.launcher3.Flags.enableRefactorTaskThumbnail
-import com.android.launcher3.Flags.privateSpaceRestrictAccessibilityDrag
-import com.android.launcher3.LauncherSettings
-import com.android.launcher3.model.data.ItemInfoWithIcon
-import com.android.launcher3.model.data.WorkspaceItemInfo
-import com.android.launcher3.pm.UserCache
+import com.android.launcher3.model.data.TaskViewItemInfo
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.launcher3.util.TransformingTouchDelegate
 import com.android.quickstep.TaskOverlayFactory
-import com.android.quickstep.TaskUtils
 import com.android.quickstep.ViewUtils.addAccessibleChildToList
 import com.android.quickstep.recents.di.RecentsDependencies
 import com.android.quickstep.recents.di.get
@@ -123,27 +117,8 @@
             else thumbnailViewDeprecated.sysUiStatusNavFlags
 
     /** Builds proto for logging */
-    val itemInfo: WorkspaceItemInfo
-        get() =
-            WorkspaceItemInfo().apply {
-                itemType = LauncherSettings.Favorites.ITEM_TYPE_TASK
-                container = LauncherSettings.Favorites.CONTAINER_TASKSWITCHER
-                val componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key)
-                user = componentKey.user
-                intent = Intent().setComponent(componentKey.componentName)
-                title = task.title
-                taskView.recentsView?.let { screenId = it.indexOfChild(taskView) }
-                if (privateSpaceRestrictAccessibilityDrag()) {
-                    if (
-                        UserCache.getInstance(taskView.context)
-                            .getUserInfo(componentKey.user)
-                            .isPrivate
-                    ) {
-                        runtimeStatusFlags =
-                            runtimeStatusFlags or ItemInfoWithIcon.FLAG_NOT_PINNABLE
-                    }
-                }
-            }
+    val itemInfo: TaskViewItemInfo
+        get() = TaskViewItemInfo(this)
 
     fun bind() {
         digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition)
@@ -181,5 +156,6 @@
         addAccessibleChildToList(snapshotView, outChildren)
         showWindowsView?.let { addAccessibleChildToList(it, outChildren) }
         digitalWellBeingToast?.let { addAccessibleChildToList(it, outChildren) }
+        overlay.addChildForAccessibility(outChildren)
     }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 7e489ea..3586dfb 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -101,7 +101,7 @@
     defStyleRes: Int = 0,
     focusBorderAnimator: BorderAnimator? = null,
     hoverBorderAnimator: BorderAnimator? = null,
-    private val type: TaskViewType = TaskViewType.SINGLE,
+    val type: TaskViewType = TaskViewType.SINGLE,
     protected val thumbnailFullscreenParams: FullscreenDrawParams = FullscreenDrawParams(context),
 ) : FrameLayout(context, attrs), ViewPool.Reusable {
     /**
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/model/data/TaskViewItemInfoTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/data/TaskViewItemInfoTest.kt
new file mode 100644
index 0000000..0103e7e
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/data/TaskViewItemInfoTest.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model.data
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.Flags.enableRefactorTaskThumbnail
+import com.android.launcher3.model.data.TaskViewItemInfo.Companion.createTaskViewAtom
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.launcher3.util.TransformingTouchDelegate
+import com.android.quickstep.TaskOverlayFactory
+import com.android.quickstep.TaskOverlayFactory.TaskOverlay
+import com.android.quickstep.recents.di.RecentsDependencies
+import com.android.quickstep.task.thumbnail.TaskThumbnailView
+import com.android.quickstep.views.RecentsView
+import com.android.quickstep.views.TaskContainer
+import com.android.quickstep.views.TaskThumbnailViewDeprecated
+import com.android.quickstep.views.TaskView
+import com.android.quickstep.views.TaskViewIcon
+import com.android.quickstep.views.TaskViewType
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.Task.TaskKey
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+/** Test for [TaskViewItemInfo] */
+@RunWith(AndroidJUnit4::class)
+class TaskViewItemInfoTest {
+    private val context = mock<Context>()
+    private val taskView = mock<TaskView>()
+    private val recentsView = mock<RecentsView<*, *>>()
+    private val overlayFactory = mock<TaskOverlayFactory>()
+
+    @Before
+    fun setUp() {
+        whenever(overlayFactory.createOverlay(any())).thenReturn(mock<TaskOverlay<*>>())
+        whenever(taskView.context).thenReturn(context)
+        whenever(taskView.recentsView).thenReturn(recentsView)
+        whenever(recentsView.indexOfChild(taskView)).thenReturn(TASK_VIEW_INDEX)
+        RecentsDependencies.initialize(InstrumentationRegistry.getInstrumentation().targetContext)
+    }
+
+    @Test
+    fun singleTask() {
+        val taskContainers = listOf(createTaskContainer(createTask(1)))
+        whenever(taskView.type).thenReturn(TaskViewType.SINGLE)
+        whenever(taskView.taskContainers).thenReturn(taskContainers)
+
+        val taskViewItemInfo = TaskViewItemInfo(taskContainers[0])
+        val taskViewAtom = taskViewItemInfo.taskViewAtom
+
+        assertThat(taskViewAtom)
+            .isEqualTo(
+                createTaskViewAtom(
+                    type = 0,
+                    index = TASK_VIEW_INDEX,
+                    componentName = "${PACKAGE}/${CLASS}",
+                    cardinality = 1,
+                )
+            )
+    }
+
+    @Test
+    fun splitTask() {
+        val taskContainers =
+            listOf(createTaskContainer(createTask(1)), createTaskContainer(createTask(2)))
+        whenever(taskView.type).thenReturn(TaskViewType.GROUPED)
+        whenever(taskView.taskContainers).thenReturn(taskContainers)
+
+        val taskViewItemInfo = TaskViewItemInfo(taskContainers[0])
+        val taskViewAtom = taskViewItemInfo.taskViewAtom
+
+        assertThat(taskViewAtom)
+            .isEqualTo(
+                createTaskViewAtom(
+                    type = 1,
+                    index = TASK_VIEW_INDEX,
+                    componentName = "${PACKAGE}/${CLASS}",
+                    cardinality = 2,
+                )
+            )
+    }
+
+    @Test
+    fun desktopTask() {
+        val taskContainers =
+            listOf(
+                createTaskContainer(createTask(1)),
+                createTaskContainer(createTask(2)),
+                createTaskContainer(createTask(3)),
+            )
+        whenever(taskView.type).thenReturn(TaskViewType.DESKTOP)
+        whenever(taskView.taskContainers).thenReturn(taskContainers)
+
+        val taskViewItemInfo = TaskViewItemInfo(taskContainers[0])
+        val taskViewAtom = taskViewItemInfo.taskViewAtom
+
+        assertThat(taskViewAtom)
+            .isEqualTo(
+                createTaskViewAtom(
+                    type = 2,
+                    index = TASK_VIEW_INDEX,
+                    componentName = "${PACKAGE}/${CLASS}",
+                    cardinality = 3,
+                )
+            )
+    }
+
+    private fun createTask(id: Int) =
+        Task(TaskKey(id, 0, Intent(), ComponentName(PACKAGE, CLASS), 0, 2000))
+
+    private fun createTaskContainer(task: Task): TaskContainer {
+        return TaskContainer(
+            taskView,
+            task,
+            if (enableRefactorTaskThumbnail()) mock<TaskThumbnailView>()
+            else mock<TaskThumbnailViewDeprecated>(),
+            mock<TaskViewIcon>(),
+            mock<TransformingTouchDelegate>(),
+            SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
+            digitalWellBeingToast = null,
+            showWindowsView = null,
+            overlayFactory,
+        )
+    }
+
+    companion object {
+        const val PACKAGE = "package"
+        const val CLASS = "class"
+        const val TASK_VIEW_INDEX = 4
+    }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
index cc8582c..5867e77 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
@@ -272,7 +272,8 @@
     private val taskbarIconsCentered: Boolean
         get() {
             return getOnUiThread {
-                val iconLayoutBounds = taskbarViewController.iconLayoutBounds
+                val iconLayoutBounds =
+                    taskbarViewController.transientTaskbarIconLayoutBoundsInParent
                 val availableWidth = taskbarUnitTestRule.activityContext.deviceProfile.widthPx
                 iconLayoutBounds.left - (availableWidth - iconLayoutBounds.right) < 2
             }
@@ -282,7 +283,7 @@
         get() {
             return getOnUiThread {
                 taskbarUnitTestRule.activityContext.deviceProfile.widthPx -
-                    taskbarViewController.iconLayoutBounds.right
+                    taskbarViewController.transientTaskbarIconLayoutBoundsInParent.right
             }
         }
 
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeControllerTest.kt
index 2e471b8..024ec4c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeControllerTest.kt
@@ -36,6 +36,7 @@
 import org.mockito.kotlin.any
 import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.atLeastOnce
+import org.mockito.kotlin.eq
 import org.mockito.kotlin.never
 import org.mockito.kotlin.times
 import org.mockito.kotlin.verify
@@ -206,7 +207,7 @@
             bubbleBarSwipeController.start()
             bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH)
         }
-        verify(bubbleStashController).showBubbleBar(expandBubbles = false)
+        verify(bubbleStashController).showBubbleBar(expandBubbles = false, bubbleBarGesture = true)
     }
 
     @Test
@@ -227,11 +228,12 @@
             bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH)
             bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH)
         }
-        verify(bubbleStashController).showBubbleBar(expandBubbles = false)
+        verify(bubbleStashController).showBubbleBar(expandBubbles = false, bubbleBarGesture = true)
         verify(bubbleStashController).stashBubbleBar()
 
         getInstrumentation().runOnMainSync { bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH) }
-        verify(bubbleStashController, times(2)).showBubbleBar(expandBubbles = false)
+        verify(bubbleStashController, times(2))
+            .showBubbleBar(expandBubbles = false, bubbleBarGesture = true)
     }
 
     @Test
@@ -241,9 +243,9 @@
             bubbleBarSwipeController.start()
             bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH)
         }
-        verify(bubbleStashController, never()).showBubbleBar(expandBubbles = true)
+        verify(bubbleStashController, never()).showBubbleBar(expandBubbles = eq(true), any())
         getInstrumentation().runOnMainSync { bubbleBarSwipeController.finish() }
-        verify(bubbleStashController).showBubbleBar(expandBubbles = true)
+        verify(bubbleStashController).showBubbleBar(expandBubbles = true, bubbleBarGesture = true)
     }
 
     @Test
@@ -253,12 +255,12 @@
             bubbleBarSwipeController.start()
             bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH)
         }
-        verify(bubbleStashController).showBubbleBar(expandBubbles = false)
+        verify(bubbleStashController).showBubbleBar(expandBubbles = false, bubbleBarGesture = true)
         getInstrumentation().runOnMainSync {
             bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH)
             bubbleBarSwipeController.finish()
         }
-        verify(bubbleStashController, never()).showBubbleBar(expandBubbles = true)
+        verify(bubbleStashController, never()).showBubbleBar(expandBubbles = eq(true), any())
     }
 
     @Test
@@ -334,7 +336,7 @@
             bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH)
             bubbleBarSwipeController.finish()
         }
-        verify(bubbleStashController).showBubbleBar(expandBubbles = true)
+        verify(bubbleStashController).showBubbleBar(expandBubbles = true, bubbleBarGesture = true)
     }
 
     @Test
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index e12876f..29d142f 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -36,6 +36,7 @@
 import com.android.launcher3.R
 import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
 import com.android.launcher3.taskbar.bubbles.BubbleBarOverflow
+import com.android.launcher3.taskbar.bubbles.BubbleBarParentViewHeightUpdateNotifier
 import com.android.launcher3.taskbar.bubbles.BubbleBarView
 import com.android.launcher3.taskbar.bubbles.BubbleView
 import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutController
@@ -69,6 +70,7 @@
 
     private val context = ApplicationProvider.getApplicationContext<Context>()
     private lateinit var animatorScheduler: TestBubbleBarViewAnimatorScheduler
+    private lateinit var bubbleBarParentViewController: TestBubbleBarParentViewHeightUpdateNotifier
     private lateinit var overflowView: BubbleView
     private lateinit var bubbleView: BubbleView
     private lateinit var bubble: BubbleBarBubble
@@ -84,6 +86,7 @@
     @Before
     fun setUp() {
         animatorScheduler = TestBubbleBarViewAnimatorScheduler()
+        bubbleBarParentViewController = TestBubbleBarParentViewHeightUpdateNotifier()
         PhysicsAnimatorTestUtils.prepareForTest()
         setupFlyoutController()
     }
@@ -102,6 +105,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -122,7 +126,7 @@
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         // execute the hide bubble animation
@@ -135,6 +139,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(handle.alpha).isEqualTo(1)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
@@ -156,6 +161,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -178,7 +184,7 @@
         assertThat(animator.isAnimating).isTrue()
 
         verify(bubbleStashController, atLeastOnce()).updateTaskbarTouchRegion()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         // verify the hide bubble animation is pending
@@ -188,6 +194,7 @@
 
         waitForFlyoutToHide()
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(animatorScheduler.delayedBlock).isNull()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
@@ -209,6 +216,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -255,6 +263,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -266,7 +275,7 @@
         // let the animation start and wait for it to complete
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         // execute the hide bubble animation
@@ -282,7 +291,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.onStashStateChangingWhileAnimating()
         }
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(animator.isAnimating).isFalse()
         verify(bubbleStashController).onNewBubbleAnimationInterrupted(any(), any())
 
@@ -306,6 +315,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -344,6 +354,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -389,6 +400,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -440,6 +452,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -454,7 +467,7 @@
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         // verify the hide bubble animation is pending
@@ -469,6 +482,7 @@
 
         waitForFlyoutToHide()
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(handle.alpha).isEqualTo(0)
         assertThat(handle.translationY)
             .isEqualTo(DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS + BAR_TRANSLATION_Y_FOR_TASKBAR)
@@ -495,6 +509,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -510,7 +525,7 @@
         assertThat(animator.isAnimating).isTrue()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -522,6 +537,7 @@
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
         InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(animator.isAnimating).isFalse()
         assertThat(bubbleBarView.alpha).isEqualTo(0)
         assertThat(handle.translationY).isEqualTo(0)
@@ -550,6 +566,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -585,6 +602,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -600,7 +618,7 @@
         assertThat(animator.isAnimating).isTrue()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -608,6 +626,7 @@
 
         waitForFlyoutToHide()
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(animator.isAnimating).isFalse()
         assertThat(bubbleBarView.alpha).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
@@ -629,6 +648,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -678,6 +698,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -689,7 +710,7 @@
         // wait for the animation to start
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(animator.isAnimating).isTrue()
@@ -704,6 +725,7 @@
 
         // verify that the hide animation was canceled
         assertThat(animatorScheduler.delayedBlock).isNull()
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
 
         verifyBubbleBarIsExpandedWithTranslation(BAR_TRANSLATION_Y_FOR_HOTSEAT)
         assertThat(animator.isAnimating).isFalse()
@@ -724,6 +746,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -745,7 +768,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         barAnimator.assertIsRunning()
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(animatorScheduler.delayedBlock).isNotNull()
@@ -754,6 +777,7 @@
         waitForFlyoutToHide()
 
         assertThat(animator.isAnimating).isFalse()
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         // the bubble bar translation y should be back to its initial value
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
 
@@ -778,6 +802,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -821,15 +846,18 @@
         whenever(bubbleStashController.bubbleBarTranslationY)
             .thenReturn(BAR_TRANSLATION_Y_FOR_HOTSEAT)
 
-        val barAnimator = PhysicsAnimator.getInstance(bubbleBarView)
-
+        val semaphore = Semaphore(0)
         var notifiedExpanded = false
-        val onExpanded = Runnable { notifiedExpanded = true }
+        val onExpanded = Runnable {
+            notifiedExpanded = true
+            semaphore.release()
+        }
         val animator =
             BubbleBarViewAnimator(
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -847,6 +875,10 @@
             animatorTestRule.advanceTimeBy(100)
         }
 
+        // verify there is a pending hide animation
+        assertThat(animatorScheduler.delayedBlock).isNotNull()
+        assertThat(animator.isAnimating).isTrue()
+
         // send the expand signal in the middle of the lift animation
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             animator.expandedWhileAnimating()
@@ -857,14 +889,11 @@
             animatorTestRule.advanceTimeBy(150)
         }
 
-        // verify there is a pending hide animation
-        assertThat(animatorScheduler.delayedBlock).isNotNull()
-        assertThat(animator.isAnimating).isTrue()
-
         // the lift animation is complete; the spring back animation should start now. wait for it
         // to complete
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
-        barAnimator.assertIsRunning()
+
+        assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue()
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
         // verify that the hide animation was canceled
@@ -893,6 +922,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpanded,
                 animatorScheduler,
             )
@@ -918,7 +948,7 @@
         // verify there is a pending hide animation
         assertThat(animatorScheduler.delayedBlock).isNotNull()
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
@@ -930,6 +960,7 @@
 
         waitForFlyoutToHide()
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(animator.isAnimating).isFalse()
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_HOTSEAT)
         assertThat(bubbleBarView.isExpanded).isTrue()
@@ -951,6 +982,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -983,7 +1015,7 @@
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
             .isEqualTo("updated message")
@@ -998,6 +1030,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(handle.alpha).isEqualTo(1)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
@@ -1019,6 +1052,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -1039,7 +1073,7 @@
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
@@ -1072,6 +1106,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(handle.alpha).isEqualTo(1)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
@@ -1093,6 +1128,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -1113,7 +1149,7 @@
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
@@ -1134,6 +1170,7 @@
             // the flyout should now reverse and expand
             animatorTestRule.advanceTimeBy(400)
         }
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
 
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
             .isEqualTo("updated message")
@@ -1156,6 +1193,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(3)
         assertThat(handle.alpha).isEqualTo(1)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
@@ -1177,6 +1215,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -1197,7 +1236,7 @@
         assertThat(bubbleBarView.scaleY).isEqualTo(1)
         assertThat(bubbleBarView.translationY).isEqualTo(BAR_TRANSLATION_Y_FOR_TASKBAR)
         assertThat(animator.isAnimating).isTrue()
-
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
         waitForFlyoutToShow()
 
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
@@ -1213,7 +1252,6 @@
         PhysicsAnimatorTestUtils.blockUntilFirstAnimationFrameWhereTrue(handleAnimator) {
             bubbleBarView.alpha < 0.5
         }
-
         // we're about to interrupt the animation which will cancel the current animation and start
         // a new one. pause the scheduler to delay starting the new animation. this allows us to run
         // the test deterministically
@@ -1226,9 +1264,11 @@
             animator.animateBubbleInForStashed(updatedBubble, isExpanding = false)
         }
 
+        // since animation was interrupted there shouldn`t be additional calls to adjust window
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(1)
+
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
         // verify there's a new job scheduled and start it. this is starting the animation from the
         // handle back to the bar
         assertThat(animatorScheduler.pausedBlock).isNotNull()
@@ -1237,9 +1277,9 @@
 
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
-
         waitForFlyoutToShow()
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(2)
         assertThat(flyoutView!!.findViewById<TextView>(R.id.bubble_flyout_text).text)
             .isEqualTo("updated message")
         assertThat(handle.alpha).isEqualTo(0)
@@ -1255,7 +1295,6 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
 
         waitForFlyoutToHide()
-
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
         // verify the hide animation was rescheduled and run it
@@ -1268,6 +1307,7 @@
         InstrumentationRegistry.getInstrumentation().runOnMainSync {}
         PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
 
+        assertThat(bubbleBarParentViewController.timesInvoked).isEqualTo(3)
         assertThat(handle.alpha).isEqualTo(1)
         assertThat(handle.translationY).isEqualTo(0)
         assertThat(bubbleBarView.alpha).isEqualTo(0)
@@ -1289,6 +1329,7 @@
                 bubbleBarView,
                 bubbleStashController,
                 flyoutController,
+                bubbleBarParentViewController,
                 onExpandedNoOp,
                 animatorScheduler,
             )
@@ -1389,10 +1430,6 @@
             }
         val flyoutCallbacks =
             object : FlyoutCallbacks {
-                override fun extendTopBoundary(space: Int) {}
-
-                override fun resetTopBoundary() {}
-
                 override fun flyoutClicked() {}
             }
         val flyoutScheduler = FlyoutScheduler { block -> block.invoke() }
@@ -1475,6 +1512,16 @@
             delayedBlock = null
         }
     }
+
+    private class TestBubbleBarParentViewHeightUpdateNotifier :
+        BubbleBarParentViewHeightUpdateNotifier {
+
+        var timesInvoked: Int = 0
+
+        override fun updateTopBoundary() {
+            timesInvoked++
+        }
+    }
 }
 
 private const val DIFF_BETWEEN_HANDLE_AND_BAR_CENTERS = -20f
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
index 103c769..91fe6a6 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
@@ -128,46 +128,6 @@
     }
 
     @Test
-    fun showFlyout_extendsTopBoundary() {
-        // set negative translation for the flyout so that it will request to extend the top
-        // boundary
-        flyoutTy = -50f
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            setupAndShowFlyout()
-            assertThat(flyoutContainer.childCount).isEqualTo(1)
-        }
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animatorTestRule.advanceTimeBy(showAnimationDuration)
-        }
-        assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(50)
-    }
-
-    @Test
-    fun showFlyout_withinBoundary() {
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            setupAndShowFlyout()
-            assertThat(flyoutContainer.childCount).isEqualTo(1)
-        }
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            animatorTestRule.advanceTimeBy(showAnimationDuration)
-        }
-        assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(0)
-    }
-
-    @Test
-    fun collapseFlyout_resetsTopBoundary() {
-        InstrumentationRegistry.getInstrumentation().runOnMainSync {
-            setupAndShowFlyout()
-            assertThat(flyoutContainer.childCount).isEqualTo(1)
-            flyoutController.collapseFlyout {}
-            animatorTestRule.advanceTimeBy(hideAnimationDuration)
-        }
-        assertThat(flyoutCallbacks.topBoundaryReset).isTrue()
-    }
-
-    @Test
     fun cancelFlyout_fadesOutFlyout() {
         InstrumentationRegistry.getInstrumentation().runOnMainSync {
             setupAndShowFlyout()
@@ -178,7 +138,6 @@
             animatorTestRule.advanceTimeBy(hideAnimationDuration)
             assertThat(flyoutView.alpha).isEqualTo(0f)
         }
-        assertThat(flyoutCallbacks.topBoundaryReset).isTrue()
     }
 
     @Test
@@ -217,7 +176,6 @@
             assertThat(flyout.findViewById<TextView>(R.id.bubble_flyout_text).text)
                 .isEqualTo("new message")
         }
-        assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(50)
     }
 
     @Test
@@ -246,7 +204,6 @@
             animatorTestRule.advanceTimeBy(showAnimationDuration)
             assertThat(flyout.alpha).isEqualTo(1)
         }
-        assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(50)
     }
 
     @Test
@@ -290,18 +247,8 @@
 
     class FakeFlyoutCallbacks : FlyoutCallbacks {
 
-        var topBoundaryExtendedSpace = 0
-        var topBoundaryReset = false
         var flyoutClicked = false
 
-        override fun extendTopBoundary(space: Int) {
-            topBoundaryExtendedSpace = space
-        }
-
-        override fun resetTopBoundary() {
-            topBoundaryReset = true
-        }
-
         override fun flyoutClicked() {
             flyoutClicked = true
         }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
index f795ab1..88b39d3 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
@@ -37,6 +37,7 @@
 import org.mockito.Mock
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
 import org.mockito.kotlin.clearInvocations
 import org.mockito.kotlin.never
 import org.mockito.kotlin.verify
@@ -76,7 +77,7 @@
             PersistentBubbleStashController(DefaultDimensionsProvider())
         setUpBubbleBarView()
         setUpBubbleBarController()
-        persistentTaskBarStashController.setHotseatVerticalCenter(HOTSEAT_VERTICAL_CENTER)
+        persistentTaskBarStashController.bubbleBarVerticalCenterForHome = HOTSEAT_VERTICAL_CENTER
         persistentTaskBarStashController.init(
             taskbarInsetsController,
             bubbleBarViewController,
@@ -342,6 +343,45 @@
         verify(taskbarInsetsController, never()).onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
     }
 
+    @Test
+    fun showBubbleBar_expand_bubbleBarGesture() {
+        whenever(bubbleBarViewController.isHiddenForNoBubbles).thenReturn(false)
+        whenever(bubbleBarViewController.isExpanded).thenReturn(false)
+
+        persistentTaskBarStashController.showBubbleBar(
+            expandBubbles = true,
+            bubbleBarGesture = true,
+        )
+
+        verify(bubbleBarViewController).setExpanded(true, true)
+    }
+
+    @Test
+    fun showBubbleBar_expand_notBubbleBarGesture() {
+        whenever(bubbleBarViewController.isHiddenForNoBubbles).thenReturn(false)
+        whenever(bubbleBarViewController.isExpanded).thenReturn(false)
+
+        persistentTaskBarStashController.showBubbleBar(
+            expandBubbles = true,
+            bubbleBarGesture = false,
+        )
+
+        verify(bubbleBarViewController).setExpanded(true, false)
+    }
+
+    @Test
+    fun showBubbleBar_notExpanding_bubbleBarGesture() {
+        whenever(bubbleBarViewController.isHiddenForNoBubbles).thenReturn(false)
+        whenever(bubbleBarViewController.isExpanded).thenReturn(false)
+
+        persistentTaskBarStashController.showBubbleBar(
+            expandBubbles = false,
+            bubbleBarGesture = true,
+        )
+
+        verify(bubbleBarViewController, never()).setExpanded(any(), any())
+    }
+
     private fun advanceTimeBy(advanceMs: Long) {
         // Advance animator for on-device tests
         getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(advanceMs) }
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
index 1bbd12a..f642345 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
@@ -109,7 +109,7 @@
         setUpStashedHandleView()
         setUpBubbleStashedHandleViewController()
         PhysicsAnimatorTestUtils.prepareForTest()
-        mTransientBubbleStashController.setHotseatVerticalCenter(HOTSEAT_VERTICAL_CENTER)
+        mTransientBubbleStashController.bubbleBarVerticalCenterForHome = HOTSEAT_VERTICAL_CENTER
         mTransientBubbleStashController.init(
             taskbarInsetsController,
             bubbleBarViewController,
@@ -362,6 +362,57 @@
     }
 
     @Test
+    fun updateStashedAndExpandedState_expand_bubbleBarGesture() {
+        mTransientBubbleStashController.isStashed = true
+        whenever(bubbleBarViewController.isHiddenForNoBubbles).thenReturn(false)
+        whenever(bubbleBarViewController.isExpanded).thenReturn(false)
+
+        getInstrumentation().runOnMainSync {
+            mTransientBubbleStashController.updateStashedAndExpandedState(
+                stash = false,
+                expand = true,
+                bubbleBarGesture = true,
+            )
+        }
+
+        verify(bubbleBarViewController).setExpanded(true, true)
+    }
+
+    @Test
+    fun updateStashedAndExpandedState_expand_notBubbleBarGesture() {
+        mTransientBubbleStashController.isStashed = true
+        whenever(bubbleBarViewController.isHiddenForNoBubbles).thenReturn(false)
+        whenever(bubbleBarViewController.isExpanded).thenReturn(false)
+
+        getInstrumentation().runOnMainSync {
+            mTransientBubbleStashController.updateStashedAndExpandedState(
+                stash = false,
+                expand = true,
+                bubbleBarGesture = false,
+            )
+        }
+
+        verify(bubbleBarViewController).setExpanded(true, false)
+    }
+
+    @Test
+    fun updateStashedAndExpandedState_notExpanding_bubbleBarGesture() {
+        mTransientBubbleStashController.isStashed = true
+        whenever(bubbleBarViewController.isHiddenForNoBubbles).thenReturn(false)
+        whenever(bubbleBarViewController.isExpanded).thenReturn(false)
+
+        getInstrumentation().runOnMainSync {
+            mTransientBubbleStashController.updateStashedAndExpandedState(
+                stash = false,
+                expand = false,
+                bubbleBarGesture = true,
+            )
+        }
+
+        verify(bubbleBarViewController, never()).setExpanded(any(), any())
+    }
+
+    @Test
     fun isSysuiLockedSwitchedToFalseForOverview_unlockAnimationIsShown() {
         // Given screen is locked and bubble bar has bubbles
         getInstrumentation().runOnMainSync {
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index cb70694..708273e 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -40,6 +40,7 @@
 import com.android.quickstep.views.RecentsViewContainer
 import com.android.systemui.shared.recents.model.Task
 import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50
+import java.util.function.Consumer
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertNull
@@ -54,7 +55,6 @@
 import org.mockito.kotlin.times
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
-import java.util.function.Consumer
 
 @RunWith(AndroidJUnit4::class)
 class SplitSelectStateControllerTest {
@@ -625,6 +625,21 @@
         verify(splitFromDesktopController).onDestroy()
     }
 
+    @Test
+    fun splitSelectStateControllerDestroyed_doNotResetDeskTopTasks() {
+        whenever(context.getOverviewPanel<RecentsView<*, *>>()).thenReturn(recentsView)
+        splitSelectStateController.setInitialTaskSelect(
+            Intent(), /*intent*/
+            -1, /*stagePosition*/
+            ItemInfo(),
+            null, /*splitEvent*/
+            -1,
+        )
+        splitSelectStateController.onDestroy()
+        splitSelectStateController.resetState()
+        verify(recentsView, times(0)).resetDesktopTaskFromSplitSelectState()
+    }
+
     // Generate GroupTask with default userId.
     private fun generateGroupTask(
         task1ComponentName: ComponentName,
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index 231c113..94e7c2e 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -18,8 +18,6 @@
 
 import android.content.ComponentName
 import android.content.Intent
-import android.platform.test.flag.junit.SetFlagsRule
-import com.android.dx.mockito.inline.extended.ExtendedMockito
 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
 import com.android.dx.mockito.inline.extended.StaticMockitoSession
 import com.android.launcher3.AbstractFloatingView
@@ -27,7 +25,7 @@
 import com.android.launcher3.Flags.enableRefactorTaskThumbnail
 import com.android.launcher3.logging.StatsLogManager
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent
-import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.model.data.TaskViewItemInfo
 import com.android.launcher3.uioverrides.QuickstepLauncher
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.launcher3.util.TransformingTouchDelegate
@@ -40,14 +38,13 @@
 import com.android.quickstep.views.TaskViewIcon
 import com.android.systemui.shared.recents.model.Task
 import com.android.systemui.shared.recents.model.Task.TaskKey
-import com.android.window.flags.Flags
 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
 import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
+import org.mockito.Mockito.`when`
 import org.mockito.kotlin.any
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.eq
@@ -57,24 +54,18 @@
 import org.mockito.kotlin.whenever
 import org.mockito.quality.Strictness
 
-/** Test for DesktopSystemShortcut */
+/** Test for [DesktopSystemShortcut] */
 class DesktopSystemShortcutTest {
 
-    @get:Rule val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
-
     private val launcher: QuickstepLauncher = mock()
     private val statsLogManager: StatsLogManager = mock()
     private val statsLogger: StatsLogManager.StatsLogger = mock()
     private val recentsView: LauncherRecentsView = mock()
     private val taskView: TaskView = mock()
-    private val workspaceItemInfo: WorkspaceItemInfo = mock()
     private val abstractFloatingViewHelper: AbstractFloatingViewHelper = mock()
-    private val iconView: TaskViewIcon = mock()
-    private val transformingTouchDelegate: TransformingTouchDelegate = mock()
+    private val overlayFactory: TaskOverlayFactory = mock()
     private val factory: TaskShortcutFactory =
         DesktopSystemShortcut.createFactory(abstractFloatingViewHelper)
-    private val overlayFactory: TaskOverlayFactory = mock()
-    private val overlay: TaskOverlay<*> = mock()
 
     private lateinit var mockitoSession: StaticMockitoSession
 
@@ -83,11 +74,10 @@
         mockitoSession =
             mockitoSession()
                 .strictness(Strictness.LENIENT)
-                .spyStatic(DesktopModeStatus::class.java)
+                .mockStatic(DesktopModeStatus::class.java)
                 .startMocking()
-        ExtendedMockito.doReturn(true).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
-        ExtendedMockito.doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
-        whenever(overlayFactory.createOverlay(any())).thenReturn(overlay)
+        whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(true)
+        whenever(overlayFactory.createOverlay(any())).thenReturn(mock<TaskOverlay<*>>())
     }
 
     @After
@@ -97,22 +87,7 @@
 
     @Test
     fun createDesktopTaskShortcutFactory_desktopModeDisabled() {
-        setFlagsRule.disableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
-
-        val task =
-            Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
-                isDockable = true
-            }
-        val taskContainer = createTaskContainer(task)
-
-        val shortcuts = factory.getShortcuts(launcher, taskContainer)
-        assertThat(shortcuts).isNull()
-    }
-
-    @Test
-    fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported() {
-        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
-        ExtendedMockito.doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+        `when`(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(false)
 
         val taskContainer = createTaskContainer(createTask())
 
@@ -121,22 +96,7 @@
     }
 
     @Test
-    fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported_OverrideEnabled() {
-        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
-        ExtendedMockito.doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
-        ExtendedMockito.doReturn(false).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
-
-        val taskContainer = spy(createTaskContainer(createTask()))
-        doReturn(workspaceItemInfo).whenever(taskContainer).itemInfo
-
-        val shortcuts = factory.getShortcuts(launcher, taskContainer)
-        assertThat(shortcuts).isNotNull()
-    }
-
-    @Test
     fun createDesktopTaskShortcutFactory_undockable() {
-        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
-
         val unDockableTask = createTask().apply { isDockable = false }
         val taskContainer = createTaskContainer(unDockableTask)
 
@@ -146,8 +106,6 @@
 
     @Test
     fun desktopSystemShortcutClicked() {
-        setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
-
         val task = createTask()
         val taskContainer = spy(createTaskContainer(task))
 
@@ -159,13 +117,14 @@
             val successCallback = it.getArgument<Runnable>(2)
             successCallback.run()
         }
-        doReturn(workspaceItemInfo).whenever(taskContainer).itemInfo
+        val taskViewItemInfo = mock<TaskViewItemInfo>()
+        doReturn(taskViewItemInfo).whenever(taskContainer).itemInfo
 
         val shortcuts = factory.getShortcuts(launcher, taskContainer)
-        assertThat(shortcuts).hasSize(1)
-        assertThat(shortcuts!!.first()).isInstanceOf(DesktopSystemShortcut::class.java)
+        assertThat(shortcuts).isNotNull()
+        assertThat(shortcuts!!.single()).isInstanceOf(DesktopSystemShortcut::class.java)
 
-        val desktopShortcut = shortcuts.first() as DesktopSystemShortcut
+        val desktopShortcut = shortcuts.single() as DesktopSystemShortcut
 
         desktopShortcut.onClick(taskView)
 
@@ -178,30 +137,24 @@
                 eq(DesktopModeTransitionSource.APP_FROM_OVERVIEW),
                 any(),
             )
-        verify(statsLogger).withItemInfo(workspaceItemInfo)
+        verify(statsLogger).withItemInfo(taskViewItemInfo)
         verify(statsLogger).log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DESKTOP_TAP)
     }
 
-    private fun createTask(): Task {
-        return Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
-            isDockable = true
-        }
-    }
+    private fun createTask() =
+        Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { isDockable = true }
 
-    private fun createTaskContainer(task: Task): TaskContainer {
-        val snapshotView =
-            if (enableRefactorTaskThumbnail()) mock<TaskThumbnailView>()
-            else mock<TaskThumbnailViewDeprecated>()
-        return TaskContainer(
+    private fun createTaskContainer(task: Task) =
+        TaskContainer(
             taskView,
             task,
-            snapshotView,
-            iconView,
-            transformingTouchDelegate,
+            if (enableRefactorTaskThumbnail()) mock<TaskThumbnailView>()
+            else mock<TaskThumbnailViewDeprecated>(),
+            mock<TaskViewIcon>(),
+            mock<TransformingTouchDelegate>(),
             SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
             digitalWellBeingToast = null,
             showWindowsView = null,
             overlayFactory,
         )
-    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/ExternalDisplaySystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/ExternalDisplaySystemShortcutTest.kt
index 8968b9c..9c2c13c 100644
--- a/quickstep/tests/src/com/android/quickstep/ExternalDisplaySystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/ExternalDisplaySystemShortcutTest.kt
@@ -18,10 +18,8 @@
 
 import android.content.ComponentName
 import android.content.Intent
-import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
-import com.android.dx.mockito.inline.extended.ExtendedMockito
 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
 import com.android.dx.mockito.inline.extended.StaticMockitoSession
 import com.android.launcher3.AbstractFloatingView
@@ -29,7 +27,7 @@
 import com.android.launcher3.Flags.enableRefactorTaskThumbnail
 import com.android.launcher3.logging.StatsLogManager
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent
-import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.model.data.TaskViewItemInfo
 import com.android.launcher3.uioverrides.QuickstepLauncher
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.launcher3.util.TransformingTouchDelegate
@@ -49,6 +47,7 @@
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
+import org.mockito.Mockito.`when`
 import org.mockito.kotlin.any
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.eq
@@ -58,7 +57,7 @@
 import org.mockito.kotlin.whenever
 import org.mockito.quality.Strictness
 
-/** Test for ExternalDisplaySystemShortcut */
+/** Test for [ExternalDisplaySystemShortcut] */
 class ExternalDisplaySystemShortcutTest {
 
     @get:Rule val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
@@ -68,14 +67,10 @@
     private val statsLogger: StatsLogManager.StatsLogger = mock()
     private val recentsView: LauncherRecentsView = mock()
     private val taskView: TaskView = mock()
-    private val workspaceItemInfo: WorkspaceItemInfo = mock()
     private val abstractFloatingViewHelper: AbstractFloatingViewHelper = mock()
-    private val iconView: TaskViewIcon = mock()
-    private val transformingTouchDelegate: TransformingTouchDelegate = mock()
+    private val overlayFactory: TaskOverlayFactory = mock()
     private val factory: TaskShortcutFactory =
         ExternalDisplaySystemShortcut.createFactory(abstractFloatingViewHelper)
-    private val overlayFactory: TaskOverlayFactory = mock()
-    private val overlay: TaskOverlay<*> = mock()
 
     private lateinit var mockitoSession: StaticMockitoSession
 
@@ -84,11 +79,10 @@
         mockitoSession =
             mockitoSession()
                 .strictness(Strictness.LENIENT)
-                .spyStatic(DesktopModeStatus::class.java)
+                .mockStatic(DesktopModeStatus::class.java)
                 .startMocking()
-        ExtendedMockito.doReturn(true).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
-        ExtendedMockito.doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
-        whenever(overlayFactory.createOverlay(any())).thenReturn(overlay)
+        whenever(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(true)
+        whenever(overlayFactory.createOverlay(any())).thenReturn(mock<TaskOverlay<*>>())
     }
 
     @After
@@ -97,23 +91,9 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     @EnableFlags(Flags.FLAG_MOVE_TO_EXTERNAL_DISPLAY_SHORTCUT)
     fun createExternalDisplayTaskShortcut_desktopModeDisabled() {
-        val task = createTask()
-        val taskContainer = createTaskContainer(task)
-
-        val shortcuts = factory.getShortcuts(launcher, taskContainer)
-        assertThat(shortcuts).isNull()
-    }
-
-    @Test
-    @EnableFlags(
-        Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
-        Flags.FLAG_MOVE_TO_EXTERNAL_DISPLAY_SHORTCUT,
-    )
-    fun createExternalDisplayTaskShortcut_desktopModeEnabled_deviceNotSupported() {
-        ExtendedMockito.doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+        `when`(DesktopModeStatus.canEnterDesktopMode(any())).thenReturn(false)
 
         val taskContainer = createTaskContainer(createTask())
 
@@ -122,26 +102,7 @@
     }
 
     @Test
-    @EnableFlags(
-        Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
-        Flags.FLAG_MOVE_TO_EXTERNAL_DISPLAY_SHORTCUT,
-    )
-    fun createExternalDisplayTaskShortcut_desktopModeEnabled_deviceNotSupported_overrideEnabled() {
-        ExtendedMockito.doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
-        ExtendedMockito.doReturn(false).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
-
-        val taskContainer = spy(createTaskContainer(createTask()))
-        doReturn(workspaceItemInfo).whenever(taskContainer).itemInfo
-
-        val shortcuts = factory.getShortcuts(launcher, taskContainer)
-        assertThat(shortcuts).isNotNull()
-    }
-
-    @Test
-    @EnableFlags(
-        Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE,
-        Flags.FLAG_MOVE_TO_EXTERNAL_DISPLAY_SHORTCUT,
-    )
+    @EnableFlags(Flags.FLAG_MOVE_TO_EXTERNAL_DISPLAY_SHORTCUT)
     fun externalDisplaySystemShortcutClicked() {
         val task = createTask()
         val taskContainer = spy(createTaskContainer(task))
@@ -154,7 +115,8 @@
             val successCallback = it.getArgument<Runnable>(1)
             successCallback.run()
         }
-        doReturn(workspaceItemInfo).whenever(taskContainer).itemInfo
+        val taskViewItemInfo = mock<TaskViewItemInfo>()
+        doReturn(taskViewItemInfo).whenever(taskContainer).itemInfo
 
         val shortcuts = factory.getShortcuts(launcher, taskContainer)
         assertThat(shortcuts).hasSize(1)
@@ -168,26 +130,23 @@
             AbstractFloatingView.TYPE_ALL and AbstractFloatingView.TYPE_REBIND_SAFE.inv()
         verify(abstractFloatingViewHelper).closeOpenViews(launcher, true, allTypesExceptRebindSafe)
         verify(recentsView).moveTaskToExternalDisplay(eq(taskContainer), any())
-        verify(statsLogger).withItemInfo(workspaceItemInfo)
+        verify(statsLogger).withItemInfo(taskViewItemInfo)
         verify(statsLogger).log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_EXTERNAL_DISPLAY_TAP)
     }
 
-    private fun createTask(): Task = Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000))
+    private fun createTask() = Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000))
 
-    private fun createTaskContainer(task: Task): TaskContainer {
-        val snapshotView =
-            if (enableRefactorTaskThumbnail()) mock<TaskThumbnailView>()
-            else mock<TaskThumbnailViewDeprecated>()
-        return TaskContainer(
+    private fun createTaskContainer(task: Task) =
+        TaskContainer(
             taskView,
             task,
-            snapshotView,
-            iconView,
-            transformingTouchDelegate,
+            if (enableRefactorTaskThumbnail()) mock<TaskThumbnailView>()
+            else mock<TaskThumbnailViewDeprecated>(),
+            mock<TaskViewIcon>(),
+            mock<TransformingTouchDelegate>(),
             SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
             digitalWellBeingToast = null,
             showWindowsView = null,
             overlayFactory,
         )
-    }
 }
diff --git a/res/color-night-v31/popup_shade_first.xml b/res/color-night-v31/popup_shade_first.xml
index 28995e3..e62ed9c 100644
--- a/res/color-night-v31/popup_shade_first.xml
+++ b/res/color-night-v31/popup_shade_first.xml
@@ -13,5 +13,5 @@
      limitations under the License.
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/materialColorSurfaceContainer"/>
+    <item android:color="@color/materialColorSurfaceContainer"/>
 </selector>
diff --git a/res/color-v31/popup_shade_first.xml b/res/color-v31/popup_shade_first.xml
index be73698..9a71cae 100644
--- a/res/color-v31/popup_shade_first.xml
+++ b/res/color-v31/popup_shade_first.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/materialColorSurfaceContainer"/>
+    <item android:color="@color/materialColorSurfaceContainer"/>
 </selector>
diff --git a/res/color/overview_button.xml b/res/color/overview_button.xml
index 0b317bd..aa6c618e 100644
--- a/res/color/overview_button.xml
+++ b/res/color/overview_button.xml
@@ -2,10 +2,10 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item
         android:alpha="1"
-        android:color="?attr/materialColorOnSurface"
+        android:color="@color/materialColorOnSurface"
         android:state_enabled="true" />
     <item
         android:alpha="?android:disabledAlpha"
-        android:color="?attr/materialColorOnSurface"
+        android:color="@color/materialColorOnSurface"
         android:state_enabled="false" />
 </selector>
\ No newline at end of file
diff --git a/res/color/popup_shade_first.xml b/res/color/popup_shade_first.xml
index be73698..9a71cae 100644
--- a/res/color/popup_shade_first.xml
+++ b/res/color/popup_shade_first.xml
@@ -14,5 +14,5 @@
      limitations under the License.
 -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/materialColorSurfaceContainer"/>
+    <item android:color="@color/materialColorSurfaceContainer"/>
 </selector>
diff --git a/res/drawable/all_apps_tabs_background_selected.xml b/res/drawable/all_apps_tabs_background_selected.xml
index 6560632..f7873da 100644
--- a/res/drawable/all_apps_tabs_background_selected.xml
+++ b/res/drawable/all_apps_tabs_background_selected.xml
@@ -21,7 +21,7 @@
             android:top="@dimen/all_apps_tabs_focus_vertical_inset">
         <shape android:shape="rectangle">
             <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
-            <solid android:color="?attr/materialColorPrimary" />
+            <solid android:color="@color/materialColorPrimary" />
         </shape>
     </item>
 </layer-list>
\ No newline at end of file
diff --git a/res/drawable/all_apps_tabs_background_selected_focused.xml b/res/drawable/all_apps_tabs_background_selected_focused.xml
index e3d86c0..2840262 100644
--- a/res/drawable/all_apps_tabs_background_selected_focused.xml
+++ b/res/drawable/all_apps_tabs_background_selected_focused.xml
@@ -17,7 +17,7 @@
     <item>
         <shape>
             <corners android:radius="16dp" />
-            <solid android:color="?attr/materialColorPrimary" />
+            <solid android:color="@color/materialColorPrimary" />
         </shape>
     </item>
 
@@ -28,10 +28,10 @@
         android:top="@dimen/all_apps_tabs_focus_border">
         <shape android:shape="rectangle">
             <corners android:radius="13dp" />
-            <solid android:color="?attr/materialColorPrimary" />
+            <solid android:color="@color/materialColorPrimary" />
             <stroke
                 android:width="@dimen/all_apps_tabs_focus_padding"
-                android:color="?attr/materialColorSurfaceDim" />
+                android:color="@color/materialColorSurfaceDim" />
         </shape>
     </item>
 </layer-list>
\ No newline at end of file
diff --git a/res/drawable/all_apps_tabs_background_unselected.xml b/res/drawable/all_apps_tabs_background_unselected.xml
index ce7b334..4004021 100644
--- a/res/drawable/all_apps_tabs_background_unselected.xml
+++ b/res/drawable/all_apps_tabs_background_unselected.xml
@@ -21,7 +21,7 @@
          android:top="@dimen/all_apps_tabs_focus_vertical_inset">
         <shape android:shape="rectangle">
             <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
-            <solid android:color="?attr/materialColorSurfaceBright" />
+            <solid android:color="@color/materialColorSurfaceBright" />
         </shape>
     </item>
 </layer-list>
\ No newline at end of file
diff --git a/res/drawable/all_apps_tabs_background_unselected_focused.xml b/res/drawable/all_apps_tabs_background_unselected_focused.xml
index 0016102..3564a07 100644
--- a/res/drawable/all_apps_tabs_background_unselected_focused.xml
+++ b/res/drawable/all_apps_tabs_background_unselected_focused.xml
@@ -17,7 +17,7 @@
     <item>
         <shape>
             <corners android:radius="16dp" />
-            <solid android:color="?attr/materialColorPrimary" />
+            <solid android:color="@color/materialColorPrimary" />
         </shape>
     </item>
 
@@ -28,10 +28,10 @@
         android:top="@dimen/all_apps_tabs_focus_border">
         <shape android:shape="rectangle">
             <corners android:radius="13dp" />
-            <solid android:color="?attr/materialColorSurfaceBright" />
+            <solid android:color="@color/materialColorSurfaceBright" />
             <stroke
                 android:width="@dimen/all_apps_tabs_focus_padding"
-                android:color="?attr/materialColorSurfaceDim" />
+                android:color="@color/materialColorSurfaceDim" />
         </shape>
     </item>
 </layer-list>
\ No newline at end of file
diff --git a/res/drawable/bg_letter_list_text.xml b/res/drawable/bg_letter_list_text.xml
index bfdd35c..073730c 100644
--- a/res/drawable/bg_letter_list_text.xml
+++ b/res/drawable/bg_letter_list_text.xml
@@ -15,7 +15,7 @@
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="oval">
-    <solid android:color="?attr/materialColorSurface" />
+    <solid android:color="@color/materialColorSurface" />
     <corners android:radius="100dp"/>
     <size
         android:width="@dimen/bg_letter_list_text_size"
diff --git a/res/drawable/bg_ps_header.xml b/res/drawable/bg_ps_header.xml
index da31445..87a21e4 100644
--- a/res/drawable/bg_ps_header.xml
+++ b/res/drawable/bg_ps_header.xml
@@ -20,7 +20,7 @@
         <shape xmlns:android="http://schemas.android.com/apk/res/android"
             android:shape="rectangle">
             <corners android:radius="@dimen/ps_container_corner_radius" />
-            <solid android:color="?attr/materialColorSurfaceContainerHigh" />
+            <solid android:color="@color/materialColorSurfaceContainerHigh" />
         </shape>
     </item>
 </ripple>
diff --git a/res/drawable/bg_ps_lock_button.xml b/res/drawable/bg_ps_lock_button.xml
index aef1e81..7a20e49 100644
--- a/res/drawable/bg_ps_lock_button.xml
+++ b/res/drawable/bg_ps_lock_button.xml
@@ -21,12 +21,12 @@
     android:viewportHeight="36">
     <path
         android:pathData="M18,0L71,0A18,18 0,0 1,89 18L89,18A18,18 0,0 1,71 36L18,36A18,18 0,0 1,0 18L0,18A18,18 0,0 1,18 0z"
-        android:fillColor="?attr/materialColorPrimaryFixedDim"/>
+        android:fillColor="@color/materialColorPrimaryFixedDim"/>
     <path
         android:pathData="M26.167,14.667H27C27.917,14.667 28.667,15.417 28.667,16.333V24.667C28.667,25.583 27.917,26.333 27,26.333H17C16.083,26.333 15.333,25.583 15.333,24.667V16.333C15.333,15.417 16.083,14.667 17,14.667H17.833V13C17.833,10.7 19.7,8.833 22,8.833C24.3,8.833 26.167,10.7 26.167,13V14.667ZM22,10.5C20.617,10.5 19.5,11.617 19.5,13V14.667H24.5V13C24.5,11.617 23.383,10.5 22,10.5ZM17,24.667V16.333H27V24.667H17ZM23.667,20.5C23.667,21.417 22.917,22.167 22,22.167C21.083,22.167 20.333,21.417 20.333,20.5C20.333,19.583 21.083,18.833 22,18.833C22.917,18.833 23.667,19.583 23.667,20.5Z"
-        android:fillColor="?attr/materialColorOnPrimaryFixed"
+        android:fillColor="@color/materialColorOnPrimaryFixed"
         android:fillType="evenOdd"/>
     <path
         android:pathData="M41.204,23V12.976H42.73V21.544H47.504V23H41.204ZM52.352,23.224C51.615,23.224 50.976,23.061 50.434,22.734C49.893,22.398 49.473,21.936 49.174,21.348C48.885,20.76 48.74,20.083 48.74,19.318C48.74,18.543 48.885,17.867 49.174,17.288C49.473,16.7 49.893,16.243 50.434,15.916C50.976,15.58 51.615,15.412 52.352,15.412C53.099,15.412 53.738,15.58 54.27,15.916C54.812,16.243 55.227,16.7 55.516,17.288C55.815,17.867 55.964,18.543 55.964,19.318C55.964,20.083 55.815,20.76 55.516,21.348C55.227,21.936 54.812,22.398 54.27,22.734C53.738,23.061 53.099,23.224 52.352,23.224ZM52.352,21.838C52.772,21.838 53.141,21.74 53.458,21.544C53.776,21.348 54.023,21.063 54.2,20.69C54.378,20.307 54.466,19.85 54.466,19.318C54.466,18.777 54.378,18.319 54.2,17.946C54.023,17.573 53.776,17.288 53.458,17.092C53.141,16.896 52.777,16.798 52.366,16.798C51.946,16.798 51.578,16.896 51.26,17.092C50.943,17.288 50.691,17.573 50.504,17.946C50.327,18.319 50.238,18.777 50.238,19.318C50.238,19.859 50.327,20.317 50.504,20.69C50.691,21.063 50.943,21.348 51.26,21.544C51.587,21.74 51.951,21.838 52.352,21.838ZM60.899,23.224C60.199,23.224 59.583,23.065 59.051,22.748C58.528,22.421 58.118,21.964 57.819,21.376C57.529,20.788 57.385,20.102 57.385,19.318C57.385,18.525 57.534,17.839 57.833,17.26C58.141,16.672 58.561,16.219 59.093,15.902C59.634,15.575 60.255,15.412 60.955,15.412C61.832,15.412 62.556,15.631 63.125,16.07C63.694,16.509 64.039,17.111 64.161,17.876L62.705,18.114C62.611,17.713 62.411,17.395 62.103,17.162C61.804,16.919 61.412,16.798 60.927,16.798C60.544,16.798 60.199,16.896 59.891,17.092C59.583,17.279 59.335,17.559 59.149,17.932C58.972,18.305 58.883,18.767 58.883,19.318C58.883,19.859 58.972,20.321 59.149,20.704C59.326,21.077 59.569,21.362 59.877,21.558C60.185,21.745 60.535,21.838 60.927,21.838C61.394,21.838 61.771,21.721 62.061,21.488C62.36,21.255 62.579,20.909 62.719,20.452L64.133,20.788C63.956,21.507 63.596,22.095 63.055,22.552C62.514,23 61.795,23.224 60.899,23.224ZM65.985,23V12.136H67.483V18.688L70.381,15.636H72.187V15.72L69.499,18.492L72.257,22.916V23H70.549L68.435,19.598L67.483,20.564V23H65.985Z"
-        android:fillColor="?attr/materialColorOnPrimaryFixed"/>
+        android:fillColor="@color/materialColorOnPrimaryFixed"/>
 </vector>
\ No newline at end of file
diff --git a/res/drawable/bg_ps_transition_image.xml b/res/drawable/bg_ps_transition_image.xml
index dfad3cf..694303c 100644
--- a/res/drawable/bg_ps_transition_image.xml
+++ b/res/drawable/bg_ps_transition_image.xml
@@ -23,13 +23,13 @@
     <path
         android:name="path"
         android:pathData="M 19.998 36.668 C 10.816 36.668 3.332 29.184 3.332 20 C 3.332 10.818 10.816 3.334 19.998 3.334 C 20.916 3.334 21.666 4.084 21.666 5 C 21.666 5.918 20.916 6.668 19.998 6.668 C 12.648 6.668 6.666 12.65 6.666 20 C 6.666 27.35 12.648 33.334 19.998 33.334 C 27.348 33.334 33.332 27.35 33.332 20 C 33.332 19.084 34.082 18.334 34.998 18.334 C 35.916 18.334 36.666 19.084 36.666 20 C 36.666 29.184 29.182 36.668 19.998 36.668 Z"
-        android:fillColor="?attr/materialColorOnPrimaryFixed"/>
+        android:fillColor="@color/materialColorOnPrimaryFixed"/>
     <path
         android:name="path_3"
         android:pathData="M 20 0 C 25.302 0 30.393 2.109 34.142 5.858 C 37.891 9.607 40 14.698 40 20 C 40 25.302 37.891 30.393 34.142 34.142 C 30.393 37.891 25.302 40 20 40 C 14.698 40 9.607 37.891 5.858 34.142 C 2.109 30.393 0 25.302 0 20 C 0 14.698 2.109 9.607 5.858 5.858 C 9.607 2.109 14.698 0 20 0"
-        android:fillColor="?attr/materialColorPrimaryFixedDim"/>
+        android:fillColor="@color/materialColorPrimaryFixedDim"/>
     <path
         android:name="path_4"
         android:pathData="M 19.999 28.334 C 15.408 28.334 11.666 24.592 11.666 20 C 11.666 15.409 15.408 11.667 19.999 11.667 C 20.458 11.667 20.833 12.042 20.833 12.5 C 20.833 12.959 20.458 13.334 19.999 13.334 C 16.324 13.334 13.333 16.325 13.333 20 C 13.333 23.675 16.324 26.667 19.999 26.667 C 23.674 26.667 26.666 23.675 26.666 20 C 26.666 19.542 27.041 19.167 27.499 19.167 C 27.958 19.167 28.333 19.542 28.333 20 C 28.333 24.592 24.591 28.334 19.999 28.334 Z"
-        android:fillColor="?attr/materialColorOnPrimaryFixed"/>
+        android:fillColor="@color/materialColorOnPrimaryFixed"/>
 </vector>
\ No newline at end of file
diff --git a/res/drawable/bg_ps_unlock_button.xml b/res/drawable/bg_ps_unlock_button.xml
index d5eedd2..563c3f6 100644
--- a/res/drawable/bg_ps_unlock_button.xml
+++ b/res/drawable/bg_ps_unlock_button.xml
@@ -21,9 +21,9 @@
     android:viewportHeight="36">
     <path
         android:pathData="M18,0L18,0A18,18 0,0 1,36 18L36,18A18,18 0,0 1,18 36L18,36A18,18 0,0 1,0 18L0,18A18,18 0,0 1,18 0z"
-        android:fillColor="?attr/materialColorPrimaryFixedDim"/>
+        android:fillColor="@color/materialColorPrimaryFixedDim"/>
     <path
         android:pathData="M22.167,14.667H23C23.917,14.667 24.667,15.417 24.667,16.333V24.667C24.667,25.583 23.917,26.333 23,26.333H13C12.083,26.333 11.333,25.583 11.333,24.667V16.333C11.333,15.417 12.083,14.667 13,14.667H13.833V13C13.833,10.7 15.7,8.833 18,8.833C20.3,8.833 22.167,10.7 22.167,13V14.667ZM18,10.5C16.617,10.5 15.5,11.617 15.5,13V14.667H20.5V13C20.5,11.617 19.383,10.5 18,10.5ZM13,24.667V16.333H23V24.667H13ZM19.667,20.5C19.667,21.417 18.917,22.167 18,22.167C17.083,22.167 16.333,21.417 16.333,20.5C16.333,19.583 17.083,18.833 18,18.833C18.917,18.833 19.667,19.583 19.667,20.5Z"
-        android:fillColor="?attr/materialColorOnPrimaryFixed"
+        android:fillColor="@color/materialColorOnPrimaryFixed"
         android:fillType="evenOdd"/>
 </vector>
\ No newline at end of file
diff --git a/res/drawable/bg_rounded_corner_bottom_sheet_handle.xml b/res/drawable/bg_rounded_corner_bottom_sheet_handle.xml
index a19465d..b0bd33b 100644
--- a/res/drawable/bg_rounded_corner_bottom_sheet_handle.xml
+++ b/res/drawable/bg_rounded_corner_bottom_sheet_handle.xml
@@ -16,6 +16,6 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle" >
-    <solid android:color="?attr/materialColorOutlineVariant"/>
+    <solid android:color="@color/materialColorOutlineVariant"/>
     <corners android:radius="@dimen/bottom_sheet_handle_corner_radius" />
 </shape>
diff --git a/res/drawable/button_top_rounded_bordered_ripple.xml b/res/drawable/button_top_rounded_bordered_ripple.xml
index 13959f6..723668f 100644
--- a/res/drawable/button_top_rounded_bordered_ripple.xml
+++ b/res/drawable/button_top_rounded_bordered_ripple.xml
@@ -25,7 +25,7 @@
                     android:topRightRadius="12dp"
                     android:bottomLeftRadius="4dp"
                     android:bottomRightRadius="4dp"  />
-                <solid android:color="?attr/materialColorSurfaceContainerHighest"/>
+                <solid android:color="@color/materialColorSurfaceContainerHighest"/>
                 <stroke
                     android:width="2dp"
                     android:color="@color/button_bg"/>
diff --git a/res/drawable/ic_close_work_edu.xml b/res/drawable/ic_close_work_edu.xml
index e4053e3..24f61dd 100644
--- a/res/drawable/ic_close_work_edu.xml
+++ b/res/drawable/ic_close_work_edu.xml
@@ -20,6 +20,6 @@
     android:viewportWidth="960"
     android:viewportHeight="960">
     <path
-        android:fillColor="?attr/materialColorOnSurface"
+        android:fillColor="@color/materialColorOnSurface"
         android:pathData="M256,760L200,704L424,480L200,256L256,200L480,424L704,200L760,256L536,480L760,704L704,760L480,536L256,760Z"/>
 </vector>
diff --git a/res/drawable/ic_corp_off.xml b/res/drawable/ic_corp_off.xml
index d4bb2f3..e58e172 100644
--- a/res/drawable/ic_corp_off.xml
+++ b/res/drawable/ic_corp_off.xml
@@ -19,6 +19,6 @@
     android:viewportHeight="24">
     <path
         android:pathData="M16,6H20C21.11,6 22,6.89 22,8V18.99C22,19.021 21.994,19.05 21.989,19.077C21.984,19.102 21.98,19.126 21.98,19.15L20,17.17V8H10.83L8,5.17V4C8,2.89 8.89,2 10,2H14C15.11,2 16,2.89 16,4V6ZM10,6H14V4H10V6ZM19,19L8,8L6,6L2.81,2.81L1.39,4.22L3.3,6.13C2.54,6.41 2.01,7.14 2.01,8L2,19C2,20.11 2.89,21 4,21H18.17L19.78,22.61L21.19,21.2L20.82,20.83L19,19ZM4,8V19H16.17L5.17,8H4Z"
-        android:fillColor="?attr/materialColorOnPrimary"
+        android:fillColor="@color/materialColorOnPrimary"
         android:fillType="evenOdd"/>
 </vector>
diff --git a/res/drawable/ic_info_no_shadow.xml b/res/drawable/ic_info_no_shadow.xml
index 29a81bd..31cf512 100644
--- a/res/drawable/ic_info_no_shadow.xml
+++ b/res/drawable/ic_info_no_shadow.xml
@@ -18,7 +18,7 @@
         android:height="24dp"
         android:viewportWidth="24"
         android:viewportHeight="24"
-        android:tint="?attr/materialColorOnSurface">
+        android:tint="@color/materialColorOnSurface">
 
     <path
         android:fillColor="@android:color/white"
diff --git a/res/drawable/ic_install_no_shadow.xml b/res/drawable/ic_install_no_shadow.xml
index 6e0125a..be06c7d 100644
--- a/res/drawable/ic_install_no_shadow.xml
+++ b/res/drawable/ic_install_no_shadow.xml
@@ -18,7 +18,7 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24"
-    android:tint="?attr/materialColorOnSurface">
+    android:tint="@color/materialColorOnSurface">
 
     <path
         android:fillColor="@android:color/white"
diff --git a/res/drawable/ic_install_to_private.xml b/res/drawable/ic_install_to_private.xml
index a16d35a..9b7a218 100644
--- a/res/drawable/ic_install_to_private.xml
+++ b/res/drawable/ic_install_to_private.xml
@@ -20,7 +20,7 @@
     android:height="24dp"
     android:viewportWidth="24"
     android:viewportHeight="24"
-    android:tint="?attr/materialColorOnSurface">
+    android:tint="@color/materialColorOnSurface">
 
     <group>
         <clip-path
diff --git a/res/drawable/ic_lock.xml b/res/drawable/ic_lock.xml
index 055e6b4..40de060 100644
--- a/res/drawable/ic_lock.xml
+++ b/res/drawable/ic_lock.xml
@@ -19,6 +19,6 @@
     android:viewportWidth="960"
     android:viewportHeight="960">
     <path
-        android:fillColor="?attr/materialColorOnPrimaryFixed"
+        android:fillColor="@color/materialColorOnPrimaryFixed"
         android:pathData="M263.72,864Q234,864 213,842.85Q192,821.7 192,792L192,408Q192,378.3 213.15,357.15Q234.3,336 264,336L288,336L288,240Q288,160.32 344.23,104.16Q400.45,48 480.23,48Q560,48 616,104.16Q672,160.32 672,240L672,336L696,336Q725.7,336 746.85,357.15Q768,378.3 768,408L768,792Q768,821.7 746.84,842.85Q725.68,864 695.96,864L263.72,864ZM264,792L696,792Q696,792 696,792Q696,792 696,792L696,408Q696,408 696,408Q696,408 696,408L264,408Q264,408 264,408Q264,408 264,408L264,792Q264,792 264,792Q264,792 264,792ZM480.21,672Q510,672 531,650.79Q552,629.58 552,599.79Q552,570 530.79,549Q509.58,528 479.79,528Q450,528 429,549.21Q408,570.42 408,600.21Q408,630 429.21,651Q450.42,672 480.21,672ZM360,336L600,336L600,240Q600,190 565,155Q530,120 480,120Q430,120 395,155Q360,190 360,240L360,336ZM264,792Q264,792 264,792Q264,792 264,792L264,408Q264,408 264,408Q264,408 264,408L264,408Q264,408 264,408Q264,408 264,408L264,792Q264,792 264,792Q264,792 264,792L264,792Z"/>
 </vector>
diff --git a/res/drawable/ic_private_profile_divider_badge.xml b/res/drawable/ic_private_profile_divider_badge.xml
index 07c740d..92292f6 100644
--- a/res/drawable/ic_private_profile_divider_badge.xml
+++ b/res/drawable/ic_private_profile_divider_badge.xml
@@ -21,6 +21,6 @@
     <group>
       <path
           android:pathData="M5,9L15,9A1,1 0,0 1,16 10L16,10A1,1 0,0 1,15 11L5,11A1,1 0,0 1,4 10L4,10A1,1 0,0 1,5 9z"
-          android:fillColor="?attr/materialColorOnSurface"/>
+          android:fillColor="@color/materialColorOnSurface"/>
     </group>
 </vector>
diff --git a/res/drawable/ic_private_space_with_background.xml b/res/drawable/ic_private_space_with_background.xml
index cc73f6d..d66549d 100644
--- a/res/drawable/ic_private_space_with_background.xml
+++ b/res/drawable/ic_private_space_with_background.xml
@@ -19,13 +19,13 @@
     android:height="48dp">
     <path
         android:pathData="M48 24A24 24 0 0 1 0 24A24 24 0 0 1 48 24Z"
-        android:fillColor="?attr/materialColorSurfaceContainerLowest" />
+        android:fillColor="@color/materialColorSurfaceContainerLowest" />
     <path
         android:pathData="M24.0021 10.6641L13.3354 14.6641V22.7841C13.3354 29.5174 17.8821 35.7974 24.0021 37.3307C30.1221 35.7974 34.6688 29.5174 34.6688 22.7841V14.6641L24.0021 10.6641ZM32.0021 22.7841C32.0021 28.1174 28.6021 33.0507 24.0021 34.5574C19.4021 33.0507 16.0021 28.1307 16.0021 22.7841V16.5174L24.0021 13.5174L32.0021 16.5174V22.7841Z"
         android:fillType="evenOdd"
-        android:fillColor="?attr/materialColorOnSurface" />
+        android:fillColor="@color/materialColorOnSurface" />
     <path
         android:pathData="M19.3354 20.6657C19.3354 22.7724 20.7488 24.5457 22.6688 25.119V31.999H25.3354V30.6657H28.0021V27.999H25.3354V25.119C27.2554 24.5457 28.6688 22.7857 28.6688 20.6657C28.6688 18.0924 26.5754 15.999 24.0021 15.999C21.4288 15.999 19.3354 18.0924 19.3354 20.6657ZM26.0021 20.6657C26.0021 21.7724 25.1088 22.6657 24.0021 22.6657C22.8954 22.6657 22.0021 21.7724 22.0021 20.6657C22.0021 19.559 22.8954 18.6657 24.0021 18.6657C25.1088 18.6657 26.0021 19.559 26.0021 20.6657Z"
         android:fillType="evenOdd"
-        android:fillColor="?attr/materialColorOnSurface" />
+        android:fillColor="@color/materialColorOnSurface" />
 </vector>
diff --git a/res/drawable/ic_ps_settings.xml b/res/drawable/ic_ps_settings.xml
index 47edeb8..5453f35 100644
--- a/res/drawable/ic_ps_settings.xml
+++ b/res/drawable/ic_ps_settings.xml
@@ -24,9 +24,9 @@
             android:pathData="M10,10h20v20h-20z"/>
         <path
             android:pathData="M21.542,28.542H18.458C17.841,28.542 17.325,28.092 17.25,27.483L17.025,25.908C16.8,25.792 16.583,25.667 16.367,25.525L14.866,26.125C14.283,26.342 13.642,26.1 13.358,25.583L11.833,22.942C11.542,22.392 11.667,21.742 12.133,21.375L13.408,20.383C13.4,20.258 13.392,20.133 13.392,20C13.392,19.875 13.4,19.742 13.408,19.617L12.142,18.625C11.65,18.25 11.525,17.575 11.833,17.058L13.375,14.4C13.658,13.883 14.3,13.65 14.866,13.875L16.375,14.483C16.591,14.342 16.808,14.217 17.025,14.1L17.25,12.508C17.325,11.925 17.841,11.467 18.45,11.467H21.533C22.15,11.467 22.667,11.917 22.742,12.525L22.966,14.1C23.191,14.217 23.408,14.342 23.625,14.483L25.125,13.883C25.716,13.667 26.358,13.908 26.642,14.425L28.175,17.075C28.475,17.625 28.341,18.275 27.875,18.642L26.608,19.633C26.617,19.758 26.625,19.883 26.625,20.017C26.625,20.15 26.617,20.275 26.608,20.4L27.875,21.392C28.341,21.767 28.475,22.417 28.183,22.942L26.633,25.625C26.35,26.142 25.708,26.375 25.133,26.15L23.633,25.55C23.417,25.692 23.2,25.817 22.983,25.933L22.758,27.525C22.675,28.092 22.158,28.542 21.542,28.542ZM21.1,27.267C21.1,27.275 21.1,27.275 21.1,27.283V27.267ZM18.9,27.25V27.267C18.908,27.267 18.908,27.258 18.9,27.25ZM18.85,26.875H21.15L21.458,24.75L21.9,24.567C22.267,24.417 22.633,24.2 23.017,23.917L23.392,23.633L25.375,24.433L26.525,22.433L24.833,21.117L24.892,20.65C24.917,20.433 24.941,20.225 24.941,20C24.941,19.775 24.917,19.558 24.892,19.35L24.833,18.883L26.525,17.567L25.367,15.567L23.375,16.367L23,16.075C22.65,15.808 22.275,15.592 21.892,15.433L21.458,15.25L21.15,13.125H18.85L18.542,15.25L18.1,15.425C17.733,15.583 17.367,15.792 16.983,16.083L16.608,16.358L14.625,15.567L13.467,17.558L15.158,18.875L15.1,19.342C15.075,19.558 15.05,19.783 15.05,20C15.05,20.217 15.066,20.442 15.1,20.65L15.158,21.117L13.467,22.433L14.616,24.433L16.608,23.633L16.983,23.925C17.341,24.2 17.7,24.408 18.091,24.567L18.533,24.75L18.85,26.875ZM25.183,24.767C25.183,24.775 25.175,24.783 25.175,24.792L25.183,24.767ZM14.808,24.758L14.816,24.775C14.816,24.767 14.808,24.758 14.808,24.758ZM25.183,15.225C25.183,15.233 25.191,15.242 25.191,15.242L25.183,15.225ZM14.825,15.208L14.816,15.225C14.816,15.225 14.825,15.217 14.825,15.208ZM21.091,12.733C21.091,12.742 21.091,12.742 21.091,12.75V12.733ZM18.908,12.717V12.733C18.908,12.725 18.908,12.725 18.908,12.717Z"
-            android:fillColor="?attr/materialColorOnSurfaceVariant"/>
+            android:fillColor="@color/materialColorOnSurfaceVariant"/>
         <path
             android:pathData="M20,22.917C21.611,22.917 22.916,21.611 22.916,20C22.916,18.389 21.611,17.083 20,17.083C18.389,17.083 17.083,18.389 17.083,20C17.083,21.611 18.389,22.917 20,22.917Z"
-            android:fillColor="?attr/materialColorOnSurfaceVariant"/>
+            android:fillColor="@color/materialColorOnSurfaceVariant"/>
     </group>
 </vector>
\ No newline at end of file
diff --git a/res/drawable/ic_schedule.xml b/res/drawable/ic_schedule.xml
index 3eeb6a2..d57b0a7 100644
--- a/res/drawable/ic_schedule.xml
+++ b/res/drawable/ic_schedule.xml
@@ -20,6 +20,6 @@
     android:viewportHeight="960"
     android:tint="?attr/colorControlNormal">
     <path
-        android:fillColor="?attr/materialColorOnPrimary"
+        android:fillColor="@color/materialColorOnPrimary"
         android:pathData="M612,668L668,612L520,464L520,280L440,280L440,496L612,668ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z"/>
 </vector>
diff --git a/res/drawable/ic_uninstall_no_shadow.xml b/res/drawable/ic_uninstall_no_shadow.xml
index 6200054..829e590 100644
--- a/res/drawable/ic_uninstall_no_shadow.xml
+++ b/res/drawable/ic_uninstall_no_shadow.xml
@@ -18,7 +18,7 @@
         android:height="20dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"
-        android:tint="?attr/materialColorOnSurface" >
+        android:tint="@color/materialColorOnSurface" >
     <path
         android:fillColor="@android:color/white"
         android:pathData="M15,4V3H9v1H4v2h1v13c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V6h1V4H15z M17,19H7V6h10V19z" />
diff --git a/res/drawable/icon_menu_arrow_background.xml b/res/drawable/icon_menu_arrow_background.xml
index 6345c2b..1de111a 100644
--- a/res/drawable/icon_menu_arrow_background.xml
+++ b/res/drawable/icon_menu_arrow_background.xml
@@ -21,7 +21,7 @@
         android:angle="0"
         android:startColor="#00000000"
         android:centerX="0.25"
-        android:centerColor="?attr/materialColorSurfaceBright"
-        android:endColor="?attr/materialColorSurfaceBright" />
+        android:centerColor="@color/materialColorSurfaceBright"
+        android:endColor="@color/materialColorSurfaceBright" />
     <corners android:radius="@dimen/dialogCornerRadius" />
 </shape>
\ No newline at end of file
diff --git a/res/drawable/popup_background.xml b/res/drawable/popup_background.xml
index 4ddd228..686456f 100644
--- a/res/drawable/popup_background.xml
+++ b/res/drawable/popup_background.xml
@@ -15,6 +15,6 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="?attr/materialColorSurfaceContainer"/>
+    <solid android:color="@color/materialColorSurfaceContainer"/>
     <corners android:radius="@dimen/dialogCornerRadius"/>
 </shape>
\ No newline at end of file
diff --git a/res/drawable/private_space_app_divider.xml b/res/drawable/private_space_app_divider.xml
index 1ea12b3..f92dca7 100644
--- a/res/drawable/private_space_app_divider.xml
+++ b/res/drawable/private_space_app_divider.xml
@@ -16,6 +16,6 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="?attr/materialColorOutlineVariant"/>
+    <solid android:color="@color/materialColorOutlineVariant"/>
     <size android:height="@dimen/all_apps_divider_height" />
 </shape>
\ No newline at end of file
diff --git a/res/drawable/ps_lock_background.xml b/res/drawable/ps_lock_background.xml
index 0be83db..bc66595 100644
--- a/res/drawable/ps_lock_background.xml
+++ b/res/drawable/ps_lock_background.xml
@@ -21,7 +21,7 @@
         <inset android:inset="4dp">
             <shape android:shape="rectangle">
                 <corners android:radius="@dimen/ps_lock_corner_radius" />
-                <solid android:color="?attr/materialColorPrimaryFixedDim" />
+                <solid android:color="@color/materialColorPrimaryFixedDim" />
                 <padding
                     android:left="@dimen/ps_lock_button_background_padding"
                     android:right="@dimen/ps_lock_button_background_padding" />
diff --git a/res/drawable/ps_settings_background.xml b/res/drawable/ps_settings_background.xml
index b0c6b5b..7746012 100644
--- a/res/drawable/ps_settings_background.xml
+++ b/res/drawable/ps_settings_background.xml
@@ -18,6 +18,6 @@
     android:inset="4dp">
     <shape android:shape="rectangle">
         <corners android:radius="@dimen/ps_lock_corner_radius" />
-        <solid android:color="?attr/materialColorSurfaceBright" />
+        <solid android:color="@color/materialColorSurfaceBright" />
     </shape>
 </inset>
\ No newline at end of file
diff --git a/res/drawable/rounded_action_button.xml b/res/drawable/rounded_action_button.xml
index ebfa996..6ee6d65 100644
--- a/res/drawable/rounded_action_button.xml
+++ b/res/drawable/rounded_action_button.xml
@@ -17,10 +17,10 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="?attr/materialColorSurfaceContainerLow" />
+    <solid android:color="@color/materialColorSurfaceContainerLow" />
     <corners android:radius="@dimen/rounded_button_radius" />
     <stroke
         android:width="1dp"
-        android:color="?attr/materialColorSurfaceContainerLow" />
+        android:color="@color/materialColorSurfaceContainerLow" />
 </shape>
 
diff --git a/res/drawable/work_card.xml b/res/drawable/work_card.xml
index 01ec947..0e37d4f 100644
--- a/res/drawable/work_card.xml
+++ b/res/drawable/work_card.xml
@@ -17,7 +17,7 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
-    <solid android:color="?attr/materialColorSurfaceContainerHighest" />
+    <solid android:color="@color/materialColorSurfaceContainerHighest" />
     <corners android:radius="@dimen/work_edu_card_radius" />
 </shape>
 
diff --git a/res/drawable/work_mode_fab_background.xml b/res/drawable/work_mode_fab_background.xml
index 5bad965..ad795eb 100644
--- a/res/drawable/work_mode_fab_background.xml
+++ b/res/drawable/work_mode_fab_background.xml
@@ -18,7 +18,7 @@
     <item>
         <shape android:shape="rectangle">
             <corners android:radius="@dimen/work_fab_radius" />
-            <solid android:color="?attr/materialColorPrimary" />
+            <solid android:color="@color/materialColorPrimary" />
             <padding
                 android:left="@dimen/work_mode_fab_background_horizontal_padding"
                 android:right="@dimen/work_mode_fab_background_horizontal_padding"/>
diff --git a/res/drawable/work_scheduler_background.xml b/res/drawable/work_scheduler_background.xml
index 6bbf029..50c8183 100644
--- a/res/drawable/work_scheduler_background.xml
+++ b/res/drawable/work_scheduler_background.xml
@@ -18,7 +18,7 @@
     <item>
         <shape android:shape="rectangle">
             <corners android:radius="@dimen/work_fab_radius" />
-            <solid android:color="?attr/materialColorPrimary" />
+            <solid android:color="@color/materialColorPrimary" />
             <padding
                 android:padding="@dimen/work_scheduler_background_padding" />
         </shape>
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index 6bce220..29da5aa 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -61,7 +61,7 @@
                 android:layout_marginBottom="@dimen/ps_lock_icon_margin_bottom"
                 android:importantForAccessibility="no"
                 android:src="@drawable/ic_lock"
-                app:tint="?attr/materialColorPrimaryFixedDim"
+                app:tint="@color/materialColorPrimaryFixedDim"
                 android:scaleType="center"/>
             <TextView
                 android:id="@+id/lock_text"
@@ -69,7 +69,7 @@
                 android:layout_height="wrap_content"
                 android:layout_marginStart="@dimen/ps_lock_icon_text_margin_start_expanded"
                 android:layout_marginEnd="@dimen/ps_lock_icon_text_margin_end_expanded"
-                android:textColor="?attr/materialColorOnPrimaryFixed"
+                android:textColor="@color/materialColorOnPrimaryFixed"
                 android:textSize="14sp"
                 android:text="@string/ps_container_lock_title"
                 android:maxLines="1"
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index e2f0e09..d6d83e4 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -37,7 +37,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:maxWidth="@dimen/work_fab_width"
-        android:textColor="?attr/materialColorOnPrimary"
+        android:textColor="@color/materialColorOnPrimary"
         android:textSize="14sp"
         android:includeFontPadding="false"
         android:textDirection="locale"
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index 887a2a5..004f12f 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -17,4 +17,50 @@
 <resources>
     <color name="material_color_surface_container_lowest">#0D0E11</color>
     <color name="material_color_on_surface">#E3E2E6</color>
+
+    <color name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</color>
+    <color name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</color>
+    <color name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</color>
+    <color name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</color>
+    <color name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</color>
+    <color name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</color>
+    <color name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</color>
+    <color name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</color>
+    <color name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</color>
+    <color name="materialColorOnErrorContainer">@color/system_on_error_container_dark</color>
+    <color name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</color>
+    <color name="materialColorInverseOnSurface">@color/system_on_surface_light</color>
+    <color name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</color>
+    <color name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</color>
+    <color name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</color>
+    <color name="materialColorSecondaryContainer">@color/system_secondary_container_dark</color>
+    <color name="materialColorErrorContainer">@color/system_error_container_dark</color>
+    <color name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</color>
+    <color name="materialColorInversePrimary">@color/system_primary_light</color>
+    <color name="materialColorSecondaryFixed">@color/system_secondary_fixed</color>
+    <color name="materialColorInverseSurface">@color/system_surface_light</color>
+    <color name="materialColorSurfaceVariant">@color/system_surface_variant_dark</color>
+    <color name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</color>
+    <color name="materialColorTertiaryFixed">@color/system_tertiary_fixed</color>
+    <color name="materialColorPrimaryContainer">@color/system_primary_container_dark</color>
+    <color name="materialColorOnBackground">@color/system_on_background_dark</color>
+    <color name="materialColorPrimaryFixed">@color/system_primary_fixed</color>
+    <color name="materialColorOnSecondary">@color/system_on_secondary_dark</color>
+    <color name="materialColorOnTertiary">@color/system_on_tertiary_dark</color>
+    <color name="materialColorSurfaceDim">@color/system_surface_dim_dark</color>
+    <color name="materialColorSurfaceBright">@color/system_surface_bright_dark</color>
+    <color name="materialColorOnError">@color/system_on_error_dark</color>
+    <color name="materialColorSurface">@color/system_surface_dark</color>
+    <color name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</color>
+    <color name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</color>
+    <color name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</color>
+    <color name="materialColorOutline">@color/system_outline_dark</color>
+    <color name="materialColorOutlineVariant">@color/system_outline_variant_dark</color>
+    <color name="materialColorOnPrimary">@color/system_on_primary_dark</color>
+    <color name="materialColorOnSurface">@color/system_on_surface_dark</color>
+    <color name="materialColorSurfaceContainer">@color/system_surface_container_dark</color>
+    <color name="materialColorPrimary">@color/system_primary_dark</color>
+    <color name="materialColorSecondary">@color/system_secondary_dark</color>
+    <color name="materialColorTertiary">@color/system_tertiary_dark</color>
+    <color name="materialColorError">@color/system_error_dark</color>
 </resources>
\ No newline at end of file
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index a891e39..89b635d 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -27,51 +27,6 @@
     </style>
 
     <style name="DynamicColorsBaseLauncherTheme" parent="@style/BaseLauncherTheme">
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorInverseOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item>
-        <item name="materialColorErrorContainer">@color/system_error_container_dark</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorInversePrimary">@color/system_primary_light</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorInverseSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item>
-        <item name="materialColorOnBackground">@color/system_on_background_dark</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item>
-        <item name="materialColorOnError">@color/system_on_error_dark</item>
-        <item name="materialColorSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item>
-        <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item>
-        <item name="materialColorOutline">@color/system_outline_dark</item>
-        <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_dark</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item>
-        <item name="materialColorPrimary">@color/system_primary_dark</item>
-        <item name="materialColorSecondary">@color/system_secondary_dark</item>
-        <item name="materialColorTertiary">@color/system_tertiary_dark</item>
-        <item name="materialColorError">@color/system_error_dark</item>
     </style>
 
     <style name="WidgetPickerActivityTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
diff --git a/res/values-v30/styles.xml b/res/values-v30/styles.xml
index a5c57c8..ec5c113 100644
--- a/res/values-v30/styles.xml
+++ b/res/values-v30/styles.xml
@@ -29,6 +29,5 @@
         <item name="android:windowLayoutInDisplayCutoutMode">always</item>
         <item name="android:enforceStatusBarContrast">false</item>
         <item name="android:enforceNavigationBarContrast">false</item>
-        <item name="materialColorOnPrimaryFixed">#FFFFFFFF</item>
     </style>
 </resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 128f84d..c477633 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -44,54 +44,6 @@
     <attr name="focusOutlineColor" format="color" />
     <attr name="focusInnerOutlineColor" format="color" />
 
-    <!--    Recreating Dynamic Color attributes found in the system. This should be the way to go on
-     all launcher projects since they all inherit from launcher3. Avoid creating other color
-     attributes if these can be user directly. -->
-    <attr name="materialColorOnSecondaryFixedVariant" format="color" />
-    <attr name="materialColorOnTertiaryFixedVariant" format="color" />
-    <attr name="materialColorSurfaceContainerLowest" format="color" />
-    <attr name="materialColorOnPrimaryFixedVariant" format="color" />
-    <attr name="materialColorOnSecondaryContainer" format="color" />
-    <attr name="materialColorOnTertiaryContainer" format="color" />
-    <attr name="materialColorSurfaceContainerLow" format="color" />
-    <attr name="materialColorOnPrimaryContainer" format="color" />
-    <attr name="materialColorSecondaryFixedDim" format="color" />
-    <attr name="materialColorOnErrorContainer" format="color" />
-    <attr name="materialColorOnSecondaryFixed" format="color" />
-    <attr name="materialColorInverseOnSurface" format="color" />
-    <attr name="materialColorTertiaryFixedDim" format="color" />
-    <attr name="materialColorOnTertiaryFixed" format="color" />
-    <attr name="materialColorPrimaryFixedDim" format="color" />
-    <attr name="materialColorSecondaryContainer" format="color" />
-    <attr name="materialColorErrorContainer" format="color" />
-    <attr name="materialColorOnPrimaryFixed" format="color" />
-    <attr name="materialColorInversePrimary" format="color" />
-    <attr name="materialColorSecondaryFixed" format="color" />
-    <attr name="materialColorInverseSurface" format="color" />
-    <attr name="materialColorSurfaceVariant" format="color" />
-    <attr name="materialColorTertiaryContainer" format="color" />
-    <attr name="materialColorTertiaryFixed" format="color" />
-    <attr name="materialColorPrimaryContainer" format="color" />
-    <attr name="materialColorOnBackground" format="color" />
-    <attr name="materialColorPrimaryFixed" format="color" />
-    <attr name="materialColorOnSecondary" format="color" />
-    <attr name="materialColorOnTertiary" format="color" />
-    <attr name="materialColorSurfaceDim" format="color" />
-    <attr name="materialColorSurfaceBright" format="color" />
-    <attr name="materialColorOnError" format="color" />
-    <attr name="materialColorSurface" format="color" />
-    <attr name="materialColorSurfaceContainerHigh" format="color" />
-    <attr name="materialColorSurfaceContainerHighest" format="color" />
-    <attr name="materialColorOnSurfaceVariant" format="color" />
-    <attr name="materialColorOutline" format="color" />
-    <attr name="materialColorOutlineVariant" format="color" />
-    <attr name="materialColorOnPrimary" format="color" />
-    <attr name="materialColorOnSurface" format="color" />
-    <attr name="materialColorSurfaceContainer" format="color" />
-    <attr name="materialColorPrimary" format="color" />
-    <attr name="materialColorSecondary" format="color" />
-    <attr name="materialColorTertiary" format="color" />
-    <attr name="materialColorError" format="color" />
 
     <attr name="pageIndicatorDotColor" format="color" />
     <attr name="folderPreviewColor" format="color" />
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 4549b86..967d97d 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -256,4 +256,50 @@
     <color name="system_tertiary_fixed_dim">#E0BBDD</color>
     <color name="system_on_tertiary_fixed">#2A122C</color>
     <color name="system_on_tertiary_fixed_variant">#593D59</color>
+
+    <color name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</color>
+    <color name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</color>
+    <color name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</color>
+    <color name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</color>
+    <color name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</color>
+    <color name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</color>
+    <color name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</color>
+    <color name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</color>
+    <color name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</color>
+    <color name="materialColorOnErrorContainer">@color/system_on_error_container_light</color>
+    <color name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</color>
+    <color name="materialColorInverseOnSurface">@color/system_on_surface_dark</color>
+    <color name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</color>
+    <color name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</color>
+    <color name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</color>
+    <color name="materialColorSecondaryContainer">@color/system_secondary_container_light</color>
+    <color name="materialColorErrorContainer">@color/system_error_container_light</color>
+    <color name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</color>
+    <color name="materialColorInversePrimary">@color/system_primary_dark</color>
+    <color name="materialColorSecondaryFixed">@color/system_secondary_fixed</color>
+    <color name="materialColorInverseSurface">@color/system_surface_dark</color>
+    <color name="materialColorSurfaceVariant">@color/system_surface_variant_light</color>
+    <color name="materialColorTertiaryContainer">@color/system_tertiary_container_light</color>
+    <color name="materialColorTertiaryFixed">@color/system_tertiary_fixed</color>
+    <color name="materialColorPrimaryContainer">@color/system_primary_container_light</color>
+    <color name="materialColorOnBackground">@color/system_on_background_light</color>
+    <color name="materialColorPrimaryFixed">@color/system_primary_fixed</color>
+    <color name="materialColorOnSecondary">@color/system_on_secondary_light</color>
+    <color name="materialColorOnTertiary">@color/system_on_tertiary_light</color>
+    <color name="materialColorSurfaceDim">@color/system_surface_dim_light</color>
+    <color name="materialColorSurfaceBright">@color/system_surface_bright_light</color>
+    <color name="materialColorOnError">@color/system_on_error_light</color>
+    <color name="materialColorSurface">@color/system_surface_light</color>
+    <color name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</color>
+    <color name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</color>
+    <color name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</color>
+    <color name="materialColorOutline">@color/system_outline_light</color>
+    <color name="materialColorOutlineVariant">@color/system_outline_variant_light</color>
+    <color name="materialColorOnPrimary">@color/system_on_primary_light</color>
+    <color name="materialColorOnSurface">@color/system_on_surface_light</color>
+    <color name="materialColorSurfaceContainer">@color/system_surface_container_light</color>
+    <color name="materialColorPrimary">@color/system_primary_light</color>
+    <color name="materialColorSecondary">@color/system_secondary_light</color>
+    <color name="materialColorTertiary">@color/system_tertiary_light</color>
+    <color name="materialColorError">@color/system_error_light</color>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 1c70d6c..04421c0 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -30,51 +30,6 @@
     </style>
 
     <style name="DynamicColorsBaseLauncherTheme" parent="@style/BaseLauncherTheme">
-        <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item>
-        <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item>
-        <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item>
-        <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item>
-        <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item>
-        <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item>
-        <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item>
-        <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item>
-        <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item>
-        <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item>
-        <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item>
-        <item name="materialColorInverseOnSurface">@color/system_on_surface_dark</item>
-        <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item>
-        <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item>
-        <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item>
-        <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item>
-        <item name="materialColorErrorContainer">@color/system_error_container_light</item>
-        <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item>
-        <item name="materialColorInversePrimary">@color/system_primary_dark</item>
-        <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item>
-        <item name="materialColorInverseSurface">@color/system_surface_dark</item>
-        <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item>
-        <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item>
-        <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item>
-        <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item>
-        <item name="materialColorOnBackground">@color/system_on_background_light</item>
-        <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item>
-        <item name="materialColorOnSecondary">@color/system_on_secondary_light</item>
-        <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item>
-        <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item>
-        <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item>
-        <item name="materialColorOnError">@color/system_on_error_light</item>
-        <item name="materialColorSurface">@color/system_surface_light</item>
-        <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item>
-        <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item>
-        <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item>
-        <item name="materialColorOutline">@color/system_outline_light</item>
-        <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item>
-        <item name="materialColorOnPrimary">@color/system_on_primary_light</item>
-        <item name="materialColorOnSurface">@color/system_on_surface_light</item>
-        <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item>
-        <item name="materialColorPrimary">@color/system_primary_light</item>
-        <item name="materialColorSecondary">@color/system_secondary_light</item>
-        <item name="materialColorTertiary">@color/system_tertiary_light</item>
-        <item name="materialColorError">@color/system_error_light</item>
     </style>
 
     <style name="DynamicColorsBaseLauncherTheme.NoActionBar">
@@ -84,8 +39,8 @@
 
     <style name="LauncherTheme" parent="@style/DynamicColorsBaseLauncherTheme">
         <item name="android:textColorSecondary">#DE000000</item>
-        <item name="allAppsScrimColor">?attr/materialColorSurfaceDim</item>
-        <item name="allappsHeaderProtectionColor">?attr/materialColorSurfaceContainerHighest</item>
+        <item name="allAppsScrimColor">@color/materialColorSurfaceDim</item>
+        <item name="allappsHeaderProtectionColor">@color/materialColorSurfaceContainerHighest</item>
         <item name="allAppsNavBarScrimColor">#66FFFFFF</item>
         <item name="popupColorPrimary">@color/popup_color_primary_light</item>
         <item name="popupColorSecondary">@color/popup_color_secondary_light</item>
@@ -104,15 +59,15 @@
         <item name="workspaceKeyShadowColor">#89000000</item>
         <item name="widgetsTheme">@style/WidgetContainerTheme</item>
         <item name="pageIndicatorDotColor">@color/page_indicator_dot_color_light</item>
-        <item name="focusOutlineColor">?attr/materialColorSecondaryFixed</item>
-        <item name="focusInnerOutlineColor">?attr/materialColorOnSecondaryFixedVariant</item>
+        <item name="focusOutlineColor">@color/materialColorSecondaryFixed</item>
+        <item name="focusInnerOutlineColor">@color/materialColorOnSecondaryFixedVariant</item>
         <item name="folderPreviewColor">@color/folder_preview_light</item>
         <item name="folderBackgroundColor">@color/folder_background_light</item>
         <item name="folderIconBorderColor">?android:attr/colorPrimary</item>
         <item name="isFolderDarkText">true</item>
         <item name="folderTextColor">@color/folder_text_color_light</item>
         <item name="folderHintTextColor">@color/folder_hint_text_color_light</item>
-        <item name="appPairSurfaceInFolder">?attr/materialColorSurfaceContainerLowest</item>
+        <item name="appPairSurfaceInFolder">@color/materialColorSurfaceContainerLowest</item>
         <item name="loadingIconColor">#CCFFFFFF</item>
         <item name="iconOnlyShortcutColor">?android:attr/textColorSecondary</item>
         <item name="eduHalfSheetBGColor">?android:attr/colorAccent</item>
@@ -158,8 +113,8 @@
         <item name="android:textColorHint">#A0FFFFFF</item>
         <item name="android:colorControlHighlight">#19FFFFFF</item>
         <item name="android:colorPrimary">#FF212121</item>
-        <item name="allAppsScrimColor">?attr/materialColorSurfaceDim</item>
-        <item name="allappsHeaderProtectionColor">?attr/materialColorSurfaceContainerLow</item>
+        <item name="allAppsScrimColor">@color/materialColorSurfaceDim</item>
+        <item name="allappsHeaderProtectionColor">@color/materialColorSurfaceContainerLow</item>
         <item name="allAppsNavBarScrimColor">#80000000</item>
         <item name="popupColorPrimary">@color/popup_color_primary_dark</item>
         <item name="popupColorSecondary">@color/popup_color_secondary_dark</item>
@@ -178,7 +133,7 @@
         <item name="isFolderDarkText">false</item>
         <item name="folderTextColor">@color/folder_text_color_dark</item>
         <item name="folderHintTextColor">@color/folder_hint_text_color_dark</item>
-        <item name="appPairSurfaceInFolder">?attr/materialColorSurfaceContainerLowest</item>
+        <item name="appPairSurfaceInFolder">@color/materialColorSurfaceContainerLowest</item>
         <item name="isMainColorDark">true</item>
         <item name="loadingIconColor">#99FFFFFF</item>
         <item name="iconOnlyShortcutColor">#B3FFFFFF</item>
@@ -482,7 +437,7 @@
 
     <style name="PrivateSpaceHeaderTextStyle">
         <item name="android:textSize">16sp</item>
-        <item name="android:textColor">?attr/materialColorOnSurface</item>
+        <item name="android:textColor">@color/materialColorOnSurface</item>
         <item name="android:fontFamily">google-sans-text-medium</item>
         <item name="android:ellipsize">end</item>
     </style>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index ed2ab81..247ee48 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -980,7 +980,7 @@
     public boolean shouldDrawAppContrastTile() {
         return mDisplay == DISPLAY_WORKSPACE && shouldTextBeVisible()
                 && PillColorProvider.getInstance(getContext()).isMatchaEnabled()
-                && enableContrastTiles();
+                && enableContrastTiles() && !TextUtils.isEmpty(getText());
     }
 
     public void setTextVisibility(boolean visible) {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 09225e7..9b6fe4e 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -1861,13 +1861,15 @@
      * the bubble bar.
      *
      * <p>Does not check for visible bubbles persistence, so caller should call
-     * {@link #shouldAdjustHotseatForBubbleBar} first.
+     * {@link #shouldAdjustHotseatOrQsbForBubbleBar} first.
      *
      * <p>If there's no adjustment needed, this method returns {@code 0}.
-     * @see #shouldAdjustHotseatForBubbleBar(Context, boolean)
+     * @see #shouldAdjustHotseatOrQsbForBubbleBar(Context, boolean)
      */
     public float getHotseatAdjustedBorderSpaceForBubbleBar(Context context) {
-        if (!shouldAdjustHotseatForBubbleBar(context)) return 0;
+        if (shouldAlignBubbleBarWithQSB() || !shouldAdjustHotseatOrQsbForBubbleBar(context)) {
+            return 0;
+        }
         // The adjustment is shrinking the hotseat's width by 1 icon on either side.
         int iconsWidth =
                 iconSizePx * numShownHotseatIcons + hotseatBorderSpace * (numShownHotseatIcons - 1);
@@ -1880,27 +1882,37 @@
      * Returns the hotseat icon translation X for the cellX index.
      *
      * <p>Does not check for visible bubbles persistence, so caller should call
-     * {@link #shouldAdjustHotseatForBubbleBar} first.
+     * {@link #shouldAdjustHotseatOrQsbForBubbleBar} first.
      *
      * <p>If there's no adjustment needed, this method returns {@code 0}.
-     * @see #shouldAdjustHotseatForBubbleBar(Context, boolean)
+     * @see #shouldAdjustHotseatOrQsbForBubbleBar(Context, boolean)
      */
     public float getHotseatAdjustedTranslation(Context context, int cellX) {
-        if (!shouldAdjustHotseatForBubbleBar(context)) return 0;
         float borderSpace = getHotseatAdjustedBorderSpaceForBubbleBar(context);
+        if (borderSpace == 0) return borderSpace;
         float borderSpaceDelta = borderSpace - hotseatBorderSpace;
         return iconSizePx + cellX * borderSpaceDelta;
     }
 
-    /** Returns whether hotseat should be adjusted for the bubble bar. */
-    public boolean shouldAdjustHotseatForBubbleBar(Context context, boolean hasBubbles) {
-        return hasBubbles && shouldAdjustHotseatForBubbleBar(context);
+    /** Returns whether hotseat or QSB should be adjusted for the bubble bar. */
+    public boolean shouldAdjustHotseatOrQsbForBubbleBar(Context context, boolean hasBubbles) {
+        return hasBubbles && shouldAdjustHotseatOrQsbForBubbleBar(context);
     }
 
-    private boolean shouldAdjustHotseatForBubbleBar(Context context) {
-        // only need to adjust if bubble bar is enabled, when QSB is on top of the hotseat and
-        // there's not enough space for the bubble bar to the right of the hotseat.
-        return !isQsbInline && getHotseatLayoutPadding(context).right <= mBubbleBarSpaceThresholdPx;
+    /** Returns whether hotseat should be adjusted for the bubble bar. */
+    public boolean shouldAdjustHotseatForBubbleBar(Context context, boolean hasBubbles) {
+        return shouldAlignBubbleBarWithHotseat()
+                && shouldAdjustHotseatOrQsbForBubbleBar(context, hasBubbles);
+    }
+
+    /** Returns whether hotseat or QSB should be adjusted for the bubble bar. */
+    public boolean shouldAdjustHotseatOrQsbForBubbleBar(Context context) {
+        // only need to adjust if QSB is on top of the hotseat and there's not enough space for the
+        // bubble bar to either side of the hotseat.
+        if (isQsbInline) return false;
+        Rect hotseatPadding = getHotseatLayoutPadding(context);
+        int hotseatMinHorizontalPadding = Math.min(hotseatPadding.left, hotseatPadding.right);
+        return hotseatMinHorizontalPadding <= mBubbleBarSpaceThresholdPx;
     }
 
     /**
@@ -2055,15 +2067,29 @@
     }
 
     /**
-     * Returns the number of pixels the hotseat icons vertical center is translated from the bottom
-     * of the screen.
+     * Returns the number of pixels the hotseat icons or QSB vertical center is translated from the
+     * bottom of the screen.
      */
-    public int getHotseatVerticalCenter() {
-        return hotseatBarSizePx
-                - (isQsbInline ? 0 : hotseatQsbVisualHeight)
-                - hotseatQsbSpace
-                - (hotseatCellHeightPx / 2)
-                + ((hotseatCellHeightPx - iconSizePx) / 2);
+    public int getBubbleBarVerticalCenterForHome() {
+        if (shouldAlignBubbleBarWithHotseat()) {
+            return hotseatBarSizePx
+                    - (isQsbInline ? 0 : hotseatQsbVisualHeight)
+                    - hotseatQsbSpace
+                    - (hotseatCellHeightPx / 2)
+                    + ((hotseatCellHeightPx - iconSizePx) / 2);
+        } else {
+            return hotseatBarSizePx - (hotseatQsbVisualHeight / 2);
+        }
+    }
+
+    /** Returns whether bubble bar should be aligned with the hotseat. */
+    public boolean shouldAlignBubbleBarWithQSB() {
+        return !shouldAlignBubbleBarWithHotseat();
+    }
+
+    /** Returns whether bubble bar should be aligned with the hotseat. */
+    public boolean shouldAlignBubbleBarWithHotseat() {
+        return isQsbInline || isGestureMode;
     }
 
     /**
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index b2ccba4..6be8098 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -186,9 +186,10 @@
      */
     public void adjustForBubbleBar(boolean isBubbleBarVisible) {
         DeviceProfile dp = mActivity.getDeviceProfile();
-        float adjustedBorderSpace = dp.getHotseatAdjustedBorderSpaceForBubbleBar(getContext());
-        boolean shouldAdjustHotseat = isBubbleBarVisible
-                && Float.compare(adjustedBorderSpace, 0f) != 0;
+        boolean shouldAdjust = isBubbleBarVisible
+                && dp.shouldAdjustHotseatOrQsbForBubbleBar(getContext());
+        boolean shouldAdjustHotseat = shouldAdjust
+                && dp.shouldAlignBubbleBarWithHotseat();
         ShortcutAndWidgetContainer icons = getShortcutsAndWidgets();
         // update the translation provider for future layout passes of hotseat icons.
         if (shouldAdjustHotseat) {
@@ -209,9 +210,12 @@
                 animatorSet.play(ObjectAnimator.ofFloat(child, VIEW_TRANSLATE_X, tx));
             }
         }
+        //TODO(b/381109832) refactor & simplify adjustment logic
+        boolean shouldAdjustQsb =
+                shouldAdjustHotseat || (shouldAdjust && dp.shouldAlignBubbleBarWithQSB());
         if (mQsb instanceof HorizontalInsettableView horizontalInsettableQsb) {
             final float currentInsetFraction = horizontalInsettableQsb.getHorizontalInsets();
-            final float targetInsetFraction = shouldAdjustHotseat
+            final float targetInsetFraction = shouldAdjustQsb
                     ? (float) dp.iconSizePx / dp.hotseatQsbWidth : 0;
             ValueAnimator qsbAnimator =
                     ValueAnimator.ofFloat(currentInsetFraction, targetInsetFraction);
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index c938482..8505a6d 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -315,8 +315,7 @@
                 0,
                 0 // Bottom left
         };
-        mBottomSheetBackgroundColor =
-                Themes.getAttrColor(getContext(), R.attr.materialColorSurfaceDim);
+        mBottomSheetBackgroundColor = getContext().getColor(R.color.materialColorSurfaceDim);
         updateBackgroundVisibility(mActivityContext.getDeviceProfile());
         mSearchUiManager.initializeSearch(this);
     }
diff --git a/src/com/android/launcher3/allapps/LetterListTextView.java b/src/com/android/launcher3/allapps/LetterListTextView.java
index 8586078..e3fea3c 100644
--- a/src/com/android/launcher3/allapps/LetterListTextView.java
+++ b/src/com/android/launcher3/allapps/LetterListTextView.java
@@ -31,7 +31,6 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.util.Themes;
 
 /**
  * A TextView that is used to display the letter list in the fast scroller.
@@ -56,7 +55,7 @@
         mLetterBackground = context.getDrawable(R.drawable.bg_letter_list_text);
         mLetterListTextWidthAndHeight = context.getResources().getDimensionPixelSize(
                 R.dimen.fastscroll_list_letter_size);
-        mTextColor = Themes.getAttrColor(context, R.attr.materialColorOnSurface);
+        mTextColor = context.getColor(R.color.materialColorOnSurface);
     }
 
     @Override
diff --git a/src/com/android/launcher3/allapps/SectionDecorationHandler.java b/src/com/android/launcher3/allapps/SectionDecorationHandler.java
index eaeb8bb..cae76ec 100644
--- a/src/com/android/launcher3/allapps/SectionDecorationHandler.java
+++ b/src/com/android/launcher3/allapps/SectionDecorationHandler.java
@@ -27,7 +27,6 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.R;
-import com.android.launcher3.util.Themes;
 
 public class SectionDecorationHandler {
 
@@ -60,10 +59,8 @@
 
         mContext = context;
         mFillAlpha = fillAlpha;
-        mFocusColor = Themes.getAttrColor(context,
-                R.attr.materialColorSurfaceBright); // UX recommended
-        mFillColor = Themes.getAttrColor(context,
-                R.attr.materialColorSurfaceContainerHigh); // UX recommended
+        mFocusColor = context.getColor(R.color.materialColorSurfaceBright); // UX recommended
+        mFillColor = context.getColor(R.color.materialColorSurfaceContainerHigh); // UX recommended
 
         mIsTopLeftRound = isTopLeftRound;
         mIsTopRightRound = isTopRightRound;
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 2550ebb..dbab52a 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -843,6 +843,13 @@
 
         @UiEvent(doc = "User long press nav handle and a long press runnable was created.")
         LAUNCHER_OMNI_GET_LONG_PRESS_RUNNABLE(1545),
+
+        // One Grid Flags
+        @UiEvent(doc = "User sets the device in Fixed Landscape")
+        FIXED_LANDSCAPE_TOGGLE_ENABLE(2014),
+
+        @UiEvent(doc = "User sets the device in Fixed Landscape")
+        FIXED_LANDSCAPE_TOGGLE_DISABLED(2020),
         // ADD MORE
         ;
 
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index c2debfa..6174d06 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -138,7 +138,7 @@
 
         // Initialize arrow view
         final Resources resources = getResources();
-        mArrowColor = Themes.getAttrColor(getContext(), R.attr.materialColorSurfaceContainer);
+        mArrowColor = getContext().getColor(R.color.materialColorSurfaceContainer);
         mChildContainerMargin = resources.getDimensionPixelSize(R.dimen.popup_margin);
         mArrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width);
         mArrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
@@ -170,8 +170,7 @@
                     getContext().getColor(R.color.popup_shade_third)
             };
         } else {
-            mColors = new int[]{Themes.getAttrColor(getContext(),
-                    R.attr.materialColorSurfaceContainer)};
+            mColors = new int[]{getContext().getColor(R.color.materialColorSurfaceContainer)};
         }
     }
 
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index 755c3eb..b748011 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -116,7 +116,7 @@
         final UserHandle user = originalInfo.user;
         return () -> {
             ApplicationInfoWrapper infoWrapper =
-                    new ApplicationInfoWrapper(context, activity.getPackageName(), user);
+                    new ApplicationInfoWrapper(context, originalInfo.getTargetPackage(), user);
             List<ShortcutInfo> shortcuts = new ShortcutRequest(context, user)
                     .withContainer(activity)
                     .query(ShortcutRequest.PUBLISHED);
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 6fd18be..4acdf19 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -180,7 +180,7 @@
         mTrackPaint.setAlpha(MAX_TRACK_ALPHA);
 
         mThumbColor = Themes.getColorAccent(context);
-        mThumbLetterScrollerColor = Themes.getAttrColor(context, R.attr.materialColorSurfaceBright);
+        mThumbLetterScrollerColor = context.getColor(R.color.materialColorSurfaceBright);
         mThumbPaint = new Paint();
         mThumbPaint.setAntiAlias(true);
         mThumbPaint.setColor(mThumbColor);
diff --git a/tests/assets/databases/GridMigrationTest/result5x5to3x3.db b/tests/assets/databases/GridMigrationTest/result5x5to3x3.db
index 686056d..6050251 100644
--- a/tests/assets/databases/GridMigrationTest/result5x5to3x3.db
+++ b/tests/assets/databases/GridMigrationTest/result5x5to3x3.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/result5x5to4x7.db b/tests/assets/databases/GridMigrationTest/result5x5to4x7.db
index cd105c5..e6cd6f0 100644
--- a/tests/assets/databases/GridMigrationTest/result5x5to4x7.db
+++ b/tests/assets/databases/GridMigrationTest/result5x5to4x7.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/result5x5to5x8.db b/tests/assets/databases/GridMigrationTest/result5x5to5x8.db
index 4b46969..311a112 100644
--- a/tests/assets/databases/GridMigrationTest/result5x5to5x8.db
+++ b/tests/assets/databases/GridMigrationTest/result5x5to5x8.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db b/tests/assets/databases/GridMigrationTest/result5x5to5x8WithShift.db
similarity index 92%
rename from tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db
rename to tests/assets/databases/GridMigrationTest/result5x5to5x8WithShift.db
index 8bea3ce..d750774 100644
--- a/tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db
+++ b/tests/assets/databases/GridMigrationTest/result5x5to5x8WithShift.db
Binary files differ
diff --git a/tests/assets/databases/GridMigrationTest/test_launcher_2.db b/tests/assets/databases/GridMigrationTest/test_launcher_2.db
new file mode 100644
index 0000000..b538e26
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/test_launcher_2.db
Binary files differ
diff --git a/tests/src/com/android/launcher3/model/GridMigrationTest.kt b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
index 379e98d..b8ffe74 100644
--- a/tests/src/com/android/launcher3/model/GridMigrationTest.kt
+++ b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
@@ -17,6 +17,7 @@
 package com.android.launcher3.model
 
 import android.platform.test.flag.junit.SetFlagsRule
+import android.util.Log
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import androidx.test.platform.app.InstrumentationRegistry
@@ -34,7 +35,14 @@
 
 private val phoneContext = InstrumentationRegistry.getInstrumentation().targetContext
 
-data class EntryData(val x: Int, val y: Int, val spanX: Int, val spanY: Int, val rank: Int)
+data class EntryData(
+    val x: Int,
+    val y: Int,
+    val screenId: Int,
+    val spanX: Int,
+    val spanY: Int,
+    val rank: Int,
+)
 
 /**
  * Holds the data needed to run a test in GridMigrationTest, usually we would have a src
@@ -72,24 +80,16 @@
 @RunWith(AndroidJUnit4::class)
 class GridMigrationTest {
     private val DB_FILE = "test_launcher.db"
+    // This DB is used for testing the heuristic where we add an extra row at the bottom.
+    private val DB_FILE_NO_SHIFT = "test_launcher_2.db"
 
     @JvmField
     @Rule
     val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
 
-    // Copying the src db for all tests.
-    @JvmField
-    @Rule
-    val fileCopier =
-        TestToPhoneFileCopier(
-            src = "databases/GridMigrationTest/$DB_FILE",
-            dest = "databases/$DB_FILE",
-            removeOnFinish = true,
-        )
-
     @Before
     fun setup() {
-        setFlagsRule.setFlags(false, Flags.FLAG_ENABLE_GRID_MIGRATION_FIX)
+        setFlagsRule.setFlags(true, Flags.FLAG_ONE_GRID_SPECS)
     }
 
     private fun migrate(src: GridMigrationData, dst: GridMigrationData) {
@@ -101,7 +101,7 @@
                 dst.gridState,
                 dst.dbHelper,
                 src.dbHelper.readableDatabase,
-                false,
+                true,
             )
         } else {
             GridSizeMigrationDBController.migrateGridIfNeeded(
@@ -110,7 +110,7 @@
                 dst.gridState,
                 dst.dbHelper,
                 src.dbHelper.readableDatabase,
-                false,
+                true,
             )
         }
     }
@@ -131,12 +131,18 @@
         }
     }
 
-    private fun compare(dst: GridMigrationData, target: GridMigrationData) {
-        val sort = compareBy<DbEntry>({ it.cellX }, { it.cellY })
-        val mapF = { it: DbEntry -> EntryData(it.cellX, it.cellY, it.spanX, it.spanY, it.rank) }
+    private fun compare(dst: GridMigrationData, target: GridMigrationData, src: GridMigrationData) {
+        val sort = compareBy<DbEntry>({ it.screenId }, { it.cellX }, { it.cellY })
+        val mapF = { it: DbEntry ->
+            EntryData(it.cellX, it.cellY, it.screenId, it.spanX, it.spanY, it.rank)
+        }
         val entriesDst = dst.readEntries().sortedWith(sort).map(mapF)
         val entriesTarget = target.readEntries().sortedWith(sort).map(mapF)
-
+        val entriesSrc = src.readEntries().sortedWith(sort).map(mapF)
+        Log.i(
+            TAG,
+            "entriesSrc: $entriesSrc\n entriesDst: $entriesDst\n entriesTarget: $entriesTarget",
+        )
         assert(entriesDst == entriesTarget) {
             "The elements on the dst database is not the same as in the target"
         }
@@ -155,9 +161,19 @@
             "Source db and destination db do not contain the same number of elements"
         }
         validateDb(dst)
-        compare(dst, target)
+        compare(dst, target, src)
     }
 
+    // Copying the src db for all tests.
+    @JvmField
+    @Rule
+    val fileCopier =
+        TestToPhoneFileCopier(
+            src = "databases/GridMigrationTest/$DB_FILE",
+            dest = "databases/$DB_FILE",
+            removeOnFinish = true,
+        )
+
     @JvmField
     @Rule
     val result5x5to3x3 =
@@ -173,8 +189,8 @@
             src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
             dst =
                 GridMigrationData(
-                    null, // in memory db, to download a new db change null for the filename of the
-                    // db name to store it. Do not use existing names.
+                    null, // in memory db, to download a new db change null for
+                    // the filename of the db name to store it. Do not use existing names.
                     DeviceGridState(3, 3, 3, TYPE_PHONE, ""),
                 ),
             target =
@@ -196,8 +212,8 @@
             src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
             dst =
                 GridMigrationData(
-                    null, // in memory db, to download a new db change null for the filename of the
-                    // db name to store it. Do not use existing names.
+                    null, // in memory db, to download a new db change null for
+                    // the filename of the db name to store it. Do not use existing names.
                     DeviceGridState(4, 7, 4, TYPE_PHONE, ""),
                 ),
             target =
@@ -206,6 +222,42 @@
 
     @JvmField
     @Rule
+    val result5x5to5x8WithShift =
+        TestToPhoneFileCopier(
+            src = "databases/GridMigrationTest/result5x5to5x8WithShift.db",
+            dest = "databases/result5x5to5x8WithShift.db",
+            removeOnFinish = true,
+        )
+
+    @Test
+    fun `5x5 to 5x8 with cells shifting down`() =
+        runTest(
+            src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
+            dst =
+                GridMigrationData(
+                    null, // in memory db, to download a new db change null
+                    // for
+                    // the filename of the db name to store it. Do not use existing names.
+                    DeviceGridState(5, 8, 5, TYPE_PHONE, ""),
+                ),
+            target =
+                GridMigrationData(
+                    "result5x5to5x8WithShift.db",
+                    DeviceGridState(5, 8, 5, TYPE_PHONE, ""),
+                ),
+        )
+
+    @JvmField
+    @Rule
+    val fileCopierNoShift =
+        TestToPhoneFileCopier(
+            src = "databases/GridMigrationTest/$DB_FILE_NO_SHIFT",
+            dest = "databases/$DB_FILE_NO_SHIFT",
+            removeOnFinish = true,
+        )
+
+    @JvmField
+    @Rule
     val result5x5to5x8 =
         TestToPhoneFileCopier(
             src = "databases/GridMigrationTest/result5x5to5x8.db",
@@ -214,44 +266,24 @@
         )
 
     @Test
-    fun `5x5 to 5x8`() =
+    fun `5x5 to 5x8 without cell shift`() =
         runTest(
-            src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
+            src =
+                GridMigrationData(
+                    DB_FILE_NO_SHIFT,
+                    DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE_NO_SHIFT),
+                ),
             dst =
                 GridMigrationData(
-                    null, // in memory db, to download a new db change null for the filename of the
-                    // db name to store it. Do not use existing names.
+                    null, // in memory db, to download a new db change null for
+                    // the filename of the db name to store it. Do not use existing names.
                     DeviceGridState(5, 8, 5, TYPE_PHONE, ""),
                 ),
             target =
                 GridMigrationData("result5x5to5x8.db", DeviceGridState(5, 8, 5, TYPE_PHONE, "")),
         )
 
-    @JvmField
-    @Rule
-    val flaggedResult5x5to5x8 =
-        TestToPhoneFileCopier(
-            src = "databases/GridMigrationTest/flagged_result5x5to5x8.db",
-            dest = "databases/flagged_result5x5to5x8.db",
-            removeOnFinish = true,
-        )
-
-    @Test
-    fun `flagged 5x5 to 5x8`() {
-        setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_GRID_MIGRATION_FIX)
-        runTest(
-            src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
-            dst =
-                GridMigrationData(
-                    null, // in memory db, to download a new db change null for the filename of the
-                    // db name to store it. Do not use existing names.
-                    DeviceGridState(5, 8, 5, TYPE_PHONE, ""),
-                ),
-            target =
-                GridMigrationData(
-                    "flagged_result5x5to5x8.db",
-                    DeviceGridState(5, 8, 5, TYPE_PHONE, ""),
-                ),
-        )
+    companion object {
+        private const val TAG = "GridMigrationTest"
     }
 }