Merge "Adding support for customize highlight region in preference" into sc-dev
diff --git a/Android.bp b/Android.bp
index e30d22f..df0a96f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -211,3 +211,30 @@
     name: "launcher-proguard-rules",
     srcs: ["proguard.flags"],
 }
+
+
+// Library with all the dependencies for building Launcher Go
+android_library {
+    name: "LauncherGoResLib",
+    srcs: [
+        "src/**/*.java",
+        "quickstep/src/**/*.java",
+        "go/src/**/*.java",
+        "go/quickstep/src/**/*.java",
+    ],
+    resource_dirs: [
+        "go/res",
+        "go/quickstep/res",
+    ],
+    static_libs: [
+        "Launcher3CommonDepsLib",
+        "QuickstepResLib",
+    ],
+    manifest: "quickstep/AndroidManifest-launcher.xml",
+    additional_manifests: [
+        "go/AndroidManifest.xml",
+        "AndroidManifest-common.xml",
+    ],
+    min_sdk_version: "29",
+}
+
diff --git a/quickstep/res/layout/scrim_view.xml b/quickstep/res/layout/scrim_view.xml
deleted file mode 100644
index 3f2daf1..0000000
--- a/quickstep/res/layout/scrim_view.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.quickstep.views.AllAppsScrimView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:id="@+id/scrim_view" />
\ No newline at end of file
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 1603321..2a06830 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -59,7 +59,7 @@
     <string name="all_apps_prediction_tip">Your predicted apps</string>
 
     <!-- Content description for a close button. [CHAR LIMIT=NONE] -->
-    <string  name="gesture_tutorial_close_button_content_description" translatable="false">Close</string>
+    <string name="gesture_tutorial_close_button_content_description" translatable="false">Close</string>
 
     <!-- Hotseat educational strings for users who don't qualify for migration -->
     <string name="hotseat_edu_title_migrate">Get app suggestions on the bottom row of your Home screen</string>
@@ -91,14 +91,6 @@
     <!-- content description for hotseat items -->
     <string name="hotseat_prediction_content_description">Predicted app: <xliff:g id="title" example="Chrome">%1$s</xliff:g></string>
 
-    <!-- primary educational text shown for first time search users -->
-    <string name="search_edu_primary">Search your phone for apps, people, settings and more!</string>
-    <!-- secondary educational text shown for first time search users -->
-    <string name="search_edu_secondary">Tap keyboard search button to launch the first search
-        result.</string>
-
-    <!-- Dismiss button string for search education view -->
-    <string name="search_edu_dismiss">Got it.</string>
     <!-- Feedback shown during interactive parts of Back gesture tutorial for left edge when the gesture is too far from the edge. [CHAR LIMIT=100] -->
     <string name="back_gesture_feedback_swipe_too_far_from_left_edge">Make sure you swipe from the far-left edge.</string>
     <!-- Feedback shown during interactive parts of Back gesture tutorial for left edge when the gesture is cancelled. [CHAR LIMIT=100] -->
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
index eca27b5..e771962 100644
--- a/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
@@ -247,10 +247,7 @@
     }
 
     @Test
-    @Ignore("There's too much that goes into needing to mock a real motion event so the "
-            + "transforms in native code get applied correctly. Once that happens then maybe we can"
-            + " write slightly more complex unit tests")
-    public void applyTransform_taskNotFrozen_90Rotate_inTwoRegions() {
+    public void applyTransform_taskNotFrozen_90Rotate_withTwoRegions() {
         mTouchTransformer.createOrAddTouchRegion(mInfo);
         mTouchTransformer.enableMultipleRegions(true, mInfo);
         mTouchTransformer
@@ -262,6 +259,7 @@
         // Portrait point in landscape orientation axis
         MotionEvent inRegion2 = generateMotionEvent(MotionEvent.ACTION_DOWN, 10, 10);
         mTouchTransformer.transform(inRegion1_down);
+        // no-op
         mTouchTransformer.transform(inRegion2);
         assertTrue(mTouchTransformer.touchInValidSwipeRegions(
                 inRegion1_down.getX(), inRegion1_down.getY()));
@@ -269,9 +267,19 @@
         assertFalse(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
 
         mTouchTransformer.transform(inRegion1_up);
+    }
 
-        // Set the new region with this MotionEvent.ACTION_DOWN
-        inRegion2 = generateAndTransformMotionEvent(MotionEvent.ACTION_DOWN, 10, 370);
+    @Test
+    public void applyTransform_90Rotate_inRotatedRegion() {
+        // Create regions for both 0 Rotation and 90 Rotation
+        mTouchTransformer.createOrAddTouchRegion(mInfo);
+        mTouchTransformer.enableMultipleRegions(true, mInfo);
+        mTouchTransformer
+                .createOrAddTouchRegion(createDisplayInfo(NORMAL_SCREEN_SIZE, Surface.ROTATION_90));
+        // Portrait point in landscape orientation axis
+        float x1 = generateTouchRegionHeight(NORMAL_SCREEN_SIZE, Surface.ROTATION_0);
+        // bottom of screen, from landscape perspective right side of screen
+        MotionEvent inRegion2 = generateAndTransformMotionEvent(MotionEvent.ACTION_DOWN, x1, 370);
         assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
     }
 
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index e9ded8a..4415b51 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -219,7 +219,7 @@
         mSplitPlaceholderView = findViewById(R.id.split_placeholder);
         RecentsView overviewPanel = (RecentsView) getOverviewPanel();
         mSplitPlaceholderView.init(
-                new SplitSelectStateController(SystemUiProxy.INSTANCE.get(this))
+                new SplitSelectStateController(mHandler, SystemUiProxy.INSTANCE.get(this))
         );
         overviewPanel.init(mActionsView, mSplitPlaceholderView);
         mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 82a83fc..009ca27 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -61,6 +61,8 @@
 import android.os.SystemProperties;
 import android.util.Pair;
 import android.view.View;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -137,6 +139,15 @@
     private static final long APP_LAUNCH_ALPHA_DOWN_DURATION =
             (long) (APP_LAUNCH_ALPHA_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
 
+    public static final int ANIMATION_NAV_FADE_IN_DURATION = 266;
+    public static final int ANIMATION_NAV_FADE_OUT_DURATION = 133;
+    public static final long ANIMATION_DELAY_NAV_FADE_IN =
+            APP_LAUNCH_DURATION - ANIMATION_NAV_FADE_IN_DURATION;
+    public static final Interpolator NAV_FADE_IN_INTERPOLATOR =
+            new PathInterpolator(0f, 0f, 0f, 1f);
+    public static final Interpolator NAV_FADE_OUT_INTERPOLATOR =
+            new PathInterpolator(0.2f, 0f, 1f, 1f);
+
     private static final long CROP_DURATION = 375;
     private static final long RADIUS_DURATION = 375;
 
@@ -276,10 +287,11 @@
      */
     protected void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
             @NonNull RemoteAnimationTargetCompat[] appTargets,
-            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing) {
+            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
+            @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing) {
         TaskViewUtils.composeRecentsLaunchAnimator(anim, v, appTargets, wallpaperTargets,
-                launcherClosing, mLauncher.getStateManager(), mLauncher.getOverviewPanel(),
-                mLauncher.getDepthController());
+                nonAppTargets, launcherClosing, mLauncher.getStateManager(),
+                mLauncher.getOverviewPanel(), mLauncher.getDepthController());
     }
 
     private boolean areAllTargetsTranslucent(@NonNull RemoteAnimationTargetCompat[] targets) {
@@ -305,6 +317,7 @@
     private void composeIconLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
             @NonNull RemoteAnimationTargetCompat[] appTargets,
             @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
+            @NonNull RemoteAnimationTargetCompat[] nonAppTargets,
             boolean launcherClosing) {
         // Set the state animation first so that any state listeners are called
         // before our internal listeners.
@@ -313,8 +326,8 @@
         final int rotationChange = getRotationChange(appTargets);
         // Note: the targetBounds are relative to the launcher
         Rect windowTargetBounds = getWindowTargetBounds(appTargets, rotationChange);
-        anim.play(getOpeningWindowAnimators(v, appTargets, wallpaperTargets, windowTargetBounds,
-                areAllTargetsTranslucent(appTargets), rotationChange));
+        anim.play(getOpeningWindowAnimators(v, appTargets, wallpaperTargets, nonAppTargets,
+                windowTargetBounds, areAllTargetsTranslucent(appTargets), rotationChange));
         if (launcherClosing) {
             Pair<AnimatorSet, Runnable> launcherContentAnimator =
                     getLauncherContentAnimator(true /* isAppOpening */,
@@ -515,6 +528,7 @@
     private Animator getOpeningWindowAnimators(View v,
             RemoteAnimationTargetCompat[] appTargets,
             RemoteAnimationTargetCompat[] wallpaperTargets,
+            RemoteAnimationTargetCompat[] nonAppTargets,
             Rect windowTargetBounds, boolean appTargetsAreTranslucent, int rotationChange) {
         RectF launcherIconBounds = new RectF();
         FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v,
@@ -523,10 +537,11 @@
         Matrix matrix = new Matrix();
 
         RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets,
-                wallpaperTargets, MODE_OPENING);
+                wallpaperTargets, nonAppTargets, MODE_OPENING);
         SurfaceTransactionApplier surfaceApplier =
                 new SurfaceTransactionApplier(floatingView);
         openingTargets.addReleaseCheck(surfaceApplier);
+        RemoteAnimationTargetCompat navBarTarget = openingTargets.getNavBarRemoteAnimationTarget();
 
         int[] dragLayerBounds = new int[2];
         mDragLayer.getLocationOnScreen(dragLayerBounds);
@@ -601,6 +616,11 @@
             FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, 0,
                     CROP_DURATION, EXAGGERATED_EASE);
 
+            FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
+                    NAV_FADE_OUT_INTERPOLATOR);
+            FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
+                    ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
+
             @Override
             public void onUpdate(float percent) {
                 // Calculate the size of the scaled icon.
@@ -706,6 +726,21 @@
                     params[i] = builder.build();
                 }
                 surfaceApplier.scheduleApply(params);
+
+                if (navBarTarget != null) {
+                    final SurfaceParams.Builder navBuilder =
+                            new SurfaceParams.Builder(navBarTarget.leash);
+                    if (mNavFadeIn.value > mNavFadeIn.getStartValue()) {
+                        matrix.setScale(scale, scale);
+                        matrix.postTranslate(windowTransX0, windowTransY0);
+                        navBuilder.withMatrix(matrix)
+                                .withWindowCrop(crop)
+                                .withAlpha(mNavFadeIn.value);
+                    } else {
+                        navBuilder.withAlpha(mNavFadeOut.value);
+                    }
+                    surfaceApplier.scheduleApply(navBuilder.build());
+                }
             }
         });
 
@@ -1088,19 +1123,18 @@
                 RemoteAnimationTargetCompat[] nonAppTargets,
                 LauncherAnimationRunner.AnimationResult result) {
             AnimatorSet anim = new AnimatorSet();
-
             boolean launcherClosing =
                     launcherIsATargetWithMode(appTargets, MODE_CLOSING);
 
             final boolean launchingFromRecents = isLaunchingFromRecents(mV, appTargets);
             final boolean launchingFromTaskbar = mLauncher.isViewInTaskbar(mV);
             if (launchingFromRecents) {
-                composeRecentsLaunchAnimator(anim, mV, appTargets, wallpaperTargets,
+                composeRecentsLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
                         launcherClosing);
             } else if (launchingFromTaskbar) {
                 // TODO
             } else {
-                composeIconLaunchAnimator(anim, mV, appTargets, wallpaperTargets,
+                composeIconLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
                         launcherClosing);
             }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index a3a1fef..01616d4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -18,12 +18,9 @@
 
 import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.graphics.OverviewScrim.SCRIM_MULTIPLIER;
-import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
@@ -40,7 +37,6 @@
 import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.graphics.OverviewScrim;
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.touch.PagedOrientationHandler;
@@ -70,9 +66,6 @@
         TASK_SECONDARY_TRANSLATION.set(mRecentsView, 0f);
 
         getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
-        OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
-        SCRIM_PROGRESS.set(scrim, state.getOverviewScrimAlpha(mLauncher));
-        SCRIM_MULTIPLIER.set(scrim, 1f);
         getTaskModalnessProperty().set(mRecentsView, state.getOverviewModalness());
         RECENTS_GRID_PROGRESS.set(mRecentsView,
                 state.displayOverviewTasksAsGrid(mLauncher.getDeviceProfile()) ? 1f : 0f);
@@ -111,16 +104,6 @@
 
         setter.setFloat(mRecentsView, getContentAlphaProperty(), toState.overviewUi ? 1 : 0,
                 config.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT));
-        OverviewScrim scrim = mLauncher.getDragLayer().getOverviewScrim();
-        setter.setFloat(scrim, SCRIM_PROGRESS, toState.getOverviewScrimAlpha(mLauncher),
-                config.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
-        setter.setFloat(scrim, SCRIM_MULTIPLIER, 1f,
-                config.getInterpolator(ANIM_OVERVIEW_SCRIM_FADE, LINEAR));
-        if (toState.areElementsVisible(mLauncher, LauncherState.SPLIT_PLACHOLDER_VIEW)) {
-            scrim.updateStableScrimmedView(mLauncher.getSplitPlaceholderView());
-        } else {
-            scrim.updateStableScrimmedView(mLauncher.getOverviewPanel());
-        }
 
         setter.setFloat(
                 mRecentsView, getTaskModalnessProperty(),
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index b2f8a40..4e03971 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -90,4 +90,9 @@
     public LauncherState getHistoryForState(LauncherState previousState) {
         return previousState == OVERVIEW ? OVERVIEW : NORMAL;
     }
+
+    @Override
+    public float getWorkspaceScrimAlpha(Launcher launcher) {
+        return 1;
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 95a855a..6cdeb0f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -103,7 +103,7 @@
     }
 
     @Override
-    public float getOverviewScrimAlpha(Launcher launcher) {
+    public float getWorkspaceScrimAlpha(Launcher launcher) {
         return 1f;
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index a990f3e..b8caf81 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -44,7 +44,6 @@
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.graphics.OverviewScrim;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
 import com.android.launcher3.util.TouchController;
@@ -141,10 +140,6 @@
             AnimatorControllerWithResistance.createRecentsResistanceFromOverviewAnim(mLauncher,
                     builder);
 
-            builder.setFloat(mLauncher.getDragLayer().getOverviewScrim(),
-                    OverviewScrim.SCRIM_MULTIPLIER, OVERVIEW_TO_HOME_SCRIM_MULTIPLIER,
-                    PULLBACK_INTERPOLATOR);
-
             if (LIVE_TILE.get()) {
                 builder.addOnFrameCallback(recentsView::redrawLiveTile);
             }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 65bbeea..74a253e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -16,6 +16,7 @@
 
 package com.android.launcher3.uioverrides.touchcontrollers;
 
+import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
 import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.HINT_STATE;
@@ -45,7 +46,6 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.graphics.OverviewScrim;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.util.VibratorWrapper;
 import com.android.quickstep.SystemUiProxy;
@@ -111,7 +111,7 @@
         float progressMultiplier = super.initCurrentAnimation();
         if (mToState == HINT_STATE) {
             // Track the drag across the entire height of the screen.
-            progressMultiplier = -1 / getShiftRange();
+            progressMultiplier = -1f / mLauncher.getDeviceProfile().heightPx;
         }
         return progressMultiplier;
     }
@@ -128,10 +128,10 @@
 
         if (mFromState == NORMAL && mToState == HINT_STATE) {
             mNormalToHintOverviewScrimAnimator = ObjectAnimator.ofFloat(
-                    mLauncher.getDragLayer().getOverviewScrim(),
-                    OverviewScrim.SCRIM_PROGRESS,
-                    mFromState.getOverviewScrimAlpha(mLauncher),
-                    mToState.getOverviewScrimAlpha(mLauncher));
+                    mLauncher.getScrimView(),
+                    VIEW_ALPHA,
+                    mFromState.getWorkspaceScrimAlpha(mLauncher),
+                    mToState.getWorkspaceScrimAlpha(mLauncher));
         }
         mStartedOverview = false;
         mReachedOverview = false;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 61cd13b..697516d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -15,6 +15,7 @@
  */
 package com.android.launcher3.uioverrides.touchcontrollers;
 
+import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
 import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -59,7 +60,6 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.graphics.OverviewScrim;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.touch.BaseSwipeDetector;
 import com.android.launcher3.touch.BothAxesSwipeDetector;
@@ -231,8 +231,8 @@
         //   - OverviewScrim
         PendingAnimation xAnim = new PendingAnimation((long) (mXRange * 2));
         xAnim.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1], LINEAR);
-        xAnim.setFloat(mLauncher.getDragLayer().getOverviewScrim(), OverviewScrim.SCRIM_PROGRESS,
-                toState.getOverviewScrimAlpha(mLauncher), LINEAR);
+        xAnim.setFloat(mLauncher.getScrimView(), VIEW_ALPHA,
+                toState.getWorkspaceScrimAlpha(mLauncher), LINEAR);
         mXOverviewAnim = xAnim.createPlaybackController();
         mXOverviewAnim.dispatchOnStart();
 
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 5a3e009..2a903eb 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -319,9 +319,9 @@
         mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
                 this::invalidateHandlerWithLauncher);
         mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_RESUME_LAST_TASK,
-                this::notifyTransitionCancelled);
+                this::resetStateForAnimationCancel);
         mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED | STATE_FINISH_WITH_NO_END,
