Merge "Created LauncherWidgetHolder as a wrapper for LauncherAppWidgetHost" into tm-qpr-dev
diff --git a/Android.bp b/Android.bp
index 6267e9f..0bbb3d2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -153,6 +153,7 @@
         "androidx.cardview_cardview",
         "com.google.android.material_material",
         "iconloader_base",
+        "view_capture"
     ],
     manifest: "AndroidManifest-common.xml",
     sdk_version: "current",
diff --git a/protos/view_capture.proto b/protos/view_capture.proto
deleted file mode 100644
index f363f36..0000000
--- a/protos/view_capture.proto
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-syntax = "proto2";
-
-package com.android.launcher3.view;
-
-option java_outer_classname = "ViewCaptureData";
-
-message ExportedData {
-
-  repeated FrameData frameData = 1;
-  repeated string classname = 2;
-}
-
-message FrameData {
-  optional int64 timestamp = 1;
-  optional ViewNode node = 2;
-}
-
-message ViewNode {
-  optional int32 classname_index = 1;
-  optional int32 hashcode = 2;
-
-  repeated ViewNode children = 3;
-
-  optional string id = 4;
-  optional int32 left = 5;
-  optional int32 top = 6;
-  optional int32 width = 7;
-  optional int32 height = 8;
-  optional int32 scrollX = 9;
-  optional int32 scrollY = 10;
-
-  optional float translationX = 11;
-  optional float translationY = 12;
-  optional float scaleX = 13 [default = 1];
-  optional float scaleY = 14 [default = 1];
-  optional float alpha = 15 [default = 1];
-
-  optional bool willNotDraw = 16;
-  optional bool clipChildren = 17;
-  optional int32 visibility = 18;
-
-  optional float elevation = 19;
-}
diff --git a/quickstep/res/layout-sw600dp-land/allset_navigation_and_hint.xml b/quickstep/res/layout-sw600dp-land/allset_navigation_and_hint.xml
new file mode 100644
index 0000000..3bfa6da
--- /dev/null
+++ b/quickstep/res/layout-sw600dp-land/allset_navigation_and_hint.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <TextView
+        android:id="@+id/navigation_settings"
+        style="@style/TextAppearance.GestureTutorial.LinkText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="32dp"
+        android:background="?android:attr/selectableItemBackground"
+        android:minHeight="48dp"
+        android:text="@string/allset_navigation_settings"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/subtitle" />
+
+    <TextView
+        android:id="@+id/hint"
+        style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/allset_page_margin_bottom"
+        android:text="@string/allset_hint"
+        android:textSize="@dimen/allset_page_swipe_up_text_size"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+</merge>
\ No newline at end of file
diff --git a/quickstep/res/layout-sw600dp/allset_navigation_and_hint.xml b/quickstep/res/layout-sw600dp/allset_navigation_and_hint.xml
new file mode 100644
index 0000000..9559072
--- /dev/null
+++ b/quickstep/res/layout-sw600dp/allset_navigation_and_hint.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <TextView
+        android:id="@+id/navigation_settings"
+        style="@style/TextAppearance.GestureTutorial.LinkText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="96dp"
+        android:background="?android:attr/selectableItemBackground"
+        android:minHeight="48dp"
+        android:text="@string/allset_navigation_settings"
+        app:layout_constraintBottom_toTopOf="@id/hint"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <TextView
+        android:id="@+id/hint"
+        style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/allset_page_margin_bottom"
+        android:text="@string/allset_hint"
+        android:textSize="@dimen/allset_page_swipe_up_text_size"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+</merge>
\ No newline at end of file
diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml
index 56e1d16..f08cabe 100644
--- a/quickstep/res/layout/activity_allset.xml
+++ b/quickstep/res/layout/activity_allset.xml
@@ -34,8 +34,6 @@
             android:layout_height="match_parent"
             android:gravity="center"
             android:scaleType="centerCrop"
-
-            app:lottie_rawRes="@raw/all_set_page_bg"
             app:lottie_autoPlay="true"
             app:lottie_loop="true" />
 
@@ -79,42 +77,8 @@
                 app:layout_constraintStart_toStartOf="parent"
                 android:gravity="start"/>
 
-            <androidx.constraintlayout.widget.Guideline
-                android:id="@+id/navigation_settings_guideline_bottom"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                app:layout_constraintGuide_percent="0.83" />
+            <include layout="@layout/allset_navigation_and_hint"/>
 
-            <TextView
-                android:id="@+id/navigation_settings"
-                style="@style/TextAppearance.GestureTutorial.LinkText"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintBottom_toBottomOf="@id/navigation_settings_guideline_bottom"
-                android:minHeight="48dp"
-                android:background="?android:attr/selectableItemBackground"
-                android:text="@string/allset_navigation_settings" />
-
-            <androidx.constraintlayout.widget.Guideline
-                android:id="@+id/hint_guideline_bottom"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                app:layout_constraintGuide_percent="0.94" />
-
-            <TextView
-                android:id="@+id/hint"
-                style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
-                android:textSize="14sp"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintEnd_toEndOf="parent"
-                app:layout_constraintBottom_toBottomOf="@id/hint_guideline_bottom"
-                android:text="@string/allset_hint"/>
         </androidx.constraintlayout.widget.ConstraintLayout>
 
     </androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/quickstep/res/layout/allset_navigation_and_hint.xml b/quickstep/res/layout/allset_navigation_and_hint.xml
new file mode 100644
index 0000000..4d5cf01
--- /dev/null
+++ b/quickstep/res/layout/allset_navigation_and_hint.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/navigation_settings_guideline_bottom"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        app:layout_constraintGuide_percent="0.83" />
+
+    <TextView
+        android:id="@+id/navigation_settings"
+        style="@style/TextAppearance.GestureTutorial.LinkText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="?android:attr/selectableItemBackground"
+        android:minHeight="48dp"
+        android:text="@string/allset_navigation_settings"
+        app:layout_constraintBottom_toBottomOf="@id/navigation_settings_guideline_bottom"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <androidx.constraintlayout.widget.Guideline
+        android:id="@+id/hint_guideline_bottom"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        app:layout_constraintGuide_percent="0.94" />
+
+    <TextView
+        android:id="@+id/hint"
+        style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/allset_hint"
+        android:textSize="@dimen/allset_page_swipe_up_text_size"
+        app:layout_constraintBottom_toBottomOf="@id/hint_guideline_bottom"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent" />
+
+</merge>
\ No newline at end of file
diff --git a/quickstep/res/layout/digital_wellbeing_toast.xml b/quickstep/res/layout/digital_wellbeing_toast.xml
index c4642e4..e493ac9 100644
--- a/quickstep/res/layout/digital_wellbeing_toast.xml
+++ b/quickstep/res/layout/digital_wellbeing_toast.xml
@@ -25,4 +25,5 @@
     android:gravity="center"
     android:importantForAccessibility="noHideDescendants"
     android:textColor="?priv-android:attr/textColorOnAccent"
-    android:textSize="14sp"/>
\ No newline at end of file
+    android:textSize="14sp"
+    android:autoSizeTextType="uniform"/>
\ No newline at end of file
diff --git a/quickstep/res/layout/transient_taskbar.xml b/quickstep/res/layout/transient_taskbar.xml
new file mode 100644
index 0000000..f9ece84
--- /dev/null
+++ b/quickstep/res/layout/transient_taskbar.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.launcher3.taskbar.TaskbarDragLayer
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/taskbar_container"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:clipChildren="false">
+
+    <com.android.launcher3.taskbar.TaskbarView
+        android:id="@+id/taskbar_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:forceHasOverlappingRendering="false"
+        android:layout_gravity="bottom"
+        android:layout_marginBottom="@dimen/transient_taskbar_margin"
+        android:clipChildren="false" />
+
+    <com.android.launcher3.taskbar.TaskbarScrimView
+        android:id="@+id/taskbar_scrim"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+    <FrameLayout
+        android:id="@+id/navbuttons_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom" >
+
+        <FrameLayout
+            android:id="@+id/start_contextual_buttons"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:paddingStart="@dimen/taskbar_contextual_button_padding"
+            android:paddingEnd="@dimen/taskbar_contextual_button_padding"
+            android:paddingTop="@dimen/taskbar_contextual_padding_top"
+            android:gravity="center_vertical"
+            android:layout_gravity="start"/>
+
+        <LinearLayout
+            android:id="@+id/end_nav_buttons"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            android:layout_gravity="end"/>
+
+        <FrameLayout
+            android:id="@+id/end_contextual_buttons"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:paddingTop="@dimen/taskbar_contextual_padding_top"
+            android:gravity="center_vertical"
+            android:layout_gravity="end"/>
+    </FrameLayout>
+
+    <com.android.launcher3.taskbar.StashedHandleView
+        android:id="@+id/stashed_handle"
+        tools:comment1="The actual size and shape will be set as a ViewOutlineProvider at runtime"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@color/taskbar_stashed_handle_dark_color"
+        android:clipToOutline="true"
+        android:layout_gravity="bottom"/>
+
+</com.android.launcher3.taskbar.TaskbarDragLayer>
\ No newline at end of file
diff --git a/quickstep/res/raw-sw600dp-land/all_set_page_bg.json b/quickstep/res/raw-sw600dp-land/all_set_page_bg.json
new file mode 100644
index 0000000..0863c31
--- /dev/null
+++ b/quickstep/res/raw-sw600dp-land/all_set_page_bg.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":180,"w":1280,"h":800,"nm":"3Second_MainWelcomeScreen_Tablet_Landscape_V02","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[288,540,0],"ix":2,"l":2},"a":{"a":0,"k":[50,50,0],"ix":1,"l":2},"s":{"a":0,"k":[25,25,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"colorAccentPrimaryVariant","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[231.832,-1174.545,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":95,"s":[231.832,-1979,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[231.832,-1174.545,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[110,110,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.839215686275,0.439215686275,0.388235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":720,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"colorAccentPrimary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-56]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":95,"s":[-38]},{"t":180,"s":[-56]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[138]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":95,"s":[-38]},{"t":180,"s":[138]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1535]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":95,"s":[1338]},{"t":180,"s":[1535]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.305882352941,0.309803921569,0.321568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/quickstep/res/raw-sw600dp/all_set_page_bg.json b/quickstep/res/raw-sw600dp/all_set_page_bg.json
new file mode 100644
index 0000000..14e8933
--- /dev/null
+++ b/quickstep/res/raw-sw600dp/all_set_page_bg.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":180,"w":800,"h":1280,"nm":"3Second_MainWelcomeScreen_Tablet_Portrait_V02","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":1,"nm":"Null 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[288,528,0],"ix":2,"l":2},"a":{"a":0,"k":[50,50,0],"ix":1,"l":2},"s":{"a":0,"k":[25,25,100],"ix":6,"l":2}},"ao":0,"sw":100,"sh":100,"sc":"#ffffff","ip":600,"op":600,"st":0,"bm":0,"hidden":0},{"ddd":0,"ind":2,"ty":4,"nm":".colorAccentPrimaryVariant","cl":"colorAccentPrimaryVariant","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[375.832,-1366.545,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":95,"s":[375.832,-2171,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[375.832,-1366.545,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[135,135,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.839215686275,0.439215686275,0.388235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":720,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".colorAccentPrimary","cl":"colorAccentPrimary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-56]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":95,"s":[-38]},{"t":180,"s":[-56]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[138]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":95,"s":[-38]},{"t":180,"s":[138]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1535]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":95,"s":[1338]},{"t":180,"s":[1535]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.305882352941,0.309803921569,0.321568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/res/raw/all_set_page_bg.json b/quickstep/res/raw/all_set_page_bg.json
similarity index 99%
rename from res/raw/all_set_page_bg.json
rename to quickstep/res/raw/all_set_page_bg.json
index 9705837..859d356 100644
--- a/res/raw/all_set_page_bg.json
+++ b/quickstep/res/raw/all_set_page_bg.json
@@ -1 +1 @@
-{"v":"5.7.8","fr":24,"ip":0,"op":72,"w":2472,"h":5352,"nm":"3Second_MAIN_Welcome","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 60","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1508,1364,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"PinkFlower","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":72,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[1505.832,1379.455,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":38,"s":[1505.832,575,0],"to":[0,0,0],"ti":[0,0,0]},{"t":72,"s":[1505.832,1379.455,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.839215686275,0.439215686275,0.388235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.839215746113,0.439215716194,0.388235324037,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":true},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":288,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Ellipse_Bottom","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-56]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":38,"s":[-38]},{"t":72,"s":[-56]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1720]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":38,"s":[1544]},{"t":72,"s":[1720]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[4069]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":38,"s":[3872]},{"t":72,"s":[4069]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.305882352941,0.309803921569,0.321568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.882353001015,0.894118006089,0.886274988511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":true},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0}],"markers":[]}
+{"v":"5.7.8","fr":24,"ip":0,"op":72,"w":2472,"h":5352,"nm":"3Second_MAIN_Welcome","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 60","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1508,1364,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"PinkFlower","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":72,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[1505.832,1379.455,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":38,"s":[1505.832,575,0],"to":[0,0,0],"ti":[0,0,0]},{"t":72,"s":[1505.832,1379.455,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.839215686275,0.439215686275,0.388235294118,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.839215746113,0.439215716194,0.388235324037,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":true},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":288,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Ellipse_Bottom","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-56]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":38,"s":[-38]},{"t":72,"s":[-56]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1720]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":38,"s":[1544]},{"t":72,"s":[1720]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[4069]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":38,"s":[3872]},{"t":72,"s":[4069]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.305882352941,0.309803921569,0.321568627451,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":4,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.882353001015,0.894118006089,0.886274988511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":true},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/quickstep/res/values-sw600dp-land/dimens.xml b/quickstep/res/values-sw600dp-land/dimens.xml
index 0cd9b2b..5507fcf 100644
--- a/quickstep/res/values-sw600dp-land/dimens.xml
+++ b/quickstep/res/values-sw600dp-land/dimens.xml
@@ -17,4 +17,9 @@
 <resources>
     <!--  Overview actions  -->
     <dimen name="overview_actions_top_margin">12dp</dimen>
+
+    <!-- All Set page -->
+    <dimen name="allset_page_margin_horizontal">48dp</dimen>
+    <dimen name="allset_page_margin_bottom">24dp</dimen>
+
 </resources>
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
index cfbbf8d..c96ad11 100644
--- a/quickstep/res/values-sw600dp/dimens.xml
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -33,4 +33,11 @@
     <dimen name="overview_page_spacing">36dp</dimen>
     <!--  The space to the left and to the right of the "Clear all" button  -->
     <dimen name="overview_grid_side_margin">64dp</dimen>
+
+    <!-- All Set page -->
+    <dimen name="allset_page_margin_horizontal">120dp</dimen>
+    <dimen name="allset_page_margin_bottom">24dp</dimen>
+    <dimen name="allset_page_allset_text_size">38sp</dimen>
+    <dimen name="allset_page_swipe_up_text_size">15sp</dimen>
+
 </resources>
diff --git a/quickstep/res/values-sw720dp-land/dimens.xml b/quickstep/res/values-sw720dp-land/dimens.xml
index 02d1189..4bc8bf3 100644
--- a/quickstep/res/values-sw720dp-land/dimens.xml
+++ b/quickstep/res/values-sw720dp-land/dimens.xml
@@ -17,4 +17,7 @@
 <resources>
     <!--  Overview actions  -->
     <dimen name="overview_actions_top_margin">20dp</dimen>
+
+    <!-- All Set page-->
+    <dimen name="allset_page_margin_bottom">24dp</dimen>
 </resources>
diff --git a/quickstep/res/values-sw720dp/dimens.xml b/quickstep/res/values-sw720dp/dimens.xml
index 284ce11..a84b939 100644
--- a/quickstep/res/values-sw720dp/dimens.xml
+++ b/quickstep/res/values-sw720dp/dimens.xml
@@ -33,4 +33,9 @@
     <dimen name="overview_page_spacing">44dp</dimen>
     <!--  The space to the left and to the right of the "Clear all" button  -->
     <dimen name="overview_grid_side_margin">64dp</dimen>
+
+    <!-- All Set page-->
+    <dimen name="allset_page_margin_bottom">0dp</dimen>
+    <dimen name="allset_page_allset_text_size">42sp</dimen>
+    <dimen name="allset_page_swipe_up_text_size">16sp</dimen>
 </resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 3add4dc..45a2cf8 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -202,6 +202,10 @@
 
     <!-- All Set page -->
     <dimen name="allset_page_margin_horizontal">40dp</dimen>
+    <dimen name="allset_page_margin_bottom">0dp</dimen>
+    <dimen name="allset_page_allset_text_size">36sp</dimen>
+    <dimen name="allset_page_swipe_up_text_size">14sp</dimen>
+
     <dimen name="allset_title_margin_top">24dp</dimen>
     <dimen name="allset_title_icon_margin_top">32dp</dimen>
     <dimen name="allset_subtitle_margin_top">24dp</dimen>
@@ -279,6 +283,12 @@
     <dimen name="taskbar_home_button_left_margin_kids">48dp</dimen>
     <dimen name="taskbar_icon_size_kids">32dp</dimen>
 
+    <!-- Transient taskbar -->
+    <dimen name="transient_taskbar_size">76dp</dimen>
+    <dimen name="transient_taskbar_margin">24dp</dimen>
+    <dimen name="transient_taskbar_shadow_blur">40dp</dimen>
+    <dimen name="transient_taskbar_key_shadow_distance">10dp</dimen>
+
     <!--  Taskbar 3 button spacing  -->
     <dimen name="taskbar_button_space_inbetween">24dp</dimen>
     <dimen name="taskbar_button_space_inbetween_phone">40dp</dimen>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 7225220..868d38b 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -51,6 +51,7 @@
         parent="TextAppearance.GestureTutorial.Feedback.Title">
         <item name="android:letterSpacing">0.03</item>
         <item name="android:lineHeight">44sp</item>
+        <item name="android:textSize">@dimen/allset_page_allset_text_size</item>
     </style>
 
     <style name="TextAppearance.GestureTutorial.Dialog.Title"
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 58b3a83..938aa5e 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -44,7 +44,7 @@
 import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
 import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
-import static com.android.launcher3.statehandlers.DepthController.STATE_DEPTH;
+import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
@@ -109,6 +109,7 @@
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.ActivityOptionsWrapper;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DynamicResource;
 import com.android.launcher3.util.ObjectWrapper;
 import com.android.launcher3.util.RunnableList;
@@ -388,7 +389,8 @@
                 @Override
                 public void onAnimationStart(Animator animation) {
                     mLauncher.addOnResumeCallback(() ->
-                            ObjectAnimator.ofFloat(mLauncher.getDepthController(), STATE_DEPTH,
+                            ObjectAnimator.ofFloat(mLauncher.getDepthController().stateDepth,
+                                    MULTI_PROPERTY_VALUE,
                                     mLauncher.getStateManager().getState().getDepth(
                                             mLauncher)).start());
                 }
@@ -412,7 +414,8 @@
             @Override
             public void onAnimationStart(Animator animation) {
                 mLauncher.addOnResumeCallback(() ->
-                        ObjectAnimator.ofFloat(mLauncher.getDepthController(), STATE_DEPTH,
+                        ObjectAnimator.ofFloat(mLauncher.getDepthController().stateDepth,
+                                MULTI_PROPERTY_VALUE,
                                 mLauncher.getStateManager().getState().getDepth(
                                         mLauncher)).start());
             }
@@ -449,7 +452,9 @@
                         4 - rotationChange);
             }
         }
