Merge "Revert "Revert "Using Transaction directly instead of building s..."" into tm-qpr-dev
diff --git a/Android.bp b/Android.bp
index 330c32e..6267e9f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -19,6 +19,54 @@
 
 min_launcher3_sdk_version = "26"
 
+// Common source files used to build launcher (java and kotlin)
+// All sources are split so they can be reused in many other libraries/apps in other folders
+filegroup {
+    name: "launcher-src",
+    srcs: [ "src/**/*.java", "src/**/*.kt" ],
+}
+
+filegroup {
+    name: "launcher-quickstep-src",
+    srcs: [ "quickstep/src/**/*.java", "quickstep/src/**/*.kt" ],
+}
+
+filegroup {
+    name: "launcher-go-src",
+    srcs: [ "go/src/**/*.java", "go/src/**/*.kt" ],
+}
+
+filegroup {
+    name: "launcher-go-quickstep-src",
+    srcs: [ "go/quickstep/src/**/*.java", "go/quickstep/src/**/*.kt" ],
+}
+
+filegroup {
+    name: "launcher-src_shortcuts_overrides",
+    srcs: [ "src_shortcuts_overrides/**/*.java", "src_shortcuts_overrides/**/*.kt" ],
+}
+
+filegroup {
+    name: "launcher-src_ui_overrides",
+    srcs: [ "src_ui_overrides/**/*.java", "src_ui_overrides/**/*.kt" ],
+}
+
+filegroup {
+    name: "launcher-ext_tests",
+    srcs: [ "ext_tests/**/*.java", "ext_tests/**/*.kt" ],
+}
+
+filegroup {
+    name: "launcher-quickstep-ext_tests",
+    srcs: [ "quickstep/ext_tests/**/*.java", "quickstep/ext_tests/**/*.kt" ],
+}
+
+// Proguard files for Launcher3
+filegroup {
+    name: "launcher-proguard-rules",
+    srcs: ["proguard.flags"],
+}
+
 android_library {
     name: "launcher-aosp-tapl",
     libs: [
@@ -139,14 +187,10 @@
         "Launcher3CommonDepsLib",
     ],
     srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
-        "src_shortcuts_overrides/**/*.java",
-        "src_shortcuts_overrides/**/*.kt",
-        "src_ui_overrides/**/*.java",
-        "src_ui_overrides/**/*.kt",
-        "ext_tests/src/**/*.java",
-        "ext_tests/src/**/*.kt",
+        ":launcher-src",
+        ":launcher-src_shortcuts_overrides",
+        ":launcher-src_ui_overrides",
+        ":launcher-ext_tests",
     ],
     resource_dirs: [
         "ext_tests/res",
@@ -202,61 +246,14 @@
 }
 
 