-                this::notifyTransitionCancelled);
+                this::resetStateForAnimationCancel);
 
         if (!LIVE_TILE.get()) {
             mStateCallback.addChangeListener(STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_PRESENT
@@ -1383,10 +1383,6 @@
         mActivity.getRootView().setOnApplyWindowInsetsListener(null);
     }
 
-    private void notifyTransitionCancelled() {
-        mAnimationFactory.onTransitionCancelled();
-    }
-
     private void resetStateForAnimationCancel() {
         boolean wasVisible = mWasLauncherAlreadyVisible || mGestureStarted;
         mActivityInterface.onTransitionCancelled(wasVisible);
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index d810947..147297a 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -368,8 +368,6 @@
 
         void createActivityInterface(long transitionLength);
 
-        default void onTransitionCancelled() { }
-
         /**
          * @param attached Whether to show RecentsView alongside the app window. If false, recents
          *                 will be hidden by some property we can animate, e.g. alpha.
@@ -436,11 +434,6 @@
         }
 
         @Override
-        public void onTransitionCancelled() {
-            mActivity.getStateManager().goToState(mStartState, false /* animate */);
-        }
-
-        @Override
         public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
             if (mIsAttachedToWindow == attached && animate) {
                 return;
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index e13d1a4..8168e88 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -27,6 +27,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.quickstep.fallback.RecentsState;
 import com.android.quickstep.util.ActivityInitListener;
@@ -139,7 +140,25 @@
 
     @Override
     public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) {
-        // no-op, fake landscape not supported for 3P
+        final StateManager<RecentsState> stateManager = getCreatedActivity().getStateManager();
+        if (stateManager.getState() == HOME) {
+            exitRunnable.run();
+            notifyRecentsOfOrientation(deviceState);
+            return;
+        }
+
+        stateManager.addStateListener(
+                new StateManager.StateListener<RecentsState>() {
+                    @Override
+                    public void onStateTransitionComplete(RecentsState toState) {
+                        // Are we going from Recents to Workspace?
+                        if (toState == HOME) {
+                            exitRunnable.run();
+                            notifyRecentsOfOrientation(deviceState);
+                            stateManager.removeStateListener(this);
+                        }
+                    }
+                });
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 7e4a352..ec1cc4a 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -247,7 +247,8 @@
             if (appearedTaskTarget.activityType == ACTIVITY_TYPE_HOME) {
                 RemoteAnimationTargets targets = new RemoteAnimationTargets(
                         new RemoteAnimationTargetCompat[] {appearedTaskTarget},
-                        new RemoteAnimationTargetCompat[0], appearedTaskTarget.mode);
+                        new RemoteAnimationTargetCompat[0], new RemoteAnimationTargetCompat[0],
+                        appearedTaskTarget.mode);
                 mHomeAlphaParams.setTargetSet(targets);
                 updateHomeAlpha();
                 return true;
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index a749f9a..2a6e478 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -53,7 +53,7 @@
  */
 class OrientationTouchTransformer {
 
-    class CurrentDisplay {
+    private static class CurrentDisplay {
         public Point size;
         public int rotation;
 
@@ -68,6 +68,13 @@
         }
 
         @Override
+        public String toString() {
+            return "CurrentDisplay:"
+                    + " rotation: " + rotation
+                    + " size: " + size;
+        }
+
+        @Override
         public boolean equals(Object o) {
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
@@ -86,21 +93,20 @@
 
     private static final String TAG = "OrientationTouchTransformer";
     private static final boolean DEBUG = false;
-    private static final int MAX_ORIENTATIONS = 4;
 
     private static final int QUICKSTEP_ROTATION_UNINITIALIZED = -1;
 
     private final Matrix mTmpMatrix = new Matrix();
     private final float[] mTmpPoint = new float[2];
 
-    private Map<CurrentDisplay, OrientationRectF> mSwipeTouchRegions =
+    private final Map<CurrentDisplay, OrientationRectF> mSwipeTouchRegions =
             new HashMap<CurrentDisplay, OrientationRectF>();
     private final RectF mAssistantLeftRegion = new RectF();
     private final RectF mAssistantRightRegion = new RectF();
     private final RectF mOneHandedModeRegion = new RectF();
     private CurrentDisplay mCurrentDisplay = new CurrentDisplay();
     private int mNavBarGesturalHeight;
-    private int mNavBarLargerGesturalHeight;
+    private final int mNavBarLargerGesturalHeight;
     private boolean mEnableMultipleRegions;
     private Resources mResources;
     private OrientationRectF mLastRectTouched;
@@ -374,10 +380,7 @@
                     return;
                 }
 
-                for (int i = 0; i < MAX_ORIENTATIONS; i++) {
-                    CurrentDisplay display = new CurrentDisplay(mCurrentDisplay.size, i);
-                    OrientationRectF rect = mSwipeTouchRegions.get(display);
-
+                for (OrientationRectF rect : mSwipeTouchRegions.values()) {
                     if (TestProtocol.sDebugTracing) {
                         Log.d(TestProtocol.NO_SWIPE_TO_HOME, "transform:DOWN, rect=" + rect);
                     }
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 1340abb..7c453e7 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -108,8 +108,7 @@
 
         SplitPlaceholderView splitPlaceholderView = findViewById(R.id.split_placeholder);
         splitPlaceholderView.init(
-                new SplitSelectStateController(
-                        SystemUiProxy.INSTANCE.get(this))
+                new SplitSelectStateController(mUiHandler, SystemUiProxy.INSTANCE.get(this))
         );
 
         mDragLayer.recreateControllers();
@@ -192,7 +191,7 @@
                     RemoteAnimationTargetCompat[] nonAppTargets,
                     AnimationResult result) -> {
             AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets,
-                    wallpaperTargets);
+                    wallpaperTargets, nonAppTargets);
             anim.addListener(resetStateListener());
             result.setAnimation(anim, RecentsActivity.this, onEndCallback::executeAllAndDestroy);
         };
@@ -213,12 +212,13 @@
      */
     private AnimatorSet  composeRecentsLaunchAnimator(TaskView taskView,
             RemoteAnimationTargetCompat[] appTargets,
-            RemoteAnimationTargetCompat[] wallpaperTargets) {
+            RemoteAnimationTargetCompat[] wallpaperTargets,
+            RemoteAnimationTargetCompat[] nonAppTargets) {
         AnimatorSet target = new AnimatorSet();
         boolean activityClosing = taskIsATargetWithMode(appTargets, getTaskId(), MODE_CLOSING);
         PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
         createRecentsWindowAnimator(taskView, !activityClosing, appTargets,
-                wallpaperTargets, null /* depthController */, pa);
+                wallpaperTargets, nonAppTargets, null /* depthController */, pa);
         target.play(pa.buildAnim());
 
         // Found a visible recents task that matches the opening app, lets launch the app from there
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index 718c5ba..3861bab 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -33,7 +33,7 @@
     public RecentsAnimationTargets(RemoteAnimationTargetCompat[] apps,
             RemoteAnimationTargetCompat[] wallpapers, Rect homeContentInsets,
             Rect minimizedHomeBounds) {
-        super(apps, wallpapers, MODE_CLOSING);
+        super(apps, wallpapers, new RemoteAnimationTargetCompat[0], MODE_CLOSING);
         this.homeContentInsets = homeContentInsets;
         this.minimizedHomeBounds = minimizedHomeBounds;
     }
diff --git a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
index ab5e3ba..a1af77d 100644
--- a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java
@@ -15,6 +15,8 @@
  */
 package com.android.quickstep;
 
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 
 import java.util.ArrayList;
@@ -30,13 +32,15 @@
     public final RemoteAnimationTargetCompat[] unfilteredApps;
     public final RemoteAnimationTargetCompat[] apps;
     public final RemoteAnimationTargetCompat[] wallpapers;
+    public final RemoteAnimationTargetCompat[] nonApps;
     public final int targetMode;
     public final boolean hasRecents;
 
     private boolean mReleased = false;
 
     public RemoteAnimationTargets(RemoteAnimationTargetCompat[] apps,
-            RemoteAnimationTargetCompat[] wallpapers, int targetMode) {
+            RemoteAnimationTargetCompat[] wallpapers, RemoteAnimationTargetCompat[] nonApps,
+            int targetMode) {
         ArrayList<RemoteAnimationTargetCompat> filteredApps = new ArrayList<>();
         boolean hasRecents = false;
         if (apps != null) {
@@ -55,6 +59,7 @@
         this.wallpapers = wallpapers;
         this.targetMode = targetMode;
         this.hasRecents = hasRecents;
+        this.nonApps = nonApps;
     }
 
     public RemoteAnimationTargetCompat findTask(int taskId) {
@@ -66,6 +71,18 @@
         return null;
     }
 
+    /**
+     * Gets the navigation bar remote animation target if exists.
+     */
+    public RemoteAnimationTargetCompat getNavBarRemoteAnimationTarget() {
+        for (RemoteAnimationTargetCompat target : nonApps) {
+            if (target.windowType == TYPE_NAVIGATION_BAR) {
+                return target;
+            }
+        }
+        return null;
+    }
+
     public boolean isAnimatingHome() {
         for (RemoteAnimationTargetCompat target : unfilteredApps) {
             if (target.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
@@ -98,6 +115,9 @@
         for (RemoteAnimationTargetCompat target : wallpapers) {
             target.release();
         }
+        for (RemoteAnimationTargetCompat target : nonApps) {
+            target.release();
+        }
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 1f332c4..0ee28bc 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -35,6 +35,7 @@
 import android.view.MotionEvent;
 
 import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.RemoteTransitionCompat;
@@ -491,6 +492,20 @@
         }
     }
 
+    /** Start multiple tasks in split-screen simultaneously. */
+    public void startTasks(int mainTaskId, Bundle mainOptions, int sideTaskId, Bundle sideOptions,
+            @SplitConfigurationOptions.StagePosition int sidePosition,
+            RemoteTransitionCompat remoteTransition) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSplitScreen.startTasks(mainTaskId, mainOptions, sideTaskId, sideOptions,
+                        sidePosition, remoteTransition.getTransition());
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call startTask");
+            }
+        }
+    }
+
     public void startShortcut(String packageName, String shortcutId, int stage, int position,
             Bundle options, UserHandle user) {
         if (mSplitScreen != null) {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 79db842..cbb2a66 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -15,9 +15,17 @@
  */
 package com.android.quickstep;
 
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+
 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_DELAY_NAV_FADE_IN;
+import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_NAV_FADE_IN_DURATION;
+import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_NAV_FADE_OUT_DURATION;
+import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_IN_INTERPOLATOR;
+import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_OUT_INTERPOLATOR;
 import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -42,7 +50,9 @@
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.os.Build;
+import android.view.SurfaceControl;
 import android.view.View;
+import android.window.TransitionInfo;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -58,6 +68,7 @@
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.util.MultiValueUpdateListener;
 import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.util.TransformParams;
@@ -67,6 +78,7 @@
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
 
 /**
  * Utility class for helpful methods related to {@link TaskView} objects and their tasks.
@@ -137,7 +149,8 @@
 
     public static void createRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
             RemoteAnimationTargetCompat[] appTargets,
-            RemoteAnimationTargetCompat[] wallpaperTargets, DepthController depthController,
+            RemoteAnimationTargetCompat[] wallpaperTargets,
+            RemoteAnimationTargetCompat[] nonAppTargets, DepthController depthController,
             PendingAnimation out) {
         boolean isRunningTask = v.isRunningTask();
         TransformParams params = null;
@@ -146,7 +159,7 @@
             params = v.getRecentsView().getLiveTileParams();
             tsv = v.getRecentsView().getLiveTileTaskViewSimulator();
         }
-        createRecentsWindowAnimator(v, skipViewChanges, appTargets, wallpaperTargets,
+        createRecentsWindowAnimator(v, skipViewChanges, appTargets, wallpaperTargets, nonAppTargets,
                 depthController, out, params, tsv);
     }
 
@@ -156,7 +169,8 @@
      */
     public static void createRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
             RemoteAnimationTargetCompat[] appTargets,
-            RemoteAnimationTargetCompat[] wallpaperTargets, DepthController depthController,
+            RemoteAnimationTargetCompat[] wallpaperTargets,
+            RemoteAnimationTargetCompat[] nonAppTargets, DepthController depthController,
             PendingAnimation out, @Nullable TransformParams params,
             @Nullable TaskViewSimulator tsv) {
         boolean isQuickSwitch = v.isEndQuickswitchCuj();
@@ -164,8 +178,9 @@
 
         boolean inLiveTileMode = LIVE_TILE.get() && v.getRecentsView().getRunningTaskIndex() != -1;
         final RemoteAnimationTargets targets =
-                new RemoteAnimationTargets(appTargets, wallpaperTargets,
+                new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets,
                         inLiveTileMode ? MODE_CLOSING : MODE_OPENING);
+        final RemoteAnimationTargetCompat navBarTarget = targets.getNavBarRemoteAnimationTarget();
 
         if (params == null) {
             SurfaceTransactionApplier applier = new SurfaceTransactionApplier(v);
@@ -180,10 +195,9 @@
         int taskIndex = recentsView.indexOfChild(v);
         Context context = v.getContext();
         DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
+        boolean showAsGrid = dp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get();
         boolean parallaxCenterAndAdjacentTask =
-                taskIndex != recentsView.getCurrentPage() && !(dp.isTablet
-                        && FeatureFlags.ENABLE_OVERVIEW_GRID.get());
-        float gridProgress = recentsView.getGridProgress();
+                taskIndex != recentsView.getCurrentPage() && !showAsGrid;
         float gridTranslationSecondary = recentsView.getGridTranslationSecondary(taskIndex);
         int startScroll = recentsView.getScrollOffset(taskIndex);
 
@@ -201,7 +215,9 @@
             tsv.setPreview(targets.apps[targets.apps.length - 1]);
             tsv.fullScreenProgress.value = 0;
             tsv.recentsViewScale.value = 1;
-            tsv.taskSecondaryTranslation.value = gridTranslationSecondary;
+            if (showAsGrid) {
+                tsv.taskSecondaryTranslation.value = gridTranslationSecondary;
+            }
             tsv.setScroll(startScroll);
 
             // Fade in the task during the initial 20% of the animation
@@ -214,13 +230,40 @@
                     AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
             out.setFloat(tsv.recentsViewScale,
                     AnimatedFloat.VALUE, tsv.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
-            out.setFloat(tsv.taskSecondaryTranslation, AnimatedFloat.VALUE, 0,
-                    TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL);
-            out.setInt(tsv, TaskViewSimulator.SCROLL, 0, TOUCH_RESPONSE_INTERPOLATOR);
+            if (showAsGrid) {
+                out.setFloat(tsv.taskSecondaryTranslation, AnimatedFloat.VALUE, 0,
+                        TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL);
+            }
+            out.setFloat(tsv.recentsViewScroll, AnimatedFloat.VALUE, 0,
+                    TOUCH_RESPONSE_INTERPOLATOR);
 
             TaskViewSimulator finalTsv = tsv;
             TransformParams finalParams = params;
             out.addOnFrameCallback(() -> finalTsv.apply(finalParams));
+            if (navBarTarget != null) {
+                final Rect cropRect = new Rect();
+                out.addOnFrameListener(new MultiValueUpdateListener() {
+                    FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0,
+                            ANIMATION_NAV_FADE_OUT_DURATION, NAV_FADE_OUT_INTERPOLATOR);
+                    FloatProp mNavFadeIn = new FloatProp(0f, 1f, ANIMATION_DELAY_NAV_FADE_IN,
+                            ANIMATION_NAV_FADE_IN_DURATION, NAV_FADE_IN_INTERPOLATOR);
+
+                    @Override
+                    public void onUpdate(float percent) {
+                        final SurfaceParams.Builder navBuilder =
+                                new SurfaceParams.Builder(navBarTarget.leash);
+                        if (mNavFadeIn.value > mNavFadeIn.getStartValue()) {
+                            finalTsv.getCurrentCropRect().round(cropRect);
+                            navBuilder.withMatrix(finalTsv.getCurrentMatrix())
+                                    .withWindowCrop(cropRect)
+                                    .withAlpha(mNavFadeIn.value);
+                        } else {
+                            navBuilder.withAlpha(mNavFadeOut.value);
+                        }
+                        finalParams.applySurfaceParams(navBuilder.build());
+                    }
+                });
+            }
             topMostSimulator = tsv;
         }
 
@@ -314,9 +357,50 @@
      * device is considered in multiWindowMode and things like insets and stuff change
      * and calculations have to be adjusted in the animations for that
      */
-    public static void composeRecentsSplitLaunchAnimator(@NonNull AnimatorSet anim,
+    public static void composeRecentsSplitLaunchAnimator(@NonNull TaskView initialView,
+            @NonNull TaskView v, @NonNull TransitionInfo transitionInfo,
+            SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {
+
+        final TransitionInfo.Change[] splitRoots = new TransitionInfo.Change[2];
+        for (int i = 0; i < transitionInfo.getChanges().size(); ++i) {
+            final TransitionInfo.Change change = transitionInfo.getChanges().get(i);
+            final int taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;
+            final int mode = change.getMode();
+            // Find the target tasks' root tasks since those are the split stages that need to
+            // be animated (the tasks themselves are children and thus inherit animation).
+            if (taskId == initialView.getTask().key.id || taskId == v.getTask().key.id) {
+                if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
+                    throw new IllegalStateException(
+                            "Expected task to be showing, but it is " + mode);
+                }
+                if (change.getParent() == null) {
+                    throw new IllegalStateException("Initiating multi-split launch but the split"
+                            + "root of " + taskId + " is already visible or has broken hierarchy.");
+                }
+                splitRoots[taskId == initialView.getTask().key.id ? 0 : 1] =
+                        transitionInfo.getChange(change.getParent());
+            }
+        }
+
+        // This is where we should animate the split roots. For now, though, just make them visible.
+        for (int i = 0; i < 2; ++i) {
+            t.show(splitRoots[i].getLeash());
+            t.setAlpha(splitRoots[i].getLeash(), 1.f);
+        }
+
+        // This contains the initial state (before animation), so apply this at the beginning of
+        // the animation.
+        t.apply();
+
+        // Once there is an animation, this should be called AFTER the animation completes.
+        finishCallback.run();
+    }
+
+    /** Legacy version (until shell transitions are enabled) */
+    public static void composeRecentsSplitLaunchAnimatorLegacy(@NonNull AnimatorSet anim,
             @NonNull TaskView v, @NonNull RemoteAnimationTargetCompat[] appTargets,
-            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing,
+            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
+            @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
             @NonNull StateManager stateManager, @NonNull DepthController depthController,
             int targetStage) {
         PendingAnimation out = new PendingAnimation(RECENTS_LAUNCH_DURATION);
@@ -332,7 +416,7 @@
         boolean inLiveTileMode =
                 ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskIndex() != -1;
         final RemoteAnimationTargets targets =
-                new RemoteAnimationTargets(appTargets, wallpaperTargets,
+                new RemoteAnimationTargets(appTargets, wallpaperTargets, nonAppTargets,
                         inLiveTileMode ? MODE_CLOSING : MODE_OPENING);
 
         if (params == null) {
@@ -374,7 +458,8 @@
                     AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
             out.setFloat(tvs.recentsViewScale,
                     AnimatedFloat.VALUE, tvs.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
-            out.setInt(tvs, TaskViewSimulator.SCROLL, 0, TOUCH_RESPONSE_INTERPOLATOR);
+            out.setFloat(tvs.recentsViewScroll,
+                    AnimatedFloat.VALUE, 0, TOUCH_RESPONSE_INTERPOLATOR);
 
             TaskViewSimulator finalTsv = tvs;
             TransformParams finalParams = params;
@@ -387,7 +472,8 @@
 
     public static void composeRecentsLaunchAnimator(@NonNull AnimatorSet anim, @NonNull View v,
             @NonNull RemoteAnimationTargetCompat[] appTargets,
-            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets, boolean launcherClosing,
+            @NonNull RemoteAnimationTargetCompat[] wallpaperTargets,
+            @NonNull RemoteAnimationTargetCompat[] nonAppTargets, boolean launcherClosing,
             @NonNull StateManager stateManager, @NonNull RecentsView recentsView,
             @NonNull DepthController depthController) {
         boolean skipLauncherChanges = !launcherClosing;
@@ -395,7 +481,7 @@
         TaskView taskView = findTaskViewToLaunch(recentsView, v, appTargets);
         PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
         createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
-                depthController, pa);
+                nonAppTargets, depthController, pa);
 
         Animator childStateAnimation = null;
         // Found a visible recents task that matches the opening app, lets launch the app from there
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 1fb9465..e9d2eb4 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -239,8 +239,9 @@
         @BinderThread
         public void onSystemUiStateChanged(int stateFlags) {
             MAIN_EXECUTOR.execute(() -> {
+                int lastFlags = mDeviceState.getSystemUiStateFlags();
                 mDeviceState.setSystemUiFlags(stateFlags);
-                TouchInteractionService.this.onSystemUiFlagsChanged();
+                TouchInteractionService.this.onSystemUiFlagsChanged(lastFlags);
             });
         }
 
@@ -362,7 +363,7 @@
         mResetGestureInputConsumer = new ResetGestureInputConsumer(mTaskAnimationManager);
         mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
         mInputConsumer.registerInputConsumer();
-        onSystemUiFlagsChanged();
+        onSystemUiFlagsChanged(mDeviceState.getSystemUiStateFlags());
         onAssistantVisibilityChanged();
 
         // Temporarily disable model preload
@@ -414,7 +415,7 @@
     }
 
     @UiThread
-    private void onSystemUiFlagsChanged() {
+    private void onSystemUiFlagsChanged(int lastSysUIFlags) {
         if (mDeviceState.isUserUnlocked()) {
             int systemUiStateFlags = mDeviceState.getSystemUiStateFlags();
             SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
@@ -422,14 +423,17 @@
             mOverviewComponentObserver.getActivityInterface().onSystemUiFlagsChanged(
                     systemUiStateFlags);
 
-            // Update the tracing state
-            if ((systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED) != 0) {
-                Log.d(TAG, "Starting tracing.");
-                ProtoTracer.INSTANCE.get(this).start();
-            } else {
-                Log.d(TAG, "Stopping tracing. Dumping to file="
-                    + ProtoTracer.INSTANCE.get(this).getTraceFile());
-                ProtoTracer.INSTANCE.get(this).stop();
+            if ((lastSysUIFlags & SYSUI_STATE_TRACING_ENABLED) !=
+                    (systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED)) {
+                // Update the tracing state
+                if ((systemUiStateFlags & SYSUI_STATE_TRACING_ENABLED) != 0) {
+                    Log.d(TAG, "Starting tracing.");
+                    ProtoTracer.INSTANCE.get(this).start();
+                } else {
+                    Log.d(TAG, "Stopping tracing. Dumping to file="
+                            + ProtoTracer.INSTANCE.get(this).getTraceFile());
+                    ProtoTracer.INSTANCE.get(this).stop();
+                }
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java b/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java
index e798d5c..b4ae1ca 100644
--- a/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java
+++ b/quickstep/src/com/android/quickstep/util/MultiValueUpdateListener.java
@@ -64,5 +64,12 @@
 
             mAllProperties.add(this);
         }
+
+        /**
+         * Gets the start value.
+         */
+        public float getStartValue() {
+            return mStart;
+        }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
index 958ee24..81c124f 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java
@@ -34,7 +34,8 @@
 
     public RemoteFadeOutAnimationListener(RemoteAnimationTargetCompat[] appTargets,
             RemoteAnimationTargetCompat[] wallpaperTargets) {
-        mTarget = new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_CLOSING);
+        mTarget = new RemoteAnimationTargets(appTargets, wallpaperTargets,
+                new RemoteAnimationTargetCompat[0], MODE_CLOSING);
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index d9154ed..9576eac 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -16,11 +16,17 @@
 
 package com.android.quickstep.util;
 
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
+
 import android.animation.AnimatorSet;
 import android.app.ActivityOptions;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.Pair;
+import android.view.SurfaceControl;
+import android.window.TransitionInfo;
 
 import androidx.annotation.Nullable;
 
@@ -31,12 +37,15 @@
 import com.android.launcher3.WrappedLauncherAnimationRunner;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TaskAnimationManager;
 import com.android.quickstep.TaskViewUtils;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.system.ActivityOptionsCompat;
 import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.RemoteTransitionCompat;
+import com.android.systemui.shared.system.RemoteTransitionRunner;
 
 /**
  * Represent data needed for the transient state when user has selected one app for split screen
@@ -47,9 +56,11 @@
     private final SystemUiProxy mSystemUiProxy;
     private TaskView mInitialTaskView;
     private SplitPositionOption mInitialPosition;
+    private final Handler mHandler;
 
-    public SplitSelectStateController(SystemUiProxy systemUiProxy) {
+    public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
         mSystemUiProxy = systemUiProxy;
+        mHandler = handler;
     }
 
     /**
@@ -64,6 +75,19 @@
      * To be called after second task selected
      */
     public void setSecondTaskId(TaskView taskView) {
+        if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
+            // Assume initial task is for top/left part of screen
+            final int[] taskIds = mInitialPosition.mStagePosition == STAGE_POSITION_TOP_OR_LEFT
+                    ? new int[]{mInitialTaskView.getTask().key.id, taskView.getTask().key.id}
+                    : new int[]{taskView.getTask().key.id, mInitialTaskView.getTask().key.id};
+
+            RemoteSplitLaunchAnimationRunner animationRunner =
+                    new RemoteSplitLaunchAnimationRunner(mInitialTaskView, taskView);
+            mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
+                    null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
+                    new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
+            return;
+        }
         // Assume initial mInitialTaskId is for top/left part of screen
         WrappedAnimationRunnerImpl initialSplitRunnerWrapped =  new SplitLaunchAnimationRunner(
                 mInitialTaskView, 0);
@@ -96,6 +120,30 @@
     }
 
     /**
+     * Requires Shell Transitions
+     */
+    private class RemoteSplitLaunchAnimationRunner implements RemoteTransitionRunner {
+
+        private final TaskView mInitialTaskView;
+        private final TaskView mTaskView;
+
+        RemoteSplitLaunchAnimationRunner(TaskView initialTaskView, TaskView taskView) {
+            mInitialTaskView = initialTaskView;
+            mTaskView = taskView;
+        }
+
+        @Override
+        public void startAnimation(TransitionInfo info, SurfaceControl.Transaction t,
+                Runnable finishCallback) {
+            TaskViewUtils.composeRecentsSplitLaunchAnimator(mInitialTaskView, mTaskView,
+                    info, t, finishCallback);
+            // After successful launch, call resetState
+            resetState();
+        }
+    }
+
+    /**
+     * LEGACY
      * @return the opposite stage and position from the {@param position} provided as first and
      *         second object, respectively
      * Ex. If position is has stage = Main and position = Top/Left, this will return
@@ -109,6 +157,7 @@
     }
 
     /**
+     * LEGACY
      * Remote animation runner for animation to launch an app.
      */
     private class SplitLaunchAnimationRunner implements WrappedAnimationRunnerImpl {
@@ -129,8 +178,8 @@
                 LauncherAnimationRunner.AnimationResult result) {
             AnimatorSet anim = new AnimatorSet();
             BaseQuickstepLauncher activity = BaseActivity.fromContext(mV.getContext());
-            TaskViewUtils.composeRecentsSplitLaunchAnimator(anim, mV,
-                    appTargets, wallpaperTargets, true, activity.getStateManager(),
+            TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(anim, mV,
+                    appTargets, wallpaperTargets, nonAppTargets, true, activity.getStateManager(),
                     activity.getDepthController(), mTargetState);
             result.setAnimation(anim, activity);
         }
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 6757e4c..c12bd9b 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -18,7 +18,6 @@
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
@@ -42,9 +41,7 @@
 import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.anim.PropertySetter;
 import com.android.launcher3.anim.SpringAnimationBuilder;
-import com.android.launcher3.graphics.OverviewScrim;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.util.DynamicResource;
@@ -134,7 +131,8 @@
 
         if (animateOverviewScrim) {
             PendingAnimation pendingAnimation = new PendingAnimation(DURATION_MS);
-            addScrimAnimationForState(launcher, NORMAL, pendingAnimation);
+            launcher.getWorkspace().getStateTransitionAnimation()
+                    .setScrim(pendingAnimation, NORMAL, new StateAnimationConfig());
             mAnimators.play(pendingAnimation.buildAnim());
         }
 
@@ -192,7 +190,8 @@
         launcher.<RecentsView>getOverviewPanel().getScroller().forceFinished(true);
 
         if (animateOverviewScrim) {
-            addScrimAnimationForState(launcher, BACKGROUND_APP, NO_ANIM_PROPERTY_SETTER);
+            launcher.getWorkspace().getStateTransitionAnimation()
+                    .setScrim(NO_ANIM_PROPERTY_SETTER, BACKGROUND_APP, config);
         }
     }
 
@@ -263,16 +262,6 @@
         mAnimators.play(alpha);
     }
 
-    private void addScrimAnimationForState(Launcher launcher, LauncherState state,
-            PropertySetter setter) {
-        launcher.getWorkspace().getStateTransitionAnimation().setScrim(setter, state);
-        setter.setFloat(
-                launcher.getDragLayer().getOverviewScrim(),
-                OverviewScrim.SCRIM_PROGRESS,
-                state.getOverviewScrimAlpha(launcher),
-                ACCEL_DEACCEL);
-    }
-
     private void addDepthAnimationForState(Launcher launcher, LauncherState state, long duration) {
         if (!(launcher instanceof BaseQuickstepLauncher)) {
             return;
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 3c8a12c..e63f8bb 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -30,17 +30,14 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
-import android.util.IntProperty;
 
 import androidx.annotation.NonNull;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.BaseActivityInterface;
-import com.android.quickstep.views.RecentsView.ScrollState;
 import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
 import com.android.quickstep.views.TaskView.FullscreenDrawParams;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -52,19 +49,6 @@
  */
 public class TaskViewSimulator implements TransformParams.BuilderProxy {
 
-    public static final IntProperty<TaskViewSimulator> SCROLL =
-            new IntProperty<TaskViewSimulator>("scroll") {
-                @Override
-                public void setValue(TaskViewSimulator simulator, int scroll) {
-                    simulator.setScroll(scroll);
-                }
-
-                @Override
-                public Integer get(TaskViewSimulator simulator) {
-                    return simulator.mScrollState.scroll;
-                }
-            };
-
     private final Rect mTmpCropRect = new Rect();
     private final RectF mTempRectF = new RectF();
     private final float[] mTempPoint = new float[2];
@@ -101,11 +85,10 @@
     public final AnimatedFloat fullScreenProgress = new AnimatedFloat();
     public final AnimatedFloat recentsViewSecondaryTranslation = new AnimatedFloat();
     public final AnimatedFloat recentsViewPrimaryTranslation = new AnimatedFloat();
-    private final ScrollState mScrollState = new ScrollState();
+    public final AnimatedFloat recentsViewScroll = new AnimatedFloat();
 
     // Cached calculations
     private boolean mLayoutValid = false;
-    private boolean mScrollValid = false;
     private int mOrientationStateId;
 
     public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
@@ -172,11 +155,8 @@
     /**
      * Updates the scroll for RecentsView
      */
-    public void setScroll(int scroll) {
-        if (mScrollState.scroll != scroll) {
-            mScrollState.scroll = scroll;
-            mScrollValid = false;
-        }
+    public void setScroll(float scroll) {
+        recentsViewScroll.value = scroll;
     }
 
     public void setDrawsBelowRecents(boolean drawsBelowRecents) {
@@ -268,20 +248,6 @@
                     mTaskRect.width(), mTaskRect.height(),
                     mDp, mOrientationState.getRecentsActivityRotation(), isRtlEnabled);
             mPositionHelper.getMatrix().invert(mInversePositionMatrix);
-
-            PagedOrientationHandler poh = mOrientationState.getOrientationHandler();
-            mScrollState.halfPageSize =
-                    poh.getPrimaryValue(mTaskRect.width(), mTaskRect.height()) / 2;
-            mScrollState.halfScreenSize = poh.getPrimaryValue(mDp.widthPx, mDp.heightPx) / 2;
-            mScrollValid = false;
-        }
-
-        if (!mScrollValid) {
-            mScrollValid = true;
-            int start = mOrientationState.getOrientationHandler()
-                    .getPrimaryValue(mTaskRect.left, mTaskRect.top);
-            mScrollState.screenCenter = start + mScrollState.scroll + mScrollState.halfPageSize;
-            mScrollState.updateInterpolation(mDp, start);
         }
 
         float fullScreenProgress = Utilities.boundToRange(this.fullScreenProgress.value, 0, 1);
@@ -306,7 +272,7 @@
         mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
                 taskSecondaryTranslation.value);
         mOrientationState.getOrientationHandler().set(
-                mMatrix, MATRIX_POST_TRANSLATE, mScrollState.scroll);
+                mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value);
 
         // Apply RecentsView matrix
         mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y);
diff --git a/quickstep/src/com/android/quickstep/util/TransformParams.java b/quickstep/src/com/android/quickstep/util/TransformParams.java
index 756331d..03d7a37 100644
--- a/quickstep/src/com/android/quickstep/util/TransformParams.java
+++ b/quickstep/src/com/android/quickstep/util/TransformParams.java
@@ -205,7 +205,7 @@
         return mTargetSet;
     }
 
-    public void applySurfaceParams(SurfaceParams[] params) {
+    public void applySurfaceParams(SurfaceParams... params) {
         if (mSyncTransactionApplier != null) {
             mSyncTransactionApplier.scheduleApply(params);
         } else {
diff --git a/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java b/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java
deleted file mode 100644
index 185080e5..0000000
--- a/quickstep/src/com/android/quickstep/views/AllAppsScrimView.java
+++ /dev/null
@@ -1,125 +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.views;
-
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.ACCEL;
-import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.util.AttributeSet;
-import android.view.animation.Interpolator;
-
-import androidx.core.graphics.ColorUtils;
-
-import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.util.Themes;
-import com.android.launcher3.views.ScrimView;
-
-/**
- * Scrim used for all-apps background. uses interpolator to coordinate fade in with
- * all-apps contents
- *
- * Note: ranges are inverted because progress goes from 1 to 0 for NORMAL->AllAPPS
- */
-public class AllAppsScrimView extends ScrimView<BaseQuickstepLauncher> {
-
-    private static final float TINT_DECAY_MULTIPLIER = .5f;
-
-    //min progress for scrim to become visible
-    private static final float SCRIM_VISIBLE_THRESHOLD = .9f;
-    //max progress where scrim alpha animates.
-    private static final float SCRIM_SOLID_THRESHOLD = .5f;
-    private final Interpolator mScrimInterpolator = Interpolators.clampToProgress(ACCEL,
-            SCRIM_SOLID_THRESHOLD,
-            SCRIM_VISIBLE_THRESHOLD);
-
-    // In transposed layout, we simply draw a flat color.
-    private boolean mDrawingFlatColor;
-
-    private final int mEndAlpha;
-    private final Paint mPaint;
-
-    private int mCurrentScrimColor;
-    private final int mTintColor;
-
-    public AllAppsScrimView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mMaxScrimAlpha = Math.round(OVERVIEW.getOverviewScrimAlpha(mLauncher) * 255);
-        mTintColor = Themes.getColorAccent(mContext);
-
-
-        mEndAlpha = Color.alpha(mEndScrim);
-        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-
-        // Just assume the easiest UI for now, until we have the proper layout information.
-        mDrawingFlatColor = true;
-    }
-
-    @Override
-    public void reInitUi() {
-        DeviceProfile dp = mLauncher.getDeviceProfile();
-        mDrawingFlatColor = dp.isVerticalBarLayout();
-        updateColors();
-        updateSysUiColors();
-        invalidate();
-    }
-
-    @Override
-    public void updateColors() {
-        super.updateColors();
-        if (mDrawingFlatColor) {
-            return;
-        }
-
-        if (mProgress >= 1) {
-            mCurrentScrimColor = 0;
-        } else {
-            float interpolationProgress = mScrimInterpolator.getInterpolation(mProgress);
-            // Note that these ranges and interpolators are inverted because progress goes 1 to 0.
-            int alpha = Math.round(Utilities.mapRange(interpolationProgress, mEndAlpha, 0));
-            int color = ColorUtils.blendARGB(mEndScrim, mTintColor,
-                    mProgress * TINT_DECAY_MULTIPLIER);
-            mCurrentScrimColor = setColorAlphaBound(color, alpha);
-        }
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mDrawingFlatColor) {
-            if (mCurrentFlatColor != 0) {
-                canvas.drawColor(mCurrentFlatColor);
-            }
-            return;
-        }
-
-        if (Color.alpha(mCurrentScrimColor) == 0) {
-            return;
-        } else if (mProgress <= 0) {
-            canvas.drawColor(mCurrentScrimColor);
-            return;
-        }
-
-        mPaint.setColor(mCurrentScrimColor);
-        canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index d616f7c..4300329 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -23,10 +23,8 @@
 
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.touch.PagedOrientationHandler;
-import com.android.quickstep.views.RecentsView.PageCallbacks;
-import com.android.quickstep.views.RecentsView.ScrollState;
 
-public class ClearAllButton extends Button implements PageCallbacks {
+public class ClearAllButton extends Button {
 
     public static final FloatProperty<ClearAllButton> VISIBILITY_ALPHA =
             new FloatProperty<ClearAllButton>("visibilityAlpha") {
@@ -99,8 +97,7 @@
         }
     }
 
-    @Override
-    public void onPageScroll(ScrollState scrollState, boolean gridEnabled) {
+    public void onRecentsViewScroll(int scrollFromEdge, boolean gridEnabled) {
         RecentsView recentsView = getRecentsView();
         if (recentsView == null) {
             return;
@@ -113,7 +110,7 @@
         }
 
         int leftEdgeScroll = recentsView.getLeftMostChildScroll();
-        float adjustedScrollFromEdge = scrollState.scrollFromEdge - leftEdgeScroll;
+        int adjustedScrollFromEdge = scrollFromEdge - leftEdgeScroll;
         float shift = Math.min(adjustedScrollFromEdge, orientationSize);
         mNormalTranslationPrimary = mIsRtl ? -shift : shift;
         if (!gridEnabled) {
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index deb674c..7c8041c 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -72,7 +72,6 @@
     private View mBanner;
     private ViewOutlineProvider mOldBannerOutlineProvider;
     private float mBannerOffsetPercentage;
-    private float mBannerAlpha = 1f;
     private float mVerticalOffset = 0f;
 
     public DigitalWellBeingToast(BaseDraggingActivity activity, TaskView taskView) {
@@ -99,10 +98,6 @@
 
         mTaskView.setContentDescription(
                 getContentDescriptionForTask(mTask, appUsageLimitTimeMs, appRemainingTimeMs));
-        RecentsView rv = mTaskView.getRecentsView();
-        if (rv != null) {
-            rv.onDigitalWellbeingToastShown();
-        }
     }
 
     public String getText() {
@@ -268,7 +263,6 @@
         layoutParams.bottomMargin = ((ViewGroup.MarginLayoutParams)
                 mTaskView.getThumbnail().getLayoutParams()).bottomMargin;
         mBanner.setTranslationY(mBannerOffsetPercentage * mBanner.getHeight());
-        mBanner.setAlpha(mBannerAlpha);
         mTaskView.addView(mBanner);
     }
 
@@ -293,18 +287,11 @@
         }
     }
 
-    void updateBannerAlpha(float alpha) {
-        if (mBanner != null && mBannerAlpha != alpha) {
-            mBannerAlpha = alpha;
-            mBanner.setAlpha(alpha);
-        }
-    }
-
     void setBannerColorTint(int color, float amount) {
         if (mBanner == null) {
             return;
         }
-        if (mBannerAlpha == 0 || amount == 0) {
+        if (amount == 0) {
             mBanner.setLayerType(View.LAYER_TYPE_NONE, null);
         }
         Paint layerPaint = new Paint();
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 896d1ae..f5a8ff8 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -149,9 +149,10 @@
     }
 
     @Override
-    protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent ev) {
-        return mActivity.getStateManager().getState().overviewUi
-                && super.shouldStealTouchFromSiblingsBelow(ev);
+    public boolean onTouchEvent(MotionEvent ev) {
+        boolean result = super.onTouchEvent(ev);
+        // Do not let touch escape to siblings below this view.
+        return result || mActivity.getStateManager().getState().overviewUi;
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/views/RecentsExtraViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsExtraViewContainer.java
index 1ea6d4a..16bc3bc 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsExtraViewContainer.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsExtraViewContainer.java
@@ -23,7 +23,7 @@
 /**
  * Empty view to house recents overview extra card
  */
-public class RecentsExtraViewContainer extends FrameLayout implements RecentsView.PageCallbacks {
+public class RecentsExtraViewContainer extends FrameLayout {
 
     private boolean mScrollable = false;
 
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 3c171fe..524bae1 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -20,6 +20,8 @@
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.makeMeasureSpec;
 
+import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
+import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
 import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
 import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
@@ -114,7 +116,6 @@
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.touch.PagedOrientationHandler;
-import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties;
 import com.android.launcher3.util.DynamicResource;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.MultiValueAlpha;
@@ -167,8 +168,6 @@
         InvariantDeviceProfile.OnIDPChangeListener, TaskVisualsChangeListener,
         SplitScreenBounds.OnChangeListener {
 
-    private static final String TAG = RecentsView.class.getSimpleName();
-
     public static final FloatProperty<RecentsView> CONTENT_ALPHA =
             new FloatProperty<RecentsView>("contentAlpha") {
                 @Override
@@ -332,7 +331,6 @@
      */
     private boolean mGestureActive;
 
-    private final ScrollState mScrollState = new ScrollState();
     // Keeps track of the previously known visible tasks for purposes of loading/unloading task data
     private final SparseBooleanArray mHasVisibleTaskData = new SparseBooleanArray();
 
@@ -342,7 +340,6 @@
 
     private final TaskOverlayFactory mTaskOverlayFactory;
 
-    private boolean mDwbToastShown;
     protected boolean mDisallowScrollToClearAll;
     private boolean mOverlayEnabled;
     protected boolean mFreezeViewVisibility;
@@ -769,7 +766,8 @@
         } else {
             TaskViewUtils.composeRecentsLaunchAnimator(
                     anim, taskView, apps,
-                    mLiveTileParams.getTargetSet().wallpapers, true /* launcherClosing */,
+                    mLiveTileParams.getTargetSet().wallpapers,
+                    mLiveTileParams.getTargetSet().nonApps, true /* launcherClosing */,
                     mActivity.getStateManager(), this,
                     getDepthController());
         }
@@ -787,8 +785,7 @@
 
             private void cleanUp(boolean canceled) {
                 if (mRecentsAnimationController != null) {
-                    mRecentsAnimationController.finish(false /* toRecents */,
-                            null /* onFinishComplete */);
+                    finishRecentsAnimation(false /* toRecents */, null /* onFinishComplete */);
                     if (canceled) {
                         mRecentsAnimationController = null;
                     } else {
@@ -865,12 +862,6 @@
         }
     }
 
-    public void onDigitalWellbeingToastShown() {
-        if (!mDwbToastShown) {
-            mDwbToastShown = true;
-        }
-    }
-
     /**
      * Whether the Clear All button is hidden or fully visible. Used to determine if center
      * displayed page is a task or the Clear All button.
@@ -963,9 +954,7 @@
                 break;
         }
 
-
-        // Do not let touch escape to siblings below this view.
-        return isHandlingTouch() || shouldStealTouchFromSiblingsBelow(ev);
+        return isHandlingTouch();
     }
 
     @Override
@@ -980,9 +969,6 @@
             super.determineScrollingStart(ev, touchSlopScale);
         }
     }
-    protected boolean shouldStealTouchFromSiblingsBelow(MotionEvent ev) {
-        return true;
-    }
 
     protected void applyLoadPlan(ArrayList<Task> tasks) {
         if (TestProtocol.sDebugTracing) {
@@ -1243,11 +1229,6 @@
         mClearAllButton.setFullscreenTranslationPrimary(
                 accumulatedTranslationX - fullscreenTranslations[firstNonHomeTaskIndex]);
 
-        // Align ClearAllButton to the left (RTL) or right (non-RTL), which is different from other
-        // TaskViews.
-        int clearAllWidthDiff = mTaskWidth - mClearAllButton.getWidth();
-        mClearAllButton.setScrollOffsetPrimary(mIsRtl ? clearAllWidthDiff : -clearAllWidthDiff);
-
         updateGridProperties(false);
     }
 
@@ -1334,17 +1315,9 @@
         if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
             return;
         }
-        mOrientationHandler.getCurveProperties(this, mInsets, mScrollState);
-        mScrollState.scrollFromEdge =
-                mIsRtl ? mScrollState.scroll : (mMaxScroll - mScrollState.scroll);
-
-        final int pageCount = getPageCount();
-        for (int i = 0; i < pageCount; i++) {
-            View page = getPageAt(i);
-            mScrollState.updateInterpolation(mActivity.getDeviceProfile(),
-                    mOrientationHandler.getChildStartWithTranslation(page));
-            ((PageCallbacks) page).onPageScroll(mScrollState, mOverviewGridEnabled);
-        }
+        int scroll = mOrientationHandler.getPrimaryScroll(this);
+        int scrollFromEdge = mIsRtl ? scroll : (mMaxScroll - scroll);
+        mClearAllButton.onRecentsViewScroll(scrollFromEdge, mOverviewGridEnabled);
     }
 
     @Override
@@ -1485,7 +1458,6 @@
 
         unloadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
         setCurrentPage(0);
-        mDwbToastShown = false;
         mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
         LayoutUtils.setViewEnabled(mActionsView, true);
         if (mOrientationState.setGestureActive(false)) {
@@ -1600,6 +1572,10 @@
         for (int i = 0; i < getTaskViewCount(); i++) {
             getTaskViewAt(i).setOrientationState(mOrientationState);
         }
+        TaskMenuView tv = (TaskMenuView) getTopOpenViewWithType(mActivity, TYPE_TASK_MENU);
+        if (tv != null) {
+            tv.onRotationChanged();
+        }
     }
 
     /**
@@ -1952,7 +1928,7 @@
                     // When the unpinned task is added, snap to first page and disable transitions
                     if (view instanceof TaskView) {
                         snapToPage(0);
-                        disableLayoutTransitions();
+                        setLayoutTransition(null);
                     }
 
                 }
@@ -1961,10 +1937,6 @@
         setLayoutTransition(mLayoutTransition);
     }
 
-    private void disableLayoutTransitions() {
-        setLayoutTransition(null);
-    }
-
     public void setSwipeDownShouldLaunchApp(boolean swipeDownShouldLaunchApp) {
         mSwipeDownShouldLaunchApp = swipeDownShouldLaunchApp;
     }
@@ -1973,44 +1945,6 @@
         return mSwipeDownShouldLaunchApp;
     }
 
-    public interface PageCallbacks {
-
-        /**
-         * Updates the page UI based on scroll params.
-         *
-         * @param gridEnabled whether Overveiw is currently showing as 2 rows grid
-         */
-        default void onPageScroll(ScrollState scrollState, boolean gridEnabled) {}
-    }
-
-    public static class ScrollState extends CurveProperties {
-
-        /**
-         * The progress from 0 to 1, where 0 is the center
-         * of the screen and 1 is the edge of the screen.
-         */
-        public float linearInterpolation;
-
-        /**
-         * The amount by which all the content is scrolled relative to the end of the list.
-         */
-        public float scrollFromEdge;
-
-        /**
-         * Updates linearInterpolation for the provided child position
-         */
-        public void updateInterpolation(DeviceProfile deviceProfile, float childStart) {
-            float pageCenter = childStart + halfPageSize;
-            float distanceFromScreenCenter = screenCenter - pageCenter;
-            // How far the page has to move from the center to be offscreen, taking into account
-            // the EDGE_SCALE_DOWN_FACTOR that will be applied at that position.
-            float distanceToReachEdge = halfScreenSize
-                    + halfPageSize * (1 - TaskView.getEdgeScaleDownFactor(deviceProfile));
-            linearInterpolation = Math.min(1,
-                    Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
-        }
-    }
-
     public void setIgnoreResetTask(int taskId) {
         mIgnoreResetTaskId = taskId;
     }
@@ -2547,9 +2481,7 @@
         mTempRectF.set(mLastComputedTaskSize);
         RectF taskPosition = mTempRectF;
         float desiredLeft = getWidth();
-        float distanceToOffscreen = desiredLeft - taskPosition.left;
         // Used to calculate the scale of the task view based on its new offset.
-        float centerToOffscreenProgress = Math.abs(offsetProgress);
         if (midpointIndex > -1) {
             // When there is a midpoint reference task, adjacent tasks have less distance to travel
             // to reach offscreen. Offset the task position to the task's starting point.
@@ -2559,10 +2491,8 @@
                     - mOrientationHandler.getChildStart(midpointChild)
                     + getDisplacementFromScreenCenter(midpointIndex));
             taskPosition.offset(distanceFromMidpoint, 0);
-            centerToOffscreenProgress = Utilities.mapRange(centerToOffscreenProgress,
-                    distanceFromMidpoint / distanceToOffscreen, 1);
         }
-        distanceToOffscreen = desiredLeft - taskPosition.left;
+        float distanceToOffscreen = desiredLeft - taskPosition.left;
         // Finally, we need to account for RecentsView scale, because it moves tasks based on its
         // pivot. To do this, we move the task position to where it would be offscreen at scale = 1
         // (computed above), then we apply the scale via getMatrix() to determine how much that
@@ -3010,6 +2940,16 @@
     }
 
     public void finishRecentsAnimation(boolean toRecents, Runnable onFinishComplete) {
+        if (!toRecents && LIVE_TILE.get()) {
+            // Reset the minimized state since we force-toggled the minimized state when entering
+            // overview, but never actually finished the recents animation.  This is a catch all for
+            // cases where we haven't already reset it.
+            SystemUiProxy p = SystemUiProxy.INSTANCE.getNoCreate();
+            if (p != null) {
+                p.setSplitScreenMinimized(false);
+            }
+        }
+
         if (mRecentsAnimationController == null) {
             if (onFinishComplete != null) {
                 onFinishComplete.run();
@@ -3076,6 +3016,13 @@
         boolean pageScrollChanged = super.getPageScrolls(outPageScrolls, layoutChildren,
                 scrollLogic);
 
+        // Align ClearAllButton to the left (RTL) or right (non-RTL), which is different from other
+        // TaskViews. This must be called after laying out ClearAllButton.
+        if (layoutChildren) {
+            int clearAllWidthDiff = mTaskWidth - mClearAllButton.getWidth();
+            mClearAllButton.setScrollOffsetPrimary(mIsRtl ? clearAllWidthDiff : -clearAllWidthDiff);
+        }
+
         final int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
@@ -3169,15 +3116,6 @@
                 taskView.getGridTranslationY());
     }
 
-    /**
-     * Returns the progress of forming a grid from carousel.
-     *
-     * @return A float from 0 to 1 where 0 is a carousel and 1 is a 2 row grid.
-     */
-    public float getGridProgress() {
-        return mGridProgress;
-    }
-
     public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
         float degreesRotated;
         if (navbarRotation == 0) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 0b84bc9..658d71d 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -31,6 +31,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
+import android.view.ViewTreeObserver.OnScrollChangedListener;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
@@ -51,7 +52,7 @@
 /**
  * Contains options for a recent task when long-pressing its icon.
  */
-public class TaskMenuView extends AbstractFloatingView {
+public class TaskMenuView extends AbstractFloatingView implements OnScrollChangedListener {
 
     private static final Rect sTempRect = new Rect();
 
@@ -120,7 +121,8 @@
         };
     }
 
-    public void setPosition(float x, float y, PagedOrientationHandler pagedOrientationHandler) {
+    private void setPosition(float x, float y) {
+        PagedOrientationHandler pagedOrientationHandler = mTaskView.getPagedOrientationHandler();
         int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
         float adjustedY = y + taskTopMargin;
         // Changing pivot to make computations easier
@@ -150,11 +152,11 @@
         }
     }
 
-    public static TaskMenuView showForTask(TaskView taskView) {
+    public static boolean showForTask(TaskView taskView) {
         BaseDraggingActivity activity = BaseDraggingActivity.fromContext(taskView.getContext());
         final TaskMenuView taskMenuView = (TaskMenuView) activity.getLayoutInflater().inflate(
                         R.layout.task_menu, activity.getDragLayer(), false);
-        return taskMenuView.populateAndShowForTask(taskView) ? taskMenuView : null;
+        return taskMenuView.populateAndShowForTask(taskView);
     }
 
     private boolean populateAndShowForTask(TaskView taskView) {
@@ -167,9 +169,16 @@
             return false;
         }
         post(this::animateOpen);
+        mActivity.getRootView().getViewTreeObserver().addOnScrollChangedListener(this);
         return true;
     }
 
+    @Override
+    public void onScrollChanged() {
+        RecentsView rv = mTaskView.getRecentsView();
+        setPosition(mTaskView.getX() - rv.getScrollX(), mTaskView.getY() - rv.getScrollY());
+    }
+
     /** @return true if successfully able to populate task view menu, false otherwise */
     private boolean populateAndLayoutMenu() {
         if (mTaskView.getTask().icon == null) {
@@ -227,8 +236,7 @@
             .mOrientationState.isRecentsActivityRotationAllowed();
         mOptionLayout.setOrientation(orientationHandler
                 .getTaskMenuLayoutOrientation(canActivityRotate, mOptionLayout));
-        setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top,
-            taskView.getPagedOrientationHandler());
+        setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top);
     }
 
     private void animateOpen() {
@@ -274,6 +282,7 @@
     private void closeComplete() {
         mIsOpen = false;
         mActivity.getDragLayer().removeView(this);
+        mActivity.getRootView().getViewTreeObserver().removeOnScrollChangedListener(this);
     }
 
     private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index e78406f..8c71ab3 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -27,6 +27,7 @@
 import static android.view.Surface.ROTATION_90;
 import static android.widget.Toast.LENGTH_SHORT;
 
+import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
 import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
 import static com.android.launcher3.Utilities.comp;
@@ -72,6 +73,7 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 
+import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
@@ -94,6 +96,7 @@
 import com.android.launcher3.util.ViewPool.Reusable;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.RemoteAnimationTargets;
+import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskIconCache;
 import com.android.quickstep.TaskOverlayFactory;
 import com.android.quickstep.TaskThumbnailCache;
@@ -102,8 +105,6 @@
 import com.android.quickstep.util.CancellableTask;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.util.TaskCornerRadius;
-import com.android.quickstep.views.RecentsView.PageCallbacks;
-import com.android.quickstep.views.RecentsView.ScrollState;
 import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -118,7 +119,7 @@
 /**
  * A task in the Recents view.
  */
-public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
+public class TaskView extends FrameLayout implements Reusable {
 
     private static final String TAG = TaskView.class.getSimpleName();
 
@@ -265,26 +266,10 @@
                 }
             };
 
-    private final OnAttachStateChangeListener mTaskMenuStateListener =
-            new OnAttachStateChangeListener() {
-                @Override
-                public void onViewAttachedToWindow(View view) {
-                }
-
-                @Override
-                public void onViewDetachedFromWindow(View view) {
-                    if (mMenuView != null) {
-                        mMenuView.removeOnAttachStateChangeListener(this);
-                        mMenuView = null;
-                    }
-                }
-            };
-
     private final TaskOutlineProvider mOutlineProvider;
 
     private Task mTask;
     private TaskThumbnailView mSnapshotView;
-    private TaskMenuView mMenuView;
     private IconView mIconView;
     private final DigitalWellBeingToast mDigitalWellBeingToast;
     private float mFullscreenProgress;
@@ -343,47 +328,7 @@
     public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mActivity = StatefulActivity.fromContext(context);
-        setOnClickListener((view) -> {
-            if (getTask() == null) {
-                return;
-            }
-            if (LIVE_TILE.get() && isRunningTask()) {
-                if (!mIsClickableAsLiveTile) {
-                    return;
-                }
-
-                mIsClickableAsLiveTile = false;
-                RecentsView recentsView = getRecentsView();
-                RemoteAnimationTargets targets = recentsView.getLiveTileParams().getTargetSet();
-                recentsView.getLiveTileTaskViewSimulator().setDrawsBelowRecents(false);
-
-                AnimatorSet anim = new AnimatorSet();
-                TaskViewUtils.composeRecentsLaunchAnimator(
-                        anim, this, targets.apps,
-                        targets.wallpapers, true /* launcherClosing */,
-                        mActivity.getStateManager(), recentsView,
-                        recentsView.getDepthController());
-                anim.addListener(new AnimatorListenerAdapter() {
-
-                    @Override
-                    public void onAnimationEnd(Animator animator) {
-                        recentsView.getLiveTileTaskViewSimulator().setDrawsBelowRecents(true);
-                        recentsView.finishRecentsAnimation(false, null);
-                        mIsClickableAsLiveTile = true;
-                    }
-                });
-                anim.start();
-            } else {
-                if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
-                    // User tapped to select second split screen app
-                    getRecentsView().confirmSplitSelect(this);
-                } else {
-                    launchTaskAnimated();
-                }
-            }
-            mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo())
-                    .log(LAUNCHER_TASK_LAUNCH_TAP);
-        });
+        setOnClickListener(this::onClick);
 
         mCurrentFullscreenParams = new FullscreenDrawParams(context);
         mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
@@ -487,10 +432,6 @@
                         + mCurrentFullscreenParams.mCurrentDrawnInsets.bottom);
     }
 
-    public TaskMenuView getMenuView() {
-        return mMenuView;
-    }
-
     public DigitalWellBeingToast getDigitalWellBeingToast() {
         return mDigitalWellBeingToast;
     }
@@ -524,10 +465,52 @@
         return mIconView;
     }
 
-    public AnimatorPlaybackController createLaunchAnimationForRunningTask() {
-        return getRecentsView().createTaskLaunchAnimation(
-                this, RECENTS_LAUNCH_DURATION, TOUCH_RESPONSE_INTERPOLATOR)
-                .createPlaybackController();
+    private void onClick(View view) {
+        if (getTask() == null) {
+            return;
+        }
+        if (LIVE_TILE.get() && isRunningTask()) {
+            if (!mIsClickableAsLiveTile) {
+                return;
+            }
+
+            // Reset the minimized state since we force-toggled the minimized state when entering
+            // overview, but never actually finished the recents animation
+            SystemUiProxy p = SystemUiProxy.INSTANCE.getNoCreate();
+            if (p != null) {
+                p.setSplitScreenMinimized(false);
+            }
+
+            mIsClickableAsLiveTile = false;
+            RecentsView recentsView = getRecentsView();
+            RemoteAnimationTargets targets = recentsView.getLiveTileParams().getTargetSet();
+            recentsView.getLiveTileTaskViewSimulator().setDrawsBelowRecents(false);
+
+            AnimatorSet anim = new AnimatorSet();
+            TaskViewUtils.composeRecentsLaunchAnimator(
+                    anim, this, targets.apps,
+                    targets.wallpapers, targets.nonApps, true /* launcherClosing */,
+                    mActivity.getStateManager(), recentsView,
+                    recentsView.getDepthController());
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animator) {
+                    recentsView.getLiveTileTaskViewSimulator().setDrawsBelowRecents(true);
+                    recentsView.finishRecentsAnimation(false, null);
+                    mIsClickableAsLiveTile = true;
+                }
+            });
+            anim.start();
+        } else {
+            if (mActivity.isInState(OVERVIEW_SPLIT_SELECT)) {
+                // User tapped to select second split screen app
+                getRecentsView().confirmSplitSelect(this);
+            } else {
+                launchTaskAnimated();
+            }
+        }
+        mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo())
+                .log(LAUNCHER_TASK_LAUNCH_TAP);
     }
 
     /**
@@ -662,15 +645,12 @@
 
         if (!getRecentsView().isClearAllHidden()) {
             getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
+            return false;
         } else {
-            mMenuView = TaskMenuView.showForTask(this);
             mActivity.getStatsLogManager().logger().withItemInfo(getItemInfo())
                     .log(LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS);
-            if (mMenuView != null) {
-                mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener);
-            }
+            return TaskMenuView.showForTask(this);
         }
-        return mMenuView != null;
     }
 
     private void setIcon(Drawable icon) {
@@ -729,10 +709,6 @@
         mIconView.setRotation(orientationHandler.getDegreesRotated());
         snapshotParams.topMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
         mSnapshotView.setLayoutParams(snapshotParams);
-
-        if (mMenuView != null) {
-            mMenuView.onRotationChanged();
-        }
     }
 
     private void setIconAndDimTransitionProgress(float progress, boolean invert) {
@@ -817,27 +793,6 @@
         onTaskListVisibilityChanged(false);
     }
 
-    @Override
-    public void onPageScroll(ScrollState scrollState, boolean gridEnabled) {
-        // Don't do anything if it's modal.
-        if (mModalness > 0) {
-            return;
-        }
-
-        float dwbBannerAlpha = Utilities.boundToRange(1.0f - 2 * scrollState.linearInterpolation,
-                0f, 1f);
-        mDigitalWellBeingToast.updateBannerAlpha(dwbBannerAlpha);
-
-        if (mMenuView != null) {
-            PagedOrientationHandler pagedOrientationHandler = getPagedOrientationHandler();
-            RecentsView recentsView = getRecentsView();
-            mMenuView.setPosition(getX() - recentsView.getScrollX(),
-                    getY() - recentsView.getScrollY(), pagedOrientationHandler);
-            mMenuView.setScaleX(getScaleX());
-            mMenuView.setScaleY(getScaleY());
-        }
-    }
-
     /**
      * Sets the contextual chip.
      *
@@ -1337,9 +1292,8 @@
     }
 
     public void initiateSplitSelect(SplitPositionOption splitPositionOption) {
-        RecentsView rv = getRecentsView();
-        getMenuView().close(false);
-        rv.initiateSplitSelect(this, splitPositionOption);
+        AbstractFloatingView.closeOpenViews(mActivity, false, TYPE_TASK_MENU);
+        getRecentsView().initiateSplitSelect(this, splitPositionOption);
     }
 
     private void setColorTint(float amount) {
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 5ffe315..0fe5432 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -120,7 +120,6 @@
                 getCurrentOverviewPage(launcher) < currentTaskAfterFlingForward));
 
         // Test opening a task.
-        startTestActivity(2);
         OverviewTask task = mLauncher.pressHome().switchToOverview().getCurrentTask();
         assertNotNull("overview.getCurrentTask() returned null (1)", task);
         assertNotNull("OverviewTask.open returned null", task.open());
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 24d764e..b570464 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -40,7 +40,7 @@
 
         <include layout="@layout/floating_header_content" />
 
-        <include layout="@layout/personal_work_tabs" />
+        <include layout="@layout/all_apps_personal_work_tabs" />
     </com.android.launcher3.allapps.FloatingHeaderView>
 
     <include
diff --git a/res/layout/personal_work_tabs.xml b/res/layout/all_apps_personal_work_tabs.xml
similarity index 100%
rename from res/layout/personal_work_tabs.xml
rename to res/layout/all_apps_personal_work_tabs.xml
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 8451b77..f34e685 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -62,9 +62,12 @@
             android:id="@+id/drop_target_bar"
             layout="@layout/drop_target_bar" />
 
-        <include
+        <com.android.launcher3.views.ScrimView
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
             android:id="@+id/scrim_view"
-            layout="@layout/scrim_view" />
+            android:background="?attr/allAppsScrimColor"
+            android:alpha="0" />
 
         <include
             android:id="@+id/apps_view"
diff --git a/res/layout/scrim_view.xml b/res/layout/scrim_view.xml
deleted file mode 100644
index a604d56..0000000
--- a/res/layout/scrim_view.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.views.ScrimView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:id="@+id/scrim_view" />
\ No newline at end of file
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index 30bd8b1..0f6fc6c 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -17,16 +17,31 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content">
 
-    <!-- The image of the widget. This view does not support padding. Any placement adjustment
-         should be done using margins. Width & height are set at runtime after scaling the preview
-         image. -->
-    <com.android.launcher3.widget.WidgetImageView
-        android:id="@+id/widget_preview"
+    <com.android.launcher3.widget.WidgetCellPreview
+        android:id="@+id/widget_preview_container"
         android:layout_width="0dp"
         android:layout_height="0dp"
         android:layout_weight="1"
         android:importantForAccessibility="no"
-        android:layout_marginVertical="8dp" />
+        android:layout_marginVertical="8dp">
+        <!-- The image of the widget. This view does not support padding. Any placement adjustment
+             should be done using margins. Width & height are set at runtime after scaling the
+             preview image. -->
+        <com.android.launcher3.widget.WidgetImageView
+            android:id="@+id/widget_preview"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:importantForAccessibility="no"
+            android:layout_gravity="fill"/>
+
+        <ImageView
+            android:id="@+id/widget_badge"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:importantForAccessibility="no"
+            android:layout_gravity="end|bottom"
+            android:layout_margin="@dimen/profile_badge_margin"/>
+    </com.android.launcher3.widget.WidgetCellPreview>
 
     <!-- The name of the widget. -->
     <TextView
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index ae877d4..e3d34f6 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -38,7 +38,7 @@
 
     </com.android.launcher3.workprofile.PersonalWorkPagedView>
 
-    <include layout="@layout/personal_work_tabs"
+    <include layout="@layout/widgets_personal_work_tabs"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginHorizontal="16dp" />
diff --git a/res/layout/widgets_list_row_header.xml b/res/layout/widgets_list_row_header.xml
index 598041c..8259c16 100644
--- a/res/layout/widgets_list_row_header.xml
+++ b/res/layout/widgets_list_row_header.xml
@@ -15,6 +15,7 @@
 -->
 <com.android.launcher3.widget.picker.WidgetsListHeader xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
     android:id="@+id/widgets_list_header"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
@@ -22,7 +23,8 @@
     android:background="@drawable/widgets_list_middle_ripple"
     android:layout_marginBottom="@dimen/widget_list_entry_bottom_margin"
     android:paddingVertical="@dimen/widget_list_header_view_vertical_padding"
-    android:orientation="horizontal">
+    android:orientation="horizontal"
+    launcher:appIconSize="48dp">
 
     <ImageView
         android:id="@+id/app_icon"
diff --git a/res/layout/widgets_personal_work_tabs.xml b/res/layout/widgets_personal_work_tabs.xml
new file mode 100644
index 0000000..3d3ae6a
--- /dev/null
+++ b/res/layout/widgets_personal_work_tabs.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+-->
+
+<com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tabs"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/all_apps_header_tab_height"
+    android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
+    android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
+    android:orientation="horizontal"
+    android:elevation="2dp"
+    style="@style/TextHeadline">
+
+    <Button
+        android:id="@+id/tab_personal"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:background="?android:attr/selectableItemBackground"
+        android:text="@string/widgets_full_sheet_personal_tab"
+        android:textColor="@color/all_apps_tab_text"
+        android:textSize="14sp" />
+
+    <Button
+        android:id="@+id/tab_work"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:background="?android:attr/selectableItemBackground"
+        android:text="@string/widgets_full_sheet_work_tab"
+        android:textColor="@color/all_apps_tab_text"
+        android:textSize="14sp" />
+</com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip>
\ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 99f6c75..381b0fe 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -162,6 +162,8 @@
         <!-- landscapeIconSize defaults to iconSize, if not specified -->
         <attr name="landscapeIconSize" format="float" />
         <attr name="iconTextSize" format="float" />
+        <!-- landscapeIconTextSize defaults to iconTextSize, if not specified -->
+        <attr name="landscapeIconTextSize" format="float" />
         <!-- If true, this display option is used to determine the default grid -->
         <attr name="canBeDefault" format="boolean" />
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1371e91..9072907 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -90,6 +90,13 @@
     <!-- Text shown when there are no matching widget search results for user's search query.
          [CHAR_LIMIT=none] -->
     <string name="no_search_results">No search results</string>
+    <!-- Tab label. A user can tap this tab to access their personal widgets. [CHAR_LIMIT=25] -->
+    <string name="widgets_full_sheet_personal_tab">Personal</string>
+    <!-- Tab label. A user can tap this tab to access their work widgets. [CHAR_LIMIT=25] -->
+    <string name="widgets_full_sheet_work_tab">Work</string>
+
+    <!-- A widget category label for grouping widgets related to conversations. [CHAR_LIMIT=30] -->
+    <string name="widget_category_conversations">Conversations</string>
 
     <!-- All Apps -->
     <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index a27cdac..fd77b80 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -150,7 +150,7 @@
     </style>
 
     <style name="HomeSettingsTheme" parent="@android:style/Theme.DeviceDefault.Settings">
-        <item name="android:navigationBarColor">@android:color/transparent</item>
+        <item name="android:navigationBarColor">?android:colorPrimaryDark</item>
         <item name="preferenceTheme">@style/HomeSettingsPreferenceTheme</item>
     </style>
 
diff --git a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
index 8baf5a3..adf720f 100644
--- a/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/BackupRestoreTest.java
@@ -35,6 +35,7 @@
 import android.content.pm.PackageInstaller;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
+import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 
@@ -64,17 +65,11 @@
     private static final long OLD_WORK_PROFILE_ID = 11;
     private static final int WORK_PROFILE_ID = 10;
 
-    private static final int SYSTEM_USER = 0;
-    private static final int FLAG_SYSTEM = 0x00000800;
-    private static final int FLAG_PROFILE = 0x00001000;
-
     private ShadowUserManager mUserManager;
     private BackupManager mBackupManager;
     private LauncherModelHelper mModelHelper;
     private SQLiteDatabase mDb;
     private InvariantDeviceProfile mIdp;
-    private UserHandle mMainProfileUser;
-    private UserHandle mWorkProfileUser;
 
     @Before
     public void setUp() {
@@ -90,17 +85,15 @@
         final UserManager userManager = RuntimeEnvironment.application.getSystemService(
                 UserManager.class);
         mUserManager = Shadow.extract(userManager);
-        // sign in to primary user
-        mMainProfileUser = mUserManager.addUser(SYSTEM_USER, "me", FLAG_SYSTEM);
         // sign in to work profile
-        mWorkProfileUser = mUserManager.addUser(WORK_PROFILE_ID, "work", FLAG_PROFILE);
+        mUserManager.addUser(WORK_PROFILE_ID, "work", ShadowUserManager.FLAG_MANAGED_PROFILE);
     }
 
     private void setupBackupManager() {
         mBackupManager = new BackupManager(RuntimeEnvironment.application);
         final LShadowBackupManager bm = Shadow.extract(mBackupManager);
-        bm.addProfile(MY_OLD_PROFILE_ID, mMainProfileUser);
-        bm.addProfile(OLD_WORK_PROFILE_ID, mWorkProfileUser);
+        bm.addProfile(MY_OLD_PROFILE_ID, Process.myUserHandle());
+        bm.addProfile(OLD_WORK_PROFILE_ID, UserHandle.of(WORK_PROFILE_ID));
     }
 
     @Test
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
index c2bf1ae..36b6f01 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
@@ -18,64 +18,197 @@
 
 import static android.os.Looper.getMainLooper;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.matches;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 import static org.robolectric.Shadows.shadowOf;
 
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.os.UserHandle;
+
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.ComponentWithLabel;
+import com.android.launcher3.icons.IconCache;
+import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.search.SearchCallback;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+import com.android.launcher3.widget.model.WidgetsListContentEntry;
+import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
+import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowPackageManager;
+import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
-import java.util.function.Consumer;
 
 @RunWith(RobolectricTestRunner.class)
 public class SimpleWidgetsSearchAlgorithmTest {
 
+    @Mock private IconCache mIconCache;
+
+    private InvariantDeviceProfile mTestProfile;
+    private WidgetsListHeaderEntry mCalendarHeaderEntry;
+    private WidgetsListContentEntry mCalendarContentEntry;
+    private WidgetsListHeaderEntry mCameraHeaderEntry;
+    private WidgetsListContentEntry mCameraContentEntry;
+    private WidgetsListHeaderEntry mClockHeaderEntry;
+    private WidgetsListContentEntry mClockContentEntry;
+    private Context mContext;
+
     private SimpleWidgetsSearchAlgorithm mSimpleWidgetsSearchAlgorithm;
     @Mock
-    private WidgetsPickerSearchPipeline mSearchPipeline;
+    private PopupDataProvider mDataProvider;
     @Mock
     private SearchCallback<WidgetsListBaseEntry> mSearchCallback;
-    @Captor
-    private ArgumentCaptor<Consumer<List<WidgetsListBaseEntry>>> mConsumerCaptor;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mSimpleWidgetsSearchAlgorithm = new SimpleWidgetsSearchAlgorithm(mSearchPipeline);
+        doAnswer(invocation -> {
+            ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
+            return componentWithLabel.getComponent().getShortClassName();
+        }).when(mIconCache).getTitleNoCache(any());
+        mTestProfile = new InvariantDeviceProfile();
+        mTestProfile.numRows = 5;
+        mTestProfile.numColumns = 5;
+        mContext = RuntimeEnvironment.application;
+
+        mCalendarHeaderEntry =
+                createWidgetsHeaderEntry("com.example.android.Calendar", "Calendar", 2);
+        mCalendarContentEntry =
+                createWidgetsContentEntry("com.example.android.Calendar", "Calendar", 2);
+        mCameraHeaderEntry = createWidgetsHeaderEntry("com.example.android.Camera", "Camera", 11);
+        mCameraContentEntry = createWidgetsContentEntry("com.example.android.Camera", "Camera", 11);
+        mClockHeaderEntry = createWidgetsHeaderEntry("com.example.android.Clock", "Clock", 3);
+        mClockContentEntry = createWidgetsContentEntry("com.example.android.Clock", "Clock", 3);
+
+
+        mSimpleWidgetsSearchAlgorithm = new SimpleWidgetsSearchAlgorithm(mDataProvider);
+        doReturn(Collections.EMPTY_LIST).when(mDataProvider).getAllWidgets();
     }
 
     @Test
-    public void doSearch_shouldQueryPipeline() {
-        mSimpleWidgetsSearchAlgorithm.doSearch("abc", mSearchCallback);
+    public void filter_shouldMatchOnAppName() {
+        doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
+                mCameraContentEntry, mClockHeaderEntry, mClockContentEntry))
+                .when(mDataProvider)
+                .getAllWidgets();
 
-        verify(mSearchPipeline).query(eq("abc"), any());
+        assertEquals(List.of(
+                new WidgetsListSearchHeaderEntry(
+                        mCalendarHeaderEntry.mPkgItem,
+                        mCalendarHeaderEntry.mTitleSectionName,
+                        mCalendarHeaderEntry.mWidgets),
+                mCalendarContentEntry,
+                new WidgetsListSearchHeaderEntry(
+                        mCameraHeaderEntry.mPkgItem,
+                        mCameraHeaderEntry.mTitleSectionName,
+                        mCameraHeaderEntry.mWidgets),
+                mCameraContentEntry),
+                SimpleWidgetsSearchAlgorithm.getFilteredWidgets(mDataProvider, "Ca"));
     }
 
     @Test
-    public void doSearch_shouldInformSearchCallbackOnQueryResult() {
-        ArrayList<WidgetsListBaseEntry> baseEntries = new ArrayList<>();
+    public void filter_shouldMatchOnWidgetLabel() {
+        doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
+                mCameraContentEntry))
+                .when(mDataProvider)
+                .getAllWidgets();
 
-        mSimpleWidgetsSearchAlgorithm.doSearch("abc", mSearchCallback);
+        assertEquals(List.of(
+                new WidgetsListSearchHeaderEntry(
+                        mCalendarHeaderEntry.mPkgItem,
+                        mCalendarHeaderEntry.mTitleSectionName,
+                        mCalendarHeaderEntry.mWidgets.subList(1, 2)),
+                new WidgetsListContentEntry(
+                        mCalendarHeaderEntry.mPkgItem,
+                        mCalendarHeaderEntry.mTitleSectionName,
+                        mCalendarHeaderEntry.mWidgets.subList(1, 2)),
+                new WidgetsListSearchHeaderEntry(
+                        mCameraHeaderEntry.mPkgItem,
+                        mCameraHeaderEntry.mTitleSectionName,
+                        mCameraHeaderEntry.mWidgets.subList(1, 3)),
+                new WidgetsListContentEntry(
+                        mCameraHeaderEntry.mPkgItem,
+                        mCameraHeaderEntry.mTitleSectionName,
+                        mCameraHeaderEntry.mWidgets.subList(1, 3))),
+                SimpleWidgetsSearchAlgorithm.getFilteredWidgets(mDataProvider, "Widget1"));
+    }
 
-        verify(mSearchPipeline).query(eq("abc"), mConsumerCaptor.capture());
-        mConsumerCaptor.getValue().accept(baseEntries);
+    @Test
+    public void doSearch_shouldInformCallback() {
+        doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
+                mCameraContentEntry, mClockHeaderEntry, mClockContentEntry))
+                .when(mDataProvider)
+                .getAllWidgets();
+        mSimpleWidgetsSearchAlgorithm.doSearch("Ca", mSearchCallback);
         shadowOf(getMainLooper()).idle();
-        // Verify SearchCallback#onSearchResult receives a query token along with the search
-        // results. The query token is the original query string concatenated with the query
-        // timestamp.
-        verify(mSearchCallback).onSearchResult(matches("abc\t\\d*"), eq(baseEntries));
+        verify(mSearchCallback).onSearchResult(
+                matches("Ca"), argThat(a -> a != null && !a.isEmpty()));
+    }
+
+    private WidgetsListHeaderEntry createWidgetsHeaderEntry(String packageName, String appName,
+            int numOfWidgets) {
+        List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
+        PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
+                widgetItems.get(0).user);
+
+        return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
+    }
+
+    private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,
+            int numOfWidgets) {
+        List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
+        PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
+                widgetItems.get(0).user);
+
+        return new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems);
+    }
+
+    private PackageItemInfo createPackageItemInfo(String packageName, String appName,
+            UserHandle userHandle) {
+        PackageItemInfo pInfo = new PackageItemInfo(packageName);
+        pInfo.title = appName;
+        pInfo.user = userHandle;
+        pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
+        return pInfo;
+    }
+
+    private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
+        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
+        ArrayList<WidgetItem> widgetItems = new ArrayList<>();
+        for (int i = 0; i < numOfWidgets; i++) {
+            ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
+            AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
+            widgetInfo.provider = cn;
+            ReflectionHelpers.setField(widgetInfo, "providerInfo",
+                    packageManager.addReceiverIfNotPresent(cn));
+
+            WidgetItem widgetItem = new WidgetItem(
+                    LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
+                    mTestProfile, mIconCache);
+            widgetItems.add(widgetItem);
+        }
+        return widgetItems;
     }
 }
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipelineTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipelineTest.java
deleted file mode 100644
index 17ededd..0000000
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipelineTest.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.widget.picker.search;
-
-import static android.os.Looper.getMainLooper;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.robolectric.Shadows.shadowOf;
-
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.os.UserHandle;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.ComponentWithLabel;
-import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.widget.model.WidgetsListContentEntry;
-import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.util.ReflectionHelpers;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-public class SimpleWidgetsSearchPipelineTest {
-    @Mock private IconCache mIconCache;
-
-    private InvariantDeviceProfile mTestProfile;
-    private WidgetsListHeaderEntry mCalendarHeaderEntry;
-    private WidgetsListContentEntry mCalendarContentEntry;
-    private WidgetsListHeaderEntry mCameraHeaderEntry;
-    private WidgetsListContentEntry mCameraContentEntry;
-    private WidgetsListHeaderEntry mClockHeaderEntry;
-    private WidgetsListContentEntry mClockContentEntry;
-    private Context mContext;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        doAnswer(invocation -> {
-            ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
-            return componentWithLabel.getComponent().getShortClassName();
-        }).when(mIconCache).getTitleNoCache(any());
-        mTestProfile = new InvariantDeviceProfile();
-        mTestProfile.numRows = 5;
-        mTestProfile.numColumns = 5;
-        mContext = RuntimeEnvironment.application;
-
-        mCalendarHeaderEntry =
-                createWidgetsHeaderEntry("com.example.android.Calendar", "Calendar", 2);
-        mCalendarContentEntry =
-                createWidgetsContentEntry("com.example.android.Calendar", "Calendar", 2);
-        mCameraHeaderEntry = createWidgetsHeaderEntry("com.example.android.Camera", "Camera", 11);
-        mCameraContentEntry = createWidgetsContentEntry("com.example.android.Camera", "Camera", 11);
-        mClockHeaderEntry = createWidgetsHeaderEntry("com.example.android.Clock", "Clock", 3);
-        mClockContentEntry = createWidgetsContentEntry("com.example.android.Clock", "Clock", 3);
-    }
-
-    @Test
-    public void query_shouldMatchOnAppName() {
-        SimpleWidgetsSearchPipeline pipeline = new SimpleWidgetsSearchPipeline(
-                List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
-                        mCameraContentEntry, mClockHeaderEntry, mClockContentEntry));
-
-        pipeline.query("Ca", results ->
-                assertEquals(results,
-                        List.of(
-                                new WidgetsListSearchHeaderEntry(
-                                        mCalendarHeaderEntry.mPkgItem,
-                                        mCalendarHeaderEntry.mTitleSectionName,
-                                        mCalendarHeaderEntry.mWidgets),
-                                mCalendarContentEntry,
-                                new WidgetsListSearchHeaderEntry(
-                                        mCameraHeaderEntry.mPkgItem,
-                                        mCameraHeaderEntry.mTitleSectionName,
-                                        mCameraHeaderEntry.mWidgets),
-                                mCameraContentEntry)));
-        shadowOf(getMainLooper()).idle();
-    }
-
-    @Test
-    public void query_shouldMatchOnWidgetLabel() {
-        SimpleWidgetsSearchPipeline pipeline = new SimpleWidgetsSearchPipeline(
-                List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
-                        mCameraContentEntry));
-
-        pipeline.query("Widget1", results ->
-                assertEquals(results,
-                        List.of(
-                                new WidgetsListSearchHeaderEntry(
-                                        mCalendarHeaderEntry.mPkgItem,
-                                        mCalendarHeaderEntry.mTitleSectionName,
-                                        mCalendarHeaderEntry.mWidgets.subList(1, 2)),
-                                new WidgetsListContentEntry(
-                                        mCalendarHeaderEntry.mPkgItem,
-                                        mCalendarHeaderEntry.mTitleSectionName,
-                                        mCalendarHeaderEntry.mWidgets.subList(1, 2)),
-                                new WidgetsListSearchHeaderEntry(
-                                        mCameraHeaderEntry.mPkgItem,
-                                        mCameraHeaderEntry.mTitleSectionName,
-                                        mCameraHeaderEntry.mWidgets.subList(1, 3)),
-                                new WidgetsListContentEntry(
-                                        mCameraHeaderEntry.mPkgItem,
-                                        mCameraHeaderEntry.mTitleSectionName,
-                                        mCameraHeaderEntry.mWidgets.subList(1, 3)))));
-        shadowOf(getMainLooper()).idle();
-    }
-
-    private WidgetsListHeaderEntry createWidgetsHeaderEntry(String packageName, String appName,
-            int numOfWidgets) {
-        List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
-        PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
-                widgetItems.get(0).user);
-
-        return new WidgetsListHeaderEntry(pInfo, /* titleSectionName= */ "", widgetItems);
-    }
-
-    private WidgetsListContentEntry createWidgetsContentEntry(String packageName, String appName,
-            int numOfWidgets) {
-        List<WidgetItem> widgetItems = generateWidgetItems(packageName, numOfWidgets);
-        PackageItemInfo pInfo = createPackageItemInfo(packageName, appName,
-                widgetItems.get(0).user);
-
-        return new WidgetsListContentEntry(pInfo, /* titleSectionName= */ "", widgetItems);
-    }
-
-    private PackageItemInfo createPackageItemInfo(String packageName, String appName,
-            UserHandle userHandle) {
-        PackageItemInfo pInfo = new PackageItemInfo(packageName);
-        pInfo.title = appName;
-        pInfo.user = userHandle;
-        pInfo.bitmap = BitmapInfo.of(Bitmap.createBitmap(10, 10, Bitmap.Config.ALPHA_8), 0);
-        return pInfo;
-    }
-
-    private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
-        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
-        ArrayList<WidgetItem> widgetItems = new ArrayList<>();
-        for (int i = 0; i < numOfWidgets; i++) {
-            ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
-            AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
-            widgetInfo.provider = cn;
-            ReflectionHelpers.setField(widgetInfo, "providerInfo",
-                    packageManager.addReceiverIfNotPresent(cn));
-
-            WidgetItem widgetItem = new WidgetItem(
-                    LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
-                    mTestProfile, mIconCache);
-            widgetItems.add(widgetItem);
-        }
-        return widgetItems;
-    }
-}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index aea38a0..35b0f27 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -506,9 +506,10 @@
 
         // Workspace
         final boolean isVerticalLayout = isVerticalBarLayout();
-        float invIconSizeDp = isVerticalLayout ? inv.landscapeIconSize : inv.iconSize;
+        float invIconSizeDp = isLandscape ? inv.landscapeIconSize : inv.iconSize;
         iconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mInfo.metrics, scale));
-        iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, mInfo.metrics) * scale);
+        float invIconTextSizeSp = isLandscape ? inv.landscapeIconTextSize : inv.iconTextSize;
+        iconTextSizePx = (int) (Utilities.pxFromSp(invIconTextSizeSp, mInfo.metrics) * scale);
         iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * scale);
 
         setCellLayoutBorderSpacing((int) (cellLayoutBorderSpacingOriginalPx * scale));
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 754e988..5612daf 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -106,6 +106,7 @@
     public float iconSize;
     public String iconShapePath;
     public float landscapeIconSize;