-        if (mDeviceProfile.isTaskbarPresentInApps && !target.willShowImeOnTarget) {
+        if (mDeviceProfile.isTaskbarPresentInApps
+                && !target.willShowImeOnTarget
+                && !DisplayController.isTransientTaskbar(mLauncher)) {
             // Animate to above the taskbar.
             bounds.bottom -= target.contentInsets.bottom;
         }
@@ -1050,8 +1055,8 @@
                 && BlurUtils.supportsBlursOnWindows();
 
         MyDepthController depthController = new MyDepthController(mLauncher);
-        ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController, STATE_DEPTH,
-                        BACKGROUND_APP.getDepth(mLauncher))
+        ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController.stateDepth,
+                        MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mLauncher))
                 .setDuration(APP_LAUNCH_DURATION);
 
         if (allowBlurringLauncher) {
@@ -1591,8 +1596,8 @@
                             true /* animateOverviewScrim */, launcherView).getAnimators());
 
                     if (!areAllTargetsTranslucent(appTargets)) {
-                        anim.play(ObjectAnimator.ofFloat(mLauncher.getDepthController(),
-                                STATE_DEPTH,
+                        anim.play(ObjectAnimator.ofFloat(mLauncher.getDepthController().stateDepth,
+                                MULTI_PROPERTY_VALUE,
                                 BACKGROUND_APP.getDepth(mLauncher), NORMAL.getDepth(mLauncher)));
                     }
 
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index 2a78bdf..867e168 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -19,6 +19,7 @@
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
+import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -112,7 +113,7 @@
             return;
         }
 
-        STATE_DEPTH.set(this, toState.getDepth(mLauncher));
+        stateDepth.setValue(toState.getDepth(mLauncher));
         if (toState == LauncherState.BACKGROUND_APP) {
             mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener);
         }
@@ -127,7 +128,8 @@
         }
 
         float toDepth = toState.getDepth(mLauncher);
-        animation.setFloat(this, STATE_DEPTH, toDepth, config.getInterpolator(ANIM_DEPTH, LINEAR));
+        animation.setFloat(stateDepth, MULTI_PROPERTY_VALUE, toDepth,
+                config.getInterpolator(ANIM_DEPTH, LINEAR));
     }
 
     @Override