-// Source code used for test helpers
-filegroup {
-    name: "launcher-src-ext-tests",
-    srcs: [
-        "ext_tests/src/**/*.java",
-        "ext_tests/src/**/*.kt",
-        "quickstep/ext_tests/src/**/*.java",
-        "quickstep/ext_tests/src/**/*.kt",
-    ],
-}
-
-// Common source files used to build launcher
-filegroup {
-    name: "launcher-src-no-build-config",
-    srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
-        "src_shortcuts_overrides/**/*.java",
-        "src_shortcuts_overrides/**/*.kt",
-        "quickstep/src/**/*.java",
-        "quickstep/src/**/*.kt",
-    ],
-}
-
-// Common source files used to build go launcher except go/src files
-filegroup {
-    name: "launcher-go-src-no-build-config",
-    srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
-        "quickstep/src/**/*.java",
-        "quickstep/src/**/*.kt",
-        "go/quickstep/src/**/*.java",
-        "go/quickstep/src/**/*.kt",
-    ],
-}
-
-// Proguard files for Launcher3
-filegroup {
-    name: "launcher-proguard-rules",
-    srcs: ["proguard.flags"],
-}
-
 // Library with all the dependencies for building Launcher Go
 android_library {
     name: "LauncherGoResLib",
     srcs: [
-        "src/**/*.java",
-        "src/**/*.kt",
-        "quickstep/src/**/*.java",
-        "quickstep/src/**/*.kt",
-        "go/src/**/*.java",
-        "go/src/**/*.kt",
-        "go/quickstep/src/**/*.java",
-        "go/quickstep/src/**/*.kt",
+        ":launcher-src",
+        ":launcher-quickstep-src",
+        ":launcher-go-src",
+        ":launcher-go-quickstep-src",
     ],
     resource_dirs: [
         "go/res",
@@ -287,7 +284,9 @@
 android_library {
     name: "Launcher3QuickStepLib",
     srcs: [
-        ":launcher-src-no-build-config",
+        ":launcher-src",
+        ":launcher-quickstep-src",
+        ":launcher-src_shortcuts_overrides",
     ],
     resource_dirs: [],
     libs: [
@@ -319,9 +318,9 @@
     static_libs: ["Launcher3CommonDepsLib"],
 
     srcs: [
-        "src/**/*.java",
-        "src_ui_overrides/**/*.java",
-        "go/src/**/*.java",
+        ":launcher-src",
+        ":launcher-go-src",
+        ":launcher-src_ui_overrides",
     ],
 
     resource_dirs: ["go/res"],
@@ -405,12 +404,7 @@
     min_sdk_version: "current",
     target_sdk_version: "current",
 
-    srcs: [
-        "src/**/*.java",
-        "quickstep/src/**/*.java",
-        "go/src/**/*.java",
-        "go/quickstep/src/**/*.java",
-    ],
+    srcs: [ ],
 
     resource_dirs: [
         "go/quickstep/res",
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index 10eedc8..151ec5a 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -45,6 +45,9 @@
 
   // Stores the origin of the Item
   repeated Attribute item_attributes = 12;
+
+  // Stores whether the navigation bar is in kids mode.
+  optional bool is_kids_mode = 13;
 }
 
 message LauncherAttributes{
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index f739f81..7292c44 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -18,6 +18,11 @@
 }
 
 filegroup {
+    name: "launcher3-quickstep-manifest",
+    srcs: ["AndroidManifest.xml"],
+}
+
+filegroup {
     name: "launcher3-quickstep-robolectric-src",
     path: "robolectric_tests",
     srcs: ["robolectric_tests/src/**/*.java"],
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 03caf90..8239d5e 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -98,6 +98,7 @@
 import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.shortcuts.DeepShortcutView;
@@ -552,7 +553,8 @@
 
             final boolean scrimEnabled = ENABLE_SCRIM_FOR_APP_LAUNCH.get();
             if (scrimEnabled) {
-                boolean useTaskbarColor = mDeviceProfile.isTaskbarPresentInApps;
+                boolean useTaskbarColor = mDeviceProfile.isTaskbarPresentInApps
+                        && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get();
                 int scrimColor = useTaskbarColor
                         ? mLauncher.getResources().getColor(R.color.taskbar_background)
                         : Themes.getAttrColor(mLauncher, R.attr.overviewScrimColor);
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index e3fd3f9..2a78bdf 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -23,7 +23,6 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
-import android.util.FloatProperty;
 import android.view.CrossWindowBlurListeners;
 import android.view.View;
 import android.view.ViewRootImpl;
@@ -32,7 +31,6 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.states.StateAnimationConfig;
@@ -47,43 +45,12 @@
 public class DepthController extends BaseDepthController implements StateHandler<LauncherState>,
         BaseActivity.MultiWindowModeChangedListener {
 
-    /**
-     * A property that updates the background blur within a given range of values (ie. even if the
-     * animator goes beyond 0..1, the interpolated value will still be bounded).
-     */
-    public static class ClampedDepthProperty extends FloatProperty<DepthController> {
-        private final float mMinValue;
-        private final float mMaxValue;
-
-        public ClampedDepthProperty(float minValue, float maxValue) {
-            super("depthClamped");
-            mMinValue = minValue;
-            mMaxValue = maxValue;
-        }
-
-        @Override
-        public void setValue(DepthController depthController, float depth) {
-            depthController.setDepth(Utilities.boundToRange(depth, mMinValue, mMaxValue));
-        }
-
-        @Override
-        public Float get(DepthController depthController) {
-            return depthController.mDepth;
-        }
-    }
-
     private final ViewTreeObserver.OnDrawListener mOnDrawListener = this::onLauncherDraw;
 
     private final Consumer<Boolean> mCrossWindowBlurListener = this::setCrossWindowBlursEnabled;
 
     private final Runnable mOpaquenessListener = this::applyDepthAndBlur;
 
-    /**
-     * If we're launching and app and should not be blurring the screen for performance reasons.
-     */
-    private boolean mBlurDisabledForAppLaunch;
-
-
     // Workaround for animating the depth when multiwindow mode changes.
     private boolean mIgnoreStateChangesDuringMultiWindowAnimation = false;
 
@@ -145,12 +112,8 @@
             return;
         }
 
-        float toDepth = toState.getDepth(mLauncher);
-        if (Float.compare(mDepth, toDepth) != 0) {
-            setDepth(toDepth);
-        } else if (toState == LauncherState.OVERVIEW) {
-            applyDepthAndBlur();
-        } else if (toState == LauncherState.BACKGROUND_APP) {
+        STATE_DEPTH.set(this, toState.getDepth(mLauncher));
+        if (toState == LauncherState.BACKGROUND_APP) {
             mLauncher.getDragLayer().getViewTreeObserver().addOnDrawListener(mOnDrawListener);
         }
     }
@@ -164,10 +127,7 @@
         }
 
         float toDepth = toState.getDepth(mLauncher);
-        if (Float.compare(mDepth, toDepth) != 0) {
-            animation.setFloat(this, STATE_DEPTH, toDepth,
-                    config.getInterpolator(ANIM_DEPTH, LINEAR));
-        }
+        animation.setFloat(this, STATE_DEPTH, toDepth, config.getInterpolator(ANIM_DEPTH, LINEAR));
     }
 
     @Override
@@ -198,9 +158,9 @@
         writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius);
         writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled);
         writer.println(prefix + "\tmSurface=" + mSurface);
-        writer.println(prefix + "\tmDepth=" + mDepth);
+        writer.println(prefix + "\tmStateDepth=" + STATE_DEPTH.get(this));
+        writer.println(prefix + "\tmWidgetDepth=" + WIDGET_DEPTH.get(this));
         writer.println(prefix + "\tmCurrentBlur=" + mCurrentBlur);
-        writer.println(prefix + "\tmBlurDisabledForAppLaunch=" + mBlurDisabledForAppLaunch);
         writer.println(prefix + "\tmInEarlyWakeUp=" + mInEarlyWakeUp);
         writer.println(prefix + "\tmIgnoreStateChangesDuringMultiWindowAnimation="
                 + mIgnoreStateChangesDuringMultiWindowAnimation);
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index b9b4fc3..555cd65 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -276,13 +276,6 @@
                 && !mLauncher.getOnboardingPrefs().getBoolean(OnboardingPrefs.TASKBAR_EDU_SEEN);
     }
 
-    /**
-     * Manually ends the taskbar education flow.
-     */
-    public void hideEdu() {
-        mControllers.taskbarEduController.hideEdu();
-    }
-
     @Override
     public void onTaskbarIconLaunched(ItemInfo item) {
         InstanceId instanceId = new InstanceIdSequence().newInstanceId();
@@ -293,8 +286,6 @@
     @Override
     public void setSystemGestureInProgress(boolean inProgress) {
         super.setSystemGestureInProgress(inProgress);
-        // TODO(b/250645563): Don't show round corners when leaving in-app state, and remove
-        // forceHideBackground call entirely.
         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/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 0c488cb..4c5e0be 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -76,6 +76,7 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.touch.ItemClickHandler;
@@ -211,7 +212,8 @@
                 new TaskbarAutohideSuspendController(this),
                 new TaskbarPopupController(this),
                 new TaskbarForceVisibleImmersiveController(this),
-                new TaskbarAllAppsController(this, dp),
+                new TaskbarOverlayController(this, dp),
+                new TaskbarAllAppsController(),
                 new TaskbarInsetsController(this),
                 new VoiceInteractionWindowController(this),
                 isDesktopMode
@@ -243,7 +245,7 @@
     /** Updates {@link DeviceProfile} instances for any Taskbar windows. */
     public void updateDeviceProfile(DeviceProfile dp, NavigationMode navMode) {
         mNavMode = navMode;
-        mControllers.taskbarAllAppsController.updateDeviceProfile(dp);
+        mControllers.taskbarOverlayController.updateDeviceProfile(dp);
         mDeviceProfile = dp.copy(this);
         updateIconSize(getResources());
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 707023b..9c2d21e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -22,6 +22,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
 import com.android.systemui.shared.rotation.RotationButtonController;
 
 import java.io.PrintWriter;
@@ -54,6 +55,7 @@
     public final TaskbarInsetsController taskbarInsetsController;
     public final VoiceInteractionWindowController voiceInteractionWindowController;
     public final TaskbarRecentAppsController taskbarRecentAppsController;
+    public final TaskbarOverlayController taskbarOverlayController;
 
     @Nullable private LoggableTaskbarController[] mControllersToLog = null;
 
@@ -81,6 +83,7 @@
             TaskbarAutohideSuspendController taskbarAutoHideSuspendController,
             TaskbarPopupController taskbarPopupController,
             TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController,
+            TaskbarOverlayController taskbarOverlayController,
             TaskbarAllAppsController taskbarAllAppsController,
             TaskbarInsetsController taskbarInsetsController,
             VoiceInteractionWindowController voiceInteractionWindowController,
@@ -101,6 +104,7 @@
         this.taskbarAutohideSuspendController = taskbarAutoHideSuspendController;
         this.taskbarPopupController = taskbarPopupController;
         this.taskbarForceVisibleImmersiveController = taskbarForceVisibleImmersiveController;
+        this.taskbarOverlayController = taskbarOverlayController;
         this.taskbarAllAppsController = taskbarAllAppsController;
         this.taskbarInsetsController = taskbarInsetsController;
         this.voiceInteractionWindowController = voiceInteractionWindowController;
@@ -129,6 +133,7 @@
         taskbarEduController.init(this);
         taskbarPopupController.init(this);
         taskbarForceVisibleImmersiveController.init(this);
+        taskbarOverlayController.init(this);
         taskbarAllAppsController.init(this, sharedState.allAppsVisible);
         navButtonController.init(this);
         taskbarInsetsController.init(this);
@@ -179,7 +184,7 @@
         taskbarAutohideSuspendController.onDestroy();
         taskbarPopupController.onDestroy();
         taskbarForceVisibleImmersiveController.onDestroy();
-        taskbarAllAppsController.onDestroy();
+        taskbarOverlayController.onDestroy();
         navButtonController.onDestroy();
         taskbarInsetsController.onDestroy();
         voiceInteractionWindowController.onDestroy();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
index 95b93fe..16cc0ac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduController.java
@@ -35,6 +35,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
 import com.android.launcher3.uioverrides.PredictedAppIcon;
 
 import java.io.PrintWriter;
@@ -87,8 +88,10 @@
     void showEdu() {
         mActivity.setTaskbarWindowFullscreen(true);
         mActivity.getDragLayer().post(() -> {
-            mTaskbarEduView = (TaskbarEduView) mActivity.getLayoutInflater().inflate(
-                    R.layout.taskbar_edu, mActivity.getDragLayer(), false);
+            TaskbarOverlayContext overlayContext =
+                    mControllers.taskbarOverlayController.requestWindow();
+            mTaskbarEduView = (TaskbarEduView) overlayContext.getLayoutInflater().inflate(
+                    R.layout.taskbar_edu, overlayContext.getDragLayer(), false);
             mTaskbarEduView.init(new TaskbarEduCallbacks());
             mControllers.navbarButtonsViewController.setSlideInViewVisible(true);
             mTaskbarEduView.setOnCloseBeginListener(
@@ -99,12 +102,6 @@
         });
     }
 
-    void hideEdu() {
-        if (mTaskbarEduView != null) {
-            mTaskbarEduView.close(true /* animate */);
-        }
-    }
-
     /**
      * Starts the given animation, ending the previous animation first if it's still playing.
      */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
index c0cbbd6..bb87f48 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduView.java
@@ -28,10 +28,11 @@
 
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
 import com.android.launcher3.views.AbstractSlideInView;
 
 /** Education view about the Taskbar. */
-public class TaskbarEduView extends AbstractSlideInView<TaskbarActivityContext>
+public class TaskbarEduView extends AbstractSlideInView<TaskbarOverlayContext>
         implements Insettable {
 
     private static final int DEFAULT_OPEN_DURATION = 500;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index bbbc1e6..32c1972 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -29,11 +29,11 @@
 import android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD
 import android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION
 import com.android.launcher3.AbstractFloatingView
-import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS
+import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY
 import com.android.launcher3.DeviceProfile
+import com.android.launcher3.R
 import com.android.launcher3.anim.AlphaUpdateListener
 import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
-import com.android.quickstep.KtR
 import java.io.PrintWriter
 
 /**
@@ -42,8 +42,7 @@
 class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTaskbarController {
 
     /** The bottom insets taskbar provides to the IME when IME is visible. */
-    val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize(
-        KtR.dimen.taskbar_ime_size)
+    val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize(R.dimen.taskbar_ime_size)
     private val touchableRegion: Region = Region()
     private val deviceProfileChangeListener = { _: DeviceProfile ->
         onTaskbarWindowHeightOrInsetsChanged()
@@ -158,8 +157,11 @@
         } else if (controllers.taskbarDragController.isSystemDragInProgress) {
             // Let touches pass through us.
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
-        } else if (AbstractFloatingView.hasOpenView(context, TYPE_TASKBAR_ALL_APPS)) {
-            // Let touches pass through us.
+        } else if (AbstractFloatingView.hasOpenView(context, TYPE_TASKBAR_OVERLAY_PROXY)) {
+            // Let touches pass through us if icons are hidden.
+            if (controllers.taskbarViewController.areIconsVisible()) {
+                insetsInfo.touchableRegion.set(touchableRegion)
+            }
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
         } else if (controllers.taskbarViewController.areIconsVisible()
             || AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 114bfec..49dba95 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -80,10 +80,10 @@
     }
 
     /**
-     * Manually closes the all apps window.
+     * Manually closes the overlay window.
      */
-    public void hideAllApps() {
-        mControllers.taskbarAllAppsController.hide();
+    public void hideOverlayWindow() {
+        mControllers.taskbarOverlayController.hideWindow();
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
index 51fa4d9..ce51f7d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
@@ -24,10 +24,11 @@
 import com.android.launcher3.allapps.AlphabeticalAppsList;
 import com.android.launcher3.allapps.BaseAdapterProvider;
 import com.android.launcher3.allapps.BaseAllAppsAdapter;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
 
 /** All apps container accessible from taskbar. */
 public class TaskbarAllAppsContainerView extends
-        ActivityAllAppsContainerView<TaskbarAllAppsContext> {
+        ActivityAllAppsContainerView<TaskbarOverlayContext> {
 
     public TaskbarAllAppsContainerView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
@@ -44,8 +45,8 @@
     }
 
     @Override
-    protected BaseAllAppsAdapter<TaskbarAllAppsContext> createAdapter(
-            AlphabeticalAppsList<TaskbarAllAppsContext> appsList,
+    protected BaseAllAppsAdapter<TaskbarOverlayContext> createAdapter(
+            AlphabeticalAppsList<TaskbarOverlayContext> appsList,
             BaseAdapterProvider[] adapterProviders) {
         return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList,
                 adapterProviders);
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java
deleted file mode 100644
index 0372f67..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java
+++ /dev/null
@@ -1,248 +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.launcher3.taskbar.allapps;
-
-import static android.view.KeyEvent.ACTION_UP;
-import static android.view.KeyEvent.KEYCODE_BACK;
-import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
-import android.content.Context;
-import android.graphics.Insets;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
-import android.view.WindowInsets;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.ActivityAllAppsContainerView;
-import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider;
-import com.android.launcher3.allapps.search.SearchAdapterProvider;
-import com.android.launcher3.dot.DotInfo;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.popup.PopupDataProvider;
-import com.android.launcher3.taskbar.BaseTaskbarContext;
-import com.android.launcher3.taskbar.TaskbarActivityContext;
-import com.android.launcher3.taskbar.TaskbarControllers;
-import com.android.launcher3.taskbar.TaskbarDragController;
-import com.android.launcher3.taskbar.TaskbarStashController;
-import com.android.launcher3.testing.TestLogging;
-import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.util.OnboardingPrefs;
-import com.android.launcher3.util.TouchController;
-import com.android.launcher3.views.BaseDragLayer;
-
-/**
- * Window context for the taskbar all apps overlay.
- * <p>
- * All apps has its own window and needs a window context. Some properties are delegated to the
- * {@link TaskbarActivityContext} such as {@link DeviceProfile} and {@link PopupDataProvider}.
- */
-class TaskbarAllAppsContext extends BaseTaskbarContext {
-    private final TaskbarActivityContext mTaskbarContext;
-    private final OnboardingPrefs<TaskbarAllAppsContext> mOnboardingPrefs;
-
-    private final TaskbarAllAppsController mWindowController;
-    private final TaskbarAllAppsViewController mAllAppsViewController;
-    private final TaskbarDragController mDragController;
-    private final TaskbarAllAppsDragLayer mDragLayer;
-    private final TaskbarAllAppsContainerView mAppsView;
-
-    // We automatically stash taskbar when all apps is opened in gesture navigation mode.
-    private final boolean mWillTaskbarBeVisuallyStashed;
-    private final int mStashedTaskbarHeight;
-
-    TaskbarAllAppsContext(
-            TaskbarActivityContext taskbarContext,
-            TaskbarAllAppsController windowController,
-            TaskbarControllers taskbarControllers) {
-        super(taskbarContext.createWindowContext(TYPE_APPLICATION_OVERLAY, null));
-        mTaskbarContext = taskbarContext;
-        mWindowController = windowController;
-        mDragController = new TaskbarDragController(this);
-        mOnboardingPrefs = new OnboardingPrefs<>(this, Utilities.getPrefs(this));
-
-        mDragLayer = new TaskbarAllAppsDragLayer(this);
-        TaskbarAllAppsSlideInView slideInView = (TaskbarAllAppsSlideInView) mLayoutInflater.inflate(
-                R.layout.taskbar_all_apps, mDragLayer, false);
-        mAllAppsViewController = new TaskbarAllAppsViewController(
-                this,
-                slideInView,
-                windowController,
-                taskbarControllers);
-        mAppsView = slideInView.getAppsView();
-
-        TaskbarStashController taskbarStashController = taskbarControllers.taskbarStashController;
-        mWillTaskbarBeVisuallyStashed = taskbarStashController.supportsVisualStashing();
-        mStashedTaskbarHeight = taskbarStashController.getStashedHeight();
-    }
-
-    TaskbarAllAppsViewController getAllAppsViewController() {
-        return mAllAppsViewController;
-    }
-
-    @Override
-    public DeviceProfile getDeviceProfile() {
-        return mWindowController.getDeviceProfile();
-    }
-
-    @Override
-    public TaskbarDragController getDragController() {
-        return mDragController;
-    }
-
-    @Override
-    public TaskbarAllAppsDragLayer getDragLayer() {
-        return mDragLayer;
-    }
-
-    @Override
-    public TaskbarAllAppsContainerView getAppsView() {
-        return mAppsView;
-    }
-
-    @Override
-    public OnboardingPrefs<TaskbarAllAppsContext> getOnboardingPrefs() {
-        return mOnboardingPrefs;
-    }
-
-    @Override
-    public boolean isBindingItems() {
-        return mTaskbarContext.isBindingItems();
-    }
-
-    @Override
-    public View.OnClickListener getItemOnClickListener() {
-        return mTaskbarContext.getItemOnClickListener();
-    }
-
-    @Override
-    public PopupDataProvider getPopupDataProvider() {
-        return mTaskbarContext.getPopupDataProvider();
-    }
-
-    @Override
-    public DotInfo getDotInfoForItem(ItemInfo info) {
-        return mTaskbarContext.getDotInfoForItem(info);
-    }
-
-    @Override
-    public void onDragStart() {}
-
-    @Override
-    public void onDragEnd() {
-        mWindowController.maybeCloseWindow();
-    }
-
-    @Override
-    public void onPopupVisibilityChanged(boolean isVisible) {}
-
-    @Override
-    public SearchAdapterProvider<?> createSearchAdapterProvider(
-            ActivityAllAppsContainerView<?> appsView) {
-        return new DefaultSearchAdapterProvider(this);
-    }
-
-    /** Root drag layer for this context. */
-    private static class TaskbarAllAppsDragLayer extends
-            BaseDragLayer<TaskbarAllAppsContext> implements OnComputeInternalInsetsListener {
-
-        private TaskbarAllAppsDragLayer(Context context) {
-            super(context, null, 1);
-            setClipChildren(false);
-            recreateControllers();
-        }
-
-        @Override
-        protected void onAttachedToWindow() {
-            super.onAttachedToWindow();
-            getViewTreeObserver().addOnComputeInternalInsetsListener(this);
-        }
-
-        @Override
-        protected void onDetachedFromWindow() {
-            super.onDetachedFromWindow();
-            getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
-        }
-
-        @Override
-        public void recreateControllers() {
-            mControllers = new TouchController[]{mActivity.mDragController};
-        }
-
-        @Override
-        public boolean dispatchTouchEvent(MotionEvent ev) {
-            TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
-            return super.dispatchTouchEvent(ev);
-        }
-
-        @Override
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) {
-                AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
-                if (topView != null && topView.onBackPressed()) {
-                    return true;
-                }
-            }
-            return super.dispatchKeyEvent(event);
-        }
-
-        @Override
-        public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
-            if (mActivity.mDragController.isSystemDragInProgress()) {
-                inoutInfo.touchableRegion.setEmpty();
-                inoutInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
-            }
-        }
-
-        @Override
-        public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-            return updateInsetsDueToStashing(insets);
-        }
-
-        /**
-         * Taskbar automatically stashes when opening all apps, but we don't report the insets as
-         * changing to avoid moving the underlying app. But internally, the apps view should still
-         * layout according to the stashed insets rather than the unstashed insets. So this method
-         * does two things:
-         * 1) Sets navigationBars bottom inset to stashedHeight.
-         * 2) Sets tappableInsets bottom inset to 0.
-         */
-        private WindowInsets updateInsetsDueToStashing(WindowInsets oldInsets) {
-            if (!mActivity.mWillTaskbarBeVisuallyStashed) {
-                return oldInsets;
-            }
-            WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
-
-            Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
-            Insets newNavInsets = Insets.of(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right,
-                    mActivity.mStashedTaskbarHeight);
-            updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), newNavInsets);
-
-            Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement());
-            Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top,
-                    oldTappableInsets.right, 0);
-            updatedInsetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets);
-
-            return updatedInsetsBuilder.build();
-        }
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index 1671a0f..ea37944 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -15,34 +15,17 @@
  */
 package com.android.launcher3.taskbar.allapps;
 
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
-import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
-import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
-
-import android.content.Context;
-import android.graphics.PixelFormat;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
 import com.android.launcher3.appprediction.PredictionRowView;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarControllers;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
 
 import java.util.List;
-import java.util.Optional;
 
 /**
  * Handles the all apps overlay window initialization, updates, and its data.
@@ -57,36 +40,14 @@
  */
 public final class TaskbarAllAppsController {
 
-    private static final String WINDOW_TITLE = "Taskbar All Apps";
-
-    private final TaskbarActivityContext mTaskbarContext;
-    private final TaskbarAllAppsProxyView mProxyView;
-    private final LayoutParams mLayoutParams;
-
-    private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
-        @Override
-        public void onTaskStackChanged() {
-            mProxyView.close(false);
-        }
-    };
-
-    private DeviceProfile mDeviceProfile;
     private TaskbarControllers mControllers;
-    /** Window context for all apps if it is open. */
-    private @Nullable TaskbarAllAppsContext mAllAppsContext;
+    private @Nullable TaskbarAllAppsContainerView mAppsView;
 
     // Application data models.
     private AppInfo[] mApps;
     private int mAppsModelFlags;
     private List<ItemInfo> mPredictedApps;
 
-    public TaskbarAllAppsController(TaskbarActivityContext context, DeviceProfile dp) {
-        mDeviceProfile = dp;
-        mTaskbarContext = context;
-        mProxyView = new TaskbarAllAppsProxyView(mTaskbarContext);
-        mLayoutParams = createLayoutParams();
-    }
-
     /** Initialize the controller. */
     public void init(TaskbarControllers controllers, boolean allAppsVisible) {
         if (!FeatureFlags.ENABLE_ALL_APPS_IN_TASKBAR.get()) {
@@ -111,8 +72,8 @@
 
         mApps = apps;
         mAppsModelFlags = flags;
-        if (mAllAppsContext != null) {
-            mAllAppsContext.getAppsView().getAppsStore().setApps(mApps, mAppsModelFlags);
+        if (mAppsView != null) {
+            mAppsView.getAppsStore().setApps(mApps, mAppsModelFlags);
         }
     }
 
@@ -123,8 +84,8 @@
         }
 
         mPredictedApps = predictedApps;
-        if (mAllAppsContext != null) {
-            mAllAppsContext.getAppsView().getFloatingHeaderView()
+        if (mAppsView != null) {
+            mAppsView.getFloatingHeaderView()
                     .findFixedRowByType(PredictionRowView.class)
                     .setPredictedApps(mPredictedApps);
         }
@@ -136,120 +97,30 @@
     }
 
     private void show(boolean animate) {
-        if (mProxyView.isOpen()) {
+        if (mAppsView != null) {
             return;
         }
-        mProxyView.show();
         // mControllers and getSharedState should never be null here. Do not handle null-pointer
         // to catch invalid states.
         mControllers.getSharedState().allAppsVisible = true;
 
-        mAllAppsContext = new TaskbarAllAppsContext(mTaskbarContext, this, mControllers);
-        mAllAppsContext.getDragController().init(mControllers);
-        TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
-        Optional.ofNullable(mAllAppsContext.getSystemService(WindowManager.class))
-                .ifPresent(m -> m.addView(mAllAppsContext.getDragLayer(), mLayoutParams));
+        TaskbarOverlayContext overlayContext =
+                mControllers.taskbarOverlayController.requestWindow();
+        TaskbarAllAppsSlideInView slideInView =
+                (TaskbarAllAppsSlideInView) overlayContext.getLayoutInflater().inflate(
+                        R.layout.taskbar_all_apps, overlayContext.getDragLayer(), false);
+        slideInView.addOnCloseListener(() -> {
+            mControllers.getSharedState().allAppsVisible = false;
+            mAppsView = null;
+        });
+        TaskbarAllAppsViewController viewController = new TaskbarAllAppsViewController(
+                overlayContext, slideInView, mControllers);
 
-        mAllAppsContext.getAppsView().getAppsStore().setApps(mApps, mAppsModelFlags);
-        mAllAppsContext.getAppsView().getFloatingHeaderView()
+        viewController.show(animate);
+        mAppsView = overlayContext.getAppsView();
+        mAppsView.getAppsStore().setApps(mApps, mAppsModelFlags);
+        mAppsView.getFloatingHeaderView()
                 .findFixedRowByType(PredictionRowView.class)
                 .setPredictedApps(mPredictedApps);
-        mAllAppsContext.getAllAppsViewController().show(animate);
-    }
-
-    /** Closes the {@link TaskbarAllAppsContainerView}. */
-    public void hide() {
-        mProxyView.close(true);
-    }
-
-    /**
-     * Removes the all apps window from the hierarchy, if all floating views are closed and there is
-     * no system drag operation in progress.
-     * <p>
-     * This method should be called after an exit animation finishes, if applicable.
-     */
-    void maybeCloseWindow() {
-        if (mAllAppsContext != null && (AbstractFloatingView.hasOpenView(mAllAppsContext, TYPE_ALL)
-                || mAllAppsContext.getDragController().isSystemDragInProgress())) {
-            return;
-        }
-        mProxyView.close(false);
-        // mControllers and getSharedState should never be null here. Do not handle null-pointer
-        // to catch invalid states.
-        mControllers.getSharedState().allAppsVisible = false;
-        onDestroy();
-    }
-
-    /** Destroys the controller and any All Apps window if present. */
-    public void onDestroy() {
-        TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
-        Optional.ofNullable(mAllAppsContext)
-                .map(c -> c.getSystemService(WindowManager.class))
-                .ifPresent(m -> m.removeViewImmediate(mAllAppsContext.getDragLayer()));
-        mAllAppsContext = null;
-    }
-
-    /** Updates {@link DeviceProfile} instance for Taskbar's All Apps window. */
-    public void updateDeviceProfile(DeviceProfile dp) {
-        mDeviceProfile = dp;
-        Optional.ofNullable(mAllAppsContext).ifPresent(c -> {
-            AbstractFloatingView.closeAllOpenViewsExcept(c, false, TYPE_REBIND_SAFE);
-            c.dispatchDeviceProfileChanged();
-        });
-    }
-
-    DeviceProfile getDeviceProfile() {
-        return mDeviceProfile;
-    }
-
-    private LayoutParams createLayoutParams() {
-        LayoutParams layoutParams = new LayoutParams(
-                TYPE_APPLICATION_OVERLAY,
-                WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                PixelFormat.TRANSLUCENT);
-        layoutParams.setTitle(WINDOW_TITLE);
-        layoutParams.gravity = Gravity.BOTTOM;
-        layoutParams.packageName = mTaskbarContext.getPackageName();
-        layoutParams.setFitInsetsTypes(0); // Handled by container view.
-        layoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        layoutParams.setSystemApplicationOverlay(true);
-        return layoutParams;
-    }
-
-    /**
-     * Proxy view connecting taskbar drag layer to the all apps window.
-     * <p>
-     * The all apps view is in a separate window and has its own drag layer, but this proxy lets it
-     * behave as though its in the taskbar drag layer. For instance, when the taskbar closes all
-     * {@link AbstractFloatingView} instances, the all apps window will also close.
-     */
-    private class TaskbarAllAppsProxyView extends AbstractFloatingView {
-
-        private TaskbarAllAppsProxyView(Context context) {
-            super(context, null);
-        }
-
-        private void show() {
-            mIsOpen = true;
-            mTaskbarContext.getDragLayer().addView(this);
-        }
-
-        @Override
-        protected void handleClose(boolean animate) {
-            mTaskbarContext.getDragLayer().removeView(this);
-            Optional.ofNullable(mAllAppsContext)
-                    .map(TaskbarAllAppsContext::getAllAppsViewController)
-                    .ifPresent(v -> v.close(animate));
-        }
-
-        @Override
-        protected boolean isOfType(int type) {
-            return (type & TYPE_TASKBAR_ALL_APPS) != 0;
-        }
-
-        @Override
-        public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-            return false;
-        }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 9d48c8d..c8bfc2a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -28,10 +28,11 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
 import com.android.launcher3.views.AbstractSlideInView;
 
 /** Wrapper for taskbar all apps with slide-in behavior. */
-public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarAllAppsContext>
+public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverlayContext>
         implements Insettable, DeviceProfile.OnDeviceProfileChangeListener {
     private TaskbarAllAppsContainerView mAppsView;
     private float mShiftRange;
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index 128fa5e..54392b2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -25,6 +25,7 @@
 import com.android.launcher3.taskbar.NavbarButtonsViewController;
 import com.android.launcher3.taskbar.TaskbarControllers;
 import com.android.launcher3.taskbar.TaskbarStashController;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
 
 /**
  * Handles the {@link TaskbarAllAppsContainerView} behavior and synchronizes its transitions with
@@ -32,16 +33,15 @@
  */
 final class TaskbarAllAppsViewController {
 
-    private final TaskbarAllAppsContext mContext;
+    private final TaskbarOverlayContext mContext;
     private final TaskbarAllAppsSlideInView mSlideInView;
     private final TaskbarAllAppsContainerView mAppsView;
     private final TaskbarStashController mTaskbarStashController;
     private final NavbarButtonsViewController mNavbarButtonsViewController;
 
     TaskbarAllAppsViewController(
-            TaskbarAllAppsContext context,
+            TaskbarOverlayContext context,
             TaskbarAllAppsSlideInView slideInView,
-            TaskbarAllAppsController windowController,
             TaskbarControllers taskbarControllers) {
 
         mContext = context;
@@ -53,7 +53,6 @@
         setUpIconLongClick();
         setUpAppDivider();
         setUpTaskbarStashing();
-        mSlideInView.addOnCloseListener(windowController::maybeCloseWindow);
     }
 
     /** Starts the {@link TaskbarAllAppsSlideInView} enter transition. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
new file mode 100644
index 0000000..5701de0
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayContext.java
@@ -0,0 +1,146 @@
+/*
+ * 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.taskbar.overlay;
+
+import android.content.Context;
+import android.view.View;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.allapps.search.DefaultSearchAdapterProvider;
+import com.android.launcher3.allapps.search.SearchAdapterProvider;
+import com.android.launcher3.dot.DotInfo;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.taskbar.BaseTaskbarContext;
+import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.launcher3.taskbar.TaskbarDragController;
+import com.android.launcher3.taskbar.TaskbarStashController;
+import com.android.launcher3.taskbar.allapps.TaskbarAllAppsContainerView;
+import com.android.launcher3.util.OnboardingPrefs;
+
+/**
+ * Window context for the taskbar overlays such as All Apps and EDU.
+ * <p>
+ * Overlays have their own window and need a window context. Some properties are delegated to the
+ * {@link TaskbarActivityContext} such as {@link PopupDataProvider}.
+ */
+public class TaskbarOverlayContext extends BaseTaskbarContext {
+    private final TaskbarActivityContext mTaskbarContext;
+    private final OnboardingPrefs<TaskbarOverlayContext> mOnboardingPrefs;
+
+    private final TaskbarOverlayController mOverlayController;
+    private final TaskbarDragController mDragController;
+    private final TaskbarOverlayDragLayer mDragLayer;
+
+    // We automatically stash taskbar when All Apps is opened in gesture navigation mode.
+    private final boolean mWillTaskbarBeVisuallyStashed;
+    private final int mStashedTaskbarHeight;
+
+    public TaskbarOverlayContext(
+            Context windowContext,
+            TaskbarActivityContext taskbarContext,
+            TaskbarControllers controllers) {
+        super(windowContext);
+        mTaskbarContext = taskbarContext;
+        mOverlayController = controllers.taskbarOverlayController;
+        mDragController = new TaskbarDragController(this);
+        mDragController.init(controllers);
+        mOnboardingPrefs = new OnboardingPrefs<>(this, Utilities.getPrefs(this));
+        mDragLayer = new TaskbarOverlayDragLayer(this);
+
+        TaskbarStashController taskbarStashController = controllers.taskbarStashController;
+        mWillTaskbarBeVisuallyStashed = taskbarStashController.supportsVisualStashing();
+        mStashedTaskbarHeight = taskbarStashController.getStashedHeight();
+    }
+
+    boolean willTaskbarBeVisuallyStashed() {
+        return mWillTaskbarBeVisuallyStashed;
+    }
+
+    int getStashedTaskbarHeight() {
+        return mStashedTaskbarHeight;
+    }
+
+    public TaskbarOverlayController getOverlayController() {
+        return mOverlayController;
+    }
+
+    @Override
+    public DeviceProfile getDeviceProfile() {
+        return mOverlayController.getDeviceProfile();
+    }
+
+    @Override
+    public TaskbarDragController getDragController() {
+        return mDragController;
+    }
+
+    @Override
+    public TaskbarOverlayDragLayer getDragLayer() {
+        return mDragLayer;
+    }
+
+    @Override
+    public TaskbarAllAppsContainerView getAppsView() {
+        return mDragLayer.findViewById(R.id.apps_view);
+    }
+
+    @Override
+    public OnboardingPrefs<TaskbarOverlayContext> getOnboardingPrefs() {
+        return mOnboardingPrefs;
+    }
+
+    @Override
+    public boolean isBindingItems() {
+        return mTaskbarContext.isBindingItems();
+    }
+
+    @Override
+    public View.OnClickListener getItemOnClickListener() {
+        return mTaskbarContext.getItemOnClickListener();
+    }
+
+    @Override
+    public PopupDataProvider getPopupDataProvider() {
+        return mTaskbarContext.getPopupDataProvider();
+    }
+
+    @Override
+    public DotInfo getDotInfoForItem(ItemInfo info) {
+        return mTaskbarContext.getDotInfoForItem(info);
+    }
+
+    @Override
+    public void onDragStart() {}
+
+    @Override
+    public void onDragEnd() {
+        mOverlayController.maybeCloseWindow();
+    }
+
+    @Override
+    public void onPopupVisibilityChanged(boolean isVisible) {}
+
+    @Override
+    public SearchAdapterProvider<?> createSearchAdapterProvider(
+            ActivityAllAppsContainerView<?> appsView) {
+        return new DefaultSearchAdapterProvider(this);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
new file mode 100644
index 0000000..0574058
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
@@ -0,0 +1,197 @@
+/*
+ * 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.taskbar.overlay;
+
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.launcher3.taskbar.TaskbarControllers;
+import com.android.systemui.shared.system.TaskStackChangeListener;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
+
+import java.util.Optional;
+
+/**
+ * Handles the Taskbar overlay window lifecycle.
+ * <p>
+ * Overlays need to be inflated in a separate window so that have the correct hierarchy. For
+ * instance, they need to be below the notification tray. If there are multiple overlays open, the
+ * same window is used.
+ */
+public final class TaskbarOverlayController {
+
+    private static final String WINDOW_TITLE = "Taskbar Overlay";
+
+    private final TaskbarActivityContext mTaskbarContext;
+    private final Context mWindowContext;
+    private final TaskbarOverlayProxyView mProxyView;
+    private final LayoutParams mLayoutParams;
+
+    private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+        @Override
+        public void onTaskStackChanged() {
+            mProxyView.close(false);
+        }
+    };
+
+    private DeviceProfile mDeviceProfile;
+    private @Nullable TaskbarOverlayContext mOverlayContext;
+    private TaskbarControllers mControllers; // Initialized in init.
+
+    public TaskbarOverlayController(
+            TaskbarActivityContext taskbarContext, DeviceProfile deviceProfile) {
+        mTaskbarContext = taskbarContext;
+        mWindowContext = mTaskbarContext.createWindowContext(TYPE_APPLICATION_OVERLAY, null);
+        mProxyView = new TaskbarOverlayProxyView();
+        mLayoutParams = createLayoutParams();
+        mDeviceProfile = deviceProfile;
+    }
+
+    /** Initialize the controller. */
+    public void init(TaskbarControllers controllers) {
+        mControllers = controllers;
+    }
+
+    /**
+     * Creates a window for Taskbar overlays, if it does not already exist. Returns the window
+     * context for the current overlay window.
+     */
+    public TaskbarOverlayContext requestWindow() {
+        if (mOverlayContext == null) {
+            mOverlayContext = new TaskbarOverlayContext(
+                    mWindowContext, mTaskbarContext, mControllers);
+        }
+
+        if (!mProxyView.isOpen()) {
+            mProxyView.show();
+            Optional.ofNullable(mOverlayContext.getSystemService(WindowManager.class))
+                    .ifPresent(m -> m.addView(mOverlayContext.getDragLayer(), mLayoutParams));
+            TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
+        }
+
+        return mOverlayContext;
+    }
+
+    /** Hides the current overlay window with animation. */
+    public void hideWindow() {
+        mProxyView.close(true);
+    }
+
+    /**
+     * Removes the overlay window from the hierarchy, if all floating views are closed and there is
+     * no system drag operation in progress.
+     * <p>
+     * This method should be called after an exit animation finishes, if applicable.
+     */
+    @SuppressLint("WrongConstant")
+    void maybeCloseWindow() {
+        if (mOverlayContext != null && (AbstractFloatingView.hasOpenView(mOverlayContext, TYPE_ALL)
+                || mOverlayContext.getDragController().isSystemDragInProgress())) {
+            return;
+        }
+        mProxyView.close(false);
+        onDestroy();
+    }
+
+    /** Destroys the controller and any overlay window if present. */
+    public void onDestroy() {
+        TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
+        Optional.ofNullable(mOverlayContext)
+                .map(c -> c.getSystemService(WindowManager.class))
+                .ifPresent(m -> m.removeViewImmediate(mOverlayContext.getDragLayer()));
+        mOverlayContext = null;
+    }
+
+    /** The current device profile for the overlay window. */
+    public DeviceProfile getDeviceProfile() {
+        return mDeviceProfile;
+    }
+
+    /** Updates {@link DeviceProfile} instance for Taskbar's overlay window. */
+    public void updateDeviceProfile(DeviceProfile dp) {
+        mDeviceProfile = dp;
+        Optional.ofNullable(mOverlayContext).ifPresent(c -> {
+            AbstractFloatingView.closeAllOpenViewsExcept(c, false, TYPE_REBIND_SAFE);
+            c.dispatchDeviceProfileChanged();
+        });
+    }
+
+    @SuppressLint("WrongConstant")
+    private LayoutParams createLayoutParams() {
+        LayoutParams layoutParams = new LayoutParams(
+                TYPE_APPLICATION_OVERLAY,
+                LayoutParams.FLAG_SPLIT_TOUCH,
+                PixelFormat.TRANSLUCENT);
+        layoutParams.setTitle(WINDOW_TITLE);
+        layoutParams.gravity = Gravity.BOTTOM;
+        layoutParams.packageName = mTaskbarContext.getPackageName();
+        layoutParams.setFitInsetsTypes(0); // Handled by container view.
+        layoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        layoutParams.setSystemApplicationOverlay(true);
+        return layoutParams;
+    }
+
+    /**
+     * Proxy view connecting taskbar drag layer to the overlay window.
+     *
+     * Overlays are in a separate window and has its own drag layer, but this proxy lets its views
+     * behave as though they are in the taskbar drag layer. For instance, when the taskbar closes
+     * all {@link AbstractFloatingView} instances, the overlay window will also close.
+     */
+    private class TaskbarOverlayProxyView extends AbstractFloatingView {
+
+        private TaskbarOverlayProxyView() {
+            super(mTaskbarContext, null);
+        }
+
+        private void show() {
+            mIsOpen = true;
+            mTaskbarContext.getDragLayer().addView(this);
+        }
+
+        @Override
+        protected void handleClose(boolean animate) {
+            mTaskbarContext.getDragLayer().removeView(this);
+            Optional.ofNullable(mOverlayContext).ifPresent(c -> closeAllOpenViews(c, animate));
+        }
+
+        @Override
+        protected boolean isOfType(int type) {
+            return (type & TYPE_TASKBAR_OVERLAY_PROXY) != 0;
+        }
+
+        @Override
+        public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+            return false;
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
new file mode 100644
index 0000000..044afd6
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -0,0 +1,126 @@
+/*
+ * 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.taskbar.overlay;
+
+import static android.view.KeyEvent.ACTION_UP;
+import static android.view.KeyEvent.KEYCODE_BACK;
+import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+
+import android.content.Context;
+import android.graphics.Insets;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.testing.TestLogging;
+import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.BaseDragLayer;
+
+/** Root drag layer for the Taskbar overlay window. */
+public class TaskbarOverlayDragLayer extends
+        BaseDragLayer<TaskbarOverlayContext> implements
+        ViewTreeObserver.OnComputeInternalInsetsListener {
+
+    TaskbarOverlayDragLayer(Context context) {
+        super(context, null, 1);
+        setClipChildren(false);
+        recreateControllers();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        getViewTreeObserver().addOnComputeInternalInsetsListener(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        getViewTreeObserver().removeOnComputeInternalInsetsListener(this);
+    }
+
+    @Override
+    public void recreateControllers() {
+        mControllers = new TouchController[]{mActivity.getDragController()};
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
+        return super.dispatchTouchEvent(ev);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) {
+            AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
+            if (topView != null && topView.onBackPressed()) {
+                return true;
+            }
+        }
+        return super.dispatchKeyEvent(event);
+    }
+
+    @Override
+    public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
+        if (mActivity.getDragController().isSystemDragInProgress()) {
+            inoutInfo.touchableRegion.setEmpty();
+            inoutInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
+        }
+    }
+
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        return updateInsetsDueToStashing(insets);
+    }
+
+    @Override
+    public void onViewRemoved(View child) {
+        super.onViewRemoved(child);
+        mActivity.getOverlayController().maybeCloseWindow();
+    }
+
+    /**
+     * Taskbar automatically stashes when opening all apps, but we don't report the insets as
+     * changing to avoid moving the underlying app. But internally, the apps view should still
+     * layout according to the stashed insets rather than the unstashed insets. So this method
+     * does two things:
+     * 1) Sets navigationBars bottom inset to stashedHeight.
+     * 2) Sets tappableInsets bottom inset to 0.
+     */
+    private WindowInsets updateInsetsDueToStashing(WindowInsets oldInsets) {
+        if (!mActivity.willTaskbarBeVisuallyStashed()) {
+            return oldInsets;
+        }
+        WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
+
+        Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
+        Insets newNavInsets = Insets.of(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right,
+                mActivity.getStashedTaskbarHeight());
+        updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), newNavInsets);
+
+        Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement());
+        Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top,
+                oldTappableInsets.right, 0);
+        updatedInsetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets);
+
+        return updatedInsetsBuilder.build();
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index ee9845b..3203f44 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -186,6 +186,8 @@
 
     private SafeCloseable mViewCapture;
 
+    private boolean mEnableWidgetDepth;
+
     @Override
     protected void setupViews() {
         super.setupViews();
@@ -206,6 +208,9 @@
         mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
         mDepthController = new DepthController(this);
         mHotseatPredictionController = new HotseatPredictionController(this);
+
+        mEnableWidgetDepth = ENABLE_WIDGET_PICKER_DEPTH.get()
+                && SystemProperties.getBoolean("ro.launcher.depth.widget", true);
     }
 
     @Override
@@ -587,9 +592,7 @@
     public void onWidgetsTransition(float progress) {
         super.onWidgetsTransition(progress);
         onTaskbarInAppDisplayProgressUpdate(progress, WIDGETS_PAGE_PROGRESS_INDEX);
-        // Change of wallpaper depth in widget picker is disabled for tests as it causes flakiness
-        // on very slow cuttlefish devices.
-        if (ENABLE_WIDGET_PICKER_DEPTH.get() && !Utilities.IS_RUNNING_IN_TEST_HARNESS) {
+        if (mEnableWidgetDepth) {
             WIDGET_DEPTH.set(getDepthController(),
                     Utilities.mapToRange(progress, 0f, 1f, 0f, getDeviceProfile().bottomSheetDepth,
                             EMPHASIZED));
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 4150d40..733c6a8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -26,6 +26,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
 
@@ -96,7 +97,7 @@
     @Override
     public int getWorkspaceScrimColor(Launcher launcher) {
         DeviceProfile dp = launcher.getDeviceProfile();
-        if (dp.isTaskbarPresentInApps) {
+        if (dp.isTaskbarPresentInApps && !FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) {
             return launcher.getColor(R.color.taskbar_background);
         }
         return Color.TRANSPARENT;
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index a343c2d..d432004 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -188,7 +188,8 @@
      * Closes any overlays.
      */
     public void closeOverlay() {
-        Optional.ofNullable(getTaskbarController()).ifPresent(TaskbarUIController::hideAllApps);
+        Optional.ofNullable(getTaskbarController()).ifPresent(
+                TaskbarUIController::hideOverlayWindow);
     }
 
     public void switchRunningTaskViewToScreenshot(HashMap<Integer, ThumbnailData> thumbnailDatas,
diff --git a/quickstep/src/com/android/quickstep/KtR.java b/quickstep/src/com/android/quickstep/KtR.java
deleted file mode 100644
index 758c6e0..0000000
--- a/quickstep/src/com/android/quickstep/KtR.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep;
-
-import com.android.launcher3.R;
-
-/**
- * Bridge class to allow using resources in Kotlin.
- * <br/>
- * TODO(b/204069723) Can't use resources directly in Kotlin
- */
-public class KtR {
-    public static final class id {
-        public static int menu_option_layout = R.id.menu_option_layout;
-    }
-
-    public static final class dimen {
-        public static int task_menu_spacing = R.dimen.task_menu_spacing;
-        public static int task_menu_horizontal_padding = R.dimen.task_menu_horizontal_padding;
-        public static int taskbar_ime_size = R.dimen.taskbar_ime_size;
-    }
-
-    public static final class layout {
-        public static int task_menu_with_arrow = R.layout.task_menu_with_arrow;
-        public static int task_view_menu_option = R.layout.task_view_menu_option;
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 1cb17cb..8522a87 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -34,11 +34,11 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.LauncherInitListener;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.statehandlers.DepthController;
-import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.taskbar.LauncherTaskbarUIController;
 import com.android.launcher3.touch.PagedOrientationHandler;
@@ -129,7 +129,8 @@
                 float fromDepthRatio = BACKGROUND_APP.getDepth(activity);
                 float toDepthRatio = OVERVIEW.getDepth(activity);
                 pa.addFloat(getDepthController(),
-                        new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
+                        new LauncherAnimUtils.ClampedProperty<>(
+                                DepthController.STATE_DEPTH, fromDepthRatio, toDepthRatio),
                         fromDepthRatio, toDepthRatio, LINEAR);
             }
         };
@@ -289,10 +290,6 @@
         } else {
             om.hideOverlay(150);
         }
-        LauncherTaskbarUIController taskbarController = getTaskbarController();
-        if (taskbarController != null) {
-            taskbarController.hideEdu();
-        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index e32aaee..bcaae99 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -200,13 +200,12 @@
     }
 
     @Override
-    public void setModalStateEnabled(boolean isModalState) {
-        super.setModalStateEnabled(isModalState);
+    public void setModalStateEnabled(boolean isModalState, boolean animate) {
         if (isModalState) {
-            mActivity.getStateManager().goToState(RecentsState.MODAL_TASK);
+            mActivity.getStateManager().goToState(RecentsState.MODAL_TASK, animate);
         } else {
             if (mActivity.isInState(RecentsState.MODAL_TASK)) {
-                mActivity.getStateManager().goToState(DEFAULT);
+                mActivity.getStateManager().goToState(DEFAULT, animate);
                 resetModalVisuals();
             }
         }
@@ -243,6 +242,9 @@
         if (finalState != MODAL_TASK) {
             setOverviewSelectEnabled(false);
         }
+        if (finalState != OVERVIEW_SPLIT_SELECT) {
+            resetFromSplitSelectionState();
+        }
 
         if (isOverlayEnabled) {
             runActionOnRemoteHandles(remoteTargetHandle ->
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
index 223eba5..8b5f091 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -55,7 +55,8 @@
     public static final RecentsState HOME = new RecentsState(3, 0);
     public static final RecentsState BG_LAUNCHER = new LauncherState(4, 0);
     public static final RecentsState OVERVIEW_SPLIT_SELECT = new RecentsState(5,
-            FLAG_SHOW_AS_GRID | FLAG_SCRIM | FLAG_OVERVIEW_UI | FLAG_CLOSE_POPUPS);
+            FLAG_SHOW_AS_GRID | FLAG_SCRIM | FLAG_OVERVIEW_UI | FLAG_CLOSE_POPUPS
+                    | FLAG_DISABLE_RESTORE);
 
     public final int ordinal;
     private final int mFlags;
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index a9ff0fb..0c422a0 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -191,7 +191,7 @@
                 info.getWidget().getSpanX(), // span_x = 17 [default = 1];
                 info.getWidget().getSpanY(), // span_y = 18 [default = 1];
                 getAttributes(info) /* attributes = 19 [(log_mode) = MODE_BYTES] */,
-                false /* is_kids_mode = 20 */
+                info.getIsKidsMode() /* is_kids_mode = 20 */
         );
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/BaseDepthController.java b/quickstep/src/com/android/quickstep/util/BaseDepthController.java
index 29ae9a1..064e675 100644
--- a/quickstep/src/com/android/quickstep/util/BaseDepthController.java
+++ b/quickstep/src/com/android/quickstep/util/BaseDepthController.java
@@ -71,7 +71,7 @@
      * Ratio from 0 to 1, where 0 is fully zoomed out, and 1 is zoomed in.
      * @see android.service.wallpaper.WallpaperService.Engine#onZoomChanged(float)
      */
-    protected float mDepth;
+    private float mDepth;
 
     protected SurfaceControl mSurface;
 
@@ -143,7 +143,7 @@
         }
     }
 
-    protected void setDepth(float depth) {
+    private void setDepth(float depth) {
         depth = Utilities.boundToRange(depth, 0, 1);
         // Round out the depth to dedupe frequent, non-perceptable updates
         int depthI = (int) (depth * 256);
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index bb8506d..2ae7136 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -162,13 +162,12 @@
     }
 
     @Override
-    public void setModalStateEnabled(boolean isModalState) {
-        super.setModalStateEnabled(isModalState);
+    public void setModalStateEnabled(boolean isModalState, boolean animate) {
         if (isModalState) {
-            mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK);
+            mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK, animate);
         } else {
             if (mActivity.isInState(LauncherState.OVERVIEW_MODAL_TASK)) {
-                mActivity.getStateManager().goToState(LauncherState.OVERVIEW);
+                mActivity.getStateManager().goToState(LauncherState.OVERVIEW, animate);
                 resetModalVisuals();
             }
         }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index dbfd358..ab19487 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1761,7 +1761,7 @@
     private void onOrientationChanged() {
         // If overview is in modal state when rotate, reset it to overview state without running
         // animation.
-        setModalStateEnabled(false);
+        setModalStateEnabled(/* isModalState= */ false, /* animate= */ false);
         if (isSplitSelectionActive()) {
             onRotateInSplitSelectionState();
         }
@@ -5199,11 +5199,8 @@
         setInsets(mInsets);
     }
 
-    /**
-     * Enables or disables modal state for RecentsView
-     * @param isModalState
-     */
-    public void setModalStateEnabled(boolean isModalState) { }
+    /** Enables or disables modal state for RecentsView */
+    public abstract void setModalStateEnabled(boolean isModalState, boolean animate);
 
     public TaskOverlayFactory getTaskOverlayFactory() {
         return mTaskOverlayFactory;
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index b586ac3..bdc0585 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -37,7 +37,6 @@
 import com.android.launcher3.popup.RoundedArrowDrawable
 import com.android.launcher3.popup.SystemShortcut
 import com.android.launcher3.util.Themes
-import com.android.quickstep.KtR
 import com.android.quickstep.TaskOverlayFactory
 import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
 
@@ -53,9 +52,9 @@
                 .fromContext<BaseDraggingActivity>(taskContainer.taskView.context)
             val taskMenuViewWithArrow = activity.layoutInflater
                 .inflate(
-                    KtR.layout.task_menu_with_arrow,
-                    activity.dragLayer,
-                    false
+                        R.layout.task_menu_with_arrow,
+                        activity.dragLayer,
+                        false
                 ) as TaskMenuViewWithArrow<*>
 
             return taskMenuViewWithArrow.populateAndShowForTask(taskContainer, alignSecondRow)
@@ -93,7 +92,7 @@
     private var optionMeasuredHeight = 0
     private val arrowHorizontalPadding: Int
         get() = if (taskView.isFocusedTask)
-            resources.getDimensionPixelSize(KtR.dimen.task_menu_horizontal_padding)
+            resources.getDimensionPixelSize(R.dimen.task_menu_horizontal_padding)
         else
             0
 
@@ -119,7 +118,7 @@
 
     override fun onFinishInflate() {
         super.onFinishInflate()
-        optionLayout = findViewById(KtR.id.menu_option_layout)
+        optionLayout = findViewById(R.id.menu_option_layout)
     }
 
     private fun populateAndShowForTask(
@@ -170,7 +169,7 @@
         // Add the spaces between items
         val divider = ShapeDrawable(RectShape())
         divider.paint.color = resources.getColor(android.R.color.transparent)
-        val dividerSpacing = resources.getDimension(KtR.dimen.task_menu_spacing).toInt()
+        val dividerSpacing = resources.getDimension(R.dimen.task_menu_spacing).toInt()
         optionLayout.showDividers = SHOW_DIVIDER_MIDDLE
 
         // Set the orientation, which makes the menu show
@@ -187,7 +186,7 @@
 
     private fun addMenuOption(menuOption: SystemShortcut<*>) {
         val menuOptionView = mActivityContext.layoutInflater.inflate(
-            KtR.layout.task_view_menu_option, this, false
+                R.layout.task_view_menu_option, this, false
         ) as LinearLayout
         menuOption.setIconAndLabelFor(
             menuOptionView.findViewById(R.id.icon),
diff --git a/res/layout/page_indicator_dots.xml b/res/layout/page_indicator_dots.xml
new file mode 100644
index 0000000..d5fe51e
--- /dev/null
+++ b/res/layout/page_indicator_dots.xml
@@ -0,0 +1,22 @@
+<?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.pageindicators.PageIndicatorDots xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/page_indicator"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/workspace_page_indicator_height"
+    android:layout_gravity="bottom | center_horizontal"
+    android:theme="@style/HomeScreenElementTheme" />
\ No newline at end of file
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 5ee6fce..73acd87 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -94,6 +94,7 @@
     public static final int TYPE_TASKBAR_EDUCATION_DIALOG = 1 << 16;
     public static final int TYPE_TASKBAR_ALL_APPS = 1 << 17;
     public static final int TYPE_ADD_TO_HOME_CONFIRMATION = 1 << 18;
+    public static final int TYPE_TASKBAR_OVERLAY_PROXY = 1 << 19;
 
     public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
             | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index c1df403..cdd8f5a 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -19,6 +19,7 @@
 import static android.animation.ValueAnimator.areAnimatorsEnabled;
 
 import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
+import static com.android.launcher3.config.FeatureFlags.SHOW_HOME_GARDENING;
 import static com.android.launcher3.dragndrop.DraggableView.DRAGGABLE_ICON;
 import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
 
@@ -552,7 +553,9 @@
     public void setSpringLoadedProgress(float progress) {
         if (Float.compare(progress, mSpringLoadedProgress) != 0) {
             mSpringLoadedProgress = progress;
-            updateBgAlpha();
+            if (!SHOW_HOME_GARDENING.get()) {
+                updateBgAlpha();
+            }
             setGridAlpha(progress);
         }
     }
@@ -577,7 +580,9 @@
     public void setScrollProgress(float progress) {
         if (Float.compare(Math.abs(progress), mScrollProgress) != 0) {
             mScrollProgress = Math.abs(progress);
-            updateBgAlpha();
+            if (!SHOW_HOME_GARDENING.get()) {
+                updateBgAlpha();
+            }
         }
     }
 
@@ -616,7 +621,7 @@
             }
         }
 
-        if (mVisualizeDropLocation) {
+        if (mVisualizeDropLocation && !SHOW_HOME_GARDENING.get()) {
             for (int i = 0; i < mDragOutlines.length; i++) {
                 final float alpha = mDragOutlineAlphas[i];
                 if (alpha <= 0) continue;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5a6b3ec..3abefe0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -43,6 +43,7 @@
 import static com.android.launcher3.Utilities.postAsyncCallback;
 import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
 import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
+import static com.android.launcher3.config.FeatureFlags.SHOW_DELIGHTFUL_PAGINATION;
 import static com.android.launcher3.logging.StatsLogManager.EventEnum;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
@@ -97,6 +98,7 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.text.method.TextKeyListener;
+import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.Log;
 import android.util.SparseArray;
@@ -163,6 +165,7 @@
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.notification.NotificationListener;
+import com.android.launcher3.pageindicators.WorkspacePageIndicator;
 import com.android.launcher3.pm.PinRequestHelper;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.popup.ArrowPopup;
@@ -1291,6 +1294,16 @@
         mAllAppsController.setupViews(mScrimView, mAppsView);
     }
 
+    @Override
+    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
+        if (SHOW_DELIGHTFUL_PAGINATION.get()
+                && WorkspacePageIndicator.class.getName().equals(name)) {
+            return LayoutInflater.from(context).inflate(R.layout.page_indicator_dots,
+                    (ViewGroup) parent, false);
+        }
+        return super.onCreateView(parent, name, context, attrs);
+    }
+
     /**
      * Creates a view representing a shortcut.
      *
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index b858d1a..4e80d41 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -218,4 +218,32 @@
             }
         };
     }
+
+    /**
+     * A property that updates the specified property within a given range of values (ie. even if
+     * the animator goes beyond 0..1, the interpolated value will still be bounded).
+     * @param <T> the specified property
+     */
+    public static class ClampedProperty<T> extends FloatProperty<T> {
+        private final FloatProperty<T> mProperty;
+        private final float mMinValue;
+        private final float mMaxValue;
+
+        public ClampedProperty(FloatProperty<T> property, float minValue, float maxValue) {
+            super(property.getName() + "Clamped");
+            mProperty = property;
+            mMinValue = minValue;
+            mMaxValue = maxValue;
+        }
+
+        @Override
+        public void setValue(T t, float v) {
+            mProperty.set(t, Utilities.boundToRange(v, mMinValue, mMaxValue));
+        }
+
+        @Override
+        public Float get(T t) {
+            return mProperty.get(t);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 66195f3..4c8f2d9 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -94,15 +94,11 @@
          */
         public static final int ITEM_TYPE_DEEP_SHORTCUT = 6;
 
-        /**
-         * The favroite is a search action
-         */
-        public static final int ITEM_TYPE_SEARCH_ACTION = 7;
 
+        // *** Below enum values are used for metrics purpose but not used in Favorites DB ***
 
         /**
          * Type of the item is recents task.
-         * TODO(hyunyoungs): move constants not related to Favorites DB to a better location.
          */
         public static final int ITEM_TYPE_TASK = 7;
 
@@ -112,6 +108,11 @@
         public static final int ITEM_TYPE_QSB = 8;
 
         /**
+         * The favorite is a search action
+         */
+        public static final int ITEM_TYPE_SEARCH_ACTION = 9;
+
+        /**
          * The icon package name in Intent.ShortcutIconResource
          * <P>Type: TEXT</P>
          */
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 6aff83e..dd70ad0 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -53,12 +53,14 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
+import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.FrameLayout;
 import android.widget.Toast;
 
 import androidx.annotation.Nullable;
@@ -107,7 +109,6 @@
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.WallpaperOffsetInterpolator;
-import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.widget.LauncherAppWidgetHost;
 import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListener;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -326,6 +327,26 @@
 
         updateCellLayoutPadding();
         updateWorkspaceWidgetsSizes();
+        setPageIndicatorInset();
+    }
+
+    private void setPageIndicatorInset() {
+        DeviceProfile grid = mLauncher.getDeviceProfile();
+
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mPageIndicator.getLayoutParams();
+
+        // Set insets for page indicator
+        Rect padding = grid.workspacePadding;
+        if (grid.isVerticalBarLayout()) {
+            lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx;
+            lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx;
+            lp.bottomMargin = padding.bottom;
+        } else {
+            lp.leftMargin = lp.rightMargin = 0;
+            lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+            lp.bottomMargin = grid.hotseatBarSizePx;
+        }
+        mPageIndicator.setLayoutParams(lp);
     }
 
     private void updateCellLayoutPadding() {
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 21a7dfb..0efa7c4 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -17,7 +17,11 @@
 
 import static android.view.View.MeasureSpec.UNSPECIFIED;
 
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED;
+import static com.android.launcher3.logger.LauncherAtom.ContainerInfo;
+import static com.android.launcher3.logger.LauncherAtom.SearchResultContainer;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED_DOWN;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED_UNKNOWN_DIRECTION;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED_UP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END;
 import static com.android.launcher3.util.LogConfig.SEARCH_LOGGING;
@@ -31,6 +35,7 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.ExtendedEditText;
 import com.android.launcher3.FastScrollRecyclerView;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
@@ -56,6 +61,7 @@
     private final SparseIntArray mViewHeights = new SparseIntArray();
     private final SparseIntArray mCachedScrollPositions = new SparseIntArray();
     private final AllAppsFastScrollHelper mFastScrollHelper;
+    private int mCumulativeVerticalScroll;
 
 
     private final AdapterDataObserver mObserver = new RecyclerView.AdapterDataObserver() {
@@ -157,7 +163,7 @@
         StatsLogManager mgr = ActivityContext.lookupContext(getContext()).getStatsLogManager();
         switch (state) {
             case SCROLL_STATE_DRAGGING:
-                mgr.logger().log(LAUNCHER_ALLAPPS_SCROLLED);
+                mCumulativeVerticalScroll = 0;
                 requestFocus();
                 mgr.logger().sendToInteractionJankMonitor(
                         LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN, this);
@@ -166,10 +172,17 @@
             case SCROLL_STATE_IDLE:
                 mgr.logger().sendToInteractionJankMonitor(
                         LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END, this);
+                logCumulativeVerticalScroll();
                 break;
         }
     }
 
+    @Override
+    public void onScrolled(int dx, int dy) {
+        super.onScrolled(dx, dy);
+        mCumulativeVerticalScroll += dy;
+    }
+
     /**
      * Maps the touch (from 0..1) to the adapter position that should be visible.
      */
@@ -349,4 +362,21 @@
     public boolean hasOverlappingRendering() {
         return false;
     }
+
+    private void logCumulativeVerticalScroll() {
+        ActivityContext context = ActivityContext.lookupContext(getContext());
+        StatsLogManager mgr = context.getStatsLogManager();
+        ExtendedEditText editText = context.getAppsView().getSearchUiManager().getEditText();
+        ContainerInfo containerInfo = ContainerInfo.newBuilder().setSearchResultContainer(
+                SearchResultContainer
+                        .newBuilder()
+                        .setQueryLength((editText == null) ? -1 : editText.length())).build();
+
+        // mCumulativeVerticalScroll == 0 when user comes back to original position, we don't
+        // know the direction of scrolling.
+        mgr.logger().withContainerInfo(containerInfo).log(
+                mCumulativeVerticalScroll == 0 ? LAUNCHER_ALLAPPS_SCROLLED_UNKNOWN_DIRECTION
+                        : (mCumulativeVerticalScroll > 0) ? LAUNCHER_ALLAPPS_SCROLLED_DOWN
+                                : LAUNCHER_ALLAPPS_SCROLLED_UP);
+    }
 }
diff --git a/src/com/android/launcher3/allapps/SearchTransitionController.java b/src/com/android/launcher3/allapps/SearchTransitionController.java
index bde4fa6..9c3dab4 100644
--- a/src/com/android/launcher3/allapps/SearchTransitionController.java
+++ b/src/com/android/launcher3/allapps/SearchTransitionController.java
@@ -170,12 +170,13 @@
     /**
      * Updates the children views of SearchRecyclerView based on the current animation progress.
      *
-     * @return the total height of animating views (excluding any app icons).
+     * @return the total height of animating views (excluding at most one row of app icons).
      */
     private int updateSearchRecyclerViewProgress() {
         int numSearchResultsAnimated = 0;
         int totalHeight = 0;
         int appRowHeight = 0;
+        boolean appRowComplete = false;
         Integer top = null;
         SearchRecyclerView searchRecyclerView = getSearchRecyclerView();
 
@@ -189,67 +190,72 @@
                 top = searchResultView.getTop();
             }
 
-            if (searchResultView instanceof BubbleTextView
-                    && searchResultView.getTag() instanceof ItemInfo
-                    && ((ItemInfo) searchResultView.getTag()).itemType == ITEM_TYPE_APPLICATION) {
-                // The first app icon will set appRowHeight, which will also contribute to
-                // totalHeight. Additional app icons should remove the appRowHeight to remain in
-                // the same row as the first app.
-                searchResultView.setY(top + totalHeight - appRowHeight);
-                if (appRowHeight == 0) {
-                    appRowHeight = searchResultView.getHeight();
-                    totalHeight += appRowHeight;
-                }
-                // Don't scale/fade app row.
-                searchResultView.setScaleY(1);
-                searchResultView.setAlpha(1);
-                continue;
-            }
-
-            // Adjust content alpha based on start progress and stagger.
-            float startContentFadeProgress = Math.max(0,
-                    TOP_CONTENT_FADE_PROGRESS_START - CONTENT_STAGGER * numSearchResultsAnimated);
-            float endContentFadeProgress = Math.min(1,
-                    startContentFadeProgress + CONTENT_FADE_PROGRESS_DURATION);
-            searchResultView.setAlpha(1 - clampToProgress(mSearchToAzProgress,
-                    startContentFadeProgress, endContentFadeProgress));
-
-            // Adjust background (or decorator) alpha based on start progress and stagger.
-            float startBackgroundFadeProgress = Math.max(0,
-                    TOP_BACKGROUND_FADE_PROGRESS_START
-                            - CONTENT_STAGGER * numSearchResultsAnimated);
-            float endBackgroundFadeProgress = Math.min(1,
-                    startBackgroundFadeProgress + BACKGROUND_FADE_PROGRESS_DURATION);
-            float backgroundAlpha = 1 - clampToProgress(mSearchToAzProgress,
-                    startBackgroundFadeProgress, endBackgroundFadeProgress);
             int adapterPosition = searchRecyclerView.getChildAdapterPosition(searchResultView);
-            boolean decoratorFilled =
-                    adapterPosition != NO_POSITION
-                            && searchRecyclerView.getApps().getAdapterItems().get(adapterPosition)
-                            .setDecorationFillAlpha((int) (255 * backgroundAlpha));
-            if (!decoratorFilled) {
-                // Try to adjust background alpha instead (e.g. for Search Edu card).
-                Drawable background = searchResultView.getBackground();
-                if (background != null) {
-                    background.setAlpha((int) (255 * backgroundAlpha));
+            int spanIndex = getSpanIndex(searchRecyclerView, adapterPosition);
+            appRowComplete |= appRowHeight > 0 && spanIndex == 0;
+            // We don't animate the first (currently only) app row we see, as that is assumed to be
+            // predicted/prefix-matched apps.
+            boolean shouldAnimate = !isAppIcon(searchResultView) || appRowComplete;
+
+            float contentAlpha = 1f;
+            float backgroundAlpha = 1f;
+            if (shouldAnimate) {
+                if (spanIndex > 0) {
+                    // Animate this item with the previous item on the same row.
+                    numSearchResultsAnimated--;
                 }
+
+                // Adjust content alpha based on start progress and stagger.
+                float startContentFadeProgress = Math.max(0,
+                        TOP_CONTENT_FADE_PROGRESS_START
+                                - CONTENT_STAGGER * numSearchResultsAnimated);
+                float endContentFadeProgress = Math.min(1,
+                        startContentFadeProgress + CONTENT_FADE_PROGRESS_DURATION);
+                contentAlpha = 1 - clampToProgress(mSearchToAzProgress,
+                        startContentFadeProgress, endContentFadeProgress);
+
+                // Adjust background (or decorator) alpha based on start progress and stagger.
+                float startBackgroundFadeProgress = Math.max(0,
+                        TOP_BACKGROUND_FADE_PROGRESS_START
+                                - CONTENT_STAGGER * numSearchResultsAnimated);
+                float endBackgroundFadeProgress = Math.min(1,
+                        startBackgroundFadeProgress + BACKGROUND_FADE_PROGRESS_DURATION);
+                backgroundAlpha = 1 - clampToProgress(mSearchToAzProgress,
+                        startBackgroundFadeProgress, endBackgroundFadeProgress);
+
+                numSearchResultsAnimated++;
+            }
+            searchResultView.setAlpha(contentAlpha);
+            // Apply background alpha to decorator if possible.
+            if (adapterPosition != NO_POSITION) {
+                searchRecyclerView.getApps().getAdapterItems()
+                        .get(adapterPosition).setDecorationFillAlpha((int) (255 * backgroundAlpha));
+            }
+            // Apply background alpha to view's background (e.g. for Search Edu card).
+            Drawable background = searchResultView.getBackground();
+            if (background != null) {
+                background.setAlpha((int) (255 * backgroundAlpha));
             }
 
-            float scaleY = 1 - mSearchToAzProgress;
+            float scaleY = 1;
+            if (shouldAnimate) {
+                scaleY = 1 - mSearchToAzProgress;
+            }
             int scaledHeight = (int) (searchResultView.getHeight() * scaleY);
             searchResultView.setScaleY(scaleY);
 
             // For rows with multiple elements, only count the height once and translate elements to
             // the same y position.
             int y = top + totalHeight;
-            int spanIndex = getSpanIndex(searchRecyclerView, adapterPosition);
             if (spanIndex > 0) {
                 // Continuation of an existing row; move this item into the row.
                 y -= scaledHeight;
             } else {
-                // Start of a new row contributes to total height and animation stagger.
-                numSearchResultsAnimated++;
+                // Start of a new row contributes to total height.
                 totalHeight += scaledHeight;
+                if (!shouldAnimate) {
+                    appRowHeight = scaledHeight;
+                }
             }
             searchResultView.setY(y);
         }
@@ -275,6 +281,11 @@
         return adapter.getSpanIndex(adapterPosition);
     }
 
+    private boolean isAppIcon(View item) {
+        return item instanceof BubbleTextView && item.getTag() instanceof ItemInfo
+                && ((ItemInfo) item.getTag()).itemType == ITEM_TYPE_APPLICATION;
+    }
+
     /** Called just before a child is attached to the SearchRecyclerView. */
     private void onSearchChildAttached(View child) {
         // Avoid allocating hardware layers for alpha changes.
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 3a530af..a8d1367 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -283,13 +283,12 @@
             "In foldables, when reordering the icons and widgets, is now going to use both sides");
 
     public static final BooleanFlag ENABLE_WIDGET_PICKER_DEPTH = new DeviceFlag(
-            "ENABLE_WIDGET_PICKER_DEPTH", false, "Enable changing depth in widget picker.");
+            "ENABLE_WIDGET_PICKER_DEPTH", true, "Enable changing depth in widget picker.");
 
-    public static final BooleanFlag SHOW_DELIGHTFUL_PAGINATION_FOLDER = new DeviceFlag(
-            "SHOW_DELIGHTFUL_PAGINATION_FOLDER", false,
-            "Enable showing the new 'delightful pagination'"
-                    + " which is a brand new animation for folder pagination");
-
+    public static final BooleanFlag SHOW_DELIGHTFUL_PAGINATION = new DeviceFlag(
+            "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");
 
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 22627b4..837e47a 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -555,6 +555,20 @@
                 + "result page etc.")
         LAUNCHER_ALLAPPS_SCROLLED(985),
 
+        @UiEvent(doc = "User scrolled up on one of the all apps surfaces such as A-Z list, search "
+                + "result page etc.")
+        LAUNCHER_ALLAPPS_SCROLLED_UP(1229),
+
+        @UiEvent(doc =
+                "User scrolled down on one of the all apps surfaces such as A-Z list, search "
+                        + "result page etc.")
+        LAUNCHER_ALLAPPS_SCROLLED_DOWN(1230),
+
+        @UiEvent(doc = "User scrolled on one of the all apps surfaces such as A-Z list, search "
+                + "result page etc and we don't know the direction since user came back to "
+                + "original position from which they scrolled.")
+        LAUNCHER_ALLAPPS_SCROLLED_UNKNOWN_DIRECTION(1231),
+
         @UiEvent(doc = "User tapped taskbar home button")
         LAUNCHER_TASKBAR_HOME_BUTTON_TAP(1003),
 
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index a8e9eb5..159af60 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -39,8 +39,10 @@
 import android.content.ComponentName;
 import android.content.ContentValues;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Process;
 import android.os.UserHandle;
+import android.provider.Settings;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -61,6 +63,7 @@
 import com.android.launcher3.logger.LauncherAtomExtensions.ExtendedContainers;
 import com.android.launcher3.model.ModelWriter;
 import com.android.launcher3.util.ContentWriter;
+import com.android.launcher3.util.SettingsCache;
 
 import java.util.Optional;
 
@@ -74,6 +77,9 @@
     // An id that doesn't match any item, including predicted apps with have an id=NO_ID
     public static final int NO_MATCHING_ID = Integer.MIN_VALUE;
 
+    /** Hidden field Settings.Secure.NAV_BAR_KIDS_MODE */
+    private static final Uri NAV_BAR_KIDS_MODE = Settings.Secure.getUriFor("nav_bar_kids_mode");
+
     /**
      * The id in the settings database for this item
      */
@@ -390,6 +396,9 @@
     protected LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
         LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
         itemBuilder.setIsWork(!Process.myUserHandle().equals(user));
+        SettingsCache settingsCache = SettingsCache.INSTANCE.getNoCreate();
+        boolean isKidsMode = settingsCache != null && settingsCache.getValue(NAV_BAR_KIDS_MODE, 0);
+        itemBuilder.setIsKidsMode(isKidsMode);
         itemBuilder.setRank(rank);
         return itemBuilder;
     }
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index b4cb0ee..98ce951 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -16,7 +16,7 @@
 
 package com.android.launcher3.pageindicators;
 
-import static com.android.launcher3.config.FeatureFlags.SHOW_DELIGHTFUL_PAGINATION_FOLDER;
+import static com.android.launcher3.config.FeatureFlags.SHOW_DELIGHTFUL_PAGINATION;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -29,6 +29,7 @@
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
+import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
@@ -38,6 +39,7 @@
 import android.view.animation.Interpolator;
 import android.view.animation.OvershootInterpolator;
 
+import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.Interpolators;
@@ -47,7 +49,7 @@
  * {@link PageIndicator} which shows dots per page. The active page is shown with the current
  * accent color.
  */
-public class PageIndicatorDots extends View implements PageIndicator {
+public class PageIndicatorDots extends View implements Insettable, PageIndicator {
 
     private static final float SHIFT_PER_ANIMATION = 0.5f;
     private static final float SHIFT_THRESHOLD = 0.1f;
@@ -128,8 +130,7 @@
         mPaginationPaint.setColor(Themes.getAttrColor(context, R.attr.folderPaginationColor));
         mDotRadius = getResources().getDimension(R.dimen.page_indicator_dot_size) / 2;
 
-
-        if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) {
+        if (SHOW_DELIGHTFUL_PAGINATION.get()) {
             mPageIndicatorSize = getResources().getDimension(
                     R.dimen.page_indicator_size);
             mPageIndicatorRadius = mPageIndicatorSize / 2;
@@ -144,7 +145,7 @@
             mPageIndicatorDrawable = null;
             mCircleGap = DOT_GAP_FACTOR * mDotRadius;
         }
-        if (!SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) {
+        if (!SHOW_DELIGHTFUL_PAGINATION.get()) {
             setOutlineProvider(new MyOutlineProver());
         }
         mIsRtl = Utilities.isRtl(getResources());
@@ -161,7 +162,7 @@
             currentScroll = totalScroll - currentScroll;
         }
 
-        if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) {
+        if (SHOW_DELIGHTFUL_PAGINATION.get()) {
             mCurrentScroll = currentScroll;
             mTotalScroll = totalScroll;
             invalidate();
@@ -296,7 +297,7 @@
             }
             for (int i = 0; i < mEntryAnimationRadiusFactors.length; i++) {
                 mPaginationPaint.setAlpha(i == mActivePage ? PAGE_INDICATOR_ALPHA : DOT_ALPHA);
-                if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) {
+                if (SHOW_DELIGHTFUL_PAGINATION.get()) {
                     if (i != mActivePage) {
                         canvas.drawCircle(x, y, mDotRadius * mEntryAnimationRadiusFactors[i],
                                 mPaginationPaint);
@@ -313,7 +314,7 @@
             // Here we draw the dots
             mPaginationPaint.setAlpha(DOT_ALPHA);
             for (int i = 0; i < mNumPages; i++) {
-                if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) {
+                if (SHOW_DELIGHTFUL_PAGINATION.get()) {
                     canvas.drawCircle(x, y, getRadius(x), mPaginationPaint);
                 } else {
                     canvas.drawCircle(x, y, mDotRadius, mPaginationPaint);
@@ -323,7 +324,7 @@
 
             // Here we draw the current page indicator
             mPaginationPaint.setAlpha(PAGE_INDICATOR_ALPHA);
-            if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) {
+            if (SHOW_DELIGHTFUL_PAGINATION.get()) {
                 drawPageIndicator(canvas, 1);
             } else {
                 canvas.drawRoundRect(getActiveRect(), mDotRadius, mDotRadius, mPaginationPaint);
@@ -389,7 +390,7 @@
         float diameter = 2 * mDotRadius;
         float startX;
 
-        if (SHOW_DELIGHTFUL_PAGINATION_FOLDER.get()) {
+        if (SHOW_DELIGHTFUL_PAGINATION.get()) {
             startX = ((getWidth() - (mNumPages * mCircleGap) + mDotRadius) / 2) - getOffset();
             sTempRect.top = (getHeight() - mPageIndicatorSize) * 0.5f;
             sTempRect.bottom = (getHeight() + mPageIndicatorSize) * 0.5f;
@@ -483,4 +484,12 @@
             }
         }
     }
+
+    /**
+     * We need to override setInsets to prevent InsettableFrameLayout from applying different
+     * margins on the pagination.
+     */
+    @Override
+    public void setInsets(Rect insets) {
+    }
 }
diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
index 87ae890..bde4e52 100644
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
@@ -14,12 +14,9 @@
 import android.os.Looper;
 import android.util.AttributeSet;
 import android.util.Property;
-import android.view.Gravity;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.widget.FrameLayout;
 
-import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
@@ -258,21 +255,11 @@
         }
     }
 
+    /**
+     * We need to override setInsets to prevent InsettableFrameLayout from applying different
+     * margins on the page indicator.
+     */
     @Override
     public void setInsets(Rect insets) {
-        DeviceProfile grid = mLauncher.getDeviceProfile();
-        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
-
-        if (grid.isVerticalBarLayout()) {
-            Rect padding = grid.workspacePadding;
-            lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx;
-            lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx;
-            lp.bottomMargin = padding.bottom;
-        } else {
-            lp.leftMargin = lp.rightMargin = 0;
-            lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
-            lp.bottomMargin = grid.hotseatBarSizePx;
-        }
-        setLayoutParams(lp);
     }
 }
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 3286afb..f5d511c 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.states;
 
+import static com.android.launcher3.config.FeatureFlags.SHOW_HOME_GARDENING;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
 
 import android.content.Context;
@@ -44,6 +45,11 @@
 
     @Override
     public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
+
+        if (SHOW_HOME_GARDENING.get()) {
+            return super.getWorkspaceScaleAndTranslation(launcher);
+        }
+
         DeviceProfile grid = launcher.getDeviceProfile();
         Workspace<?> ws = launcher.getWorkspace();
         if (ws.getChildCount() == 0) {
@@ -62,6 +68,9 @@
 
     @Override
     protected float getDepthUnchecked(Context context) {
+        if (SHOW_HOME_GARDENING.get()) {
+            return 0;
+        }
         return 0.5f;
     }
 
@@ -72,6 +81,10 @@
 
     @Override
     public float getWorkspaceBackgroundAlpha(Launcher launcher) {
+        if (SHOW_HOME_GARDENING.get()) {
+            return 0;
+        }
+
         return 0.2f;
     }
 }
diff --git a/src/com/android/launcher3/util/MultiPropertyFactory.java b/src/com/android/launcher3/util/MultiPropertyFactory.java
index e7a7785..43daf08 100644
--- a/src/com/android/launcher3/util/MultiPropertyFactory.java
+++ b/src/com/android/launcher3/util/MultiPropertyFactory.java
@@ -107,12 +107,9 @@
 
         @Override
         public Float get(T object) {
-            // The scale of the view should match mLastAggregatedValue. Still, if it has been
-            // changed without using this property, it can differ. As this get method is usually
-            // used to set the starting point on an animation, this would result in some jumps
-            // when the view scale is different than the last aggregated value. To stay on the
-            // safe side, let's return the real view scale.
-            return mProperty.get(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.
+            return mValue;
         }
 
         @Override