+    public float landscapeIconTextSize;
     public int iconBitmapSize;
     public int fillResIconDpi;
     public float iconTextSize;
@@ -163,6 +164,7 @@
         landscapeIconSize = p.landscapeIconSize;
         iconBitmapSize = p.iconBitmapSize;
         iconTextSize = p.iconTextSize;
+        landscapeIconTextSize = p.landscapeIconTextSize;
         numHotseatIcons = p.numHotseatIcons;
         numAllAppsColumns = p.numAllAppsColumns;
         isScalable = p.isScalable;
@@ -293,6 +295,7 @@
         landscapeIconSize = displayOption.landscapeIconSize;
         iconBitmapSize = ResourceUtils.pxFromDp(iconSize, displayInfo.metrics);
         iconTextSize = displayOption.iconTextSize;
+        landscapeIconTextSize = displayOption.landscapeIconTextSize;
         fillResIconDpi = getLauncherIconDensity(iconBitmapSize);
 
         minCellHeight = displayOption.minCellHeight;
@@ -678,6 +681,7 @@
         private float iconSize;
         private float iconTextSize;
         private float landscapeIconSize;
+        private float landscapeIconTextSize;
         private float allAppsIconSize;
         private float allAppsIconTextSize;
 
@@ -702,6 +706,8 @@
             landscapeIconSize = a.getFloat(R.styleable.ProfileDisplayOption_landscapeIconSize,
                     iconSize);
             iconTextSize = a.getFloat(R.styleable.ProfileDisplayOption_iconTextSize, 0);