@@ -140,7 +142,7 @@
     public void onMultiWindowModeChanged(boolean isInMultiWindowMode) {
         mIgnoreStateChangesDuringMultiWindowAnimation = true;
 
-        ObjectAnimator mwAnimation = ObjectAnimator.ofFloat(this, STATE_DEPTH,
+        ObjectAnimator mwAnimation = ObjectAnimator.ofFloat(stateDepth, MULTI_PROPERTY_VALUE,
                 mLauncher.getStateManager().getState().getDepth(mLauncher, isInMultiWindowMode))
                 .setDuration(300);
         mwAnimation.addListener(new AnimatorListenerAdapter() {
@@ -158,8 +160,8 @@
         writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius);
         writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled);
         writer.println(prefix + "\tmSurface=" + mSurface);
-        writer.println(prefix + "\tmStateDepth=" + STATE_DEPTH.get(this));
-        writer.println(prefix + "\tmWidgetDepth=" + WIDGET_DEPTH.get(this));
+        writer.println(prefix + "\tmStateDepth=" + stateDepth.getValue());
+        writer.println(prefix + "\tmWidgetDepth=" + widgetDepth.getValue());
         writer.println(prefix + "\tmCurrentBlur=" + mCurrentBlur);
         writer.println(prefix + "\tmInEarlyWakeUp=" + mInEarlyWakeUp);
         writer.println(prefix + "\tmIgnoreStateChangesDuringMultiWindowAnimation="
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
index 0ab3cfd5..48481d8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
@@ -18,6 +18,8 @@
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_NOTIFICATIONS;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_QUICK_SETTINGS;
 
+import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
@@ -31,6 +33,8 @@
     private final TaskbarActivityContext mContext;
     private final FrameLayout mNavButtonsView;
     private final ViewGroup mNavButtonContainer;
+    private final ViewGroup mStartContextualContainer;
+    private final View mAllAppsButton;
 
     private TaskbarControllers mControllers;
 
@@ -40,6 +44,12 @@
         mContext = context;
         mNavButtonsView = navButtonsView;
         mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons);
+        mStartContextualContainer = mNavButtonsView.findViewById(R.id.start_contextual_buttons);
+        mAllAppsButton = LayoutInflater.from(context)
+                .inflate(R.layout.taskbar_all_apps_button, mStartContextualContainer, false);
+        mAllAppsButton.setOnClickListener((View v) -> {
+            mControllers.taskbarAllAppsController.show();
+        });
     }
 
     /**
@@ -57,6 +67,8 @@
         addButton(R.drawable.ic_sysbar_notifications, BUTTON_NOTIFICATIONS,
                 mNavButtonContainer, mControllers.navButtonController,
                 R.id.notifications_button);
+        // All apps button
+        mStartContextualContainer.addView(mAllAppsButton);
     }
 
     /** Cleans up on destroy */
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 555cd65..c9e42b7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -44,6 +44,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.OnboardingPrefs;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.RecentsAnimationCallbacks;
@@ -227,7 +228,9 @@
             } else {
                 // Adjust task transition spec to account for taskbar being visible
                 @ColorInt int taskAnimationBackgroundColor =
-                        mLauncher.getColor(R.color.taskbar_background);
+                        DisplayController.isTransientTaskbar(mLauncher)
+                                ? mLauncher.getColor(R.color.transient_taskbar_background)
+                                : mLauncher.getColor(R.color.taskbar_background);
 
                 TaskTransitionSpec customTaskAnimationSpec = new TaskTransitionSpec(
                         taskAnimationBackgroundColor,
@@ -286,6 +289,10 @@
     @Override
     public void setSystemGestureInProgress(boolean inProgress) {
         super.setSystemGestureInProgress(inProgress);
+        if (DisplayController.isTransientTaskbar(mLauncher)) {
+            forceHideBackground(false);
+            return;
+        }
         if (!FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) {
             // Launcher's ScrimView will draw the background throughout the gesture. But once the
             // gesture ends, start drawing taskbar's background again since launcher might stop
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 026fa23..875327d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -31,6 +31,7 @@
 import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_KEYGUARD;
 import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_SMALL_SCREEN;
 import static com.android.launcher3.taskbar.Utilities.appendFlag;
+import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
@@ -84,6 +85,7 @@
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory;
 import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter;
 import com.android.launcher3.util.DimensionUtils;
+import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
@@ -227,13 +229,13 @@
 
         mPropertyHolders.add(new StatePropertyHolder(
                 mControllers.taskbarViewController.getTaskbarIconAlpha()
-                        .getProperty(ALPHA_INDEX_KEYGUARD),
+                        .get(ALPHA_INDEX_KEYGUARD),
                 flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0
                         && (flags & FLAG_SCREEN_PINNING_ACTIVE) == 0));
 
         mPropertyHolders.add(new StatePropertyHolder(
                 mControllers.taskbarViewController.getTaskbarIconAlpha()
-                        .getProperty(ALPHA_INDEX_SMALL_SCREEN),
+                        .get(ALPHA_INDEX_SMALL_SCREEN),
                 flags -> (flags & FLAG_SMALL_SCREEN) == 0));
 
         mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
@@ -340,7 +342,7 @@
         mBackButtonAlpha = new MultiValueAlpha(mBackButton, NUM_ALPHA_CHANNELS);
         mBackButtonAlpha.setUpdateVisibility(true);
         mPropertyHolders.add(new StatePropertyHolder(
-                mBackButtonAlpha.getProperty(ALPHA_INDEX_KEYGUARD_OR_DISABLE),
+                mBackButtonAlpha.get(ALPHA_INDEX_KEYGUARD_OR_DISABLE),
                 flags -> {
                     // Show only if not disabled, and if not on the keyguard or otherwise only when
                     // the bouncer or a lockscreen app is showing above the keyguard
@@ -368,7 +370,7 @@
         mHomeButtonAlpha = new MultiValueAlpha(mHomeButton, NUM_ALPHA_CHANNELS);
         mHomeButtonAlpha.setUpdateVisibility(true);
         mPropertyHolders.add(
-                new StatePropertyHolder(mHomeButtonAlpha.getProperty(
+                new StatePropertyHolder(mHomeButtonAlpha.get(
                         ALPHA_INDEX_KEYGUARD_OR_DISABLE),
                 flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
                         (flags & FLAG_DISABLE_HOME) == 0));
@@ -720,7 +722,7 @@
 
             // Hide back button in SUW if keyboard is showing (IME draws its own back).
             mPropertyHolders.add(new StatePropertyHolder(
-                    mBackButtonAlpha.getProperty(ALPHA_INDEX_SUW),
+                    mBackButtonAlpha.get(ALPHA_INDEX_SUW),
                     flags -> (flags & FLAG_IME_VISIBLE) == 0));
 
             // TODO(b/210906568) Dark intensity is currently not propagated during setup, so set
@@ -1046,9 +1048,9 @@
             mAnimator.addListener(new AlphaUpdateListener(view));
         }
 
-        StatePropertyHolder(MultiValueAlpha.AlphaProperty alphaProperty,
+        StatePropertyHolder(MultiProperty alphaProperty,
                 IntPredicate enableCondition) {
-            this(alphaProperty, enableCondition, MultiValueAlpha.VALUE, 1, 0);
+            this(alphaProperty, enableCondition, MULTI_PROPERTY_VALUE, 1, 0);
         }
 
         StatePropertyHolder(AnimatedFloat animatedFloat, IntPredicate enableCondition) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index e23e27e..12dbcb3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -31,6 +31,7 @@
 import com.android.launcher3.anim.RevealOutlineAnimation;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
 import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.quickstep.AnimatedFloat;
 import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
@@ -105,7 +106,7 @@
                     .getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width);
         }
 
-        mTaskbarStashedHandleAlpha.getProperty(ALPHA_INDEX_STASHED).setValue(
+        mTaskbarStashedHandleAlpha.get(ALPHA_INDEX_STASHED).setValue(
                 isPhoneGestureNavMode(deviceProfile) ? 1 : 0);
         mTaskbarStashedHandleHintScale.updateValue(1f);
 
@@ -166,7 +167,7 @@
         return TaskbarManager.isPhoneMode(deviceProfile) && !mActivity.isThreeButtonNav();
     }
 
-    public MultiValueAlpha getStashedHandleAlpha() {
+    public MultiPropertyFactory<View> getStashedHandleAlpha() {
         return mTaskbarStashedHandleAlpha;
     }
 
@@ -222,7 +223,7 @@
      * Should be called when the home button is disabled, so we can hide this handle as well.
      */
     public void setIsHomeButtonDisabled(boolean homeDisabled) {
-        mTaskbarStashedHandleAlpha.getProperty(ALPHA_INDEX_HOME_DISABLED).setValue(
+        mTaskbarStashedHandleAlpha.get(ALPHA_INDEX_HOME_DISABLED).setValue(
                 homeDisabled ? 0 : 1);
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 4c5e0be..593605f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -135,14 +135,16 @@
     private boolean mBindingItems = false;
     private boolean mAddedWindow = false;
 
+    // The bounds of the taskbar items relative to TaskbarDragLayer
+    private final Rect mTransientTaskbarBounds = new Rect();
 
     private final TaskbarShortcutMenuAccessibilityDelegate mAccessibilityDelegate;
 
-    public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
+    public TaskbarActivityContext(Context windowContext, DeviceProfile launcherDp,
             TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
             unfoldTransitionProgressProvider) {
         super(windowContext);
-        mDeviceProfile = dp.copy(this);
+        mDeviceProfile = launcherDp.copy(this);
 
         final Resources resources = getResources();
 
@@ -172,8 +174,10 @@
         mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
 
         // Inflate views.
-        mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(
-                R.layout.taskbar, null, false);
+        int taskbarLayout = DisplayController.isTransientTaskbar(this)
+                ? R.layout.transient_taskbar
+                : R.layout.taskbar;
+        mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(taskbarLayout, null, false);
         TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
         TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
         FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
@@ -212,7 +216,7 @@
                 new TaskbarAutohideSuspendController(this),
                 new TaskbarPopupController(this),
                 new TaskbarForceVisibleImmersiveController(this),
-                new TaskbarOverlayController(this, dp),
+                new TaskbarOverlayController(this, launcherDp),
                 new TaskbarAllAppsController(),
                 new TaskbarInsetsController(this),
                 new VoiceInteractionWindowController(this),
@@ -243,10 +247,10 @@
     }
 
     /** Updates {@link DeviceProfile} instances for any Taskbar windows. */
-    public void updateDeviceProfile(DeviceProfile dp, NavigationMode navMode) {
+    public void updateDeviceProfile(DeviceProfile launcherDp, NavigationMode navMode) {
         mNavMode = navMode;
-        mControllers.taskbarOverlayController.updateDeviceProfile(dp);
-        mDeviceProfile = dp.copy(this);
+        mControllers.taskbarOverlayController.updateLauncherDeviceProfile(launcherDp);
+        mDeviceProfile = launcherDp.copy(this);
         updateIconSize(getResources());
 
         AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE);
@@ -257,12 +261,21 @@
     }
 
     private void updateIconSize(Resources resources) {
-        float taskbarIconSize = resources.getDimension(R.dimen.taskbar_icon_size);
+        float taskbarIconSize = DisplayController.isTransientTaskbar(this)
+                ? resources.getDimension(R.dimen.transient_taskbar_icon_size)
+                : resources.getDimension(R.dimen.taskbar_icon_size);
         mDeviceProfile.updateIconSize(1, resources);
         float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
         mDeviceProfile.updateIconSize(iconScale, resources);
     }
 
+    /**
+     * Returns the View bounds of transient taskbar.
+     */
+    public Rect getTransientTaskbarBounds() {
+        return mTransientTaskbarBounds;
+    }
+
     @VisibleForTesting
     @Override
     public StatsLogManager getStatsLogManager() {
@@ -523,7 +536,7 @@
     private void onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim) {
         float alpha = isExpanded ? 0 : 1;
         AnimatorSet anim = new AnimatorSet();
-        anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().getProperty(
+        anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().get(
                 TaskbarViewController.ALPHA_INDEX_NOTIFICATION_EXPANDED).animateToValue(alpha));
         if (!isThreeButtonNav()) {
             anim.play(mControllers.taskbarDragLayerController.getNotificationShadeBgTaskbar()
@@ -623,16 +636,24 @@
      * Returns the default height of the window, including the static corner radii above taskbar.
      */
     public int getDefaultTaskbarWindowHeight() {
+        Resources resources = getResources();
+
         if (FLAG_HIDE_NAVBAR_WINDOW && mDeviceProfile.isPhone) {
-            Resources resources = getResources();
             return isThreeButtonNav() ?
                     resources.getDimensionPixelSize(R.dimen.taskbar_size) :
                     resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
         }
 
         if (!isUserSetupComplete()) {
-            return getResources().getDimensionPixelSize(R.dimen.taskbar_suw_frame);
+            return resources.getDimensionPixelSize(R.dimen.taskbar_suw_frame);
         }
+
+        if (DisplayController.isTransientTaskbar(this)) {
+            return resources.getDimensionPixelSize(R.dimen.transient_taskbar_size)
+                    + (2 * resources.getDimensionPixelSize(R.dimen.transient_taskbar_margin))
+                    + resources.getDimensionPixelSize(R.dimen.transient_taskbar_shadow_blur);
+        }
+
         return mDeviceProfile.taskbarSize + Math.max(getLeftCornerRadius(), getRightCornerRadius());
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index 1177bdb..d0e2b22 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -16,10 +16,16 @@
 
 package com.android.launcher3.taskbar
 
+import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
+import com.android.launcher3.Utilities.mapToRange
+
 import android.graphics.Canvas
+import android.graphics.Color
 import android.graphics.Paint
 import android.graphics.Path
 import com.android.launcher3.R
+import com.android.launcher3.anim.Interpolators
+import com.android.launcher3.util.DisplayController
 
 /**
  * Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners.
@@ -29,6 +35,13 @@
     val paint: Paint = Paint()
     var backgroundHeight = context.deviceProfile.taskbarSize.toFloat()
 
+    private var maxBackgroundHeight = context.deviceProfile.taskbarSize.toFloat()
+    private val transientBackgroundBounds = context.transientTaskbarBounds
+
+    private var shadowBlur = 0f
+    private var keyShadowDistance = 0f
+    private var bottomMargin = 0
+
     private val leftCornerRadius = context.leftCornerRadius.toFloat()
     private val rightCornerRadius = context.rightCornerRadius.toFloat()
     private val invertedLeftCornerPath: Path = Path()
@@ -39,6 +52,15 @@
         paint.flags = Paint.ANTI_ALIAS_FLAG
         paint.style = Paint.Style.FILL
 
+        if (DisplayController.isTransientTaskbar(context)) {
+            paint.color = context.getColor(R.color.transient_taskbar_background)
+
+            val res = context.resources
+            bottomMargin = res.getDimensionPixelSize(R.dimen.transient_taskbar_margin)
+            shadowBlur = res.getDimension(R.dimen.transient_taskbar_shadow_blur)
+            keyShadowDistance = res.getDimension(R.dimen.transient_taskbar_key_shadow_distance)
+        }
+
         // Create the paths for the inverted rounded corners above the taskbar. Start with a filled
         // square, and then subtract out a circle from the appropriate corner.
         val square = Path()
@@ -58,17 +80,42 @@
      */
     fun draw(canvas: Canvas) {
         canvas.save()
-        canvas.translate(0f, canvas.height - backgroundHeight)
+        canvas.translate(0f, canvas.height - backgroundHeight - bottomMargin)
+        if (transientBackgroundBounds.isEmpty) {
+            // Draw the background behind taskbar content.
+            canvas.drawRect(0f, 0f, canvas.width.toFloat(), backgroundHeight, paint)
 
-        // Draw the background behind taskbar content.
-        canvas.drawRect(0f, 0f, canvas.width.toFloat(), backgroundHeight, paint)
+            // Draw the inverted rounded corners above the taskbar.
+            canvas.translate(0f, -leftCornerRadius)
+            canvas.drawPath(invertedLeftCornerPath, paint)
+            canvas.translate(0f, leftCornerRadius)
+            canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius)
+            canvas.drawPath(invertedRightCornerPath, paint)
+        } else {
+            val scaleFactor = backgroundHeight / maxBackgroundHeight
+            val width = transientBackgroundBounds.width()
+            val widthScale = mapToRange(scaleFactor, 0f, 1f, 0.4f, 1f, Interpolators.LINEAR)
+            val newWidth = widthScale * width
+            val delta = width - newWidth
 
-        // Draw the inverted rounded corners above the taskbar.
-        canvas.translate(0f, -leftCornerRadius)
-        canvas.drawPath(invertedLeftCornerPath, paint)
-        canvas.translate(0f, leftCornerRadius)
-        canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius)
-        canvas.drawPath(invertedRightCornerPath, paint)
+            // Draw shadow.
+            val shadowAlpha = mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, 25f,
+                Interpolators.LINEAR)
+            paint.setShadowLayer(shadowBlur, 0f, keyShadowDistance,
+                setColorAlphaBound(Color.BLACK, Math.round(shadowAlpha))
+            )
+
+            // Draw background.
+            val radius = backgroundHeight / 2f;
+
+            canvas.drawRoundRect(
+                transientBackgroundBounds.left + (delta / 2f),
+                0f,
+                transientBackgroundBounds.right - (delta / 2f),
+                backgroundHeight,
+                radius, radius, paint
+            )
+        }
 
         canvas.restore()
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
index 6c793a6..f7aafe0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
@@ -31,13 +31,10 @@
 import android.view.View;
 
 import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.util.MultiValueAlpha;
+import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.TouchController;
 import com.android.quickstep.AnimatedFloat;
 
-import java.util.Optional;
-import java.util.function.Consumer;
-
 /**
  * Controller for taskbar when force visible in immersive mode is set.
  */
@@ -54,8 +51,6 @@
     private final Runnable mUndimmingRunnable = this::undimIcons;
     private final AnimatedFloat mIconAlphaForDimming = new AnimatedFloat(
             this::updateIconDimmingAlpha);
-    private final Consumer<MultiValueAlpha> mImmersiveModeAlphaUpdater = alpha -> alpha.getProperty(
-            ALPHA_INDEX_IMMERSIVE_MODE).setValue(mIconAlphaForDimming.value);
     private final View.AccessibilityDelegate mKidsModeAccessibilityDelegate =
             new View.AccessibilityDelegate() {
                 @Override
@@ -145,22 +140,20 @@
     }
 
     private void updateIconDimmingAlpha() {
-        getBackButtonAlphaOptional().ifPresent(mImmersiveModeAlphaUpdater);
-        getHomeButtonAlphaOptional().ifPresent(mImmersiveModeAlphaUpdater);
-    }
-
-    private Optional<MultiValueAlpha> getBackButtonAlphaOptional() {
         if (mControllers == null || mControllers.navbarButtonsViewController == null) {
-            return Optional.empty();
+            return;
         }
-        return Optional.ofNullable(mControllers.navbarButtonsViewController.getBackButtonAlpha());
-    }
 
-    private Optional<MultiValueAlpha> getHomeButtonAlphaOptional() {
-        if (mControllers == null || mControllers.navbarButtonsViewController == null) {
-            return Optional.empty();
+        MultiPropertyFactory<View> ba =
+                mControllers.navbarButtonsViewController.getBackButtonAlpha();
+        if (ba != null) {
+            ba.get(ALPHA_INDEX_IMMERSIVE_MODE).setValue(mIconAlphaForDimming.value);
         }
-        return Optional.ofNullable(mControllers.navbarButtonsViewController.getHomeButtonAlpha());
+        MultiPropertyFactory<View> ha =
+                mControllers.navbarButtonsViewController.getHomeButtonAlpha();
+        if (ba != null) {
+            ha.get(ALPHA_INDEX_IMMERSIVE_MODE).setValue(mIconAlphaForDimming.value);
+        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index de37b70..63f1486 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -38,7 +38,7 @@
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.launcher3.util.MultiValueAlpha;
+import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.RecentsAnimationCallbacks;
 import com.android.quickstep.RecentsAnimationController;
@@ -49,7 +49,6 @@
 import java.io.PrintWriter;
 import java.util.HashMap;
 import java.util.StringJoiner;
-import java.util.function.Consumer;
 
 /**
  * Track LauncherState, RecentsAnimation, resumed state for task bar in one place here and animate
@@ -73,7 +72,7 @@
 
     private TaskbarControllers mControllers;
     private AnimatedFloat mTaskbarBackgroundAlpha;
-    private MultiValueAlpha.AlphaProperty mIconAlphaForHome;
+    private MultiProperty mIconAlphaForHome;
     private QuickstepLauncher mLauncher;
 
     private Integer mPrevState;
@@ -89,18 +88,8 @@
     // We skip any view synchronizations during init/destroy.
     private boolean mCanSyncViews;
 
-    private final Consumer<Float> mIconAlphaForHomeConsumer = alpha -> {
-        /*
-         * Hide Launcher Hotseat icons when Taskbar icons have opacity. Both icon sets
-         * should not be visible at the same time.
-         */
-        mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1);
-        mLauncher.getHotseat().setQsbAlpha(
-                mLauncher.getDeviceProfile().isQsbInline && alpha > 0 ? 0 : 1);
-    };
-
     private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
-            dp -> mIconAlphaForHomeConsumer.accept(mIconAlphaForHome.getValue());
+            dp -> updateIconAlphaForHome(mIconAlphaForHome.getValue());
 
     private final StateManager.StateListener<LauncherState> mStateListener =
             new StateManager.StateListener<LauncherState>() {
@@ -139,9 +128,8 @@
 
         mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController
                 .getTaskbarBackgroundAlpha();
-        MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha();
-        mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
-        mIconAlphaForHome.setConsumer(mIconAlphaForHomeConsumer);
+        mIconAlphaForHome = mControllers.taskbarViewController
+                .getTaskbarIconAlpha().get(ALPHA_INDEX_HOME);
 
         mIconAlignment.finishAnimation();
         onIconAlignmentRatioChanged();
@@ -162,7 +150,6 @@
 
         mIconAlignment.finishAnimation();
 
-        mIconAlphaForHome.setConsumer(null);
         mLauncher.getHotseat().setIconsAlpha(1f);
         mLauncher.getStateManager().removeStateListener(mStateListener);
 
@@ -383,7 +370,7 @@
                 @Override
                 public void onAnimationStart(Animator animation) {
                     if (mLauncher.getHotseat().getIconsAlpha() > 0) {
-                        mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha());
+                        updateIconAlphaForHome(mLauncher.getHotseat().getIconsAlpha());
                     }
                 }
             });
@@ -405,7 +392,7 @@
                 mIconAlignment.value, mIconAlignment.getEndValue(), mLauncher.getDeviceProfile());
         mControllers.navbarButtonsViewController.updateTaskbarAlignment(mIconAlignment.value);
         // Switch taskbar and hotseat in last frame
-        mIconAlphaForHome.setValue(taskbarWillBeVisible ? 1 : 0);
+        updateIconAlphaForHome(taskbarWillBeVisible ? 1 : 0);
 
         // Sync the first frame where we swap taskbar and hotseat.
         if (firstFrameVisChanged && mCanSyncViews && !Utilities.IS_RUNNING_IN_TEST_HARNESS) {
@@ -415,6 +402,18 @@
         }
     }
 
+    private void updateIconAlphaForHome(float alpha) {
+        mIconAlphaForHome.setValue(alpha);
+
+        /*
+         * Hide Launcher Hotseat icons when Taskbar icons have opacity. Both icon sets
+         * should not be visible at the same time.
+         */
+        mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1);
+        mLauncher.getHotseat().setQsbAlpha(
+                mLauncher.getDeviceProfile().isQsbInline && alpha > 0 ? 0 : 1);
+    }
+
     private final class TaskBarRecentsAnimationListener implements
             RecentsAnimationCallbacks.RecentsAnimationListener {
         private final RecentsAnimationCallbacks mCallbacks;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index c5e1b8f..64eb99e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -44,7 +44,7 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
+import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.SystemUiProxy;
 
@@ -144,11 +144,11 @@
     private AnimatedFloat mTaskbarBackgroundOffset;
     private AnimatedFloat mTaskbarImeBgAlpha;
     // TaskbarView icon properties.
-    private AlphaProperty mIconAlphaForStash;
+    private MultiProperty mIconAlphaForStash;
     private AnimatedFloat mIconScaleForStash;
     private AnimatedFloat mIconTranslationYForStash;
     // Stashed handle properties.
-    private AlphaProperty mTaskbarStashedHandleAlpha;
+    private MultiProperty mTaskbarStashedHandleAlpha;
     private AnimatedFloat mTaskbarStashedHandleHintScale;
 
     /** Whether we are currently visually stashed (might change based on launcher state). */
@@ -199,14 +199,14 @@
         mTaskbarImeBgAlpha = dragLayerController.getImeBgTaskbar();
 
         TaskbarViewController taskbarViewController = controllers.taskbarViewController;
-        mIconAlphaForStash = taskbarViewController.getTaskbarIconAlpha().getProperty(
+        mIconAlphaForStash = taskbarViewController.getTaskbarIconAlpha().get(
                 TaskbarViewController.ALPHA_INDEX_STASH);
         mIconScaleForStash = taskbarViewController.getTaskbarIconScaleForStash();
         mIconTranslationYForStash = taskbarViewController.getTaskbarIconTranslationYForStash();
 
         StashedHandleViewController stashedHandleController =
                 controllers.stashedHandleViewController;
-        mTaskbarStashedHandleAlpha = stashedHandleController.getStashedHandleAlpha().getProperty(
+        mTaskbarStashedHandleAlpha = stashedHandleController.getStashedHandleAlpha().get(
                 StashedHandleViewController.ALPHA_INDEX_STASHED);
         mTaskbarStashedHandleHintScale = stashedHandleController.getStashedHandleHintScale();
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 31c2132..c754a59 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -44,6 +45,7 @@
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.DoubleShadowBubbleTextView;
@@ -60,7 +62,7 @@
     public int mThemeIconsBackground;
 
     private final int[] mTempOutLocation = new int[2];
-    private final Rect mIconLayoutBounds = new Rect();
+    private final Rect mIconLayoutBounds;
     private final int mIconTouchSize;
     private final int mItemMarginLeftRight;
     private final int mItemPadding;
@@ -106,11 +108,14 @@
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         mActivityContext = ActivityContext.lookupContext(context);
+        mIconLayoutBounds = mActivityContext.getTransientTaskbarBounds();
 
         Resources resources = getResources();
         mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size);
 
-        int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
+        int actualMargin = DisplayController.isTransientTaskbar(mActivityContext)
+                ? resources.getDimensionPixelSize(R.dimen.transient_taskbar_icon_spacing)
+                : resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
         int actualIconSize = mActivityContext.getDeviceProfile().iconSizePx;
 
         // We layout the icons to be of mIconTouchSize in width and height
@@ -126,6 +131,9 @@
             mAllAppsButton = LayoutInflater.from(context)
                     .inflate(R.layout.taskbar_all_apps_button, this, false);
             mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+            if (mActivityContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) {
+                mAllAppsButton.setVisibility(GONE);
+            }
         }
 
         // TODO: Disable touch events on QSB otherwise it can crash.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 16dd90d..f0277a4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
@@ -47,9 +48,11 @@
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.icons.ThemedIconDrawable;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.HorizontalInsettableView;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
+import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.SystemUiProxy;
@@ -87,6 +90,8 @@
     private AnimatedFloat mTaskbarNavButtonTranslationY;
     private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay;
 
+    private final int mTaskbarBottomMargin;
+
     private final AnimatedFloat mThemeIconsBackground = new AnimatedFloat(
             this::updateIconsBackground);
 
@@ -111,6 +116,9 @@
         mTaskbarIconAlpha = new MultiValueAlpha(mTaskbarView, NUM_ALPHA_CHANNELS);
         mTaskbarIconAlpha.setUpdateVisibility(true);
         mModelCallbacks = new TaskbarModelCallbacks(activity, mTaskbarView);
+        mTaskbarBottomMargin = DisplayController.isTransientTaskbar(activity)
+                ? activity.getResources().getDimensionPixelSize(R.dimen.transient_taskbar_margin)
+                : 0;
     }
 
     public void init(TaskbarControllers controllers) {
@@ -146,7 +154,7 @@
         return mTaskbarView.areIconsVisible();
     }
 
-    public MultiValueAlpha getTaskbarIconAlpha() {
+    public MultiPropertyFactory<View> getTaskbarIconAlpha() {
         return mTaskbarIconAlpha;
     }
 
@@ -161,7 +169,7 @@
      * Should be called when the IME switcher visibility changes.
      */
     public void setIsImeSwitcherVisible(boolean isImeSwitcherVisible) {
-        mTaskbarIconAlpha.getProperty(ALPHA_INDEX_IME_BUTTON_NAV).setValue(
+        mTaskbarIconAlpha.get(ALPHA_INDEX_IME_BUTTON_NAV).setValue(
                 isImeSwitcherVisible ? 0 : 1);
     }
 
@@ -170,7 +178,7 @@
      */
     public void setRecentsButtonDisabled(boolean isDisabled) {
         // TODO: check TaskbarStashController#supportsStashing(), to stash instead of setting alpha.
-        mTaskbarIconAlpha.getProperty(ALPHA_INDEX_RECENTS_DISABLED).setValue(isDisabled ? 0 : 1);
+        mTaskbarIconAlpha.get(ALPHA_INDEX_RECENTS_DISABLED).setValue(isDisabled ? 0 : 1);
     }
 
     /**
@@ -316,6 +324,8 @@
                 float scale = ((float) taskbarDp.iconSizePx) / launcherDp.hotseatQsbVisualHeight;
                 setter.addFloat(child, SCALE_PROPERTY, scale, 1f, LINEAR);
 
+                setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, LINEAR);
+
                 setter.addFloat(child, VIEW_ALPHA, 0f, 1f,
                         isToHome
                                 ? Interpolators.clampToProgress(LINEAR, 0f, 0.35f)
@@ -341,6 +351,8 @@
             float childCenter = (child.getLeft() + child.getRight()) / 2f;
             setter.setFloat(child, ICON_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR);
 
+            setter.setFloat(child, VIEW_TRANSLATE_Y, mTaskbarBottomMargin, LINEAR);
+
             setter.setFloat(child, SCALE_PROPERTY, scaleUp, LINEAR);
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
index 076900c..837af58 100644
--- a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
@@ -63,11 +63,11 @@
         // Fade out taskbar icons and stashed handle.
         val taskbarIconAlpha = if (isVoiceInteractionWindowVisible) 0f else 1f
         val fadeTaskbarIcons = controllers.taskbarViewController.taskbarIconAlpha
-            .getProperty(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
+            .get(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
             .animateToValue(taskbarIconAlpha)
             .setDuration(TASKBAR_ICONS_FADE_DURATION)
         val fadeStashedHandle = controllers.stashedHandleViewController.stashedHandleAlpha
-            .getProperty(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
+            .get(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
             .animateToValue(taskbarIconAlpha)
             .setDuration(STASHED_HANDLE_FADE_DURATION)
         fadeTaskbarIcons.start()
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
index 5701de0..7e3163d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
@@ -84,7 +84,7 @@
 
     @Override
     public DeviceProfile getDeviceProfile() {
-        return mOverlayController.getDeviceProfile();
+        return mOverlayController.getLauncherDeviceProfile();
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
index 0574058..6c7bdbf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
@@ -63,17 +63,17 @@
         }
     };
 
-    private DeviceProfile mDeviceProfile;
+    private DeviceProfile mLauncherDeviceProfile;
     private @Nullable TaskbarOverlayContext mOverlayContext;
     private TaskbarControllers mControllers; // Initialized in init.
 
     public TaskbarOverlayController(
-            TaskbarActivityContext taskbarContext, DeviceProfile deviceProfile) {
+            TaskbarActivityContext taskbarContext, DeviceProfile launcherDeviceProfile) {
         mTaskbarContext = taskbarContext;
         mWindowContext = mTaskbarContext.createWindowContext(TYPE_APPLICATION_OVERLAY, null);
         mProxyView = new TaskbarOverlayProxyView();
         mLayoutParams = createLayoutParams();
-        mDeviceProfile = deviceProfile;
+        mLauncherDeviceProfile = launcherDeviceProfile;
     }
 
     /** Initialize the controller. */
@@ -132,13 +132,13 @@
     }
 
     /** The current device profile for the overlay window. */
-    public DeviceProfile getDeviceProfile() {
-        return mDeviceProfile;
+    public DeviceProfile getLauncherDeviceProfile() {
+        return mLauncherDeviceProfile;
     }
 
     /** Updates {@link DeviceProfile} instance for Taskbar's overlay window. */
-    public void updateDeviceProfile(DeviceProfile dp) {
-        mDeviceProfile = dp;
+    public void updateLauncherDeviceProfile(DeviceProfile dp) {
+        mLauncherDeviceProfile = dp;
         Optional.ofNullable(mOverlayContext).ifPresent(c -> {
             AbstractFloatingView.closeAllOpenViewsExcept(c, false, TYPE_REBIND_SAFE);
             c.dispatchDeviceProfileChanged();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 77c1518..eaf577b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -45,7 +45,6 @@
 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.util.BaseDepthController.WIDGET_DEPTH;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
 
 import android.animation.AnimatorSet;
@@ -59,6 +58,7 @@
 import android.content.res.Configuration;
 import android.hardware.SensorManager;
 import android.hardware.devicestate.DeviceStateManager;
+import android.media.permission.SafeCloseable;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.IBinder;
@@ -72,6 +72,7 @@
 
 import androidx.annotation.Nullable;
 
+import com.android.app.viewcapture.ViewCapture;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherSettings.Favorites;
@@ -121,7 +122,6 @@
 import com.android.launcher3.util.PendingRequestArgs;
 import com.android.launcher3.util.PendingSplitSelectInfo;
 import com.android.launcher3.util.RunnableList;
-import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.TouchController;
 import com.android.quickstep.OverviewCommandHelper;
@@ -136,7 +136,6 @@
 import com.android.quickstep.util.RemoteFadeOutAnimationListener;
 import com.android.quickstep.util.SplitSelectStateController;
 import com.android.quickstep.util.TISBindHelper;
-import com.android.quickstep.util.ViewCapture;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
@@ -403,7 +402,7 @@
 
         super.onDestroy();
         mHotseatPredictionController.destroy();
-        mViewCapture.close();
+        if (mViewCapture != null) mViewCapture.close();
     }
 
     @Override
@@ -504,7 +503,9 @@
         }
         addMultiWindowModeChangedListener(mDepthController);
         initUnfoldTransitionProgressProvider();
-        mViewCapture = ViewCapture.INSTANCE.get(this).startCapture(getWindow());
+        if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
+            mViewCapture = ViewCapture.getInstance().startCapture(getWindow());
+        }
     }
 
     @Override
@@ -597,9 +598,8 @@
         super.onWidgetsTransition(progress);
         onTaskbarInAppDisplayProgressUpdate(progress, WIDGETS_PAGE_PROGRESS_INDEX);
         if (mEnableWidgetDepth) {
-            WIDGET_DEPTH.set(getDepthController(),
-                    Utilities.mapToRange(progress, 0f, 1f, 0f, getDeviceProfile().bottomSheetDepth,
-                            EMPHASIZED));
+            getDepthController().widgetDepth.setValue(Utilities.mapToRange(
+                    progress, 0f, 1f, 0f, getDeviceProfile().bottomSheetDepth, EMPHASIZED));
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 0e1120b..e8e8328 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -20,6 +20,7 @@
 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
+import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
 import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
@@ -43,7 +44,6 @@
 import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.touch.PagedOrientationHandler;
-import com.android.launcher3.util.MultiValueAlpha;
 import com.android.quickstep.util.AnimUtils;
 import com.android.quickstep.util.SplitAnimationTimings;
 import com.android.quickstep.views.ClearAllButton;
@@ -164,7 +164,7 @@
                 clearAllButtonAlpha, LINEAR);
         float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS) ? 1 : 0;
         propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
-                MultiValueAlpha.VALUE, overviewButtonAlpha, config.getInterpolator(
+                MULTI_PROPERTY_VALUE, overviewButtonAlpha, config.getInterpolator(
                         ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
     }
 
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index d4b713b..ff7c668 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1892,11 +1892,13 @@
     }
 
     private void finishCurrentTransitionToRecents() {
-        if (mRecentsAnimationController != null
+        if (mRecentsView != null
                 && mActivityInterface.getDesktopVisibilityController() != null
                 && mActivityInterface.getDesktopVisibilityController().areFreeformTasksVisible()) {
-            mRecentsAnimationController.finish(true /* toRecents */,
-                    () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
+            mRecentsView.switchToScreenshot(() -> {
+                mRecentsView.finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
+                        () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
+            });
         } else {
             mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
             if (mRecentsAnimationController != null) {
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 0a7d226..ecb3747 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -22,6 +22,7 @@
 import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
@@ -129,9 +130,9 @@
                 // Animate the blur and wallpaper zoom
                 float fromDepthRatio = BACKGROUND_APP.getDepth(activity);
                 float toDepthRatio = OVERVIEW.getDepth(activity);
-                pa.addFloat(getDepthController(),
+                pa.addFloat(getDepthController().stateDepth,
                         new LauncherAnimUtils.ClampedProperty<>(
-                                DepthController.STATE_DEPTH, fromDepthRatio, toDepthRatio),
+                                MULTI_PROPERTY_VALUE, fromDepthRatio, toDepthRatio),
                         fromDepthRatio, toDepthRatio, LINEAR);
             }
         };
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 7d6bbac..9d5e7c3 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -36,7 +36,7 @@
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
 import static com.android.launcher3.anim.Interpolators.clampToProgress;
-import static com.android.launcher3.statehandlers.DepthController.STATE_DEPTH;
+import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -376,8 +376,8 @@
         });
 
         if (depthController != null) {
-            out.setFloat(depthController, STATE_DEPTH, BACKGROUND_APP.getDepth(baseActivity),
-                    TOUCH_RESPONSE_INTERPOLATOR);
+            out.setFloat(depthController.stateDepth, MULTI_PROPERTY_VALUE,
+                    BACKGROUND_APP.getDepth(baseActivity), TOUCH_RESPONSE_INTERPOLATOR);
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 80db362..e9f9d80 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -67,6 +67,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
+import com.android.app.viewcapture.ViewCapture;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -103,7 +104,6 @@
 import com.android.quickstep.util.ProtoTracer;
 import com.android.quickstep.util.ProxyScreenStatusProvider;
 import com.android.quickstep.util.SplitScreenBounds;
-import com.android.quickstep.util.ViewCapture;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -1238,7 +1238,9 @@
             }
             mTaskbarManager.dumpLogs("", pw);
 
-            ViewCapture.INSTANCE.get(this).dump(pw, fd);
+            if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
+                ViewCapture.getInstance().dump(pw, fd, this);
+            }
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 19a6c38..062e50e 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -45,7 +45,7 @@
 import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.util.MultiValueAlpha;
+import com.android.launcher3.util.MultiPropertyFactory;
 import com.android.quickstep.RecentsActivity;
 import com.android.quickstep.views.ClearAllButton;
 
@@ -95,7 +95,7 @@
                 clearAllButtonAlpha, LINEAR);
         float overviewButtonAlpha = state.hasOverviewActions() ? 1 : 0;
         setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
-                MultiValueAlpha.VALUE, overviewButtonAlpha, LINEAR);
+                MultiPropertyFactory.MULTI_PROPERTY_VALUE, overviewButtonAlpha, LINEAR);
 
         float[] scaleAndOffset = state.getOverviewScaleAndOffset(mActivity);
         setter.setFloat(mRecentsView, RECENTS_SCALE_PROPERTY, scaleAndOffset[0],
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 8ad17cb..7ff576e 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -143,6 +143,11 @@
 
         mVibrator = getSystemService(Vibrator.class);
         mAnimatedBackground = findViewById(R.id.animated_background);
+        // There's a bug in the currently used external Lottie library (v5.2.0), and it doesn't load
+        // the correct animation from the raw resources when configuration changes, so we need to
+        // manually load the resource and pass it to Lottie.
+        mAnimatedBackground.setAnimation(getResources().openRawResource(R.raw.all_set_page_bg),
+                null);
         startBackgroundAnimation();
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/BaseDepthController.java b/quickstep/src/com/android/quickstep/util/BaseDepthController.java
index 064e675..877e28a 100644
--- a/quickstep/src/com/android/quickstep/util/BaseDepthController.java
+++ b/quickstep/src/com/android/quickstep/util/BaseDepthController.java
@@ -25,6 +25,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.MultiPropertyFactory;
+import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.systemui.shared.system.BlurUtils;
 
 /**
@@ -45,20 +46,15 @@
                 }
             };
 
-    private static final MultiPropertyFactory<BaseDepthController> DEPTH_PROPERTY_FACTORY =
-            new MultiPropertyFactory<>("depthProperty", DEPTH, Float::max);
-
-    private static final int DEPTH_INDEX_STATE_TRANSITION = 1;
-    private static final int DEPTH_INDEX_WIDGET = 2;
-
-    /** Property to set the depth for state transition. */
-    public static final FloatProperty<BaseDepthController> STATE_DEPTH =
-            DEPTH_PROPERTY_FACTORY.get(DEPTH_INDEX_STATE_TRANSITION);
-    /** Property to set the depth for widget picker. */
-    public static final FloatProperty<BaseDepthController> WIDGET_DEPTH =
-            DEPTH_PROPERTY_FACTORY.get(DEPTH_INDEX_WIDGET);
+    private static final int DEPTH_INDEX_STATE_TRANSITION = 0;
+    private static final int DEPTH_INDEX_WIDGET = 1;
+    private static final int DEPTH_INDEX_COUNT = 2;
 
     protected final Launcher mLauncher;
+    /** Property to set the depth for state transition. */
+    public final MultiProperty stateDepth;
+    /** Property to set the depth for widget picker. */
+    public final MultiProperty widgetDepth;
 
     /**
      * Blur radius when completely zoomed out, in pixels.
@@ -92,6 +88,11 @@
         mLauncher = activity;
         mMaxBlurRadius = activity.getResources().getInteger(R.integer.max_depth_blur_radius);
         mWallpaperManager = activity.getSystemService(WallpaperManager.class);
+
+        MultiPropertyFactory<BaseDepthController> depthProperty =
+                new MultiPropertyFactory<>(this, DEPTH, DEPTH_INDEX_COUNT, Float::max);
+        stateDepth = depthProperty.get(DEPTH_INDEX_STATE_TRANSITION);
+        widgetDepth = depthProperty.get(DEPTH_INDEX_WIDGET);
     }
 
     protected void setCrossWindowBlursEnabled(boolean isEnabled) {
diff --git a/quickstep/src/com/android/quickstep/util/ViewCapture.java b/quickstep/src/com/android/quickstep/util/ViewCapture.java
deleted file mode 100644
index ba7d7f5..0000000
--- a/quickstep/src/com/android/quickstep/util/ViewCapture.java
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.util;
-
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.launcher3.util.Executors.createAndStartNewLooper;
-
-import static java.util.stream.Collectors.toList;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.Looper;
-import android.os.Process;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.text.TextUtils;
-import android.util.Base64;
-import android.util.Base64OutputStream;
-import android.util.Log;
-import android.util.Pair;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.View.OnAttachStateChangeListener;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver.OnDrawListener;
-import android.view.Window;
-
-import androidx.annotation.UiThread;
-import androidx.annotation.WorkerThread;
-
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.LooperExecutor;
-import com.android.launcher3.util.MainThreadInitializedObject;
-import com.android.launcher3.util.SafeCloseable;
-import com.android.launcher3.view.ViewCaptureData.ExportedData;
-import com.android.launcher3.view.ViewCaptureData.FrameData;
-import com.android.launcher3.view.ViewCaptureData.ViewNode;
-
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.FutureTask;
-import java.util.function.Consumer;
-import java.util.zip.GZIPOutputStream;
-
-/**
- * Utility class for capturing view data every frame
- */
-public class ViewCapture {
-
-    private static final String TAG = "ViewCapture";
-
-    // These flags are copies of two private flags in the View class.
-    private static final int PFLAG_INVALIDATED = 0x80000000;
-    private static final int PFLAG_DIRTY_MASK = 0x00200000;
-
-    // Number of frames to keep in memory
-    private static final int MEMORY_SIZE = 2000;
-    // Initial size of the reference pool. This is at least be 5 * total number of views in
-    // Launcher. This allows the first free frames avoid object allocation during view capture.
-    private static final int INIT_POOL_SIZE = 300;
-
-    public static final MainThreadInitializedObject<ViewCapture> INSTANCE =
-            new MainThreadInitializedObject<>(ViewCapture::new);
-
-    private final List<WindowListener> mListeners = new ArrayList<>();
-
-    private final Context mContext;
-    private final Executor mExecutor;
-
-    // Pool used for capturing view tree on the UI thread.
-    private ViewRef mPool = new ViewRef();
-
-    private ViewCapture(Context context) {
-        mContext = context;
-        if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
-            Looper looper = createAndStartNewLooper("ViewCapture",
-                    Process.THREAD_PRIORITY_FOREGROUND);
-            mExecutor = new LooperExecutor(looper);
-            mExecutor.execute(this::initPool);
-        } else {
-            mExecutor = UI_HELPER_EXECUTOR;
-        }
-    }
-
-    @UiThread
-    private void addToPool(ViewRef start, ViewRef end) {
-        end.next = mPool;
-        mPool = start;
-    }
-
-    @WorkerThread
-    private void initPool() {
-        ViewRef start = new ViewRef();
-        ViewRef current = start;
-
-        for (int i = 0; i < INIT_POOL_SIZE; i++) {
-            current.next = new ViewRef();
-            current = current.next;
-        }
-
-        ViewRef finalCurrent = current;
-        MAIN_EXECUTOR.execute(() -> addToPool(start, finalCurrent));
-    }
-
-    /**
-     * Attaches the ViewCapture to the provided window and returns a handle to detach the listener
-     */
-    public SafeCloseable startCapture(Window window) {
-        String title = window.getAttributes().getTitle().toString();
-        String name = TextUtils.isEmpty(title) ? window.toString() : title;
-        return startCapture(window.getDecorView(), name);
-    }
-
-    /**
-     * Attaches the ViewCapture to the provided window and returns a handle to detach the listener
-     */
-    public SafeCloseable startCapture(View view, String name) {
-        if (!FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
-            return () -> { };
-        }
-
-        WindowListener listener = new WindowListener(view, name);
-        mExecutor.execute(() -> MAIN_EXECUTOR.execute(listener::attachToRoot));
-        mListeners.add(listener);
-        return () -> {
-            mListeners.remove(listener);
-            listener.destroy();
-        };
-    }
-
-    /**
-     * Dumps all the active view captures
-     */
-    public void dump(PrintWriter writer, FileDescriptor out) {
-        if (!FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) {
-            return;
-        }
-        ViewIdProvider idProvider = new ViewIdProvider(mContext.getResources());
-
-        // Collect all the tasks first so that all the tasks are posted on the executor
-        List<Pair<String, FutureTask<ExportedData>>> tasks = mListeners.stream()
-                .map(l -> {
-                    FutureTask<ExportedData> task =
-                            new FutureTask<ExportedData>(() -> l.dumpToProto(idProvider));
-                    mExecutor.execute(task);
-                    return Pair.create(l.name, task);
-                })
-                .collect(toList());
-
-        tasks.forEach(pair -> {
-            writer.println();
-            writer.println(" ContinuousViewCapture:");
-            writer.println(" window " + pair.first + ":");
-            writer.println("  pkg:" + mContext.getPackageName());
-            writer.print("  data:");
-            writer.flush();
-            try (OutputStream os = new FileOutputStream(out)) {
-                ExportedData data = pair.second.get();
-                OutputStream encodedOS = new GZIPOutputStream(new Base64OutputStream(os,
-                        Base64.NO_CLOSE | Base64.NO_PADDING | Base64.NO_WRAP));
-                data.writeTo(encodedOS);
-                encodedOS.close();
-                os.flush();
-            } catch (Exception e) {
-                Log.e(TAG, "Error capturing proto", e);
-            }
-            writer.println();
-            writer.println("--end--");
-        });
-    }
-
-    private class WindowListener implements OnDrawListener {
-
-        private final View mRoot;
-        public final String name;
-
-        private final ViewRef mViewRef = new ViewRef();
-
-        private int mFrameIndexBg = -1;
-        private boolean mIsFirstFrame = true;
-        private final long[] mFrameTimesBg = new long[MEMORY_SIZE];
-        private final ViewPropertyRef[] mNodesBg = new ViewPropertyRef[MEMORY_SIZE];
-
-        private boolean mDestroyed = false;
-        private final Consumer<ViewRef> mCaptureCallback = this::captureViewPropertiesBg;
-
-        WindowListener(View view, String name) {
-            mRoot = view;
-            this.name = name;
-        }
-
-        @Override
-        public void onDraw() {
-            Trace.beginSection("view_capture");
-            captureViewTree(mRoot, mViewRef);
-            ViewRef captured = mViewRef.next;
-            if (captured != null) {
-                captured.callback = mCaptureCallback;
-                captured.creationTime = SystemClock.uptimeMillis();
-                mExecutor.execute(captured);
-            }
-            mIsFirstFrame = false;
-            Trace.endSection();
-        }
-
-        /**
-         * Captures the View property on the background thread, and transfer all the ViewRef objects
-         * back to the pool
-         */
-        @WorkerThread
-        private void captureViewPropertiesBg(ViewRef viewRefStart) {
-            long time = viewRefStart.creationTime;
-            mFrameIndexBg++;
-            if (mFrameIndexBg >= MEMORY_SIZE) {
-                mFrameIndexBg = 0;
-            }
-            mFrameTimesBg[mFrameIndexBg] = time;
-
-            ViewPropertyRef recycle = mNodesBg[mFrameIndexBg];
-
-            ViewPropertyRef resultStart = null;
-            ViewPropertyRef resultEnd = null;
-
-            ViewRef viewRefEnd = viewRefStart;
-            while (viewRefEnd != null) {
-                ViewPropertyRef propertyRef = recycle;
-                if (propertyRef == null) {
-                    propertyRef = new ViewPropertyRef();
-                } else {
-                    recycle = recycle.next;
-                    propertyRef.next = null;
-                }
-
-                ViewPropertyRef copy = null;
-                if (viewRefEnd.childCount < 0) {
-                    copy = findInLastFrame(viewRefEnd.view.hashCode());
-                    viewRefEnd.childCount = (copy != null) ? copy.childCount : 0;
-                }
-                viewRefEnd.transferTo(propertyRef);
-
-                if (resultStart == null) {
-                    resultStart = propertyRef;
-                    resultEnd = resultStart;
-                } else {
-                    resultEnd.next = propertyRef;
-                    resultEnd = resultEnd.next;
-                }
-
-                if (copy != null) {
-                    int pending = copy.childCount;
-                    while (pending > 0) {
-                        copy = copy.next;
-                        pending = pending - 1 + copy.childCount;
-
-                        propertyRef = recycle;
-                        if (propertyRef == null) {
-                            propertyRef = new ViewPropertyRef();
-                        } else {
-                            recycle = recycle.next;
-                            propertyRef.next = null;
-                        }
-
-                        copy.transferTo(propertyRef);
-
-                        resultEnd.next = propertyRef;
-                        resultEnd = resultEnd.next;
-                    }
-                }
-
-                if (viewRefEnd.next == null) {
-                    // The compiler will complain about using a non-final variable from
-                    // an outer class in a lambda if we pass in viewRefEnd directly.
-                    final ViewRef finalViewRefEnd = viewRefEnd;
-                    MAIN_EXECUTOR.execute(() -> addToPool(viewRefStart, finalViewRefEnd));
-                    break;
-                }
-                viewRefEnd = viewRefEnd.next;
-            }
-            mNodesBg[mFrameIndexBg] = resultStart;
-        }
-
-        private ViewPropertyRef findInLastFrame(int hashCode) {
-            int lastFrameIndex = (mFrameIndexBg == 0) ? MEMORY_SIZE - 1 : mFrameIndexBg - 1;
-            ViewPropertyRef viewPropertyRef = mNodesBg[lastFrameIndex];
-            while (viewPropertyRef != null && viewPropertyRef.hashCode != hashCode) {
-                viewPropertyRef = viewPropertyRef.next;
-            }
-            return viewPropertyRef;
-        }
-
-        void attachToRoot() {
-            if (mRoot.isAttachedToWindow()) {
-                mRoot.getViewTreeObserver().addOnDrawListener(this);
-            } else {
-                mRoot.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
-                    @Override
-                    public void onViewAttachedToWindow(View v) {
-                        if (!mDestroyed) {
-                            mRoot.getViewTreeObserver().addOnDrawListener(WindowListener.this);
-                        }
-                        mRoot.removeOnAttachStateChangeListener(this);
-                    }
-
-                    @Override
-                    public void onViewDetachedFromWindow(View v) { }
-                });
-            }
-        }
-
-        void destroy() {
-            mRoot.getViewTreeObserver().removeOnDrawListener(this);
-            mDestroyed = true;
-        }
-
-        @WorkerThread
-        private ExportedData dumpToProto(ViewIdProvider idProvider) {
-            ExportedData.Builder dataBuilder = ExportedData.newBuilder();
-            ArrayList<Class> classList = new ArrayList<>();
-
-            int size = (mNodesBg[MEMORY_SIZE - 1] == null) ? mFrameIndexBg + 1 : MEMORY_SIZE;
-            for (int i = size - 1; i >= 0; i--) {
-                int index = (MEMORY_SIZE + mFrameIndexBg - i) % MEMORY_SIZE;
-                ViewNode.Builder nodeBuilder = ViewNode.newBuilder();
-                mNodesBg[index].toProto(idProvider, classList, nodeBuilder);
-                dataBuilder.addFrameData(FrameData.newBuilder()
-                        .setNode(nodeBuilder)
-                        .setTimestamp(mFrameTimesBg[index]));
-            }
-            return dataBuilder
-                    .addAllClassname(classList.stream().map(Class::getName).collect(toList()))
-                    .build();
-        }
-
-        private ViewRef captureViewTree(View view, ViewRef start) {
-            ViewRef ref;
-            if (mPool != null) {
-                ref = mPool;
-                mPool = mPool.next;
-                ref.next = null;
-            } else {
-                ref = new ViewRef();
-            }
-            ref.view = view;
-            start.next = ref;
-            if (view instanceof ViewGroup) {
-                ViewGroup parent = (ViewGroup) view;
-                // If a view has not changed since the last frame, we will copy
-                // its children from the last processed frame's data.
-                if ((view.mPrivateFlags & (PFLAG_INVALIDATED | PFLAG_DIRTY_MASK)) == 0
-                        && !mIsFirstFrame) {
-                    // A negative child count is the signal to copy this view from the last frame.
-                    ref.childCount = -parent.getChildCount();
-                    return ref;
-                }
-                ViewRef result = ref;
-                int childCount = ref.childCount = parent.getChildCount();
-                for (int i = 0; i < childCount; i++) {
-                    result = captureViewTree(parent.getChildAt(i), result);
-                }
-                return result;
-            } else {
-                ref.childCount = 0;
-                return ref;
-            }
-        }
-    }
-
-    private static class ViewPropertyRef {
-        // We store reference in memory to avoid generating and storing too many strings
-        public Class clazz;
-        public int hashCode;
-        public int childCount = 0;
-
-        public int id;
-        public int left, top, right, bottom;
-        public int scrollX, scrollY;
-
-        public float translateX, translateY;
-        public float scaleX, scaleY;
-        public float alpha;
-        public float elevation;
-
-        public int visibility;
-        public boolean willNotDraw;
-        public boolean clipChildren;
-
-        public ViewPropertyRef next;
-
-        public void transferTo(ViewPropertyRef out) {
-            out.clazz = this.clazz;
-            out.hashCode = this.hashCode;
-            out.childCount = this.childCount;
-            out.id = this.id;
-            out.left = this.left;
-            out.top = this.top;
-            out.right = this.right;
-            out.bottom = this.bottom;
-            out.scrollX = this.scrollX;
-            out.scrollY = this.scrollY;
-            out.scaleX = this.scaleX;
-            out.scaleY = this.scaleY;
-            out.translateX = this.translateX;
-            out.translateY = this.translateY;
-            out.alpha = this.alpha;
-            out.visibility = this.visibility;
-            out.willNotDraw = this.willNotDraw;
-            out.clipChildren = this.clipChildren;
-            out.elevation = this.elevation;
-        }
-
-        /**
-         * Converts the data to the proto representation and returns the next property ref
-         * at the end of the iteration.
-         * @return
-         */
-        public ViewPropertyRef toProto(ViewIdProvider idProvider, ArrayList<Class> classList,
-                ViewNode.Builder outBuilder) {
-            int classnameIndex = classList.indexOf(clazz);
-            if (classnameIndex < 0) {
-                classnameIndex = classList.size();
-                classList.add(clazz);
-            }
-            outBuilder
-                    .setClassnameIndex(classnameIndex)
-                    .setHashcode(hashCode)
-                    .setId(idProvider.getName(id))
-                    .setLeft(left)
-                    .setTop(top)
-                    .setWidth(right - left)
-                    .setHeight(bottom - top)
-                    .setTranslationX(translateX)
-                    .setTranslationY(translateY)
-                    .setScaleX(scaleX)
-                    .setScaleY(scaleY)
-                    .setAlpha(alpha)
-                    .setVisibility(visibility)
-                    .setWillNotDraw(willNotDraw)
-                    .setElevation(elevation)
-                    .setClipChildren(clipChildren);
-
-            ViewPropertyRef result = next;
-            for (int i = 0; (i < childCount) && (result != null); i++) {
-                ViewNode.Builder childBuilder = ViewNode.newBuilder();
-                result = result.toProto(idProvider, classList, childBuilder);
-                outBuilder.addChildren(childBuilder);
-            }
-            return result;
-        }
-    }
-
-    private static class ViewRef implements Runnable {
-        public View view;
-        public int childCount = 0;
-        public ViewRef next;
-
-        public Consumer<ViewRef> callback = null;
-        public long creationTime = 0;
-
-        public void transferTo(ViewPropertyRef out) {
-            out.childCount = this.childCount;
-
-            View view = this.view;
-            this.view = null;
-
-            out.clazz = view.getClass();
-            out.hashCode = view.hashCode();
-            out.id = view.getId();
-            out.left = view.getLeft();
-            out.top = view.getTop();
-            out.right = view.getRight();
-            out.bottom = view.getBottom();
-            out.scrollX = view.getScrollX();
-            out.scrollY = view.getScrollY();
-
-            out.translateX = view.getTranslationX();
-            out.translateY = view.getTranslationY();
-            out.scaleX = view.getScaleX();
-            out.scaleY = view.getScaleY();
-            out.alpha = view.getAlpha();
-            out.elevation = view.getElevation();
-
-            out.visibility = view.getVisibility();
-            out.willNotDraw = view.willNotDraw();
-        }
-
-        @Override
-        public void run() {
-            Consumer<ViewRef> oldCallback = callback;
-            callback = null;
-            if (oldCallback != null) {
-                oldCallback.accept(this);
-            }
-        }
-    }
-
-    private static final class ViewIdProvider {
-
-        private final SparseArray<String> mNames = new SparseArray<>();
-        private final Resources mRes;
-
-        ViewIdProvider(Resources res) {
-            mRes = res;
-        }
-
-        String getName(int id) {
-            String name = mNames.get(id);
-            if (name == null) {
-                if (id >= 0) {
-                    try {
-                        name = mRes.getResourceTypeName(id) + '/' + mRes.getResourceEntryName(id);
-                    } catch (Resources.NotFoundException e) {
-                        name = "id/" + "0x" + Integer.toHexString(id).toUpperCase();
-                    }
-                } else {
-                    name = "NO_ID";
-                }
-                mNames.put(id, name);
-            }
-            return name;
-        }
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 8385afe..5167bd7 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -286,31 +286,23 @@
 
     @Override
     public RunnableList launchTasks() {
-        showDesktopApps();
-        getRecentsView().onTaskLaunchedInLiveTileMode();
+        SystemUiProxy.INSTANCE.get(getContext()).showDesktopApps();
+        getRecentsView().startHome();
         return new RunnableList();
     }
 
     @Nullable
     @Override
     public RunnableList launchTaskAnimated() {
-        RunnableList endCallback = new RunnableList();
-        showDesktopApps();
-        RecentsView<?, ?> recentsView = getRecentsView();
-        recentsView.addSideTaskLaunchCallback(endCallback);
-        return endCallback;
+        return launchTasks();
     }
 
     @Override
     public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
-        showDesktopApps();
+        launchTasks();
         callback.accept(true);
     }
 
-    private void showDesktopApps() {
-        SystemUiProxy.INSTANCE.get(getContext()).showDesktopApps();
-    }
-
     @Override
     void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
         // Sets new thumbnails based on the incoming data and refreshes the rest.
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 514d5b9..a16ff8f 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -33,8 +33,8 @@
 import com.android.launcher3.R;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.launcher3.util.NavigationMode;
 import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
 import com.android.quickstep.util.LayoutUtils;
@@ -130,7 +130,6 @@
         mMultiValueAlpha.setUpdateVisibility(true);
 
         findViewById(R.id.action_screenshot).setOnClickListener(this);
-
         mSplitButton = findViewById(R.id.action_split);
         mSplitButton.setOnClickListener(this);
     }
@@ -177,7 +176,7 @@
             mHiddenFlags &= ~visibilityFlags;
         }
         boolean isHidden = mHiddenFlags != 0;
-        mMultiValueAlpha.getProperty(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1);
+        mMultiValueAlpha.get(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1);
     }
 
     /**
@@ -232,20 +231,20 @@
         updateSplitButtonEnabledState();
     }
 
-    public AlphaProperty getContentAlpha() {
-        return mMultiValueAlpha.getProperty(INDEX_CONTENT_ALPHA);
+    public MultiProperty getContentAlpha() {
+        return mMultiValueAlpha.get(INDEX_CONTENT_ALPHA);
     }
 
-    public AlphaProperty getVisibilityAlpha() {
-        return mMultiValueAlpha.getProperty(INDEX_VISIBILITY_ALPHA);
+    public MultiProperty getVisibilityAlpha() {
+        return mMultiValueAlpha.get(INDEX_VISIBILITY_ALPHA);
     }
 
-    public AlphaProperty getFullscreenAlpha() {
-        return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
+    public MultiProperty getFullscreenAlpha() {
+        return mMultiValueAlpha.get(INDEX_FULLSCREEN_ALPHA);
     }
 
-    public AlphaProperty getShareTargetAlpha() {
-        return mMultiValueAlpha.getProperty(INDEX_SHARE_TARGET_ALPHA);
+    public MultiProperty getShareTargetAlpha() {
+        return mMultiValueAlpha.get(INDEX_SHARE_TARGET_ALPHA);
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 72467e6..ce96b71 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -45,10 +45,10 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
-import static com.android.launcher3.statehandlers.DepthController.STATE_DEPTH;
 import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
@@ -147,7 +147,6 @@
 import com.android.launcher3.util.DynamicResource;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
-import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.ResourceBasedOverride.Overrides;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
@@ -1897,7 +1896,7 @@
 
     private void animateActionsViewAlpha(float alphaValue, long duration) {
         mActionsViewAlphaAnimator = ObjectAnimator.ofFloat(
-                mActionsView.getVisibilityAlpha(), MultiValueAlpha.VALUE, alphaValue);
+                mActionsView.getVisibilityAlpha(), MULTI_PROPERTY_VALUE, alphaValue);
         mActionsViewAlphaAnimatorFinalValue = alphaValue;
         mActionsViewAlphaAnimator.setDuration(duration);
         // Set autocancel to prevent race-conditiony setting of alpha from other animations
@@ -4554,8 +4553,8 @@
 
         DepthController depthController = getDepthController();
         if (depthController != null) {
-            ObjectAnimator depthAnimator = ObjectAnimator.ofFloat(depthController, STATE_DEPTH,
-                    BACKGROUND_APP.getDepth(mActivity));
+            ObjectAnimator depthAnimator = ObjectAnimator.ofFloat(depthController.stateDepth,
+                    MULTI_PROPERTY_VALUE, BACKGROUND_APP.getDepth(mActivity));
             anim.play(depthAnimator);
         }
         anim.play(ObjectAnimator.ofFloat(this, TASK_THUMBNAIL_SPLASH_ALPHA, 0f, 1f));
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 6eb77a4..0fdd469 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -79,6 +79,7 @@
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.util.ActivityOptionsWrapper;
 import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
@@ -1574,9 +1575,12 @@
         /** The current scale we apply to the thumbnail to adjust for new left/right insets. */
         public float mScale = 1;
 
+        private boolean mIsTaskbarTransient;
+
         public FullscreenDrawParams(Context context) {
             mCornerRadius = TaskCornerRadius.get(context);
             mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context);
+            mIsTaskbarTransient = DisplayController.isTransientTaskbar(context);
 
             mCurrentDrawnCornerRadius = mCornerRadius;
         }
@@ -1586,7 +1590,7 @@
          */
         public void setProgress(float fullscreenProgress, float parentScale, float taskViewScale,
                 int previewWidth, DeviceProfile dp, PreviewPositionHelper pph) {
-            RectF insets = getInsetsToDrawInFullscreen(pph, dp);
+            RectF insets = getInsetsToDrawInFullscreen(pph, dp, mIsTaskbarTransient);
 
             float currentInsetsLeft = insets.left * fullscreenProgress;
             float currentInsetsTop = insets.top * fullscreenProgress;
@@ -1609,7 +1613,11 @@
         /**
          * Insets to used for clipping the thumbnail (in case it is drawing outside its own space)
          */
-        private static RectF getInsetsToDrawInFullscreen(PreviewPositionHelper pph, DeviceProfile dp) {
+        private static RectF getInsetsToDrawInFullscreen(PreviewPositionHelper pph,
+                DeviceProfile dp, boolean isTaskbarTransient) {
+            if (isTaskbarTransient) {
+                return pph.getClippedInsets();
+            }
             return dp.isTaskbarPresent && !dp.isTaskbarPresentInApps
                     ? pph.getClippedInsets() : EMPTY_RECT_F;
         }
diff --git a/res/color-v31/transient_taskbar_background.xml b/res/color-v31/transient_taskbar_background.xml
new file mode 100644
index 0000000..bce947d
--- /dev/null
+++ b/res/color-v31/transient_taskbar_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+  <item android:color="@android:color/system_neutral1_500" android:lStar="95" />
+</selector>
+
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a9ba07d..0a28b6c 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -361,6 +361,13 @@
     <dimen name="min_hotseat_icon_space">18dp</dimen>
     <dimen name="min_hotseat_qsb_width">0dp</dimen>
     <dimen name="taskbar_icon_size">44dp</dimen>
+    <dimen name="transient_taskbar_icon_size">57dp</dimen>
+    <!-- Transient taskbar (placeholders to compile in Launcher3 without Quickstep) -->
+    <dimen name="transient_taskbar_size">0dp</dimen>
+    <dimen name="transient_taskbar_margin">0dp</dimen>
+    <dimen name="transient_taskbar_shadow_blur">0dp</dimen>
+    <dimen name="transient_taskbar_key_shadow_distance">0dp</dimen>
+    <dimen name="transient_taskbar_icon_spacing">10dp</dimen>
     <!-- Note that this applies to both sides of all icons, so visible space is double this. -->
     <dimen name="taskbar_icon_spacing">8dp</dimen>
     <dimen name="taskbar_nav_buttons_size">0dp</dimen>
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 1c26f04..edd809c 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -312,7 +312,9 @@
         }
 
         if (isTaskbarPresent) {
-            taskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_size);
+            taskbarSize = DisplayController.isTransientTaskbar(context)
+                    ? res.getDimensionPixelSize(R.dimen.transient_taskbar_size)
+                    : res.getDimensionPixelSize(R.dimen.taskbar_size);
             stashedTaskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
         }
 
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 6a262c3..a8d371e 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -1027,7 +1027,7 @@
                     R.styleable.ProfileDisplayOption_allAppsIconSize, iconSizes[INDEX_DEFAULT]);
             allAppsIconSizes[INDEX_LANDSCAPE] = a.getFloat(
                     R.styleable.ProfileDisplayOption_allAppsIconSizeLandscape,
-                    iconSizes[INDEX_DEFAULT]);
+                    allAppsIconSizes[INDEX_DEFAULT]);
             allAppsIconSizes[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat(
                     R.styleable.ProfileDisplayOption_allAppsIconSizeTwoPanelPortrait,
                     allAppsIconSizes[INDEX_DEFAULT]);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 7cf9296..7269d14 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -131,6 +131,7 @@
 import com.android.launcher3.allapps.AllAppsStore;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.allapps.BaseAllAppsContainerView;
+import com.android.launcher3.allapps.BaseSearchConfig;
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.anim.PropertyListBuilder;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -394,6 +395,7 @@
     private LauncherState mPrevLauncherState;
 
     private StringCache mStringCache;
+    private BaseSearchConfig mBaseSearchConfig;
 
     @Override
     @TargetApi(Build.VERSION_CODES.S)
@@ -544,6 +546,9 @@
             getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
         }
         setTitle(R.string.home_screen);