+            landscapeIconTextSize = a.getFloat(
+                    R.styleable.ProfileDisplayOption_landscapeIconTextSize, iconTextSize);
 
             allAppsIconSize = a.getFloat(R.styleable.ProfileDisplayOption_allAppsIconSize,
                     iconSize);
@@ -731,6 +737,7 @@
             landscapeIconSize *= w;
             allAppsIconSize *= w;
             iconTextSize *= w;
+            landscapeIconTextSize *= w;
             allAppsIconTextSize *= w;
             minCellHeight *= w;
             minCellWidth *= w;
@@ -744,6 +751,7 @@
             landscapeIconSize += p.landscapeIconSize;
             allAppsIconSize += p.allAppsIconSize;
             iconTextSize += p.iconTextSize;
+            landscapeIconTextSize += p.landscapeIconTextSize;
             allAppsIconTextSize += p.allAppsIconTextSize;
             minCellHeight += p.minCellHeight;
             minCellWidth += p.minCellWidth;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index df5f953..5091543 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1191,8 +1191,7 @@
 
         // Setup the drag controller (drop targets have to be added in reverse order in priority)
         mDropTargetBar.setup(mDragController);
-
-        mAllAppsController.setupViews(mAppsView, mScrimView);
+        mAllAppsController.setupViews(mAppsView);
     }
 
     /**
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 1003958..0c509a1 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -209,11 +209,11 @@
         return 1f;
     }
 
-    public float getWorkspaceScrimAlpha(Launcher launcher) {
+    public float getWorkspaceBackgroundAlpha(Launcher launcher) {
         return 0;
     }
 
-    public float getOverviewScrimAlpha(Launcher launcher) {
+    public float getWorkspaceScrimAlpha(Launcher launcher) {
         return 0;
     }
 
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 01f7c71..7496703 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -926,8 +926,7 @@
         if (disallowIntercept) {
             // We need to make sure to cancel our long press if
             // a scrollable widget takes over touch events
-            final View currentPage = getPageAt(mCurrentPage);
-            currentPage.cancelLongPress();
+            cancelCurrentPageLongPress();
         }
         super.requestDisallowInterceptTouchEvent(disallowIntercept);
     }
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index 1bbbb2b..5036104 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -24,6 +24,7 @@
 import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.WorkerThread;
 
@@ -36,6 +37,8 @@
  */
 public class SessionCommitReceiver extends BroadcastReceiver {
 
+    private static final String LOG = "SessionCommitReceiver";
+
     // Preference key for automatically adding icon to homescreen.
     public static final String ADD_ICON_PREFERENCE_KEY = "pref_add_icon_to_home";
 
@@ -68,6 +71,11 @@
             return;
         }
 
+        Log.i(LOG,
+                "Adding package name to install queue. Package name: " + info.getAppPackageName()
+                        + ", has app icon: " + (info.getAppIcon() != null)
+                        + ", has app label: " + !TextUtils.isEmpty(info.getAppLabel()));
+
         ItemInstallQueue.INSTANCE.get(context)
                 .queueItem(info.getAppPackageName(), user);
     }
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index e0a4d4a..24de19f 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -38,6 +38,7 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
+import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCRIM_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
 
 import android.animation.ValueAnimator;
@@ -150,7 +151,7 @@
         propertySetter.setFloat(mWorkspace.getPageIndicator(), VIEW_TRANSLATE_Y,
                 hotseatScaleAndTranslation.translationY, hotseatTranslationInterpolator);
 
-        setScrim(propertySetter, state);
+        setScrim(propertySetter, state, config);
     }
 
     /**
@@ -165,14 +166,19 @@
                 - sibling.getLeft() - sibling.getTranslationX());
     }
 
-    public void setScrim(PropertySetter propertySetter, LauncherState state) {
+    public void setScrim(PropertySetter propertySetter, LauncherState state,
+            StateAnimationConfig config) {
         WorkspaceDragScrim workspaceDragScrim = mLauncher.getDragLayer().getWorkspaceDragScrim();
         propertySetter.setFloat(workspaceDragScrim, SCRIM_PROGRESS,
-                state.getWorkspaceScrimAlpha(mLauncher), LINEAR);
+                state.getWorkspaceBackgroundAlpha(mLauncher), LINEAR);
 
         SysUiScrim sysUiScrim = mLauncher.getDragLayer().getSysUiScrim();
         propertySetter.setFloat(sysUiScrim, SYSUI_PROGRESS,
                 state.hasFlag(FLAG_HAS_SYS_UI_SCRIM) ? 1 : 0, LINEAR);
+
+        propertySetter.setViewAlpha(mLauncher.getScrimView(),
+                state.getWorkspaceScrimAlpha(mLauncher),
+                config.getInterpolator(ANIM_WORKSPACE_SCRIM_FADE, LINEAR));
     }
 
     public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index c21d774..0060b83 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -43,7 +43,6 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.views.ScrimView;
 
 /**
  * Handles AllApps view transition.
@@ -72,10 +71,7 @@
                 }
             };
 
-    private static final int APPS_VIEW_ALPHA_CHANNEL_INDEX = 0;
-
     private AllAppsContainerView mAppsView;
-    private ScrimView mScrimView;
 
     private final Launcher mLauncher;
     private boolean mIsVerticalLayout;
@@ -125,8 +121,6 @@
      */
     public void setProgress(float progress) {
         mProgress = progress;
-
-        mScrimView.setProgress(progress);
         mAppsView.setTranslationY(mProgress * mShiftRange);
     }
 