+
+        // TODO: move the SearchConfig to SearchState when new LauncherState is created.
+        mBaseSearchConfig = new BaseSearchConfig();
     }
 
     protected LauncherOverlayManager getDefaultOverlay() {
@@ -1591,12 +1596,8 @@
         return mOldConfig.orientation;
     }
 
-    /**
-     * Whether keyboard sync is enabled for transitions between Home and All Apps.
-     * TODO(b/251387263): move this method inside an All Apps specific config class.
-     */
-    public boolean isKeyboardSyncEnabled() {
-        return false;
+    public BaseSearchConfig getSearchConfig() {
+        return mBaseSearchConfig;
     }
 
     @Override
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 264c0a7..62e7ef3 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -35,6 +35,7 @@
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.ZOOM_OUT;
 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
+import static com.android.launcher3.config.FeatureFlags.HOME_GARDENING_WORKSPACE_BUTTONS;
 import static com.android.launcher3.config.FeatureFlags.SHOW_HOME_GARDENING;
 import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS;
 import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS;
@@ -171,6 +172,18 @@
             });
         }
 
+        if (HOME_GARDENING_WORKSPACE_BUTTONS.get()) {
+            propertySetter.setViewAlpha(
+                    mLauncher.getHotseat().getQsb(),
+                    state == SPRING_LOADED ? 0 : 1,
+                    workspaceFadeInterpolator);
+            propertySetter.addEndListener(success -> {
+                if (success) {
+                    mLauncher.getHotseat().getQsb().setClickable(state != SPRING_LOADED);
+                }
+            });
+        }
+
         // Update the accessibility flags for hotseat based on launcher state.
         hotseat.setImportantForAccessibility(
                 state.hasFlag(FLAG_HOTSEAT_INACCESSIBLE)
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 001b494..fa2c6e9 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.allapps;
 
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
 import static com.android.launcher3.LauncherState.NORMAL;
@@ -42,6 +43,7 @@
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.util.MultiPropertyFactory;
+import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.views.ScrimView;
 
@@ -74,6 +76,8 @@
                 }
             };
 
+    private static final float ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT = 0f;
+
     public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PULL_BACK_TRANSLATION =
             new FloatProperty<AllAppsTransitionController>("allAppsPullBackTranslation") {
 
@@ -82,8 +86,7 @@
                     if (controller.mIsTablet) {
                         return controller.mAppsView.getActiveRecyclerView().getTranslationY();
                     } else {
-                        return controller.getAppsViewPullbackTranslationY().get(
-                                controller.mAppsView);
+                        return controller.getAppsViewPullbackTranslationY().getValue();
                     }
                 }
 
@@ -91,13 +94,18 @@
                 public void setValue(AllAppsTransitionController controller, float translation) {
                     if (controller.mIsTablet) {
                         controller.mAppsView.getActiveRecyclerView().setTranslationY(translation);
+                        controller.getAppsViewPullbackTranslationY().setValue(
+                                ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT);
                     } else {
-                        controller.getAppsViewPullbackTranslationY().set(controller.mAppsView,
-                                translation);
+                        controller.getAppsViewPullbackTranslationY().setValue(translation);
+                        controller.mAppsView.getActiveRecyclerView().setTranslationY(
+                                ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT);
                     }
                 }
             };
 
+    private static final float ALL_APPS_PULL_BACK_ALPHA_DEFAULT = 1f;
+
     public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PULL_BACK_ALPHA =
             new FloatProperty<AllAppsTransitionController>("allAppsPullBackAlpha") {
 
@@ -114,8 +122,12 @@
                 public void setValue(AllAppsTransitionController controller, float alpha) {
                     if (controller.mIsTablet) {
                         controller.mAppsView.getActiveRecyclerView().setAlpha(alpha);
+                        controller.getAppsViewPullbackAlpha().setValue(
+                                ALL_APPS_PULL_BACK_ALPHA_DEFAULT);
                     } else {
                         controller.getAppsViewPullbackAlpha().setValue(alpha);
+                        controller.mAppsView.getActiveRecyclerView().setAlpha(
+                                ALL_APPS_PULL_BACK_ALPHA_DEFAULT);
                     }
                 }
             };