@@ -191,9 +185,8 @@
         return AnimationSuccessListener.forRunnable(this::onProgressAnimationEnd);
     }
 
-    public void setupViews(AllAppsContainerView appsView, ScrimView scrimView) {
+    public void setupViews(AllAppsContainerView appsView) {
         mAppsView = appsView;
-        mScrimView = scrimView;
         if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && Utilities.ATLEAST_R) {
             mLauncher.getSystemUiController().updateUiState(UI_STATE_ALLAPPS,
                     View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
@@ -207,10 +200,6 @@
     void setScrollRangeDelta(float delta) {
         mScrollRangeDelta = delta;
         mShiftRange = mLauncher.getDeviceProfile().heightPx - mScrollRangeDelta;
-
-        if (mScrimView != null) {
-            mScrimView.reInitUi();
-        }
     }
 
     /**
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index 4e90c9e..9068331 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -117,11 +117,18 @@
      * Adds a callback to be run on every frame of the animation
      */
     public void addOnFrameCallback(Runnable runnable) {
+        addOnFrameListener(anim -> runnable.run());
+    }
+
+    /**
+     * Adds a listener to be run on every frame of the animation
+     */
+    public void addOnFrameListener(ValueAnimator.AnimatorUpdateListener listener) {
         if (mProgressAnimator == null) {
             mProgressAnimator = ValueAnimator.ofFloat(0, 1);
         }
 
-        mProgressAnimator.addUpdateListener(anim -> runnable.run());
+        mProgressAnimator.addUpdateListener(listener);
     }
 
     /**
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index f5fbe2b..6331ef2 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -95,6 +95,10 @@
     public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag(
             "ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps");
 
+    public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(
+            "ENABLE_PEOPLE_TILE_PREVIEW", false,
+            "Experimental: Shows conversation shortcuts on home screen as search results");
+
     public static final BooleanFlag FOLDER_NAME_SUGGEST = new DeviceFlag(
             "FOLDER_NAME_SUGGEST", true,
             "Suggests folder names instead of blank text.");
diff --git a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
index 7b32bbf..2135f5d 100644
--- a/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
+++ b/src/com/android/launcher3/dragndrop/AppWidgetHostViewDrawable.java
@@ -17,12 +17,8 @@
 
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
-import android.graphics.Outline;
 import android.graphics.Paint;
-import android.graphics.Path;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -36,38 +32,15 @@
 
     private final LauncherAppWidgetHostView mAppWidgetHostView;
     private Paint mPaint = new Paint();
-    private final Path mClipPath;
-    private final boolean mWasAttached;
 
     public AppWidgetHostViewDrawable(LauncherAppWidgetHostView appWidgetHostView) {
         mAppWidgetHostView = appWidgetHostView;
-        mWasAttached = appWidgetHostView.isAttachedToWindow();
-        Path clipPath = null;
-        if (appWidgetHostView.getClipToOutline()) {
-            Outline outline = new Outline();
-            mAppWidgetHostView.getOutlineProvider().getOutline(mAppWidgetHostView, outline);
-            Rect rect = new Rect();
-            if (outline.getRect(rect)) {
-                float radius = outline.getRadius();
-                clipPath = new Path();
-                clipPath.addRoundRect(new RectF(rect), radius, radius, Path.Direction.CCW);
-            }
-        }
-        mClipPath = clipPath;
     }
 
     @Override
     public void draw(Canvas canvas) {
         int saveCount = canvas.saveLayer(0, 0, getIntrinsicWidth(), getIntrinsicHeight(), mPaint);
-        if (mClipPath != null) {
-            canvas.clipPath(mClipPath);
-        }
-        // If the view was never attached, or is current attached, then draw. Otherwise do not try
-        // to draw, or we might trigger bugs with items that get drawn while requiring the view to
-        // be attached.
-        if (!mWasAttached || mAppWidgetHostView.isAttachedToWindow()) {
-            mAppWidgetHostView.draw(canvas);
-        }
+        mAppWidgetHostView.draw(canvas);
         canvas.restoreToCount(saveCount);
     }
 
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 419c3f1..c80fd90 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -46,7 +46,6 @@
 import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.folder.Folder;
-import com.android.launcher3.graphics.OverviewScrim;
 import com.android.launcher3.graphics.SysUiScrim;
 import com.android.launcher3.graphics.WorkspaceDragScrim;
 import com.android.launcher3.keyboard.ViewGroupFocusHelper;
@@ -84,7 +83,6 @@
 
     // Related to adjacent page hints
     private final ViewGroupFocusHelper mFocusIndicatorHelper;
-    private final OverviewScrim mOverviewScrim;
     private WorkspaceDragScrim mWorkspaceDragScrim;
     private SysUiScrim mSysUiScrim;
     private LauncherRootView mRootView;
@@ -103,15 +101,12 @@
         setChildrenDrawingOrderEnabled(true);
 
         mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
-        mOverviewScrim = new OverviewScrim(this);
     }
 
     public void setup(DragController dragController, Workspace workspace) {
         mDragController = dragController;
         recreateControllers();
 
-        mOverviewScrim.setup();
-
         mWorkspaceDragScrim = new WorkspaceDragScrim((this));
         mWorkspaceDragScrim.setWorkspace(workspace);
 
@@ -529,20 +524,8 @@
     protected void dispatchDraw(Canvas canvas) {
         // Draw the background below children.
         mWorkspaceDragScrim.draw(canvas);
-        mOverviewScrim.updateCurrentScrimmedView(this);
         mFocusIndicatorHelper.draw(canvas);
         super.dispatchDraw(canvas);
-        if (mOverviewScrim.getScrimmedView() == null) {
-            mOverviewScrim.draw(canvas);
-        }
-    }
-
-    @Override
-    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
-        if (child == mOverviewScrim.getScrimmedView()) {
-            mOverviewScrim.draw(canvas);
-        }
-        return super.drawChild(canvas, child, drawingTime);
     }
 
     @Override
@@ -564,8 +547,4 @@
     public SysUiScrim getSysUiScrim() {
         return mSysUiScrim;
     }
-
-    public OverviewScrim getOverviewScrim() {
-        return mOverviewScrim;
-    }
 }
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index a1b7997..cf1cb45 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -78,7 +78,6 @@
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
 import com.android.launcher3.Workspace.ItemOperator;
 import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
 import com.android.launcher3.accessibility.FolderAccessibilityHelper;
@@ -534,9 +533,25 @@
     }
 
     private void startAnimation(final AnimatorSet a) {
-        final Workspace workspace = mLauncher.getWorkspace();
-        final CellLayout currentCellLayout =
-                (CellLayout) workspace.getChildAt(workspace.getCurrentPage());
+        mLauncher.getWorkspace().getVisiblePages()
+                .forEach(visiblePage -> addAnimatorListenerForPage(a, (CellLayout) visiblePage));
+
+        a.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mState = STATE_ANIMATING;
+                mCurrentAnimator = a;
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mCurrentAnimator = null;
+            }
+        });
+        a.start();
+    }
+
+    private void addAnimatorListenerForPage(AnimatorSet a, CellLayout currentCellLayout) {
         final boolean useHardware = shouldUseHardwareLayerForAnimation(currentCellLayout);
         final boolean wasHardwareAccelerated = currentCellLayout.isHardwareLayerEnabled();
 
@@ -546,8 +561,6 @@
                 if (useHardware) {
                     currentCellLayout.enableHardwareLayer(true);
                 }
-                mState = STATE_ANIMATING;
-                mCurrentAnimator = a;
             }
 
             @Override
@@ -555,10 +568,8 @@
                 if (useHardware) {
                     currentCellLayout.enableHardwareLayer(wasHardwareAccelerated);
                 }
-                mCurrentAnimator = null;
             }
         });
-        a.start();
     }
 
     private boolean shouldUseHardwareLayerForAnimation(CellLayout currentCellLayout) {
diff --git a/src/com/android/launcher3/graphics/OverviewScrim.java b/src/com/android/launcher3/graphics/OverviewScrim.java
deleted file mode 100644
index 7aadb96..0000000
--- a/src/com/android/launcher3/graphics/OverviewScrim.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2019 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.graphics;
-
-import static android.view.View.VISIBLE;
-
-import android.util.FloatProperty;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.WallpaperColorInfo;
-import com.android.launcher3.util.Themes;
-
-/**
- * View scrim which draws behind overview (recent apps).
- */
-public class OverviewScrim extends Scrim {
-
-    public static final FloatProperty<OverviewScrim> SCRIM_MULTIPLIER =
-            new FloatProperty<OverviewScrim>("scrimMultiplier") {
-                @Override
-                public Float get(OverviewScrim scrim) {
-                    return scrim.mScrimMultiplier;
-                }
-
-                @Override
-                public void setValue(OverviewScrim scrim, float v) {
-                    scrim.setScrimMultiplier(v);
-                }
-            };
-
-    private @NonNull View mStableScrimmedView;
-    // Might be higher up if mStableScrimmedView is invisible.
-    private @Nullable View mCurrentScrimmedView;
-
-    private float mScrimMultiplier = 1f;
-
-    public OverviewScrim(View view) {
-        super(view);
-
-        mScrimColor = Themes.getAttrColor(view.getContext(), R.attr.allAppsScrimColor);
-    }
-
-    /**
-     * Initializes once view hierarchy is established.
-     */
-    public void setup() {
-        mStableScrimmedView = mCurrentScrimmedView = mLauncher.getOverviewPanel();
-    }
-
-    /**
-     * @param view The view we want the scrim to be behind
-     */
-    public void updateStableScrimmedView(View view) {
-        mStableScrimmedView = view;
-    }
-
-    public void updateCurrentScrimmedView(ViewGroup root) {
-        // Find the lowest view that is at or above the view we want to show the scrim behind.
-        mCurrentScrimmedView = mStableScrimmedView;
-        int currentIndex = root.indexOfChild(mCurrentScrimmedView);
-        final int childCount = root.getChildCount();
-        while (mCurrentScrimmedView != null && mCurrentScrimmedView.getVisibility() != VISIBLE
-                && currentIndex < childCount) {
-            currentIndex++;
-            mCurrentScrimmedView = root.getChildAt(currentIndex);
-        }
-    }
-
-    @Override
-    public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
-        // No super, don't respond to wallpaper colors, follow device ones instead
-    }
-
-    /**
-     * @return The view to draw the scrim behind, or null if all visible views should be scrimmed.
-     */
-    public @Nullable View getScrimmedView() {
-        return mCurrentScrimmedView;
-    }
-
-    private void setScrimMultiplier(float scrimMultiplier) {
-        if (Float.compare(mScrimMultiplier, scrimMultiplier) != 0) {
-            mScrimMultiplier = scrimMultiplier;
-            invalidate();
-        }
-    }
-
-    @Override
-    protected int getScrimAlpha() {
-        return Math.round(super.getScrimAlpha() * mScrimMultiplier);
-    }
-}
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 988794c..a2c0f5c 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -39,6 +39,7 @@
 
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherFiles;
+import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
@@ -304,6 +305,11 @@
         CacheEntry entry = getEntryForPackageLocked(
                 infoInOut.packageName, infoInOut.user, useLowResIcon);
         applyCacheEntry(entry, infoInOut);
+        if (infoInOut.category == PackageItemInfo.CONVERSATIONS) {
+            infoInOut.title = mContext.getString(R.string.widget_category_conversations);
+            infoInOut.contentDescription = mPackageManager.getUserBadgedLabel(
+                    infoInOut.title, infoInOut.user);
+        }
     }
 
     protected void applyCacheEntry(CacheEntry entry, ItemInfoWithIcon info) {
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 56dbbd3..fd51ba8 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -20,6 +20,7 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.os.UserHandle;
+import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.Pair;
 
@@ -47,6 +48,8 @@
  */
 public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
 
+    private static final String LOG = "AddWorkspaceItemsTask";
+
     private final List<Pair<ItemInfo, Object>> mItemList;
 
     /**
@@ -167,6 +170,8 @@
 
                 // Save the WorkspaceItemInfo for binding in the workspace
                 addedItemsFinal.add(itemInfo);
+
+                Log.i(LOG, "Adding item info to workspace: " + itemInfo);
             }
         }
 
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index df8367f..836d804 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -63,6 +63,8 @@
  */
 public class ItemInstallQueue {
 
+    private static final String LOG = "ItemInstallQueue";
+
     public static final int FLAG_ACTIVITY_PAUSED = 1;
     public static final int FLAG_LOADER_RUNNING = 2;
     public static final int FLAG_DRAG_AND_DROP = 4;
@@ -183,7 +185,17 @@
 
     private void queuePendingShortcutInfo(PendingInstallShortcutInfo info) {
         // Queue the item up for adding if launcher has not loaded properly yet
-        MODEL_EXECUTOR.post(() -> addToQueue(info));
+        MODEL_EXECUTOR.post(() -> {
+            Pair<ItemInfo, Object> itemInfo = info.getItemInfo(mContext);
+            if (itemInfo == null) {
+                Log.i(LOG, "Adding PendingInstallShortcutInfo with no attached info to queue.");
+            } else {
+                Log.i(LOG, "Adding PendingInstallShortcutInfo to queue. Attached info: "
+                        + itemInfo.first);
+            }
+
+            addToQueue(info);
+        });
         flushInstallQueue();
     }
 
diff --git a/src/com/android/launcher3/model/data/PackageItemInfo.java b/src/com/android/launcher3/model/data/PackageItemInfo.java
index 7617d7e..a81fe6a 100644
--- a/src/com/android/launcher3/model/data/PackageItemInfo.java
+++ b/src/com/android/launcher3/model/data/PackageItemInfo.java
@@ -16,27 +16,47 @@
 
 package com.android.launcher3.model.data;
 
+import androidx.annotation.IntDef;
+
 import com.android.launcher3.LauncherSettings;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
  * Represents a {@link Package} in the widget tray section.
  */
 public class PackageItemInfo extends ItemInfoWithIcon {
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({NO_CATEGORY, CONVERSATIONS})
+    public @interface Category{}
+    /** The package is not categorized in the widget tray. */
+    public static final int NO_CATEGORY = 0;
+    /** The package is categorized to conversations widget in the widget tray. */
+    public static final int CONVERSATIONS = 1;
 
     /**
      * Package name of the {@link PackageItemInfo}.
      */
-    public String packageName;
+    public final String packageName;
+
+    /** Represents a widget category shown in the widget tray section. */
+    @Category public final int category;
 
     public PackageItemInfo(String packageName) {
+        this(packageName, NO_CATEGORY);
+    }
+
+    public PackageItemInfo(String packageName, @Category int category) {
         this.packageName = packageName;
+        this.category = category;
         this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
     }
 
     public PackageItemInfo(PackageItemInfo copy) {
         this.packageName = copy.packageName;
+        this.category = copy.category;
         this.itemType = LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
     }
 
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index 0091af1..72f1c58 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -29,6 +29,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
@@ -56,6 +57,8 @@
  */
 public class InstallSessionHelper {
 
+    private static final String LOG = "InstallSessionHelper";
+
     // Set<String> of session ids of promise icons that have been added to the home screen
     // as FLAG_PROMISE_NEW_INSTALLS.
     protected static final String PROMISE_ICON_IDS = "promise_icon_ids";
@@ -219,6 +222,9 @@
                 && !promiseIconAddedForId(sessionInfo.getSessionId())
                 && !new PackageManagerHelper(mAppContext).isAppInstalled(
                         sessionInfo.getAppPackageName(), getUserHandle(sessionInfo))) {
+            Log.i(LOG, "Adding package name to install queue: "
+                    + sessionInfo.getAppPackageName());
+
             ItemInstallQueue.INSTANCE.get(mAppContext)
                     .queueItem(sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
 
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 1c1418c..cc658c9 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -30,12 +30,13 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.views.BubbleTextHolder;
 
 /**
  * A {@link android.widget.FrameLayout} that contains a {@link DeepShortcutView}.
  * This lets us animate the DeepShortcutView (icon and text) separately from the background.
  */
-public class DeepShortcutView extends FrameLayout {
+public class DeepShortcutView extends FrameLayout implements BubbleTextHolder {
 
     private static final Point sTempPoint = new Point();
 
@@ -64,6 +65,7 @@
         mIconView = findViewById(R.id.icon);
     }
 
+    @Override
     public BubbleTextView getBubbleText() {
         return mBubbleText;
     }
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index 76f89bc..22c9d5b 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -49,7 +49,7 @@
     }
 
     @Override
-    public float getOverviewScrimAlpha(Launcher launcher) {
+    public float getWorkspaceScrimAlpha(Launcher launcher) {
         return 0.4f;
     }
 
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index d593013..39bcdc5 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -88,7 +88,7 @@
     }
 
     @Override
-    public float getWorkspaceScrimAlpha(Launcher launcher) {
+    public float getWorkspaceBackgroundAlpha(Launcher launcher) {
         return 0.3f;
     }
 
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index 8e7dcc0..0dbfb0b 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -56,7 +56,7 @@
             ANIM_OVERVIEW_TRANSLATE_Y,
             ANIM_OVERVIEW_FADE,
             ANIM_ALL_APPS_FADE,
-            ANIM_OVERVIEW_SCRIM_FADE,
+            ANIM_WORKSPACE_SCRIM_FADE,
             ANIM_ALL_APPS_HEADER_FADE,
             ANIM_OVERVIEW_MODAL,
             ANIM_DEPTH,
@@ -75,7 +75,7 @@
     public static final int ANIM_OVERVIEW_TRANSLATE_Y = 8;
     public static final int ANIM_OVERVIEW_FADE = 9;
     public static final int ANIM_ALL_APPS_FADE = 10;
-    public static final int ANIM_OVERVIEW_SCRIM_FADE = 11;
+    public static final int ANIM_WORKSPACE_SCRIM_FADE = 11;
     public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions
     public static final int ANIM_OVERVIEW_MODAL = 13;
     public static final int ANIM_DEPTH = 14;
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index dd5611e..a241e63 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -75,14 +75,6 @@
     }
 
     @Override
-    public void getCurveProperties(PagedView view, Rect insets, CurveProperties out) {
-        out.scroll = view.getScrollY();
-        out.halfPageSize = view.getNormalChildHeight() / 2;
-        out.halfScreenSize = view.getMeasuredHeight() / 2;
-        out.screenCenter = insets.top + view.getPaddingTop() + out.scroll + out.halfPageSize;
-    }
-
-    @Override
     public boolean isLayoutNaturalToLauncher() {
         return false;
     }
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 9140a04..b85d08a 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -93,7 +93,6 @@
     void delegateScrollTo(PagedView pagedView, int primaryScroll);
     void delegateScrollBy(PagedView pagedView, int unboundedScroll, int x, int y);
     void scrollerStartScroll(OverScroller scroller, int newPosition);
-    void getCurveProperties(PagedView view, Rect insets, CurveProperties out);
     boolean isLayoutNaturalToLauncher();
     float getTaskMenuX(float x, View thumbnailView);
     float getTaskMenuY(float y, View thumbnailView);
@@ -121,13 +120,6 @@
      */
     void adjustFloatingIconStartVelocity(PointF velocity);
 
-    class CurveProperties {
-        public int scroll;
-        public int halfPageSize;
-        public int screenCenter;
-        public int halfScreenSize;
-    }
-
     class ChildBounds {
 
         public final int primaryDimension;
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 2ca0340..2fb5952 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -22,7 +22,6 @@
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_SIDE;
 
 import android.content.res.Resources;
 import android.graphics.PointF;
@@ -74,14 +73,6 @@
     }
 
     @Override
-    public void getCurveProperties(PagedView view, Rect insets, CurveProperties out) {
-        out.scroll = view.getScrollX();
-        out.halfPageSize = view.getNormalChildWidth() / 2;
-        out.halfScreenSize = view.getMeasuredWidth() / 2;
-        out.screenCenter = insets.left + view.getPaddingLeft() + out.scroll + out.halfPageSize;
-    }
-
-    @Override
     public boolean isLayoutNaturalToLauncher() {
         return true;
     }
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index e08f881..f79313f 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -216,7 +216,7 @@
         return mLauncher.getDragLayer();
     }
 
-    protected static View createColorScrim(Context context, int bgColor) {
+    protected View createColorScrim(Context context, int bgColor) {
         View view = new View(context);
         view.forceHasOverlappingRendering(false);
         view.setBackgroundColor(bgColor);
diff --git a/src/com/android/launcher3/views/BubbleTextHolder.java b/src/com/android/launcher3/views/BubbleTextHolder.java
new file mode 100644
index 0000000..47d3563
--- /dev/null
+++ b/src/com/android/launcher3/views/BubbleTextHolder.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.views;
+
+import com.android.launcher3.BubbleTextView;
+
+/**
+ * Views that contain {@link BubbleTextView} should implement this interface.
+ */
+public interface BubbleTextHolder {
+    BubbleTextView getBubbleText();
+}
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 23c3722..96268ce 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -210,8 +210,8 @@
     public static void getLocationBoundsForView(Launcher launcher, View v, boolean isOpening,
             RectF outRect, Rect outViewBounds) {
         boolean ignoreTransform = !isOpening;
-        if (v instanceof DeepShortcutView) {
-            v = ((DeepShortcutView) v).getBubbleText();
+        if (v instanceof BubbleTextHolder) {
+            v = ((BubbleTextHolder) v).getBubbleText();
             ignoreTransform = false;
         } else if (v.getParent() instanceof DeepShortcutView) {
             v = ((DeepShortcutView) v.getParent()).getIconView();
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 72926dd..c9424de 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -15,14 +15,9 @@
  */
 package com.android.launcher3.views;
 
-import static androidx.core.graphics.ColorUtils.compositeColors;
-
-import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_SCRIM_VIEW;
 
 import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
@@ -32,104 +27,61 @@
 import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.uioverrides.WallpaperColorInfo;
-import com.android.launcher3.uioverrides.WallpaperColorInfo.OnChangeListener;
+import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
 
 /**
  * Simple scrim which draws a flat color
  */
-public class ScrimView<T extends Launcher> extends View implements Insettable, OnChangeListener {
-    private static final float STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD = .1f;
+public class ScrimView extends View implements Insettable {
+    private static final float STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD = 0.9f;
 
-    protected final T mLauncher;
-    private final WallpaperColorInfo mWallpaperColorInfo;
-    protected final int mEndScrim;
-    protected final boolean mIsScrimDark;
-
-    protected float mMaxScrimAlpha;
-
-    protected float mProgress = 1;
-    protected int mScrimColor;
-
-    protected int mCurrentFlatColor;
-    protected int mEndFlatColor;
-    protected int mEndFlatColorAlpha;
+    private final boolean mIsScrimDark;
+    private SystemUiController mSystemUiController;
 
     public ScrimView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mLauncher = Launcher.cast(Launcher.getLauncher(context));
-        mWallpaperColorInfo = WallpaperColorInfo.INSTANCE.get(context);
-        mEndScrim = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
-        mIsScrimDark = ColorUtils.calculateLuminance(mEndScrim) < 0.5f;
-
-        mMaxScrimAlpha = 0.7f;
+        mIsScrimDark = ColorUtils.calculateLuminance(
+                Themes.getAttrColor(context, R.attr.allAppsScrimColor)) < 0.5f;
         setFocusable(false);
     }
 
     @Override
     public void setInsets(Rect insets) { }
 
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mWallpaperColorInfo.addOnChangeListener(this);
-        onExtractedColorsChanged(mWallpaperColorInfo);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mWallpaperColorInfo.removeOnChangeListener(this);
-    }
-
     @Override
     public boolean hasOverlappingRendering() {
         return false;
     }
 
     @Override
-    public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
-        mScrimColor = wallpaperColorInfo.getMainColor();
-        mEndFlatColor = compositeColors(mEndScrim, setColorAlphaBound(
-                mScrimColor, Math.round(mMaxScrimAlpha * 255)));
-        mEndFlatColorAlpha = Color.alpha(mEndFlatColor);
-        updateColors();
-        invalidate();
-    }
-
-    public void setProgress(float progress) {
-        if (mProgress != progress) {
-            mProgress = progress;
-            updateColors();
-            updateSysUiColors();
-            invalidate();
-        }
-    }
-
-    public void reInitUi() { }
-
-    protected void updateColors() {
-        mCurrentFlatColor = mProgress >= 1 ? 0 : setColorAlphaBound(
-                mEndFlatColor, Math.round((1 - mProgress) * mEndFlatColorAlpha));
-    }
-
-    protected void updateSysUiColors() {
-        // Use a light system UI (dark icons) if all apps is behind at least half of the
-        // status bar.
-        boolean forceChange = mProgress <= STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD;
-        if (forceChange) {
-            mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark);
-        } else {
-            mLauncher.getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, 0);
-        }
+    protected boolean onSetAlpha(int alpha) {
+        updateSysUiColors();
+        return super.onSetAlpha(alpha);
     }
 
     @Override
-    protected void onDraw(Canvas canvas) {
-        if (mCurrentFlatColor != 0) {
-            canvas.drawColor(mCurrentFlatColor);
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+        updateSysUiColors();
+    }
+
+    private void updateSysUiColors() {
+        // Use a light system UI (dark icons) if all apps is behind at least half of the
+        // status bar.
+        boolean forceChange =
+                getVisibility() == VISIBLE && getAlpha() > STATUS_BAR_COLOR_FORCE_UPDATE_THRESHOLD;
+        if (forceChange) {
+            getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, !mIsScrimDark);
+        } else {
+            getSystemUiController().updateUiState(UI_STATE_SCRIM_VIEW, 0);
         }
     }
+
+    private SystemUiController getSystemUiController() {
+        if (mSystemUiController == null) {
+            mSystemUiController = Launcher.getLauncher(getContext()).getSystemUiController();
+        }
+        return mSystemUiController;
+    }
 }
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index fc63af0..95b887c 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -19,6 +19,7 @@
 
 import android.content.Context;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -108,7 +109,7 @@
 
         // If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
         // we abort the drag.
-        if (image.getDrawable() == null) {
+        if (image.getDrawable() == null && v.getAppWidgetHostViewPreview() == null) {
             return false;
         }
 
@@ -116,11 +117,21 @@
         dragHelper.setRemoteViewsPreview(v.getPreview());
         dragHelper.setAppWidgetHostViewPreview(v.getAppWidgetHostViewPreview());
 
-        int[] loc = new int[2];
-        getPopupContainer().getLocationInDragLayer(image, loc);
+        if (image.getDrawable() != null) {
+            int[] loc = new int[2];
+            getPopupContainer().getLocationInDragLayer(image, loc);
 
-        dragHelper.startDrag(image.getBitmapBounds(), image.getDrawable().getIntrinsicWidth(),
-                image.getWidth(), new Point(loc[0], loc[1]), this, new DragOptions());
+            dragHelper.startDrag(image.getBitmapBounds(), image.getDrawable().getIntrinsicWidth(),
+                    image.getWidth(), new Point(loc[0], loc[1]), this, new DragOptions());
+        } else {
+            View preview = v.getAppWidgetHostViewPreview();
+            int[] loc = new int[2];
+            getPopupContainer().getLocationInDragLayer(preview, loc);
+
+            Rect r = new Rect(0, 0, preview.getWidth(), preview.getHeight());
+            dragHelper.startDrag(r, preview.getMeasuredWidth(), preview.getMeasuredWidth(),
+                    new Point(loc[0], loc[1]), this, new DragOptions());
+        }
         close(true);
         return true;
     }
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 3e61e56..e78d517 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -115,6 +115,7 @@
             }
             if (mAppWidgetHostViewPreview != null) {
                 preview = new AppWidgetHostViewDrawable(mAppWidgetHostViewPreview);
+                previewSizeBeforeScale[0] = mAppWidgetHostViewPreview.getMeasuredWidth();
                 launcher.getDragController()
                         .addDragListener(new AppWidgetHostViewDragListener(launcher));
             }
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 40b256b..5e7c961 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -28,9 +28,11 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
+import android.view.ViewGroup;
 import android.view.ViewPropertyAnimator;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
+import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.RemoteViews;
 import android.widget.TextView;
@@ -42,7 +44,6 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.WidgetPreviewLoader;
-import com.android.launcher3.dragndrop.AppWidgetHostViewDrawable;
 import com.android.launcher3.icons.BaseIconFactory;
 import com.android.launcher3.icons.BitmapRenderer;
 import com.android.launcher3.icons.FastBitmapDrawable;
@@ -77,7 +78,9 @@
     private int mCellSize;
     private float mPreviewScale = 1f;
 
+    private FrameLayout mWidgetImageContainer;
     private WidgetImageView mWidgetImage;
+    private ImageView mWidgetBadge;
     private TextView mWidgetName;
     private TextView mWidgetDims;
     private TextView mWidgetDescription;
@@ -133,7 +136,9 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
 
+        mWidgetImageContainer = findViewById(R.id.widget_preview_container);
         mWidgetImage = findViewById(R.id.widget_preview);
+        mWidgetBadge = findViewById(R.id.widget_badge);
         mWidgetName = findViewById(R.id.widget_name);
         mWidgetDims = findViewById(R.id.widget_dims);
         mWidgetDescription = findViewById(R.id.widget_description);
@@ -155,7 +160,9 @@
             Log.d(TAG, "reset called on:" + mWidgetName.getText());
         }
         mWidgetImage.animate().cancel();
-        mWidgetImage.setDrawable(null, null);
+        mWidgetImage.setDrawable(null);
+        mWidgetImage.setVisibility(View.VISIBLE);
+        mWidgetBadge.setImageDrawable(null);
         mWidgetName.setText(null);
         mWidgetDims.setText(null);
         mWidgetDescription.setText(null);
@@ -167,6 +174,9 @@
             mActiveRequest = null;
         }
         mPreview = null;
+        if (mAppWidgetHostViewPreview != null) {
+            mWidgetImageContainer.removeView(mAppWidgetHostViewPreview);
+        }
         mAppWidgetHostViewPreview = null;
     }
 
@@ -215,6 +225,13 @@
             mAppWidgetHostViewPreview.setPadding(/* left= */ 0, /* top= */0, /* right= */
                     0, /* bottom= */ 0);
             mAppWidgetHostViewPreview.updateAppWidget(/* remoteViews= */ null);
+            // Gravity 77 = "fill"
+            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.MATCH_PARENT, /* gravity= */ 77);
+            mAppWidgetHostViewPreview.setLayoutParams(params);
+            mWidgetImageContainer.addView(mAppWidgetHostViewPreview, /* index= */ 0);
+            mWidgetImage.setVisibility(View.GONE);
         }
     }
 