@@ -140,10 +152,8 @@
 
     private ScrimView mScrimView;
 
-    private final MultiPropertyFactory<View>
-            mAppsViewTranslationYPropertyFactory = new MultiPropertyFactory<>(
-            "appsViewTranslationY", View.TRANSLATION_Y, Float::sum);
     private MultiValueAlpha mAppsViewAlpha;
+    private MultiPropertyFactory<View> mAppsViewTranslationY;
 
     private boolean mIsTablet;
 
@@ -184,7 +194,7 @@
      */
     public void setProgress(float progress) {
         mProgress = progress;
-        getAppsViewProgressTranslationY().set(mAppsView, mProgress * mShiftRange);
+        getAppsViewProgressTranslationY().setValue(mProgress * mShiftRange);
         mLauncher.onAllAppsTransition(1 - progress);
     }
 
@@ -192,20 +202,20 @@
         return mProgress;
     }
 
-    private FloatProperty<View> getAppsViewProgressTranslationY() {
-        return mAppsViewTranslationYPropertyFactory.get(INDEX_APPS_VIEW_PROGRESS);
+    private MultiProperty getAppsViewProgressTranslationY() {
+        return mAppsViewTranslationY.get(INDEX_APPS_VIEW_PROGRESS);
     }
 
-    private FloatProperty<View> getAppsViewPullbackTranslationY() {
-        return mAppsViewTranslationYPropertyFactory.get(INDEX_APPS_VIEW_PULLBACK);
+    private MultiProperty getAppsViewPullbackTranslationY() {
+        return mAppsViewTranslationY.get(INDEX_APPS_VIEW_PULLBACK);
     }
 
-    private MultiValueAlpha.AlphaProperty getAppsViewProgressAlpha() {
-        return mAppsViewAlpha.getProperty(INDEX_APPS_VIEW_PROGRESS);
+    private MultiProperty getAppsViewProgressAlpha() {
+        return mAppsViewAlpha.get(INDEX_APPS_VIEW_PROGRESS);
     }
 
-    private MultiValueAlpha.AlphaProperty getAppsViewPullbackAlpha() {
-        return mAppsViewAlpha.getProperty(INDEX_APPS_VIEW_PULLBACK);
+    private MultiProperty getAppsViewPullbackAlpha() {
+        return mAppsViewAlpha.get(INDEX_APPS_VIEW_PULLBACK);
     }
 
     /**
@@ -228,14 +238,14 @@
             StateAnimationConfig config, PendingAnimation builder) {
         if (mLauncher.isInState(ALL_APPS) && !ALL_APPS.equals(toState)) {
             // For atomic animations, we close the keyboard immediately.
-            if (!config.userControlled && !mLauncher.isKeyboardSyncEnabled()) {
+            if (!config.userControlled && !mLauncher.getSearchConfig().isKeyboardSyncEnabled()) {
                 mLauncher.getAppsView().getSearchUiManager().getEditText().hideKeyboard();
             }
 
             builder.addEndListener(success -> {
                 // Reset pull back progress and alpha after switching states.
-                ALL_APPS_PULL_BACK_TRANSLATION.set(this, 0f);
-                ALL_APPS_PULL_BACK_ALPHA.set(this, 1f);
+                ALL_APPS_PULL_BACK_TRANSLATION.set(this, ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT);
+                ALL_APPS_PULL_BACK_ALPHA.set(this, ALL_APPS_PULL_BACK_ALPHA_DEFAULT);
 
                 // We only want to close the keyboard if the animation has completed successfully.
                 // The reason is that with keyboard sync, if the user swipes down from All Apps with
@@ -283,7 +293,7 @@
         boolean hasAllAppsContent = (visibleElements & ALL_APPS_CONTENT) != 0;
 
         Interpolator allAppsFade = config.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR);
-        setter.setFloat(getAppsViewProgressAlpha(), MultiValueAlpha.VALUE,
+        setter.setFloat(getAppsViewProgressAlpha(), MultiPropertyFactory.MULTI_PROPERTY_VALUE,
                 hasAllAppsContent ? 1 : 0, allAppsFade);
 
         boolean shouldProtectHeader =
@@ -302,8 +312,11 @@
         mScrimView = scrimView;
         mAppsView = appsView;
         mAppsView.setScrimView(scrimView);
+
         mAppsViewAlpha = new MultiValueAlpha(mAppsView, APPS_VIEW_INDEX_COUNT);
         mAppsViewAlpha.setUpdateVisibility(true);
+        mAppsViewTranslationY = new MultiPropertyFactory<>(
+                mAppsView, VIEW_TRANSLATE_Y, APPS_VIEW_INDEX_COUNT, Float::sum);
     }
 
     /**
diff --git a/src/com/android/launcher3/allapps/BaseSearchConfig.java b/src/com/android/launcher3/allapps/BaseSearchConfig.java
new file mode 100644
index 0000000..9f47e8d
--- /dev/null
+++ b/src/com/android/launcher3/allapps/BaseSearchConfig.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.allapps;
+
+/** Base config values for search. */
+public class BaseSearchConfig {
+    public BaseSearchConfig() {}
+
+    /**
+     * Returns whether to enable the synchronized keyboard transition between Home and All Apps.
+     */
+    public boolean isKeyboardSyncEnabled() {
+        return false;
+    }
+}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 75c28f9..037a77e 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -156,6 +156,11 @@
             "ENABLE_SMARTSPACE_DISMISS", true,
             "Adds a menu option to dismiss the current Enhanced Smartspace card.");
 
+    public static final BooleanFlag ENABLE_OVERLAY_CONNECTION_OPTIM = getDebugFlag(
+            "ENABLE_OVERLAY_CONNECTION_OPTIM",
+            false,
+            "Enable optimizing overlay service connection");
+
     /**
      * Enables region sampling for text color: Needs system health assessment before turning on
      */
@@ -285,17 +290,21 @@
     public static final BooleanFlag ENABLE_WIDGET_PICKER_DEPTH = new DeviceFlag(
             "ENABLE_WIDGET_PICKER_DEPTH", true, "Enable changing depth in widget picker.");
 
-    public static final BooleanFlag SHOW_DELIGHTFUL_PAGINATION = new DeviceFlag(
+    public static final BooleanFlag SHOW_DELIGHTFUL_PAGINATION = getDebugFlag(
             "SHOW_DELIGHTFUL_PAGINATION", false,
             "Enable showing the new 'delightful pagination' which is a brand"
                     + " new animation for folder pagination and workspace pagination");
     public static final BooleanFlag POPUP_MATERIAL_U = new DeviceFlag(
             "POPUP_MATERIAL_U", false, "Switch popup UX to use material U");
 
-    public static final BooleanFlag SHOW_HOME_GARDENING = new DeviceFlag(
+    public static final BooleanFlag SHOW_HOME_GARDENING = getDebugFlag(
             "SHOW_HOME_GARDENING", false,
             "Show the new home gardening mode");
 
+    public static final BooleanFlag HOME_GARDENING_WORKSPACE_BUTTONS = getDebugFlag(
+            "HOME_GARDENING_WORKSPACE_BUTTONS", false,
+            "Change workspace edit buttons to reflect home gardening");
+
     public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(
             "ENABLE_TRANSIENT_TASKBAR", false, "Enables transient taskbar.");
 
@@ -303,6 +312,9 @@
             "SECONDARY_DRAG_N_DROP_TO_PIN", false,
             "Enable dragging and dropping to pin apps within secondary display");
 
+    public static final BooleanFlag SHOW_DOT_PAGINATION = getDebugFlag(
+            "SHOW_DOT_PAGINATION", false, "Enable showing dot pagination in workspace");
+
     public static void initialize(Context context) {
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 0bcb97a..efd511d 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -113,6 +113,7 @@
     public void setFolder(Folder folder) {
         mFolder = folder;
         mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
+        mPageIndicator.setShouldAutoHide(false);
         initParentViews(folder);
     }
 
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 98ce951..3770de8 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -32,13 +32,18 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
 import android.util.AttributeSet;
-import android.util.Property;
+import android.util.FloatProperty;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewOutlineProvider;
 import android.view.animation.Interpolator;
 import android.view.animation.OvershootInterpolator;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
@@ -54,6 +59,8 @@
     private static final float SHIFT_PER_ANIMATION = 0.5f;
     private static final float SHIFT_THRESHOLD = 0.1f;
     private static final long ANIMATION_DURATION = 150;
+    private static final int PAGINATION_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
+    private static final int ALPHA_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration();
 
     private static final int ENTER_ANIMATION_START_DELAY = 300;
     private static final int ENTER_ANIMATION_STAGGERED_DELAY = 150;
@@ -63,6 +70,9 @@
     private static final int DOT_ALPHA = 128;
     private static final int DOT_GAP_FACTOR = 3;
     private static final float DOT_GAP_FACTOR_FLOAT = 3.8f;
+    private static final int VISIBLE_ALPHA = 1;
+    private static final int INVISIBLE_ALPHA = 0;
+    private Paint mPaginationPaint;
 
     // This value approximately overshoots to 1.5 times the original size.
     private static final float ENTER_ANIMATION_OVERSHOOT_TENSION = 4.9f;
@@ -71,22 +81,36 @@
 
     private static final RectF sTempRect = new RectF();
 
-    private static final Property<PageIndicatorDots, Float> CURRENT_POSITION
-            = new Property<PageIndicatorDots, Float>(float.class, "current_position") {
-        @Override
-        public Float get(PageIndicatorDots obj) {
-            return obj.mCurrentPosition;
-        }
+    private static final FloatProperty<PageIndicatorDots> CURRENT_POSITION =
+            new FloatProperty<PageIndicatorDots>("current_position") {
+                @Override
+                public Float get(PageIndicatorDots obj) {
+                    return obj.mCurrentPosition;
+                }
 
-        @Override
-        public void set(PageIndicatorDots obj, Float pos) {
-            obj.mCurrentPosition = pos;
-            obj.invalidate();
-            obj.invalidateOutline();
-        }
-    };
+                @Override
+                public void setValue(PageIndicatorDots obj, float pos) {
+                    obj.mCurrentPosition = pos;
+                    obj.invalidate();
+                    obj.invalidateOutline();
+                }
+            };
 
-    private final Paint mPaginationPaint;
+    private static final FloatProperty<PageIndicatorDots> PAGINATION_ALPHA =
+            new FloatProperty<PageIndicatorDots>("pagination_alpha") {
+                @Override
+                public Float get(PageIndicatorDots obj) {
+                    return obj.getAlpha();
+                }
+
+                @Override
+                public void setValue(PageIndicatorDots obj, float alpha) {
+                    obj.setAlpha(alpha);
+                    obj.invalidate();
+                }
+            };
+
+    private final Handler mDelayedPaginationFadeHandler = new Handler(Looper.getMainLooper());
     private final Drawable mPageIndicatorDrawable;
     private final float mDotRadius;
     private final float mCircleGap;
@@ -98,6 +122,8 @@
     private int mActivePage;
     private int mCurrentScroll;
     private int mTotalScroll;
+    private boolean mShouldAutoHide = true;
+    private int mToAlpha;
 
     /**
      * The current position of the active dot including the animation progress.
@@ -111,9 +137,12 @@
     private float mCurrentPosition;
     private float mFinalPosition;
     private ObjectAnimator mAnimator;
+    private @Nullable ObjectAnimator mAlphaAnimator;
 
     private float[] mEntryAnimationRadiusFactors;
 
+    private Runnable mHidePaginationRunnable = () -> animatePaginationToAlpha(INVISIBLE_ALPHA);
+
     public PageIndicatorDots(Context context) {
         this(context, null);
     }
@@ -153,6 +182,8 @@
 
     @Override
     public void setScroll(int currentScroll, int totalScroll) {
+        animatePaginationToAlpha(VISIBLE_ALPHA);
+
         if (mNumPages <= 1) {
             mCurrentScroll = 0;
             return;
@@ -166,6 +197,11 @@
             mCurrentScroll = currentScroll;
             mTotalScroll = totalScroll;
             invalidate();
+
+            if (mShouldAutoHide
+                    && (getScrollPerPage() == 0 || mCurrentScroll % getScrollPerPage() == 0)) {
+                hideAfterDelay();
+            }
             return;
         }
 
@@ -187,6 +223,64 @@
         }
     }
 
+    @Override
+    public void setShouldAutoHide(boolean shouldAutoHide) {
+        mShouldAutoHide = shouldAutoHide;
+        if (shouldAutoHide && this.getAlpha() > INVISIBLE_ALPHA) {
+            hideAfterDelay();
+        } else if (!shouldAutoHide) {
+            mDelayedPaginationFadeHandler.removeCallbacksAndMessages(null);
+        }
+    }
+
+    private void hideAfterDelay() {
+        mDelayedPaginationFadeHandler.removeCallbacksAndMessages(null);
+        mDelayedPaginationFadeHandler.postDelayed(mHidePaginationRunnable, PAGINATION_FADE_DELAY);
+    }
+
+    private void animatePaginationToAlpha(int alpha) {
+        if (alpha == mToAlpha) {
+            // Ignore the new animation if it is going to the same alpha as the current animation.
+            return;
+        }
+        mToAlpha = alpha;
+
+        if (mAlphaAnimator != null) {
+            mAlphaAnimator.cancel();
+        }
+        mAlphaAnimator = ObjectAnimator.ofFloat(this, PAGINATION_ALPHA,
+                alpha);
+        mAlphaAnimator.setDuration(ALPHA_ANIMATE_DURATION);
+        mAlphaAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mAlphaAnimator = null;
+            }
+        });
+        mAlphaAnimator.start();
+
+    }
+
+    /**
+     * Pauses all currently running animations.
+     */
+    @Override
+    public void pauseAnimations() {
+        if (mAlphaAnimator != null) {
+            mAlphaAnimator.pause();
+        }
+    }
+
+    /**
+     * Force-ends all currently running or paused animations.
+     */
+    @Override
+    public void skipAnimationsToEnd() {
+        if (mAlphaAnimator != null) {
+            mAlphaAnimator.end();
+        }
+    }
+
     private void animateToPosition(float position) {
         mFinalPosition = position;
         if (Math.abs(mCurrentPosition - mFinalPosition) < SHIFT_THRESHOLD) {
@@ -282,6 +376,10 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
+        if ((mShouldAutoHide && mTotalScroll == 0) || mNumPages < 2) {
+            return;
+        }
+
         // Draw all page indicators;
         float circleGap = mCircleGap;
         float startX = (getWidth() - (mNumPages * circleGap) + mDotRadius) / 2;
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index e57c88d..f9f7ac0 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -20,6 +20,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
 import static com.android.launcher3.Utilities.dpiFromPx;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_TRANSIENT_TASKBAR;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter;
 import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
@@ -123,6 +124,14 @@
         return INSTANCE.get(context).getInfo().navigationMode;
     }
 
+    /**
+     * Returns whether taskbar is transient.
+     */
+    public static boolean isTransientTaskbar(Context context) {
+        return ENABLE_TRANSIENT_TASKBAR.get()
+                && getNavigationMode(context) == NavigationMode.NO_BUTTON;
+    }
+
     @Override
     public void close() {
         mDestroyed = true;
diff --git a/src/com/android/launcher3/util/MultiPropertyFactory.java b/src/com/android/launcher3/util/MultiPropertyFactory.java
index 43daf08..f34c4c2 100644
--- a/src/com/android/launcher3/util/MultiPropertyFactory.java
+++ b/src/com/android/launcher3/util/MultiPropertyFactory.java
@@ -16,10 +16,13 @@
 
 package com.android.launcher3.util;
 
-import android.util.ArrayMap;
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
 import android.util.FloatProperty;
 import android.util.Log;
-import android.util.Property;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
 
 /**
  * Allows to combine multiple values set by several sources.
@@ -35,15 +38,30 @@
  */
 public class MultiPropertyFactory<T> {
 
+    public static final FloatProperty<MultiPropertyFactory<?>.MultiProperty> MULTI_PROPERTY_VALUE =
+            new FloatProperty<MultiPropertyFactory<?>.MultiProperty>("value") {
+
+                @Override
+                public Float get(MultiPropertyFactory<?>.MultiProperty property) {
+                    return property.mValue;
+                }
+
+                @Override
+                public void setValue(MultiPropertyFactory<?>.MultiProperty property, float value) {
+                    property.setValue(value);
+                }
+            };
+
     private static final boolean DEBUG = false;
     private static final String TAG = "MultiPropertyFactory";
-    private final String mName;
-    private final ArrayMap<Integer, MultiProperty> mProperties = new ArrayMap<>();
+    private final MultiPropertyFactory<?>.MultiProperty[] mProperties;
 
     // This is an optimization for cases when set is called repeatedly with the same setterIndex.
     private float mAggregationOfOthers = 0f;
-    private Integer mLastIndexSet = -1;
-    private final Property<T, Float> mProperty;
+    private int mLastIndexSet = -1;
+
+    protected final T mTarget;
+    private final FloatProperty<T> mProperty;
     private final FloatBiFunction mAggregator;
 
     /**
@@ -56,59 +74,99 @@
         float apply(float a, float b);
     }
 
-    public MultiPropertyFactory(String name, Property<T, Float> property,
+    public MultiPropertyFactory(T target, FloatProperty<T> property, int size,
             FloatBiFunction aggregator) {
-        mName = name;
+        this(target, property, size, aggregator, 0);
+    }
+
+    public MultiPropertyFactory(T target, FloatProperty<T> property, int size,
+            FloatBiFunction aggregator, float defaultPropertyValue) {
+        mTarget = target;
         mProperty = property;
         mAggregator = aggregator;
+
+        mProperties = new MultiPropertyFactory<?>.MultiProperty[size];
+        for (int i = 0; i < size; i++) {
+            mProperties[i] = new MultiProperty(i, defaultPropertyValue);
+        }
     }
 
     /** Returns the [MultiFloatProperty] associated with [inx], creating it if not present. */
-    public MultiProperty get(Integer index) {
-        return mProperties.computeIfAbsent(index,
-                (k) -> new MultiProperty(index, mName + "_" + index));
+    public MultiProperty get(int index) {
+        return (MultiProperty) mProperties[index];
+    }
+
+    @Override
+    public String toString() {
+        return Arrays.deepToString(mProperties);
+    }
+
+    /**
+     * Dumps the alpha channel values to the given PrintWriter
+     *
+     * @param prefix String to be used before every line
+     * @param pw PrintWriter where the logs should be dumped
+     * @param label String used to help identify this object
+     * @param alphaIndexLabels Strings that represent each alpha channel, these should be entered
+     *                         in the order of the indexes they represent, starting from 0.
+     */
+    public void dump(String prefix, PrintWriter pw, String label, String... alphaIndexLabels) {
+        pw.println(prefix + label);
+
+        String innerPrefix = prefix + '\t';
+        for (int i = 0; i < alphaIndexLabels.length; i++) {
+            if (i >= mProperties.length) {
+                pw.println(innerPrefix + alphaIndexLabels[i] + " given for alpha index " + i
+                        + " however there are only " + mProperties.length + " alpha channels.");
+                continue;
+            }
+            pw.println(innerPrefix + alphaIndexLabels[i] + "=" + get(i).getValue());
+        }
     }
 
     /**
      * Each [setValue] will be aggregated with the other properties values created by the
      * corresponding factory.
      */
-    class MultiProperty extends FloatProperty<T> {
-        private final int mInx;
-        private float mValue = 0f;
+    public class MultiProperty {
 
-        MultiProperty(int inx, String name) {
-            super(name);
+        private final int mInx;
+        private final float mDefaultValue;
+        private float mValue;
+
+        MultiProperty(int inx, float defaultValue) {
             mInx = inx;
+            mDefaultValue = defaultValue;
+            mValue = defaultValue;
         }
 
-        @Override
-        public void setValue(T obj, float newValue) {
+        public void setValue(float newValue) {
             if (mLastIndexSet != mInx) {
-                mAggregationOfOthers = 0f;
-                mProperties.forEach((key, property) -> {
-                    if (key != mInx) {
+                mAggregationOfOthers = mDefaultValue;
+                for (MultiPropertyFactory<?>.MultiProperty other : mProperties) {
+                    if (other.mInx != mInx) {
                         mAggregationOfOthers =
-                                mAggregator.apply(mAggregationOfOthers, property.mValue);
+                                mAggregator.apply(mAggregationOfOthers, other.mValue);
                     }
-                });
+                }
+
                 mLastIndexSet = mInx;
             }
             float lastAggregatedValue = mAggregator.apply(mAggregationOfOthers, newValue);
             mValue = newValue;
-            apply(obj, lastAggregatedValue);
+            apply(lastAggregatedValue);
 
             if (DEBUG) {
-                Log.d(TAG, "name=" + mName
-                        + " newValue=" + newValue + " mInx=" + mInx
-                        + " aggregated=" + lastAggregatedValue + " others= " + mProperties);
+                Log.d(TAG, "name=" + mProperty.getName()
+                        + " target=" + mTarget.getClass()
+                        + " newValue=" + newValue
+                        + " mInx=" + mInx
+                        + " aggregated=" + lastAggregatedValue
+                        + " others= " + Arrays.deepToString(mProperties));
             }
         }
 
-        @Override
-        public Float get(T object) {
-            // Callers of MultiProperty should only care about the sub-property that it sets. If
-            // the overall value is needed, mProperty.get should be called directly.
+        public float getValue() {
             return mValue;
         }
 
@@ -116,9 +174,19 @@
         public String toString() {
             return String.valueOf(mValue);
         }
+
+        /**
+         * Creates and returns an Animator from the current value to the given value. Future
+         * animator on the same target automatically cancels the previous one.
+         */
+        public Animator animateToValue(float value) {
+            ObjectAnimator animator = ObjectAnimator.ofFloat(this, MULTI_PROPERTY_VALUE, value);
+            animator.setAutoCancel(true);
+            return animator;
+        }
     }
 
-    protected void apply(T object, float value) {
-        mProperty.set(object, value);
+    protected void apply(float value) {
+        mProperty.set(mTarget, value);
     }
 }
diff --git a/src/com/android/launcher3/util/MultiValueAlpha.java b/src/com/android/launcher3/util/MultiValueAlpha.java
index 4b46a0a..ac016a8 100644
--- a/src/com/android/launcher3/util/MultiValueAlpha.java
+++ b/src/com/android/launcher3/util/MultiValueAlpha.java
@@ -16,62 +16,24 @@
 
 package com.android.launcher3.util;
 
-import android.animation.Animator;
-import android.animation.ObjectAnimator;
-import android.util.FloatProperty;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
+
 import android.view.View;
 
 import com.android.launcher3.anim.AlphaUpdateListener;
 
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.function.Consumer;
-
 /**
  * Utility class to handle separating a single value as a factor of multiple values
  */
-public class MultiValueAlpha {
+public class MultiValueAlpha extends MultiPropertyFactory<View> {
 
-    public static final FloatProperty<AlphaProperty> VALUE =
-            new FloatProperty<AlphaProperty>("value") {
+    private static final FloatBiFunction ALPHA_AGGREGATOR = (a, b) -> a * b;
 
-                @Override
-                public Float get(AlphaProperty alphaProperty) {
-                    return alphaProperty.mValue;
-                }
-
-                @Override
-                public void setValue(AlphaProperty object, float value) {
-                    object.setValue(value);
-                }
-            };
-
-    private final View mView;
-    private final AlphaProperty[] mMyProperties;
-
-    private int mValidMask;
     // Whether we should change from INVISIBLE to VISIBLE and vice versa at low alpha values.
     private boolean mUpdateVisibility;
 
     public MultiValueAlpha(View view, int size) {
-        mView = view;
-        mMyProperties = new AlphaProperty[size];
-
-        mValidMask = 0;
-        for (int i = 0; i < size; i++) {
-            int myMask = 1 << i;
-            mValidMask |= myMask;
-            mMyProperties[i] = new AlphaProperty(myMask);
-        }
-    }
-
-    @Override
-    public String toString() {
-        return Arrays.toString(mMyProperties);
-    }
-
-    public AlphaProperty getProperty(int index) {
-        return mMyProperties[index];
+        super(view, VIEW_ALPHA, size, ALPHA_AGGREGATOR, 1f);
     }
 
     /** Sets whether we should update between INVISIBLE and VISIBLE based on alpha. */
@@ -79,97 +41,11 @@
         mUpdateVisibility = updateVisibility;
     }
 
-    /**
-     * Dumps the alpha channel values to the given PrintWriter
-     *
-     * @param prefix String to be used before every line
-     * @param pw PrintWriter where the logs should be dumped
-     * @param label String used to help identify this object
-     * @param alphaIndexLabels Strings that represent each alpha channel, these should be entered
-     *                         in the order of the indexes they represent, starting from 0.
-     */
-    public void dump(String prefix, PrintWriter pw, String label, String... alphaIndexLabels) {
-        pw.println(prefix + label);
-
-        String innerPrefix = prefix + '\t';
-        for (int i = 0; i < alphaIndexLabels.length; i++) {
-            if (i >= mMyProperties.length) {
-                pw.println(innerPrefix + alphaIndexLabels[i] + " given for alpha index " + i
-                        + " however there are only " + mMyProperties.length + " alpha channels.");
-                continue;
-            }
-            pw.println(innerPrefix + alphaIndexLabels[i] + "=" + getProperty(i).getValue());
-        }
-    }
-
-    public class AlphaProperty {
-
-        private final int mMyMask;
-
-        private float mValue = 1;
-        // Factor of all other alpha channels, only valid if mMyMask is present in mValidMask.
-        private float mOthers = 1;
-
-        private Consumer<Float> mConsumer;
-
-        AlphaProperty(int myMask) {
-            mMyMask = myMask;
-        }
-
-        public void setValue(float value) {
-            if (mValue == value) {
-                return;
-            }
-
-            if ((mValidMask & mMyMask) == 0) {
-                // Our cache value is not correct, recompute it.
-                mOthers = 1;
-                for (AlphaProperty prop : mMyProperties) {
-                    if (prop != this) {
-                        mOthers *= prop.mValue;
-                    }
-                }
-            }
-
-            // Since we have changed our value, all other caches except our own need to be
-            // recomputed. Change mValidMask to indicate the new valid caches (only our own).
-            mValidMask = mMyMask;
-            mValue = value;
-
-            final float alpha = mOthers * mValue;
-            mView.setAlpha(alpha);
-            if (mUpdateVisibility) {
-                AlphaUpdateListener.updateVisibility(mView);
-            }
-            if (mConsumer != null) {
-                mConsumer.accept(mValue);
-            }
-        }
-
-        public float getValue() {
-            return mValue;
-        }
-
-        public void setConsumer(Consumer<Float> consumer) {
-            mConsumer = consumer;
-            if (mConsumer != null) {
-                mConsumer.accept(mValue);
-            }
-        }
-
-        @Override
-        public String toString() {
-            return Float.toString(mValue);
-        }
-
-        /**
-         * Creates and returns an Animator from the current value to the given value. Future
-         * animator on the same target automatically cancels the previous one.
-         */
-        public Animator animateToValue(float value) {
-            ObjectAnimator animator = ObjectAnimator.ofFloat(this, VALUE, value);
-            animator.setAutoCancel(true);
-            return animator;
+    @Override
+    protected void apply(float value) {
+        super.apply(value);
+        if (mUpdateVisibility) {
+            AlphaUpdateListener.updateVisibility(mTarget);
         }
     }
 }
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 1e154a2..8ff6888 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -22,7 +22,6 @@
 
 import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 
-import android.app.WallpaperManager;
 import android.content.Context;
 import android.graphics.Insets;
 import android.graphics.Rect;
@@ -41,8 +40,8 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.launcher3.util.TouchController;
 
 import java.io.PrintWriter;
@@ -108,7 +107,6 @@
 
     protected final T mActivity;
     private final MultiValueAlpha mMultiValueAlpha;
-    private final WallpaperManager mWallpaperManager;
 
     // All the touch controllers for the view
     protected TouchController[] mControllers;
@@ -121,9 +119,8 @@
 
     public BaseDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) {
         super(context, attrs);
-        mActivity = (T) ActivityContext.lookupContext(context);
+        mActivity = ActivityContext.lookupContext(context);
         mMultiValueAlpha = new MultiValueAlpha(this, alphaChannelCount);
-        mWallpaperManager = context.getSystemService(WallpaperManager.class);
     }
 
     /**
@@ -273,12 +270,6 @@
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
-        if (ev.getActionIndex() > 0) {
-            // This means there is multiple touch inputs, ignore it, we could also cancel the
-            // previous touch but the user might cancel the drag by accident.
-            return true;
-        }
-
         switch (ev.getAction()) {
             case ACTION_DOWN: {
                 if ((mTouchDispatchState & TOUCH_DISPATCHING_TO_VIEW_IN_PROGRESS) != 0) {
@@ -508,8 +499,8 @@
         return new LayoutParams(p);
     }
 
-    public AlphaProperty getAlphaProperty(int index) {
-        return mMultiValueAlpha.getProperty(index);
+    public MultiProperty getAlphaProperty(int index) {
+        return mMultiValueAlpha.get(index);
     }
 
     public void dump(String prefix, PrintWriter writer) {
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index fc1e880..bc3889f 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -92,10 +92,6 @@
 
     // The following member variables are only used during drag-n-drop.
     private boolean mIsInDragMode = false;
-    /** The drag content width which is only set when the drag content scale is not 1f. */
-    private int mDragContentWidth = 0;
-    /** The drag content height which is only set when the drag content scale is not 1f. */
-    private int mDragContentHeight = 0;
 
     private boolean mTrackingWidgetUpdate = false;
 
@@ -314,27 +310,9 @@
         }
     }
 
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        if (mIsInDragMode && mDragContentWidth > 0 && mDragContentHeight > 0
-                && getChildCount() == 1) {
-            measureChild(getChildAt(0), MeasureSpec.getSize(mDragContentWidth),
-                    MeasureSpec.getSize(mDragContentHeight));
-        }
-    }
-
     /** Starts the drag mode. */
     public void startDrag() {
         mIsInDragMode = true;
-        // In the case of dragging a scaled preview from widgets picker, we should reuse the
-        // previously measured dimension from WidgetCell#measureAndComputeWidgetPreviewScale, which
-        // measures the dimension of a widget preview without its parent's bound before scaling
-        // down.
-        if ((getScaleX() != 1f || getScaleY() != 1f) && getChildCount() == 1) {
-            mDragContentWidth = getChildAt(0).getMeasuredWidth();
-            mDragContentHeight = getChildAt(0).getMeasuredHeight();
-        }
     }
 
     /** Handles a drag event occurred on a workspace page corresponding to the {@code screenId}. */
@@ -347,8 +325,6 @@
     /** Ends the drag mode. */
     public void endDrag() {
         mIsInDragMode = false;
-        mDragContentWidth = 0;
-        mDragContentHeight = 0;
         requestLayout();
     }
 
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 2796721..ce47d70 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -284,6 +284,40 @@
         ensurePreviewWithCallback(callback, cachedPreview);
     }
 
+    private static class ScaledAppWidgetHostView extends LauncherAppWidgetHostView {
+        private boolean mKeepOrigForDragging = true;
+
+        ScaledAppWidgetHostView(Context context) {
+            super(context);
+        }
+
+        /**
+         * Set if the view will keep its original scale when dragged
+         * @param isKeepOrig True if keep original scale when dragged, false otherwise
+         */
+        public void setKeepOrigForDragging(boolean isKeepOrig) {
+            mKeepOrigForDragging = isKeepOrig;
+        }
+
+        /**
+         * @return True if the view is set to preserve original scale when dragged, false otherwise
+         */
+        public boolean isKeepOrigForDragging() {
+            return mKeepOrigForDragging;
+        }
+
+        @Override
+        public void startDrag() {
+            super.startDrag();
+            if (!isKeepOrigForDragging()) {
+                // restore to original scale when being dragged, if set to do so
+                setScaleToFit(1.0f);
+            }
+            // When the drag start, translations need to be set to zero to center the view
+            setTranslationForCentering(0f, 0f);
+        }
+    }
+
     private void applyPreviewOnAppWidgetHostView(WidgetItem item) {
         if (mRemoteViewsPreview != null) {
             mAppWidgetHostViewPreview = createAppWidgetHostView(getContext());
@@ -299,7 +333,7 @@
         // a preview during drag & drop. And thus, we should use LauncherAppWidgetHostView, which
         // supports applying local color extraction during drag & drop.
         mAppWidgetHostViewPreview = isLauncherContext(context)
-                ? new LauncherAppWidgetHostView(context)
+                ? new ScaledAppWidgetHostView(context)
                 : createAppWidgetHostView(context);
         LauncherAppWidgetProviderInfo launcherAppWidgetProviderInfo =
                 LauncherAppWidgetProviderInfo.fromProviderInfo(context, item.widgetInfo.clone());
@@ -398,23 +432,41 @@
             int containerWidth = (int) (mTargetPreviewWidth * mPreviewContainerScale);
             int containerHeight = (int) (mTargetPreviewHeight * mPreviewContainerScale);
             setContainerSize(containerWidth, containerHeight);
+            boolean shouldMeasureAndScale = false;
             if (mAppWidgetHostViewPreview.getChildCount() == 1) {
                 View widgetContent = mAppWidgetHostViewPreview.getChildAt(0);
                 ViewGroup.LayoutParams layoutParams = widgetContent.getLayoutParams();
                 // We only scale preview if both the width & height of the outermost view group are
                 // not set to MATCH_PARENT.
-                boolean shouldScale =
+                shouldMeasureAndScale =
                         layoutParams.width != MATCH_PARENT && layoutParams.height != MATCH_PARENT;
-                if (shouldScale) {
+                if (shouldMeasureAndScale) {
                     setNoClip(mWidgetImageContainer);
                     setNoClip(mAppWidgetHostViewPreview);
                     mAppWidgetHostViewScale = measureAndComputeWidgetPreviewScale();
-                    mAppWidgetHostViewPreview.setScaleToFit(mAppWidgetHostViewScale);
                 }
             }
+
             FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
-                    containerWidth, containerHeight, Gravity.FILL);
+                    mTargetPreviewWidth, mTargetPreviewHeight, Gravity.FILL);
             mAppWidgetHostViewPreview.setLayoutParams(params);
+
+            if (!shouldMeasureAndScale
+                    && mAppWidgetHostViewPreview instanceof ScaledAppWidgetHostView) {
+                // If the view is not measured & scaled, at least one side will match the grid size,
+                // so it should be safe to restore the original scale once it is dragged.
+                ScaledAppWidgetHostView tempView =
+                        (ScaledAppWidgetHostView) mAppWidgetHostViewPreview;
+                tempView.setKeepOrigForDragging(false);
+                tempView.setScaleToFit(mPreviewContainerScale);
+            } else if (!shouldMeasureAndScale) {
+                mAppWidgetHostViewPreview.setScaleToFit(mPreviewContainerScale);
+            } else {
+                mAppWidgetHostViewPreview.setScaleToFit(mAppWidgetHostViewScale);
+            }
+            mAppWidgetHostViewPreview.setTranslationForCentering(
+                    -(params.width - (params.width * mPreviewContainerScale)) / 2.0f,
+                    -(params.height - (params.height * mPreviewContainerScale)) / 2.0f);
             mWidgetImageContainer.addView(mAppWidgetHostViewPreview, /* index= */ 0);
             mWidgetImage.setVisibility(View.GONE);
             applyPreview(null);
diff --git a/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt b/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
index a4f189c..bf3a092 100644
--- a/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
+++ b/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
@@ -39,21 +39,21 @@
         }
     }
 
-    private val factory = MultiPropertyFactory("depth_property", receiveProperty) {
+    private val factory = MultiPropertyFactory(null, receiveProperty, 3) {
         x: Float, y: Float -> x + y
     }
 
-    private val p1 = factory.get(1)
-    private val p2 = factory.get(2)
-    private val p3 = factory.get(3)
+    private val p1 = factory.get(0)
+    private val p2 = factory.get(1)
+    private val p3 = factory.get(2)
 
     @Test
     fun set_sameIndexes_allApplied() {
         val v1 = 50f
         val v2 = 100f
-        p1.set(null, v1)
-        p1.set(null, v1)
-        p1.set(null, v2)
+        p1.value = v1
+        p1.value = v1
+        p1.value = v2
 
         assertThat(received).containsExactly(v1, v1, v2)
     }
@@ -63,9 +63,9 @@
         val v1 = 50f
         val v2 = 100f
         val v3 = 150f
-        p1.set(null, v1)
-        p2.set(null, v2)
-        p3.set(null, v3)
+        p1.value = v1
+        p2.value = v2
+        p3.value = v3
 
         assertThat(received).containsExactly(v1, v1 + v2, v1 + v2 + v3)
     }