@@ -258,21 +275,36 @@
             return;
         }
         if (drawable != null) {
-            LayoutParams layoutParams = (LayoutParams) mWidgetImage.getLayoutParams();
-            layoutParams.width = (int) (drawable.getIntrinsicWidth() * mPreviewScale);
-            layoutParams.height = (int) (drawable.getIntrinsicHeight() * mPreviewScale);
-            mWidgetImage.setLayoutParams(layoutParams);
-
-            mWidgetImage.setDrawable(drawable, mWidgetPreviewLoader.getBadgeForUser(mItem.user,
-                    BaseIconFactory.getBadgeSizeForIconSize(mDeviceProfile.allAppsIconSizePx)));
-            if (mAnimatePreview) {
-                mWidgetImage.setAlpha(0f);
-                ViewPropertyAnimator anim = mWidgetImage.animate();
-                anim.alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
-            } else {
-                mWidgetImage.setAlpha(1f);
+            setContainerSize(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
+            mWidgetImage.setDrawable(drawable);
+            mWidgetImage.setVisibility(View.VISIBLE);
+            if (mAppWidgetHostViewPreview != null) {
+                removeView(mAppWidgetHostViewPreview);
+                mAppWidgetHostViewPreview = null;
             }
         }
+        Drawable badge = mWidgetPreviewLoader.getBadgeForUser(mItem.user,
+                BaseIconFactory.getBadgeSizeForIconSize(mDeviceProfile.allAppsIconSizePx));
+        if (badge == null) {
+            mWidgetBadge.setVisibility(View.GONE);
+        } else {
+            mWidgetBadge.setVisibility(View.VISIBLE);
+            mWidgetBadge.setImageDrawable(badge);
+        }
+        if (mAnimatePreview) {
+            mWidgetImageContainer.setAlpha(0f);
+            ViewPropertyAnimator anim = mWidgetImageContainer.animate();
+            anim.alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
+        } else {
+            mWidgetImageContainer.setAlpha(1f);
+        }
+    }
+
+    private void setContainerSize(int width, int height) {
+        LayoutParams layoutParams = (LayoutParams) mWidgetImageContainer.getLayoutParams();
+        layoutParams.width = (int) (width * mPreviewScale);
+        layoutParams.height = (int) (height * mPreviewScale);
+        mWidgetImageContainer.setLayoutParams(layoutParams);
     }
 
     public void ensurePreview() {
@@ -290,15 +322,8 @@
             int viewWidth = dp.cellWidthPx * mItem.spanX;
             int viewHeight = dp.cellHeightPx * mItem.spanY;
 
-            mAppWidgetHostViewPreview.measure(
-                    MeasureSpec.makeMeasureSpec(viewWidth, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY));
-
-            viewWidth = mAppWidgetHostViewPreview.getMeasuredWidth();
-            viewHeight = mAppWidgetHostViewPreview.getMeasuredHeight();
-            mAppWidgetHostViewPreview.layout(0, 0, viewWidth, viewHeight);
-            Drawable drawable = new AppWidgetHostViewDrawable(mAppWidgetHostViewPreview);
-            applyPreview(drawable);
+            setContainerSize(viewWidth, viewHeight);
+            applyPreview((Drawable) null);
             return;
         }
         if (mActiveRequest != null) {
diff --git a/src/com/android/launcher3/widget/WidgetCellPreview.java b/src/com/android/launcher3/widget/WidgetCellPreview.java
new file mode 100644
index 0000000..ad3a61a
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetCellPreview.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.FrameLayout;
+
+/**
+ * View group managing the widget preview: either using a {@link WidgetImageView} or an actual
+ * {@link LauncherAppWidgetHostView}.
+ */
+public class WidgetCellPreview extends FrameLayout {
+    public WidgetCellPreview(Context context) {
+        this(context, null);
+    }
+
+    public WidgetCellPreview(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public WidgetCellPreview(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        super.onInterceptTouchEvent(ev);
+        return true;
+    }
+
+}
diff --git a/src/com/android/launcher3/widget/WidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java
index 39d701c..11f4485 100644
--- a/src/com/android/launcher3/widget/WidgetImageView.java
+++ b/src/com/android/launcher3/widget/WidgetImageView.java
@@ -25,7 +25,6 @@
 import android.view.View;
 
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 
 /**
  * View that draws a bitmap horizontally centered. If the image width is greater than the view
@@ -37,7 +36,6 @@
     private final int mBadgeMargin;
 
     private Drawable mDrawable;
-    private Drawable mBadge;
 
     public WidgetImageView(Context context) {
         this(context, null);
@@ -54,9 +52,9 @@
                 .getDimensionPixelSize(R.dimen.profile_badge_margin);
     }
 
-    public void setDrawable(Drawable drawable, Drawable badge) {
+    /** Set the drawable to use for this view. */
+    public void setDrawable(Drawable drawable) {
         mDrawable = drawable;
-        mBadge = badge;
         invalidate();
     }
 
@@ -70,11 +68,6 @@
             updateDstRectF();
             mDrawable.setBounds(getBitmapBounds());
             mDrawable.draw(canvas);
-
-            // Only draw the badge if a preview was drawn.
-            if (mBadge != null) {
-                mBadge.draw(canvas);
-            }
         }
     }
 
@@ -105,17 +98,6 @@
             mDstRectF.top = (myHeight - scaledHeight) / 2;
             mDstRectF.bottom = (myHeight + scaledHeight) / 2;
         }
-
-        if (mBadge != null) {
-            Rect bounds = mBadge.getBounds();
-            int left = Utilities.boundToRange(
-                    (int) (mDstRectF.right + mBadgeMargin - bounds.width()),
-                    mBadgeMargin, getWidth() - bounds.width());
-            int top = Utilities.boundToRange(
-                    (int) (mDstRectF.bottom + mBadgeMargin - bounds.height()),
-                    mBadgeMargin, getHeight() - bounds.height());
-            mBadge.setBounds(left, top, bounds.width() + left, bounds.height() + top);
-        }
     }
 
     /**
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index bbb0d92..0670928 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -170,9 +170,9 @@
         WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext())
                 .inflate(R.layout.widget_cell, parent, false);
 
-        WidgetImageView preview = widget.findViewById(R.id.widget_preview);
-        preview.setOnClickListener(this);
-        preview.setOnLongClickListener(this);
+        View preview_container = widget.findViewById(R.id.widget_preview_container);
+        preview_container.setOnClickListener(this);
+        preview_container.setOnLongClickListener(this);
         widget.setAnimatePreview(false);
 
         parent.addView(widget);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index d13884a..a4257a2 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -169,7 +169,7 @@
         onWidgetsBound();
 
         mSearchAndRecommendationViewHolder.mSearchBar.initialize(
-                mLauncher.getPopupDataProvider().getAllWidgets(), /* searchModeListener= */ this);
+                mLauncher.getPopupDataProvider(), /* searchModeListener= */ this);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index 497c72e..8794a4a 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -156,6 +156,11 @@
     private void applyDrawables(Drawable icon) {
         icon.setBounds(0, 0, mIconSize, mIconSize);
 
+        LinearLayout.LayoutParams layoutParams =
+                (LinearLayout.LayoutParams) mAppIcon.getLayoutParams();
+        layoutParams.width = mIconSize;
+        layoutParams.height = mIconSize;
+        mAppIcon.setLayoutParams(layoutParams);
         mAppIcon.setImageDrawable(icon);
 
         // If the current icon is a placeholder color, animate its update.
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index c1d64b1..1524ab3 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -31,7 +31,6 @@
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.recyclerview.ViewHolderBinder;
 import com.android.launcher3.widget.WidgetCell;
-import com.android.launcher3.widget.WidgetImageView;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 import com.android.launcher3.widget.util.WidgetsTableUtils;
 
@@ -170,7 +169,7 @@
                     WidgetCell widget = (WidgetCell) mLayoutInflater.inflate(
                             R.layout.widget_cell, tableRow, false);
                     // set up touch.
-                    WidgetImageView preview = widget.findViewById(R.id.widget_preview);
+                    View preview = widget.findViewById(R.id.widget_preview_container);
                     preview.setOnClickListener(mIconClickListener);
                     preview.setOnLongClickListener(mIconLongClickListener);
                     tableRow.addView(widget);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
index 6569fb0..b95bb16 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -17,8 +17,10 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TableLayout;
 import android.widget.TableRow;
@@ -31,14 +33,15 @@
 import com.android.launcher3.R;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.widget.WidgetCell;
-import com.android.launcher3.widget.WidgetImageView;
 
 import java.util.ArrayList;
 import java.util.List;
 
 /** A {@link TableLayout} for showing recommended widgets. */
 public final class WidgetsRecommendationTableLayout extends TableLayout {
-    private static final float SCALE_DOWN_RATIO = 0.9f;
+    private static final String TAG = "WidgetsRecommendationTableLayout";
+    private static final float DOWN_SCALE_RATIO = 0.9f;
+    private static final float MAX_DOWN_SCALE_RATIO = 0.5f;
     private final DeviceProfile mDeviceProfile;
     private final float mWidgetCellTextViewsHeight;
 
@@ -119,9 +122,9 @@
                 getContext()).inflate(R.layout.widget_cell, parent, false);
 
         widget.setOnTouchListener(mWidgetCellOnTouchListener);
-        WidgetImageView preview = widget.findViewById(R.id.widget_preview);
-        preview.setOnClickListener(mWidgetCellOnClickListener);
-        preview.setOnLongClickListener(mWidgetCellOnLongClickListener);
+        View previewContainer = widget.findViewById(R.id.widget_preview_container);
+        previewContainer.setOnClickListener(mWidgetCellOnClickListener);
+        previewContainer.setOnLongClickListener(mWidgetCellOnLongClickListener);
         widget.setAnimatePreview(false);
 
         parent.addView(widget);
@@ -131,6 +134,10 @@
     private RecommendationTableData fitRecommendedWidgetsToTableSpace(
             float previewScale,
             List<ArrayList<WidgetItem>> recommendedWidgetsInTable) {
+        if (previewScale < MAX_DOWN_SCALE_RATIO) {
+            Log.w(TAG, "Hide recommended widgets. Can't down scale previews to " + previewScale);
+            return new RecommendationTableData(List.of(), previewScale);
+        }
         // A naive estimation of the widgets recommendation table height without inflation.
         float totalHeight = 0;
         for (int i = 0; i < recommendedWidgetsInTable.size(); i++) {
@@ -157,7 +164,7 @@
                             /* toIndex= */recommendedWidgetsInTable.size() - 1));
         }
 
-        float nextPreviewScale = previewScale * SCALE_DOWN_RATIO;
+        float nextPreviewScale = previewScale * DOWN_SCALE_RATIO;
         return fitRecommendedWidgetsToTableSpace(nextPreviewScale, recommendedWidgetsInTable);
     }
 
diff --git a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
index 56a08b1..42f1bb2 100644
--- a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
+++ b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
@@ -26,10 +26,7 @@
 
 import com.android.launcher3.ExtendedEditText;
 import com.android.launcher3.R;
-import com.android.launcher3.search.SearchAlgorithm;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.List;
+import com.android.launcher3.popup.PopupDataProvider;
 
 /**
  * View for a search bar with an edit text with a cancel button.
@@ -54,12 +51,10 @@
     }
 
     @Override
-    public void initialize(List<WidgetsListBaseEntry> allWidgets,
-            SearchModeListener searchModeListener) {
-        SearchAlgorithm<WidgetsListBaseEntry> algo =
-                new SimpleWidgetsSearchAlgorithm(new SimpleWidgetsSearchPipeline(allWidgets));
+    public void initialize(PopupDataProvider dataProvider, SearchModeListener searchModeListener) {
         mController = new WidgetsSearchBarController(
-                algo, mEditText, mCancelButton, searchModeListener);
+                new SimpleWidgetsSearchAlgorithm(dataProvider),
+                mEditText, mCancelButton, searchModeListener);
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
index 15d2454..9be3b5f 100644
--- a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
+++ b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithm.java
@@ -16,42 +16,41 @@
 
 package com.android.launcher3.widget.picker.search;
 
-import android.os.Handler;
-import android.util.Log;
+import static com.android.launcher3.search.StringMatcherUtility.matches;
 
+import android.os.Handler;
+
+import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.search.SearchAlgorithm;
 import com.android.launcher3.search.SearchCallback;
+import com.android.launcher3.search.StringMatcherUtility.StringMatcher;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+import com.android.launcher3.widget.model.WidgetsListContentEntry;
+import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
+import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
 
 import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * Implementation of {@link SearchAlgorithm} that posts a task to query on the main thread.
  */
 public final class SimpleWidgetsSearchAlgorithm implements SearchAlgorithm<WidgetsListBaseEntry> {
 
-    private static final boolean DEBUG = false;
-    private static final String TAG = "SimpleWidgetsSearchAlgo";
-    private static final String DELIM = "\t";
-
     private final Handler mResultHandler;
-    private final WidgetsPickerSearchPipeline mSearchPipeline;
+    private final PopupDataProvider mDataProvider;
 
-    public SimpleWidgetsSearchAlgorithm(WidgetsPickerSearchPipeline searchPipeline) {
+    public SimpleWidgetsSearchAlgorithm(PopupDataProvider dataProvider) {
         mResultHandler = new Handler();
-        mSearchPipeline = searchPipeline;
+        mDataProvider = dataProvider;
     }
 
     @Override
     public void doSearch(String query, SearchCallback<WidgetsListBaseEntry> callback) {
-        long startTime = System.currentTimeMillis();
-        String queryToken = query + DELIM + startTime;
-        if (DEBUG) {
-            Log.d(TAG, "doSearch queryToken:" + queryToken);
-        }
-        mSearchPipeline.query(query,
-                results -> mResultHandler.post(
-                        () -> callback.onSearchResult(queryToken, new ArrayList(results))));
+        ArrayList<WidgetsListBaseEntry> result = getFilteredWidgets(mDataProvider, query);
+        mResultHandler.post(() -> callback.onSearchResult(query, result));
     }
 
     @Override
@@ -60,4 +59,36 @@
             mResultHandler.removeCallbacksAndMessages(/*token= */null);
         }
     }
+
+    /**
+     * Returns entries for all matched widgets
+     */
+    public static ArrayList<WidgetsListBaseEntry> getFilteredWidgets(
+            PopupDataProvider dataProvider, String input) {
+        ArrayList<WidgetsListBaseEntry> results = new ArrayList<>();
+        dataProvider.getAllWidgets().stream()
+                .filter(entry -> entry instanceof WidgetsListHeaderEntry)
+                .forEach(headerEntry -> {
+                    List<WidgetItem> matchedWidgetItems = filterWidgetItems(
+                            input, headerEntry.mPkgItem.title.toString(), headerEntry.mWidgets);
+                    if (matchedWidgetItems.size() > 0) {
+                        results.add(new WidgetsListSearchHeaderEntry(headerEntry.mPkgItem,
+                                headerEntry.mTitleSectionName, matchedWidgetItems));
+                        results.add(new WidgetsListContentEntry(headerEntry.mPkgItem,
+                                headerEntry.mTitleSectionName, matchedWidgetItems));
+                    }
+                });
+        return results;
+    }
+
+    private static List<WidgetItem> filterWidgetItems(String query, String packageTitle,
+            List<WidgetItem> items) {
+        StringMatcher matcher = StringMatcher.getInstance();
+        if (matches(query, packageTitle, matcher)) {
+            return items;
+        }
+        return items.stream()
+                .filter(item -> matches(query, item.label, matcher))
+                .collect(Collectors.toList());
+    }
 }
diff --git a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipeline.java b/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipeline.java
deleted file mode 100644
index 5222e8e..0000000
--- a/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchPipeline.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.widget.picker.search;
-
-import static com.android.launcher3.search.StringMatcherUtility.matches;
-
-import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.search.StringMatcherUtility.StringMatcher;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-import com.android.launcher3.widget.model.WidgetsListContentEntry;
-import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
-import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-import java.util.stream.Collectors;
-
-/**
- * Implementation of {@link WidgetsPickerSearchPipeline} that performs search by prefix matching on
- * app names and widget labels.
- */
-public final class SimpleWidgetsSearchPipeline implements WidgetsPickerSearchPipeline {
-
-    private final List<WidgetsListBaseEntry> mAllEntries;
-
-    public SimpleWidgetsSearchPipeline(List<WidgetsListBaseEntry> allEntries) {
-        mAllEntries = allEntries;
-    }
-
-    @Override
-    public void query(String input, Consumer<List<WidgetsListBaseEntry>> callback) {
-        ArrayList<WidgetsListBaseEntry> results = new ArrayList<>();
-        mAllEntries.stream().filter(entry -> entry instanceof WidgetsListHeaderEntry)
-                .forEach(headerEntry -> {
-                    List<WidgetItem> matchedWidgetItems = filterWidgetItems(
-                            input, headerEntry.mPkgItem.title.toString(), headerEntry.mWidgets);
-                    if (matchedWidgetItems.size() > 0) {
-                        results.add(new WidgetsListSearchHeaderEntry(headerEntry.mPkgItem,
-                                headerEntry.mTitleSectionName, matchedWidgetItems));
-                        results.add(new WidgetsListContentEntry(headerEntry.mPkgItem,
-                                headerEntry.mTitleSectionName, matchedWidgetItems));
-                    }
-                });
-        callback.accept(results);
-    }
-
-    private List<WidgetItem> filterWidgetItems(String query, String packageTitle,
-            List<WidgetItem> items) {
-        StringMatcher matcher = StringMatcher.getInstance();
-        if (matches(query, packageTitle, matcher)) {
-            return items;
-        }
-        return items.stream()
-                .filter(item -> matches(query, item.label, matcher))
-                .collect(Collectors.toList());
-    }
-}
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java b/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java
deleted file mode 100644
index d12782c..0000000
--- a/src/com/android/launcher3/widget/picker/search/WidgetsPickerSearchPipeline.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.widget.picker.search;
-
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.List;
-import java.util.function.Consumer;
-
-/**
- * An interface for a pipeline to handle widgets search.
- */
-public interface WidgetsPickerSearchPipeline {
-
-    /**
-     * Performs a search query asynchronically. Invokes {@code callback} when the search is
-     * complete.
-     */
-    void query(String input, Consumer<List<WidgetsListBaseEntry>> callback);
-
-    /**
-     * Cancels any ongoing search request.
-     */
-    default void cancel() {};
-
-    /**
-     * Cleans up after search is no longer needed.
-     */
-    default void destroy() {};
-}
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
index 3ac82c0..0ac47ce 100644
--- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
+++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
@@ -16,9 +16,7 @@
 
 package com.android.launcher3.widget.picker.search;
 
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-
-import java.util.List;
+import com.android.launcher3.popup.PopupDataProvider;
 
 /**
  * Interface for a widgets picker search bar.
@@ -27,7 +25,7 @@
     /**
      * Attaches a controller to the search bar which interacts with {@code searchModeListener}.
      */
-    void initialize(List<WidgetsListBaseEntry> allWidgets, SearchModeListener searchModeListener);
+    void initialize(PopupDataProvider dataProvider, SearchModeListener searchModeListener);
 
     /**
      * Clears search bar.
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index f82f2cc..be18e54 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -36,6 +36,7 @@
 import com.android.launcher3.widget.picker.WidgetsDiffReporter;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -58,6 +59,9 @@
     private static final String TAG = "WidgetsModel";
     private static final boolean DEBUG = false;
 
+    private static final ComponentName CONVERSATION_WIDGET = ComponentName.createRelative(
+            "com.android.systemui", ".people.widget.PeopleSpaceWidgetProvider");
+
     /* Map of widgets and shortcuts that are tracked per package. */
     private final Map<PackageItemInfo, List<WidgetItem>> mWidgetsList = new HashMap<>();
 
@@ -156,7 +160,7 @@
 
         // Temporary list for {@link PackageItemInfos} to avoid having to go through
         // {@link mPackageItemInfos} to locate the key to be used for {@link #mWidgetsList}
-        HashMap<PackageUserKey, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
+        HashMap<WidgetPackageOrCategoryKey, PackageItemInfo> tmpPackageItemInfos = new HashMap<>();
 
         // Clear the lists only if this is an update on all widgets and shortcuts. If packageUser
         // isn't null, only updates the shortcuts and widgets for the app represented in
@@ -168,11 +172,11 @@
         mWidgetsList.putAll(rawWidgetsShortcuts.stream()
                 .filter(new WidgetValidityCheck(app))
                 .collect(Collectors.groupingBy(item -> {
-                    PackageUserKey packageUserKey = new PackageUserKey(
-                            item.componentName.getPackageName(), item.user);
+                    WidgetPackageOrCategoryKey packageUserKey = getWidgetPackageOrCategoryKey(item);
                     PackageItemInfo pInfo = tmpPackageItemInfos.get(packageUserKey);
                     if (pInfo == null) {
-                        pInfo = new PackageItemInfo(packageUserKey.mPackageName);
+                        pInfo = new PackageItemInfo(item.componentName.getPackageName(),
+                                packageUserKey.mCategory);
                         pInfo.user = item.user;
                         tmpPackageItemInfos.put(packageUserKey,  pInfo);
                     }
@@ -224,6 +228,13 @@
         return null;
     }
 
+    private WidgetPackageOrCategoryKey getWidgetPackageOrCategoryKey(WidgetItem item) {
+        if (CONVERSATION_WIDGET.equals(item.componentName)) {
+            return new WidgetPackageOrCategoryKey(PackageItemInfo.CONVERSATIONS, item.user);
+        }
+        return new WidgetPackageOrCategoryKey(item.componentName.getPackageName(), item.user);
+    }
+
     private static class WidgetValidityCheck implements Predicate<WidgetItem> {
 
         private final InvariantDeviceProfile mIdp;
@@ -265,4 +276,40 @@
             return true;
         }
     }
+
+    /** A hash key for grouping widgets by package name or category. */
+    private static class WidgetPackageOrCategoryKey {
+        /**
+         * The package name of the widget provider.
+         *
+         * <p>This shouldn't be empty if {@link #mCategory} has a value,
+         * {@link PackageItemInfo#NO_CATEGORY}.
+         */
+        public final String mPackage;
+        /** A widget category. */
+        @PackageItemInfo.Category public final int mCategory;
+        public final UserHandle mUser;
+        private final int mHashCode;
+
+        WidgetPackageOrCategoryKey(String packageName, UserHandle user) {
+            this(packageName,  PackageItemInfo.NO_CATEGORY, user);
+        }
+
+        WidgetPackageOrCategoryKey(@PackageItemInfo.Category int category, UserHandle user) {
+            this("", category, user);
+        }
+
+        private WidgetPackageOrCategoryKey(String packageName,
+                @PackageItemInfo.Category int category, UserHandle user) {
+            mPackage = packageName;
+            mCategory = category;
+            mUser = user;
+            mHashCode = Arrays.hashCode(new Object[]{mPackage, mCategory, mUser});
+        }
+
+        @Override
+        public int hashCode() {
+            return mHashCode;
+        }
+    }
 }
\ No newline at end of file
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
index ff28148..53748b7 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -74,4 +74,9 @@
     public float getVerticalProgress(Launcher launcher) {
         return 0f;
     }
+
+    @Override
+    public float getWorkspaceScrimAlpha(Launcher launcher) {
+        return 1;
+    }
 }
diff --git a/tests/res/layout/test_layout_appwidget_dynamic_colors.xml b/tests/res/layout/test_layout_appwidget_dynamic_colors.xml
index 21625c6..56c343e 100644
--- a/tests/res/layout/test_layout_appwidget_dynamic_colors.xml
+++ b/tests/res/layout/test_layout_appwidget_dynamic_colors.xml
@@ -14,7 +14,7 @@
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:text="prim"/>
+            android:text="neut1"/>
         <ImageView
             android:layout_width="24dp"
             android:layout_height="24dp"
@@ -28,7 +28,7 @@
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:text="second"/>
+            android:text="accent1"/>
         <ImageView
             android:layout_width="24dp"
             android:layout_height="24dp"
@@ -42,11 +42,11 @@
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:text="neutral"/>
+            android:text="accent2"/>
         <ImageView
             android:layout_width="24dp"
             android:layout_height="24dp"
-            android:background="@android:color/system_neutral2_500"/>
+            android:background="@android:color/system_accent2_500"/>
     </LinearLayout>
 
     </LinearLayout>
\ No newline at end of file