Merge "Remove legacy involveSplitScreen API"
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 258f24a..d15a2d2 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -56,7 +56,7 @@
             android:visibility="gone" />
 
         <Space
-            android:id="@+id/share_space"
+            android:id="@+id/oav_three_button_space"
             android:layout_width="0dp"
             android:layout_height="1dp"
             android:layout_weight="1"
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 313db8c..c85fe6c 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -35,16 +35,13 @@
              loading full resolution screenshots. -->
     <dimen name="recents_fast_fling_velocity">600dp</dimen>
 
-    <!-- These velocities are in dp / s -->
-    <dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
-    <dimen name="quickstep_fling_min_velocity">250dp</dimen>
-
     <!-- These speeds are in dp / ms -->
     <dimen name="motion_pause_detector_speed_very_slow">0.0285dp</dimen>
     <dimen name="motion_pause_detector_speed_slow">0.15dp</dimen>
     <dimen name="motion_pause_detector_speed_somewhat_fast">0.285dp</dimen>
     <dimen name="motion_pause_detector_speed_fast">1.4dp</dimen>
     <dimen name="motion_pause_detector_min_displacement_from_app">36dp</dimen>
+    <dimen name="quickstep_fling_threshold_speed">0.5dp</dimen>
 
     <!-- Launcher app transition -->
     <dimen name="content_trans_y">50dp</dimen>
diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml
index 8f4ce43..605774d 100644
--- a/quickstep/res/values/override.xml
+++ b/quickstep/res/values/override.xml
@@ -25,8 +25,6 @@
 
   <string name="main_process_initializer_class" translatable="false">com.android.quickstep.QuickstepProcessInitializer</string>
 
-  <string name="user_event_dispatcher_class" translatable="false">com.android.quickstep.logging.UserEventDispatcherExtension</string>
-
   <string name="model_delegate_class" translatable="false">com.android.launcher3.model.QuickstepModelDelegate</string>
 
 </resources>
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 2543148..b53e834 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -57,6 +57,7 @@
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.Trace;
 import android.util.Pair;
 import android.view.View;
 
@@ -137,6 +138,7 @@
 
     // Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down.
     public static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f;
+    public static final String TRANSITION_OPEN_LAUNCHER = "transition:OpenLauncher";
 
     protected final BaseQuickstepLauncher mLauncher;
 
@@ -857,6 +859,21 @@
                 // is initialized.
                 if (launcherIsATargetWithMode(appTargets, MODE_OPENING)
                         || mLauncher.isForceInvisible()) {
+                    if (Trace.isEnabled()) {
+                        anim.addListener(new AnimatorListenerAdapter() {
+                            @Override
+                            public void onAnimationStart(Animator animation) {
+                                Trace.beginAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
+                                super.onAnimationStart(animation);
+                            }
+
+                            @Override
+                            public void onAnimationEnd(Animator animation) {
+                                super.onAnimationEnd(animation);
+                                Trace.endAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
+                            }
+                        });
+                    }
                     // Only register the content animation for cancellation when state changes
                     mLauncher.getStateManager().setCurrentAnimation(anim);
 
@@ -891,6 +908,9 @@
      */
     private class AppLaunchAnimationRunner implements WrappedAnimationRunnerImpl {
 
+        private static final String TRANSITION_LAUNCH_FROM_RECENTS = "transition:LaunchFromRecents";
+        private static final String TRANSITION_LAUNCH_FROM_ICON = "transition:LaunchFromIcon";
+
         private final Handler mHandler;
         private final View mV;
 
@@ -913,7 +933,8 @@
             boolean launcherClosing =
                     launcherIsATargetWithMode(appTargets, MODE_CLOSING);
 
-            if (isLaunchingFromRecents(mV, appTargets)) {
+            final boolean launchingFromRecents = isLaunchingFromRecents(mV, appTargets);
+            if (launchingFromRecents) {
                 composeRecentsLaunchAnimator(anim, mV, appTargets, wallpaperTargets,
                         launcherClosing);
             } else {
@@ -921,6 +942,26 @@
                         launcherClosing);
             }
 
+            if (Trace.isEnabled()) {
+                final String section =
+                        launchingFromRecents
+                                ? TRANSITION_LAUNCH_FROM_RECENTS : TRANSITION_LAUNCH_FROM_ICON;
+
+                anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationStart(Animator animation) {
+                        Trace.beginAsyncSection(section, 0);
+                        super.onAnimationStart(animation);
+                    }
+
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        super.onAnimationEnd(animation);
+                        Trace.endAsyncSection(section, 0);
+                    }
+                });
+            }
+
             if (launcherClosing) {
                 anim.addListener(mForceInvisibleListener);
             }
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index 810f4e3..f92b3e3 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -63,7 +63,6 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.function.Consumer;
 
 /**
  * Data model for digital wellbeing status of apps.
@@ -222,9 +221,8 @@
             reloadLauncherInNormalMode(context);
             return;
         }
-        runWithMinimalDeviceConfigs((bundle) -> {
-            if (bundle.getInt(EXTRA_MINIMAL_DEVICE_STATE, UNKNOWN_MINIMAL_DEVICE_STATE)
-                    == IN_MINIMAL_DEVICE) {
+        mWorkerHandler.post(() -> {
+            if (isInMinimalDeviceMode()) {
                 reloadLauncherInMinimalMode(context);
             } else {
                 reloadLauncherInNormalMode(context);
@@ -253,31 +251,30 @@
                 .authority(mWellbeingProviderPkg + ".api");
     }
 
-    /**
-     * Fetch most up-to-date minimal device config.
-     */
     @WorkerThread
-    private void runWithMinimalDeviceConfigs(Consumer<Bundle> consumer) {
+    private boolean isInMinimalDeviceMode() {
         if (!FeatureFlags.ENABLE_MINIMAL_DEVICE.get()) {
-            return;
+            return false;
         }
         if (DEBUG || mIsInTest) {
-            Log.d(TAG, "runWithMinimalDeviceConfigs() called");
+            Log.d(TAG, "isInMinimalDeviceMode() called");
         }
         Preconditions.assertNonUiThread();
 
         final Uri contentUri = apiBuilder().build();
-        final Bundle remoteBundle;
         try (ContentProviderClient client = mContext.getContentResolver()
                 .acquireUnstableContentProviderClient(contentUri)) {
-            remoteBundle = client.call(
+            final Bundle remoteBundle = client == null ? null : client.call(
                     METHOD_GET_MINIMAL_DEVICE_CONFIG, null /* args */, null /* extras */);
-            consumer.accept(remoteBundle);
+            return remoteBundle != null
+                    && remoteBundle.getInt(EXTRA_MINIMAL_DEVICE_STATE,
+                    UNKNOWN_MINIMAL_DEVICE_STATE) == IN_MINIMAL_DEVICE;
         } catch (Exception e) {
             Log.e(TAG, "Failed to retrieve data from " + contentUri + ": " + e);
             if (mIsInTest) throw new RuntimeException(e);
         }
-        if (DEBUG || mIsInTest) Log.i(TAG, "runWithMinimalDeviceConfigs(): finished");
+        if (DEBUG || mIsInTest) Log.i(TAG, "isInMinimalDeviceMode(): finished");
+        return false;
     }
 
     private boolean updateActions(String... packageNames) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 94af134..77fd103 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -36,13 +36,10 @@
 import static com.android.launcher3.anim.Interpolators.clampToProgress;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
 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.ANIM_VERTICAL_PROGRESS;
 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_TRANSLATE;
@@ -64,7 +61,6 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.allapps.AllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsTransitionController;
-import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.quickstep.SysUINavigationMode;
@@ -81,10 +77,8 @@
     private static final float RECENTS_PREPARE_SCALE = 1.33f;
 
     public static final int INDEX_SHELF_ANIM = RecentsAtomicAnimationFactory.NEXT_INDEX + 0;
-    public static final int INDEX_PAUSE_TO_OVERVIEW_ANIM =
-            RecentsAtomicAnimationFactory.NEXT_INDEX + 1;
 
-    private static final int MY_ANIM_COUNT = 2;
+    private static final int MY_ANIM_COUNT = 1;
     protected static final int NEXT_INDEX = RecentsAtomicAnimationFactory.NEXT_INDEX
             + MY_ANIM_COUNT;
 
@@ -92,8 +86,6 @@
     // cache the value.
     private int mHintToNormalDuration = -1;
 
-    public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300;
-
     public QuickstepAtomicAnimationFactory(QuickstepLauncher activity) {
         super(activity, MY_ANIM_COUNT);
     }
@@ -132,21 +124,6 @@
 
                 return springAnim;
             }
-            case INDEX_PAUSE_TO_OVERVIEW_ANIM: {
-                StateAnimationConfig config = new StateAnimationConfig();
-                config.duration = ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
-
-                config.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
-                config.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3);
-                if ((OVERVIEW.getVisibleElements(mActivity) & HOTSEAT_ICONS) != 0) {
-                    config.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
-                    config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
-                }
-
-                StateManager<LauncherState> stateManager = mActivity.getStateManager();
-                return stateManager.createAtomicAnimation(
-                        stateManager.getCurrentStableState(), OVERVIEW, config);
-            }
             default:
                 return super.createStateElementAnimation(index, values);
         }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index d574294..7616844 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -170,6 +170,8 @@
             if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
                 builder.addOnFrameCallback(recentsView::redrawLiveTile);
             }
+
+            AbstractFloatingView.closeOpenContainer(mLauncher, AbstractFloatingView.TYPE_TASK_MENU);
         } else if (mStartState == ALL_APPS) {
             AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
             builder.setFloat(allAppsController, ALL_APPS_PROGRESS,
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 591d3ca..c78d474 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -75,6 +75,7 @@
     private final float mMotionPauseMinDisplacement;
 
     private boolean mDidTouchStartInNavBar;
+    private boolean mStartedOverview;
     private boolean mReachedOverview;
     // The last recorded displacement before we reached overview.
     private PointF mStartDisplacement = new PointF();
@@ -128,7 +129,7 @@
         mMotionPauseDetector.clear();
 
         if (handlingOverviewAnim()) {
-            mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseChanged);
+            mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseDetected);
         }
 
         if (mFromState == NORMAL && mToState == HINT_STATE) {
@@ -138,6 +139,7 @@
                     mFromState.getOverviewScrimAlpha(mLauncher),
                     mToState.getOverviewScrimAlpha(mLauncher));
         }
+        mStartedOverview = false;
         mReachedOverview = false;
         mOverviewResistYAnim = null;
     }
@@ -152,7 +154,7 @@
 
     @Override
     public void onDragEnd(float velocity) {
-        if (mMotionPauseDetector.isPaused() && handlingOverviewAnim()) {
+        if (mStartedOverview) {
             goToOverviewOrHomeOnDragEnd(velocity);
         } else {
             super.onDragEnd(velocity);
@@ -185,7 +187,7 @@
         }
     }
 
-    private void onMotionPauseChanged(boolean isPaused) {
+    private void onMotionPauseDetected() {
         if (mCurrentAnimation == null) {
             return;
         }
@@ -199,6 +201,7 @@
                 maybeSwipeInteractionToOverviewComplete();
             });
         });
+        mStartedOverview = true;
         VibratorWrapper.INSTANCE.get(mLauncher).vibrate(OVERVIEW_HAPTIC);
     }
 
@@ -219,7 +222,7 @@
         if (TestProtocol.sDebugTracing) {
             Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NoButtonNavbarToOverviewTouchController");
         }
-        if (mMotionPauseDetector.isPaused()) {
+        if (mStartedOverview) {
             if (!mReachedOverview) {
                 mStartDisplacement.set(xDisplacement, yDisplacement);
                 mStartY = event.getY();
@@ -234,8 +237,6 @@
                             * OVERVIEW_MOVEMENT_FACTOR);
                 }
             }
-            // Stay in Overview.
-            return true;
         }
 
         float upDisplacement = -yDisplacement;
@@ -243,13 +244,12 @@
                 || upDisplacement < mMotionPauseMinDisplacement);
         mMotionPauseDetector.addPosition(event);
 
-        return super.onDrag(yDisplacement, xDisplacement, event);
+        // Stay in Overview.
+        return mStartedOverview || super.onDrag(yDisplacement, xDisplacement, event);
     }
 
     private void goToOverviewOrHomeOnDragEnd(float velocity) {
-        float velocityDp = dpiFromPx(velocity);
-        boolean isFling = Math.abs(velocityDp) > 1;
-        boolean goToHomeInsteadOfOverview = isFling;
+        boolean goToHomeInsteadOfOverview = !mMotionPauseDetector.isPaused();
         if (goToHomeInsteadOfOverview) {
             new OverviewToHomeAnim(mLauncher, ()-> onSwipeInteractionCompleted(NORMAL, Touch.FLING))
                     .animateWithVelocity(velocity);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 4b0642f..a6a3497 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -35,7 +35,6 @@
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
 import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
 import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
-import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_PAUSE_TO_OVERVIEW_ANIM;
 import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
@@ -80,13 +79,14 @@
  * the user as possible, also handles swipe up and hold to go to overview and swiping back home.
  */
 public class NoButtonQuickSwitchTouchController implements TouchController,
-        BothAxesSwipeDetector.Listener, MotionPauseDetector.OnMotionPauseListener {
+        BothAxesSwipeDetector.Listener {
 
     /** The minimum progress of the scale/translationY animation until drag end. */
     private static final float Y_ANIM_MIN_PROGRESS = 0.25f;
     private static final Interpolator FADE_OUT_INTERPOLATOR = DEACCEL_5;
     private static final Interpolator TRANSLATE_OUT_INTERPOLATOR = ACCEL_0_75;
     private static final Interpolator SCALE_DOWN_INTERPOLATOR = LINEAR;
+    private static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300;
 
     private final BaseQuickstepLauncher mLauncher;
     private final BothAxesSwipeDetector mSwipeDetector;
@@ -167,7 +167,7 @@
         if (start) {
             mStartState = mLauncher.getStateManager().getState();
 
-            mMotionPauseDetector.setOnMotionPauseListener(this);
+            mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseDetected);
 
             // We have detected horizontal drag start, now allow swipe up as well.
             mSwipeDetector.setDetectableScrollConditions(DIRECTION_RIGHT | DIRECTION_UP,
@@ -177,8 +177,7 @@
         }
     }
 
-    @Override
-    public void onMotionPauseChanged(boolean isPaused) {
+    private void onMotionPauseDetected() {
         VibratorWrapper.INSTANCE.get(mLauncher).vibrate(OVERVIEW_HAPTIC);
     }
 
@@ -271,11 +270,7 @@
         mIsHomeScreenVisible = FADE_OUT_INTERPOLATOR.getInterpolation(xProgress)
                 <= 1 - ALPHA_CUTOFF_THRESHOLD;
 
-
-        // Only allow motion pause if the home screen is invisible, since some
-        // home screen elements will appear in the shelf on motion pause.
-        mMotionPauseDetector.setDisallowPause(mIsHomeScreenVisible
-                || -displacement.y < mMotionPauseMinDisplacement);
+        mMotionPauseDetector.setDisallowPause(-displacement.y < mMotionPauseMinDisplacement);
         mMotionPauseDetector.addPosition(ev);
 
         if (mXOverviewAnim != null) {
@@ -296,8 +291,10 @@
         if (mMotionPauseDetector.isPaused() && noFling) {
             cancelAnimations();
 
-            Animator overviewAnim = mLauncher.createAtomicAnimationFactory()
-                    .createStateElementAnimation(INDEX_PAUSE_TO_OVERVIEW_ANIM);
+            StateAnimationConfig config = new StateAnimationConfig();
+            config.duration = ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
+            Animator overviewAnim = mLauncher.getStateManager().createAtomicAnimation(
+                    mStartState, OVERVIEW, config);
             overviewAnim.addListener(new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 1208c6c..059a703 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -89,13 +89,16 @@
 
     @Override
     protected boolean canInterceptTouch(MotionEvent ev) {
+        // If we are swiping to all apps instead of overview, allow it from anywhere.
+        boolean interceptAnywhere = mLauncher.isInState(NORMAL) && !mAllowDragToOverview;
         if (mCurrentAnimation != null) {
             if (mFinishFastOnSecondTouch) {
                 mCurrentAnimation.getAnimationPlayer().end();
             }
 
             AllAppsTransitionController allAppsController = mLauncher.getAllAppsController();
-            if (ev.getY() >= allAppsController.getShiftRange() * allAppsController.getProgress()) {
+            if (ev.getY() >= allAppsController.getShiftRange() * allAppsController.getProgress()
+                    || interceptAnywhere) {
                 // If we are already animating from a previous state, we can intercept as long as
                 // the touch is below the current all apps progress (to allow for double swipe).
                 return true;
@@ -117,9 +120,7 @@
                 return false;
             }
         } else {
-            // If we are swiping to all apps instead of overview, allow it from anywhere.
-            boolean interceptAnywhere = mLauncher.isInState(NORMAL) && !mAllowDragToOverview;
-            // For all other states, only listen if the event originated below the hotseat height
+            // For non-normal states, only listen if the event originated below the hotseat height
             if (!interceptAnywhere && !isTouchOverHotseat(mLauncher, ev)) {
                 return false;
             }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index aaa2720..26ad377 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -19,6 +19,7 @@
 
 import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
+import static com.android.launcher3.QuickstepAppTransitionManagerImpl.TRANSITION_OPEN_LAUNCHER;
 import static com.android.launcher3.anim.Interpolators.DEACCEL;
 import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
@@ -53,6 +54,7 @@
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
@@ -89,6 +91,7 @@
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.InputConsumerProxy;
+import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.RectFSpringAnim;
 import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.TransformParams;
@@ -201,6 +204,7 @@
     // Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
     private RunningWindowAnim mRunningWindowAnim;
     private boolean mIsMotionPaused;
+    private boolean mHasMotionEverBeenPaused;
 
     private boolean mContinuingLastGesture;
 
@@ -482,13 +486,20 @@
                 .getHighResLoadingState().setVisible(true);
     }
 
-    /**
-     * Called when motion pause is detected
-     */
-    public void onMotionPauseChanged(boolean isPaused) {
-        mIsMotionPaused = isPaused;
-        maybeUpdateRecentsAttachedState();
-        performHapticFeedback();
+    public MotionPauseDetector.OnMotionPauseListener getMotionPauseListener() {
+        return new MotionPauseDetector.OnMotionPauseListener() {
+            @Override
+            public void onMotionPauseDetected() {
+                mHasMotionEverBeenPaused = true;
+                maybeUpdateRecentsAttachedState();
+                performHapticFeedback();
+            }
+
+            @Override
+            public void onMotionPauseChanged(boolean isPaused) {
+                mIsMotionPaused = isPaused;
+            }
+        };
     }
 
     public void maybeUpdateRecentsAttachedState() {
@@ -519,7 +530,7 @@
             // The window is going away so make sure recents is always visible in this case.
             recentsAttachedToAppWindow = true;
         } else {
-            recentsAttachedToAppWindow = mIsMotionPaused || mIsLikelyToStartNewTask;
+            recentsAttachedToAppWindow = mHasMotionEverBeenPaused || mIsLikelyToStartNewTask;
         }
         mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
 
@@ -742,8 +753,9 @@
     @UiThread
     public void onGestureEnded(float endVelocity, PointF velocity, PointF downPos) {
         float flingThreshold = mContext.getResources()
-                .getDimension(R.dimen.quickstep_fling_threshold_velocity);
-        boolean isFling = mGestureStarted && Math.abs(endVelocity) > flingThreshold;
+                .getDimension(R.dimen.quickstep_fling_threshold_speed);
+        boolean isFling = mGestureStarted && !mIsMotionPaused
+                && Math.abs(endVelocity) > flingThreshold;
         mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED);
 
         mLogAction = isFling ? Touch.FLING : Touch.SWIPE;
@@ -858,7 +870,7 @@
 
             if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp && !willGoToNewTaskOnSwipeUp) {
                 endTarget = HOME;
-            } else if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp && !mIsMotionPaused) {
+            } else if (mDeviceState.isFullyGesturalNavMode() && isSwipeUp) {
                 // If swiping at a diagonal, base end target on the faster velocity.
                 endTarget = NEW_TASK;
             } else if (isSwipeUp) {
@@ -878,7 +890,6 @@
     @UiThread
     private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity,
             boolean isCancel) {
-        PointF velocityPxPerMs = new PointF(velocity.x / 1000, velocity.y / 1000);
         long duration = MAX_SWIPE_DURATION;
         float currentShift = mCurrentShift.value;
         final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity,
@@ -893,14 +904,12 @@
             startShift = currentShift;
             interpolator = endTarget == RECENTS ? OVERSHOOT_1_2 : DEACCEL;
         } else {
-            startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y
+            startShift = Utilities.boundToRange(currentShift - velocity.y
                     * getSingleFrameMs(mContext) / mTransitionDragLength, 0, mDragLengthFactor);
-            float minFlingVelocity = mContext.getResources()
-                    .getDimension(R.dimen.quickstep_fling_min_velocity);
-            if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
+            if (mTransitionDragLength > 0) {
                 if (endTarget == RECENTS && !mDeviceState.isFullyGesturalNavMode()) {
                     Interpolators.OvershootParams overshoot = new Interpolators.OvershootParams(
-                            startShift, endShift, endShift, endVelocity / 1000,
+                            startShift, endShift, endShift, endVelocity,
                             mTransitionDragLength, mContext);
                     endShift = overshoot.end;
                     interpolator = overshoot.interpolator;
@@ -912,7 +921,7 @@
                     // we want the page's snap velocity to approximately match the velocity at
                     // which the user flings, so we scale the duration by a value near to the
                     // derivative of the scroll interpolator at zero, ie. 2.
-                    long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
+                    long baseDuration = Math.round(Math.abs(distanceToTravel / velocity.y));
                     duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
 
                     if (endTarget == RECENTS) {
@@ -952,7 +961,7 @@
             mGestureState.setState(STATE_RECENTS_SCROLLING_FINISHED);
         }
 
-        animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocityPxPerMs);
+        animateToProgress(startShift, endShift, duration, interpolator, endTarget, velocity);
     }
 
     private void doLogGesture(GestureEndTarget endTarget, @Nullable TaskView targetTask) {
@@ -1135,6 +1144,7 @@
         anim.addAnimatorListener(new AnimationSuccessListener() {
             @Override
             public void onAnimationStart(Animator animation) {
+                Trace.beginAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
                 if (mActivity != null) {
                     removeLiveTileOverlay();
                 }
@@ -1149,6 +1159,12 @@
                 maybeUpdateRecentsAttachedState(false);
                 mActivityInterface.onSwipeUpToHomeComplete(mDeviceState);
             }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                super.onAnimationEnd(animation);
+                Trace.endAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
+            }
         });
         if (mRecentsAnimationTargets != null) {
             mRecentsAnimationTargets.addReleaseCheck(anim);
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index e4b8ce2..39af0db 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -58,6 +58,12 @@
                         FeatureFlags.ENABLE_OVERVIEW_SHARE.get());
                 return response;
             }
+
+            case TestProtocol.REQUEST_OVERVIEW_CONTENT_PUSH_ENABLED: {
+                response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        FeatureFlags.ENABLE_OVERVIEW_CONTENT_PUSH.get());
+                return response;
+            }
         }
 
         return super.call(method);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index e9fc423..d8064a2 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -569,6 +569,7 @@
         pw.println("  isUserUnlocked=" + mIsUserUnlocked);
         pw.println("  isOneHandedModeEnabled=" + mIsOneHandedModeEnabled);
         pw.println("  isSwipeToNotificationEnabled=" + mIsSwipeToNotificationEnabled);
+        pw.println("  deferredGestureRegion=" + mDeferredGestureRegion);
         mRotationTouchHelper.dump(pw);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index f29a5c8..df93e0b 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -64,8 +64,8 @@
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.TestProtocol;
-import com.android.launcher3.tracing.nano.LauncherTraceProto;
-import com.android.launcher3.tracing.nano.TouchInteractionServiceProto;
+import com.android.launcher3.tracing.LauncherTraceProto;
+import com.android.launcher3.tracing.TouchInteractionServiceProto;
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.util.OnboardingPrefs;
 import com.android.launcher3.util.TraceHelper;
@@ -105,7 +105,7 @@
  */
 @TargetApi(Build.VERSION_CODES.R)
 public class TouchInteractionService extends Service implements PluginListener<OverscrollPlugin>,
-        ProtoTraceable<LauncherTraceProto> {
+        ProtoTraceable<LauncherTraceProto.Builder> {
 
     private static final String TAG = "TouchInteractionService";
 
@@ -368,9 +368,12 @@
 
             // Update the tracing state
             if ((mDeviceState.getSystemUiStateFlags() & SYSUI_STATE_TRACING_ENABLED) != 0) {
-                ProtoTracer.INSTANCE.get(TouchInteractionService.this).start();
+                Log.d(TAG, "Starting tracing.");
+                ProtoTracer.INSTANCE.get(this).start();
             } else {
-                ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop();
+                Log.d(TAG, "Stopping tracing. Dumping to file="
+                    + ProtoTracer.INSTANCE.get(this).getTraceFile());
+                ProtoTracer.INSTANCE.get(this).stop();
             }
         }
     }
@@ -394,7 +397,7 @@
         disposeEventHandlers();
         mDeviceState.destroy();
         SystemUiProxy.INSTANCE.get(this).setProxy(null);
-        ProtoTracer.INSTANCE.get(TouchInteractionService.this).stop();
+        ProtoTracer.INSTANCE.get(this).stop();
         ProtoTracer.INSTANCE.get(this).remove(this);
 
         getSystemService(AccessibilityManager.class)
@@ -508,6 +511,7 @@
             reset();
         }
         TraceHelper.INSTANCE.endFlagsOverride(traceToken);
+        ProtoTracer.INSTANCE.get(this).scheduleFrameUpdate();
     }
 
     private GestureState createGestureState(GestureState previousGestureState) {
@@ -826,8 +830,7 @@
             pw.println("  mConsumer=" + mConsumer.getName());
             ActiveGestureLog.INSTANCE.dump("", pw);
             pw.println("ProtoTrace:");
-            pw.println("  file="
-                    + ProtoTracer.INSTANCE.get(TouchInteractionService.this).getTraceFile());
+            pw.println("  file=" + ProtoTracer.INSTANCE.get(this).getTraceFile());
         }
     }
 
@@ -883,11 +886,10 @@
     }
 
     @Override
-    public void writeToProto(LauncherTraceProto proto) {
-        if (proto.touchInteractionService == null) {
-            proto.touchInteractionService = new TouchInteractionServiceProto();
-        }
-        proto.touchInteractionService.serviceConnected = true;
-        proto.touchInteractionService.serviceConnected = true;
+    public void writeToProto(LauncherTraceProto.Builder proto) {
+        TouchInteractionServiceProto.Builder serviceProto =
+            TouchInteractionServiceProto.newBuilder();
+        serviceProto.setServiceConnected(true);
+        proto.setTouchInteractionService(serviceProto);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 584ff28..5aaea00 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -21,6 +21,7 @@
 
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.Utilities.squaredTouchSlop;
+import static com.android.launcher3.util.VelocityUtils.PX_PER_MS;
 import static com.android.quickstep.AbsSwipeUpHandler.MIN_PROGRESS_FOR_OVERVIEW;
 import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
 import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
@@ -35,7 +36,6 @@
 import android.graphics.PointF;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
-import android.view.ViewConfiguration;
 
 import com.android.launcher3.R;
 import com.android.launcher3.anim.Interpolators;
@@ -180,12 +180,11 @@
      */
     private void finishTouchTracking(MotionEvent ev) {
         if (mThresholdCrossed && ev.getAction() == ACTION_UP) {
-            mVelocityTracker.computeCurrentVelocity(1000,
-                    ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity());
+            mVelocityTracker.computeCurrentVelocity(PX_PER_MS);
 
             float velocityY = mVelocityTracker.getYVelocity();
             float flingThreshold = mContext.getResources()
-                    .getDimension(R.dimen.quickstep_fling_threshold_velocity);
+                    .getDimension(R.dimen.quickstep_fling_threshold_speed);
 
             boolean dismissTask;
             if (Math.abs(velocityY) > flingThreshold) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index f02e5e6..b1a1133 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -28,6 +28,7 @@
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.util.TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS;
+import static com.android.launcher3.util.VelocityUtils.PX_PER_MS;
 import static com.android.quickstep.GestureState.STATE_OVERSCROLL_WINDOW_CREATED;
 import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -52,9 +53,9 @@
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.Preconditions;
 import com.android.launcher3.util.TraceHelper;
-import com.android.quickstep.BaseActivityInterface;
 import com.android.quickstep.AbsSwipeUpHandler;
 import com.android.quickstep.AbsSwipeUpHandler.Factory;
+import com.android.quickstep.BaseActivityInterface;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.InputConsumer;
 import com.android.quickstep.RecentsAnimationCallbacks;
@@ -365,7 +366,7 @@
         mInteractionHandler = mHandlerFactory.newHandler(mGestureState, touchTimeMs,
                 mTaskAnimationManager.isRecentsAnimationRunning());
         mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished);
-        mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler::onMotionPauseChanged);
+        mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler.getMotionPauseListener());
         Intent intent = new Intent(mInteractionHandler.getLaunchIntent());
         mInteractionHandler.initWhenReady(intent);
 
@@ -393,8 +394,7 @@
             if (ev.getActionMasked() == ACTION_CANCEL) {
                 mInteractionHandler.onGestureCancelled();
             } else {
-                mVelocityTracker.computeCurrentVelocity(1000,
-                        ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
+                mVelocityTracker.computeCurrentVelocity(PX_PER_MS);
                 float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);
                 float velocityY = mVelocityTracker.getYVelocity(mActivePointerId);
                 float velocity = mNavBarPosition.isRightEdge()
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
index b9827ff..a8bf333 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ScreenPinnedInputConsumer.java
@@ -42,18 +42,16 @@
         mMotionPauseMinDisplacement = context.getResources().getDimension(
                 R.dimen.motion_pause_detector_min_displacement_from_app);
         mMotionPauseDetector = new MotionPauseDetector(context, true /* makePauseHarderToTrigger*/);
-        mMotionPauseDetector.setOnMotionPauseListener(isPaused -> {
-            if (isPaused) {
-                SystemUiProxy.INSTANCE.get(context).stopScreenPinning();
-                BaseDraggingActivity launcherActivity = gestureState.getActivityInterface()
-                        .getCreatedActivity();
-                if (launcherActivity != null) {
-                    launcherActivity.getRootView().performHapticFeedback(
-                            HapticFeedbackConstants.LONG_PRESS,
-                            HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
-                }
-                mMotionPauseDetector.clear();
+        mMotionPauseDetector.setOnMotionPauseListener(() -> {
+            SystemUiProxy.INSTANCE.get(context).stopScreenPinning();
+            BaseDraggingActivity launcherActivity = gestureState.getActivityInterface()
+                    .getCreatedActivity();
+            if (launcherActivity != null) {
+                launcherActivity.getRootView().performHapticFeedback(
+                        HapticFeedbackConstants.LONG_PRESS,
+                        HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
             }
+            mMotionPauseDetector.clear();
         });
     }
 
diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
index 81c4d0c..f897ecc 100644
--- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
@@ -144,7 +144,6 @@
         if (mGestureCallback == null || mAssistantGestureActive) {
             return;
         }
-        finalVelocity.set(finalVelocity.x / 1000, finalVelocity.y / 1000);
         if (mTouchCameFromNavBar) {
             mGestureCallback.onNavBarGestureAttempted(wasFling
                     ? HOME_GESTURE_COMPLETED : OVERVIEW_GESTURE_COMPLETED, finalVelocity);
@@ -182,7 +181,7 @@
                 mLaunchedAssistant = false;
                 mSwipeUpTouchTracker.init();
                 mMotionPauseDetector.clear();
-                mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseChanged);
+                mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseDetected);
                 break;
             case MotionEvent.ACTION_MOVE:
                 mLastPos.set(event.getX(), event.getY());
@@ -220,7 +219,6 @@
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
                 mMotionPauseDetector.clear();
-                mMotionPauseDetector.setOnMotionPauseListener(null);
                 if (mGestureCallback != null && !intercepted && mTouchCameFromNavBar) {
                     mGestureCallback.onNavBarGestureAttempted(
                             HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION, new PointF());
@@ -252,10 +250,8 @@
         return intercepted;
     }
 
-    protected void onMotionPauseChanged(boolean isPaused) {
-        if (isPaused) {
-            VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
-        }
+    protected void onMotionPauseDetected() {
+        VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index b862936..d0f6879 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -184,11 +184,15 @@
         }
         if (mIsPaused != isPaused) {
             mIsPaused = isPaused;
+            boolean isFirstDetectedPause = !mHasEverBeenPaused && mIsPaused;
             if (mIsPaused) {
                 AccessibilityManagerCompat.sendPauseDetectedEventToTest(mContext);
                 mHasEverBeenPaused = true;
             }
             if (mOnMotionPauseListener != null) {
+                if (isFirstDetectedPause) {
+                    mOnMotionPauseListener.onMotionPauseDetected();
+                }
                 mOnMotionPauseListener.onMotionPauseChanged(mIsPaused);
             }
         }
@@ -211,7 +215,10 @@
     }
 
     public interface OnMotionPauseListener {
-        void onMotionPauseChanged(boolean isPaused);
+        /** Called only the first time motion pause is detected. */
+        void onMotionPauseDetected();
+        /** Called every time motion changes from paused to not paused and vice versa. */
+        default void onMotionPauseChanged(boolean isPaused) { }
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/util/ProtoTracer.java b/quickstep/src/com/android/quickstep/util/ProtoTracer.java
index 190763a..ef9586d 100644
--- a/quickstep/src/com/android/quickstep/util/ProtoTracer.java
+++ b/quickstep/src/com/android/quickstep/util/ProtoTracer.java
@@ -16,24 +16,23 @@
 
 package com.android.quickstep.util;
 
-import static com.android.launcher3.tracing.nano.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_H;
-import static com.android.launcher3.tracing.nano.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_L;
+import static com.android.launcher3.tracing.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_H_VALUE;
+import static com.android.launcher3.tracing.LauncherTraceFileProto.MagicNumber.MAGIC_NUMBER_L_VALUE;
 
 import android.content.Context;
 import android.os.SystemClock;
 
-import com.android.launcher3.tracing.nano.LauncherTraceProto;
-import com.android.launcher3.tracing.nano.LauncherTraceEntryProto;
-import com.android.launcher3.tracing.nano.LauncherTraceFileProto;
+import android.os.Trace;
+import com.android.launcher3.tracing.LauncherTraceProto;
+import com.android.launcher3.tracing.LauncherTraceEntryProto;
+import com.android.launcher3.tracing.LauncherTraceFileProto;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.systemui.shared.tracing.FrameProtoTracer;
 import com.android.systemui.shared.tracing.FrameProtoTracer.ProtoTraceParams;
 import com.android.systemui.shared.tracing.ProtoTraceable;
-import com.google.protobuf.nano.MessageNano;
+import com.google.protobuf.MessageLite;
 
 import java.io.File;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Queue;
 
@@ -41,18 +40,20 @@
 /**
  * Controller for coordinating winscope proto tracing.
  */
-public class ProtoTracer implements ProtoTraceParams<MessageNano,
-        LauncherTraceFileProto, LauncherTraceEntryProto, LauncherTraceProto> {
+public class ProtoTracer implements ProtoTraceParams<MessageLite.Builder,
+        LauncherTraceFileProto.Builder, LauncherTraceEntryProto.Builder,
+                LauncherTraceProto.Builder> {
 
     public static final MainThreadInitializedObject<ProtoTracer> INSTANCE =
             new MainThreadInitializedObject<>(ProtoTracer::new);
 
     private static final String TAG = "ProtoTracer";
-    private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+    private static final long MAGIC_NUMBER_VALUE =
+            ((long) MAGIC_NUMBER_H_VALUE << 32) | MAGIC_NUMBER_L_VALUE;
 
     private final Context mContext;
-    private final FrameProtoTracer<MessageNano,
-            LauncherTraceFileProto, LauncherTraceEntryProto, LauncherTraceProto> mProtoTracer;
+    private final FrameProtoTracer<MessageLite.Builder, LauncherTraceFileProto.Builder,
+        LauncherTraceEntryProto.Builder, LauncherTraceProto.Builder> mProtoTracer;
 
     public ProtoTracer(Context context) {
         mContext = context;
@@ -65,40 +66,47 @@
     }
 
     @Override
-    public LauncherTraceFileProto getEncapsulatingTraceProto() {
-        return new LauncherTraceFileProto();
+    public LauncherTraceFileProto.Builder getEncapsulatingTraceProto() {
+        return LauncherTraceFileProto.newBuilder();
     }
 
     @Override
-    public LauncherTraceEntryProto updateBufferProto(LauncherTraceEntryProto reuseObj,
-            ArrayList<ProtoTraceable<LauncherTraceProto>> traceables) {
-        LauncherTraceEntryProto proto = reuseObj != null
-                ? reuseObj
-                : new LauncherTraceEntryProto();
-        proto.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
-        proto.launcher = proto.launcher != null ? proto.launcher : new LauncherTraceProto();
+    public LauncherTraceEntryProto.Builder updateBufferProto(
+            LauncherTraceEntryProto.Builder reuseObj,
+            ArrayList<ProtoTraceable<LauncherTraceProto.Builder>> traceables) {
+        Trace.beginSection("ProtoTracer.updateBufferProto");
+        LauncherTraceEntryProto.Builder proto = LauncherTraceEntryProto.newBuilder();
+        proto.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+        LauncherTraceProto.Builder launcherProto = LauncherTraceProto.newBuilder();
         for (ProtoTraceable t : traceables) {
-            t.writeToProto(proto.launcher);
+            t.writeToProto(launcherProto);
         }
+        proto.setLauncher(launcherProto);
+        Trace.endSection();
         return proto;
     }
 
     @Override
-    public byte[] serializeEncapsulatingProto(LauncherTraceFileProto encapsulatingProto,
-            Queue<LauncherTraceEntryProto> buffer) {
-        encapsulatingProto.magicNumber = MAGIC_NUMBER_VALUE;
-        encapsulatingProto.entry = buffer.toArray(new LauncherTraceEntryProto[0]);
-        return MessageNano.toByteArray(encapsulatingProto);
+    public byte[] serializeEncapsulatingProto(LauncherTraceFileProto.Builder encapsulatingProto,
+            Queue<LauncherTraceEntryProto.Builder> buffer) {
+        Trace.beginSection("ProtoTracer.serializeEncapsulatingProto");
+        encapsulatingProto.setMagicNumber(MAGIC_NUMBER_VALUE);
+        for (LauncherTraceEntryProto.Builder entry : buffer) {
+            encapsulatingProto.addEntry(entry);
+        }
+        byte[] bytes = encapsulatingProto.build().toByteArray();
+        Trace.endSection();
+        return bytes;
     }
 
     @Override
-    public byte[] getProtoBytes(MessageNano proto) {
-        return MessageNano.toByteArray(proto);
+    public byte[] getProtoBytes(MessageLite.Builder proto) {
+        return proto.build().toByteArray();
     }
 
     @Override
-    public int getProtoSize(MessageNano proto) {
-        return proto.getCachedSize();
+    public int getProtoSize(MessageLite.Builder proto) {
+        return proto.build().getSerializedSize();
     }
 
     public void start() {
@@ -109,11 +117,11 @@
         mProtoTracer.stop();
     }
 
-    public void add(ProtoTraceable<LauncherTraceProto> traceable) {
+    public void add(ProtoTraceable<LauncherTraceProto.Builder> traceable) {
         mProtoTracer.add(traceable);
     }
 
-    public void remove(ProtoTraceable<LauncherTraceProto> traceable) {
+    public void remove(ProtoTraceable<LauncherTraceProto.Builder> traceable) {
         mProtoTracer.remove(traceable);
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java b/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
index 29b9558..7bbde30 100644
--- a/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
+++ b/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
@@ -21,13 +21,14 @@
 import static android.view.MotionEvent.ACTION_UP;
 
 import static com.android.launcher3.Utilities.squaredHypot;
+import static com.android.launcher3.util.VelocityUtils.PX_PER_MS;
 
 import android.content.Context;
 import android.graphics.PointF;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
-import android.view.ViewConfiguration;
 
+import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 
 /**
@@ -50,7 +51,8 @@
             NavBarPosition navBarPosition, Runnable onInterceptTouch,
             OnSwipeUpListener onSwipeUp) {
         mSquaredTouchSlop = Utilities.squaredTouchSlop(context);
-        mMinFlingVelocity = ViewConfiguration.get(context).getScaledMinimumFlingVelocity();
+        mMinFlingVelocity = context.getResources().getDimension(
+                R.dimen.quickstep_fling_threshold_speed);
         mNavBarPosition = navBarPosition;
         mDisableHorizontalSwipe = disableHorizontalSwipe;
         mOnInterceptTouch = onInterceptTouch;
@@ -130,7 +132,7 @@
     }
 
     private void onGestureEnd(MotionEvent ev) {
-        mVelocityTracker.computeCurrentVelocity(1000);
+        mVelocityTracker.computeCurrentVelocity(PX_PER_MS);
         float velocityX = mVelocityTracker.getXVelocity();
         float velocityY = mVelocityTracker.getYVelocity();
         float velocity = mNavBarPosition.isRightEdge()
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 8f60991..2a6c9e9 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -113,7 +113,7 @@
         findViewById(R.id.action_screenshot).setOnClickListener(this);
         if (ENABLE_OVERVIEW_SHARE.get()) {
             share.setVisibility(VISIBLE);
-            findViewById(R.id.share_space).setVisibility(VISIBLE);
+            findViewById(R.id.oav_three_button_space).setVisibility(VISIBLE);
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 982a7c4..0362377 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -79,7 +79,6 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
-import android.view.TouchDelegate;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
@@ -706,12 +705,9 @@
         super.onTouchEvent(ev);
 
         TaskView taskView = getCurrentPageTaskView();
-        if (taskView != null) {
-            TouchDelegate mChildTouchDelegate = taskView.getIconTouchDelegate(ev);
-            if (mChildTouchDelegate != null && mChildTouchDelegate.onTouchEvent(ev)) {
-                // Keep consuming events to pass to delegate
-                return true;
-            }
+        if (taskView != null && taskView.offerTouchToChildren(ev)) {
+            // Keep consuming events to pass to delegate
+            return true;
         }
 
         final int x = (int) ev.getX();
@@ -2255,7 +2251,7 @@
     public void setRecentsAnimationTargets(RecentsAnimationController recentsAnimationController,
             RecentsAnimationTargets recentsAnimationTargets) {
         mRecentsAnimationController = recentsAnimationController;
-        if (recentsAnimationTargets != null) {
+        if (recentsAnimationTargets != null && recentsAnimationTargets.apps.length > 0) {
             mLiveTileTaskViewSimulator.setPreview(
                     recentsAnimationTargets.apps[recentsAnimationTargets.apps.length - 1]);
             mLiveTileParams.setTargetSet(recentsAnimationTargets);
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 656d59e..d47eba6 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -246,7 +246,7 @@
         setScaleX(taskView.getScaleX());
         setScaleY(taskView.getScaleY());
         boolean canActivityRotate = taskView.getRecentsView()
-            .mOrientationState.canRecentsActivityRotate();
+            .mOrientationState.isRecentsActivityRotationAllowed();
         mOptionLayout.setOrientation(orientationHandler
                 .getTaskMenuLayoutOrientation(canActivityRotate, mOptionLayout));
         setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top,
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 259cd4d..321821b 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -135,6 +135,7 @@
      * delegated bounds only to be updated.
      */
     private TransformingTouchDelegate mIconTouchDelegate;
+    private TransformingTouchDelegate mChipTouchDelegate;
 
     private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
             Collections.singletonList(new Rect());
@@ -200,6 +201,7 @@
     private View mContextualChipWrapper;
     private View mContextualChip;
     private final float[] mIconCenterCoords = new float[2];
+    private final float[] mChipCenterCoords = new float[2];
 
     public TaskView(Context context) {
         this(context, null);
@@ -259,11 +261,22 @@
         mIconTouchDelegate = new TransformingTouchDelegate(mIconView);
     }
 
-    public TouchDelegate getIconTouchDelegate(MotionEvent event) {
+    /**
+     * Whether the taskview should take the touch event from parent. Events passed to children
+     * that might require special handling.
+     */
+    public boolean offerTouchToChildren(MotionEvent event) {
         if (event.getAction() == MotionEvent.ACTION_DOWN) {
             computeAndSetIconTouchDelegate();
+            computeAndSetChipTouchDelegate();
         }
-        return mIconTouchDelegate;
+        if (mIconTouchDelegate != null && mIconTouchDelegate.onTouchEvent(event)) {
+            return true;
+        }
+        if (mChipTouchDelegate != null && mChipTouchDelegate.onTouchEvent(event)) {
+            return true;
+        }
+        return false;
     }
 
     private void computeAndSetIconTouchDelegate() {
@@ -278,6 +291,23 @@
                 (int) (mIconCenterCoords[1] + iconHalfSize));
     }
 
+    private void computeAndSetChipTouchDelegate() {
+        if (mContextualChipWrapper != null) {
+            float chipHalfWidth = mContextualChipWrapper.getWidth() / 2f;
+            float chipHalfHeight = mContextualChipWrapper.getHeight() / 2f;
+            mChipCenterCoords[0] = chipHalfWidth;
+            mChipCenterCoords[1] = chipHalfHeight;
+            getDescendantCoordRelativeToAncestor(mContextualChipWrapper, mActivity.getDragLayer(),
+                    mChipCenterCoords,
+                    false);
+            mChipTouchDelegate.setBounds(
+                    (int) (mChipCenterCoords[0] - chipHalfWidth),
+                    (int) (mChipCenterCoords[1] - chipHalfHeight),
+                    (int) (mChipCenterCoords[0] + chipHalfWidth),
+                    (int) (mChipCenterCoords[1] + chipHalfHeight));
+        }
+    }
+
     /**
      * The modalness of this view is how it should be displayed when it is shown on its own in the
      * modal state of overview.
@@ -712,6 +742,7 @@
                 mContextualChip.animate().scaleX(1f).scaleY(1f).setDuration(50);
             }
             if (mContextualChipWrapper != null) {
+                mChipTouchDelegate = new TransformingTouchDelegate(mContextualChipWrapper);
                 mContextualChipWrapper.animate().alpha(1f).setDuration(50);
             }
         }
@@ -733,6 +764,7 @@
         View oldContextualChipWrapper = mContextualChipWrapper;
         mContextualChipWrapper = null;
         mContextualChip = null;
+        mChipTouchDelegate = null;
         return oldContextualChipWrapper;
     }
 
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index ecd4e2b..c5863c1 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -201,6 +201,12 @@
     @PortraitLandscape
     public void testOverviewActions() throws Exception {
         if (mLauncher.getNavigationModel() != NavigationModel.TWO_BUTTON) {
+            // Experimenting for b/165029151:
+            final Overview overview = mLauncher.pressHome().switchToOverview();
+            if (overview.hasTasks()) overview.dismissAllTasks();
+            mLauncher.pressHome();
+            //
+
             startTestAppsWithCheck();
             OverviewActions actionsView =
                     mLauncher.pressHome().switchToOverview().getOverviewActions();
diff --git a/res/layout/search_result_people_item.xml b/res/layout/search_result_people_item.xml
new file mode 100644
index 0000000..a603941
--- /dev/null
+++ b/res/layout/search_result_people_item.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 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.SearchResultPeopleView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:gravity="center_vertical"
+    android:layout_height="wrap_content"
+    android:padding="8dp"
+    android:orientation="horizontal">
+
+    <View
+        android:id="@+id/icon"
+        android:layout_marginRight="8dp"
+        android:layout_width="@dimen/deep_shortcut_icon_size"
+        android:layout_height="@dimen/deep_shortcut_icon_size" />
+
+    <TextView
+        android:layout_width="0dp"
+        android:textColor="?android:attr/textColorPrimary"
+        android:id="@+id/title"
+        android:layout_height="wrap_content"
+        android:layout_weight="1" />
+
+    <ImageButton
+        android:id="@+id/provider_0"
+        android:scaleType="fitCenter"
+        android:adjustViewBounds="true"
+        android:layout_margin="5dp"
+        android:background="?android:attr/selectableItemBackground"
+        android:layout_width="@dimen/deep_shortcut_icon_size"
+        android:layout_height="@dimen/deep_shortcut_icon_size" />
+
+    <ImageButton
+        android:id="@+id/provider_1"
+        android:layout_margin="5dp"
+        android:scaleType="fitCenter"
+        android:adjustViewBounds="true"
+        android:background="?android:attr/selectableItemBackground"
+        android:layout_width="@dimen/deep_shortcut_icon_size"
+        android:layout_height="@dimen/deep_shortcut_icon_size" />
+
+    <ImageButton
+        android:id="@+id/provider_2"
+        android:layout_margin="5dp"
+        android:scaleType="fitCenter"
+        android:adjustViewBounds="true"
+        android:background="?android:attr/selectableItemBackground"
+        android:layout_width="@dimen/deep_shortcut_icon_size"
+        android:layout_height="@dimen/deep_shortcut_icon_size" />
+
+</com.android.launcher3.views.SearchResultPeopleView>
\ No newline at end of file
diff --git a/res/layout/search_result_shortcut.xml b/res/layout/search_result_shortcut.xml
new file mode 100644
index 0000000..c350c97
--- /dev/null
+++ b/res/layout/search_result_shortcut.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 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.SearchResultShortcut xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:launcher="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:gravity="center_vertical"
+    android:padding="@dimen/dynamic_grid_edge_margin">
+
+    <com.android.launcher3.BubbleTextView
+        android:id="@+id/bubble_text"
+        style="@style/BaseIcon"
+        android:drawablePadding="@dimen/dynamic_grid_icon_drawable_padding"
+        android:gravity="start|center_vertical"
+        android:textAlignment="viewStart"
+        android:textColor="?android:attr/textColorPrimary"
+        android:textSize="16sp"
+        android:layout_height="wrap_content"
+        launcher:iconDisplay="hero_app"
+        launcher:layoutHorizontal="true" />
+
+    <View
+        android:id="@+id/icon"
+        android:layout_width="@dimen/deep_shortcut_icon_size"
+        android:layout_height="@dimen/deep_shortcut_icon_size"
+        android:layout_gravity="start|center_vertical"
+        android:background="@drawable/ic_deepshortcut_placeholder" />
+
+</com.android.launcher3.views.SearchResultShortcut>
\ No newline at end of file
diff --git a/res/values/config.xml b/res/values/config.xml
index fc0a5e1..325b62f 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -59,7 +59,6 @@
     <bool name="hotseat_transpose_layout_with_orientation">true</bool>
 
     <!-- Various classes overriden by projects/build flavors. -->
-    <string name="app_filter_class" translatable="false"></string>
     <string name="user_event_dispatcher_class" translatable="false"></string>
     <string name="folder_name_provider_class" translatable="false"></string>
     <string name="stats_log_manager_class" translatable="false"></string>
@@ -187,4 +186,6 @@
 
     <string-array name="live_wallpapers_remove_sysui_scrims">
     </string-array>
+
+    <string-array name="filtered_components" ></string-array>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ad3e2b7..6ab8150 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -58,6 +58,8 @@
     <!-- All Apps -->
     <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
     <string name="all_apps_search_bar_hint">Search apps</string>
+    <!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
+    <string name="all_apps_on_device_search_bar_hint">Search this phone and more...</string>
     <!-- Loading apps text. [CHAR_LIMIT=50] -->
     <string name="all_apps_loading_message">Loading apps&#8230;</string>
     <!-- No-search-results text. [CHAR_LIMIT=50] -->
diff --git a/src/com/android/launcher3/AppFilter.java b/src/com/android/launcher3/AppFilter.java
index 9b6166f..3db456c 100644
--- a/src/com/android/launcher3/AppFilter.java
+++ b/src/com/android/launcher3/AppFilter.java
@@ -3,15 +3,25 @@
 import android.content.ComponentName;
 import android.content.Context;
 
-import com.android.launcher3.util.ResourceBasedOverride;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
 
-public class AppFilter implements ResourceBasedOverride {
+/**
+ * Utility class to filter out components from various lists
+ */
+public class AppFilter {
 
-    public static AppFilter newInstance(Context context) {
-        return Overrides.getObject(AppFilter.class, context, R.string.app_filter_class);
+    private final Set<ComponentName> mFilteredComponents;
+
+    public AppFilter(Context context) {
+        mFilteredComponents = Arrays.stream(
+                context.getResources().getStringArray(R.array.filtered_components))
+                .map(ComponentName::unflattenFromString)
+                .collect(Collectors.toSet());
     }
 
     public boolean shouldShowApp(ComponentName app) {
-        return true;
+        return !mFilteredComponents.contains(app);
     }
 }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index cacd3fb..90566f3 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -88,14 +88,19 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.OvershootInterpolator;
 import android.widget.Toast;
 
 import androidx.annotation.CallSuper;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.StringRes;
 import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
 
 import com.android.launcher3.DropTarget.DragObject;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
@@ -205,7 +210,8 @@
  * Default launcher application.
  */
 public class Launcher extends StatefulActivity<LauncherState> implements LauncherExterns,
-        Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin> {
+        Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin>,
+        LifecycleOwner {
     public static final String TAG = "Launcher";
 
     public static final ActivityTracker<Launcher> ACTIVITY_TRACKER = new ActivityTracker<>();
@@ -266,6 +272,8 @@
     private LauncherAppTransitionManager mAppTransitionManager;
     private Configuration mOldConfig;
 
+    private LifecycleRegistry mLifecycleRegistry;
+
     @Thunk
     Workspace mWorkspace;
     @Thunk
@@ -466,6 +474,19 @@
 
         mUserChangedCallbackCloseable = UserCache.INSTANCE.get(this).addUserChangeListener(
                 () -> getStateManager().goToState(NORMAL));
+
+        if (Utilities.ATLEAST_R) {
+            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
+        }
+
+        mLifecycleRegistry = new LifecycleRegistry(this);
+        mLifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
+    }
+
+    @NonNull
+    @Override
+    public Lifecycle getLifecycle() {
+        return mLifecycleRegistry;
     }
 
     protected LauncherOverlayManager getDefaultOverlay() {
@@ -881,6 +902,7 @@
 
     @Override
     protected void onStop() {
+        mLifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
         super.onStop();
         if (mDeferOverlayCallbacks) {
             checkIfOverlayStillDeferred();
@@ -904,6 +926,7 @@
 
         mAppWidgetHost.setListenIfResumed(true);
         TraceHelper.INSTANCE.endSection(traceToken);
+        mLifecycleRegistry.setCurrentState(Lifecycle.State.STARTED);
     }
 
     @Override
@@ -1063,6 +1086,7 @@
         }
 
         TraceHelper.INSTANCE.endSection(traceToken);
+        mLifecycleRegistry.setCurrentState(Lifecycle.State.RESUMED);
     }
 
     @Override
@@ -1070,6 +1094,7 @@
         // Ensure that items added to Launcher are queued until Launcher returns
         ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_ACTIVITY_PAUSED);
 
+        mLifecycleRegistry.setCurrentState(Lifecycle.State.STARTED);
         super.onPause();
         mDragController.cancelDrag();
         mLastTouchUpTime = -1;
@@ -1552,6 +1577,7 @@
         mOverlayManager.onActivityDestroyed(this);
         mAppTransitionManager.unregisterRemoteAnimations();
         mUserChangedCallbackCloseable.close();
+        mLifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED);
     }
 
     public LauncherAccessibilityDelegate getAccessibilityDelegate() {
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index b278e81..bfe327e 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -122,7 +122,7 @@
         mInvariantDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context);
         mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName);
         mWidgetCache = new WidgetPreviewLoader(mContext, mIconCache);
-        mModel = new LauncherModel(context, this, mIconCache, AppFilter.newInstance(mContext));
+        mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext));
     }
 
     protected void onNotificationSettingsChanged(boolean areNotificationDotsEnabled) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 8da81ac..45aaa1b 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -93,6 +93,7 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pageindicators.WorkspacePageIndicator;
 import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.touch.WorkspaceTouchListener;
@@ -436,10 +437,6 @@
             enforceDragParity("onDragEnd", 0, 0);
         }
 
-        if (!mDeferRemoveExtraEmptyScreen) {
-            removeExtraEmptyScreen(mDragSourceInternal != null);
-        }
-
         updateChildrenLayersEnabled();
         mDragInfo = null;
         mOutlineProvider = null;
@@ -657,6 +654,7 @@
         convertFinalScreenToEmptyScreenIfNecessary();
         if (hasExtraEmptyScreen()) {
             removeView(mWorkspaceScreens.get(EXTRA_EMPTY_SCREEN_ID));
+            setCurrentPage(getNextPage());
             mWorkspaceScreens.remove(EXTRA_EMPTY_SCREEN_ID);
             mScreenOrder.removeValue(EXTRA_EMPTY_SCREEN_ID);
 
@@ -1873,6 +1871,18 @@
                             };
                         }
                     }
+                    StateManager<LauncherState> stateManager = mLauncher.getStateManager();
+                    stateManager.addStateListener(new StateManager.StateListener<LauncherState>() {
+                        @Override
+                        public void onStateTransitionComplete(LauncherState finalState) {
+                            if (finalState == NORMAL) {
+                                if (!mDeferRemoveExtraEmptyScreen) {
+                                    removeExtraEmptyScreen(true /* stripEmptyScreens */);
+                                }
+                                stateManager.removeStateListener(this);
+                            }
+                        }
+                    });
 
                     mLauncher.getModelWriter().modifyItemInDatabase(info, container, screenId,
                             lp.cellX, lp.cellY, item.spanX, item.spanY);
@@ -2453,7 +2463,7 @@
             Runnable onAnimationCompleteRunnable = new Runnable() {
                 @Override
                 public void run() {
-                    // Normally removeExtraEmptyScreen is called in Workspace#onDragEnd, but when
+                    // Normally removeExtraEmptyScreen is called in Workspace#onDrop, but when
                     // adding an item that may not be dropped right away (due to a config activity)
                     // we defer the removal until the activity returns.
                     deferRemoveExtraEmptyScreen();
diff --git a/src/com/android/launcher3/WorkspaceLayoutManager.java b/src/com/android/launcher3/WorkspaceLayoutManager.java
index c3d4aeb..ea887cc 100644
--- a/src/com/android/launcher3/WorkspaceLayoutManager.java
+++ b/src/com/android/launcher3/WorkspaceLayoutManager.java
@@ -28,7 +28,7 @@
 
     String TAG = "Launcher.Workspace";
 
-    // The screen id used for the empty screen always present to the right.
+    // The screen id used for the empty screen always present at the end.
     int EXTRA_EMPTY_SCREEN_ID = -201;
     // The is the first screen. It is always present, even if its empty.
     int FIRST_SCREEN_ID = 0;
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 1f51566..5079469 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -67,6 +67,9 @@
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.RecyclerViewFastScroller;
 import com.android.launcher3.views.SpringRelativeLayout;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
+
+import java.util.function.IntConsumer;
 
 /**
  * The all apps view container.
@@ -538,34 +541,35 @@
      * Handles selection on focused view and returns success
      */
     public boolean selectFocusedView(View v) {
-        ItemInfo itemInfo = getHighlightedItemInfo();
-        if (itemInfo != null) {
-            return mLauncher.startActivitySafely(v, itemInfo.getIntent(), itemInfo);
+        ItemInfo headerItem = getHighlightedItemFromHeader();
+        if (headerItem != null) {
+            return mLauncher.startActivitySafely(v, headerItem.getIntent(), headerItem);
         }
         AdapterItem focusedItem = getActiveRecyclerView().getApps().getFocusedChild();
         if (focusedItem instanceof AdapterItemWithPayload) {
-            Runnable onSelection = ((AdapterItemWithPayload) focusedItem).getSelectionHandler();
+            IntConsumer onSelection =
+                    ((AdapterItemWithPayload) focusedItem).getSelectionHandler();
             if (onSelection != null) {
-                onSelection.run();
+                onSelection.accept(SearchTargetEvent.QUICK_SELECT);
                 return true;
             }
         }
+        if (focusedItem.appInfo != null) {
+            ItemInfo itemInfo = focusedItem.appInfo;
+            return mLauncher.startActivitySafely(v, itemInfo.getIntent(), itemInfo);
+        }
         return false;
     }
 
     /**
-     * Returns the ItemInfo of a view that is in focus, ready to be launched by an IME.
+     * Returns the ItemInfo of a focused view inside {@link FloatingHeaderView}
      */
-    public ItemInfo getHighlightedItemInfo() {
+    public ItemInfo getHighlightedItemFromHeader() {
         View view = getFloatingHeaderView().getFocusedChild();
         if (view != null && view.getTag() instanceof ItemInfo) {
             return ((ItemInfo) view.getTag());
         }
-        if (getActiveRecyclerView().getApps().getFocusedChild() != null) {
-            // TODO: when new pipelines are included, getSearchResults
-            // should be supported at recycler view level and not apps list level.
-            return getActiveRecyclerView().getApps().getFocusedChild().appInfo;
-        }
+
         return null;
     }
 
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index da161ac..d1340fa 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.Bundle;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -36,9 +37,6 @@
 import androidx.core.view.accessibility.AccessibilityEventCompat;
 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
 import androidx.core.view.accessibility.AccessibilityRecordCompat;
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.LifecycleRegistry;
 import androidx.lifecycle.LiveData;
 import androidx.recyclerview.widget.GridLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
@@ -48,21 +46,26 @@
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController.PayloadResultHandler;
 import com.android.launcher3.allapps.search.SearchSectionInfo;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.views.HeroSearchResultView;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
 
 import java.util.List;
+import java.util.function.IntConsumer;
 
 /**
  * The grid view adapter of all the apps.
  */
 public class AllAppsGridAdapter extends
-        RecyclerView.Adapter<AllAppsGridAdapter.ViewHolder> implements
-        LifecycleOwner {
+        RecyclerView.Adapter<AllAppsGridAdapter.ViewHolder> {
 
     public static final String TAG = "AppsGridAdapter";
 
@@ -89,12 +92,14 @@
 
     public static final int VIEW_TYPE_SEARCH_SLICE = 1 << 9;
 
+    public static final int VIEW_TYPE_SEARCH_SHORTCUT = 1 << 10;
+
+    public static final int VIEW_TYPE_SEARCH_PEOPLE = 1 << 11;
+
     // Common view type masks
     public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
     public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
 
-    private final LifecycleRegistry mLifecycleRegistry;
-
     /**
      * ViewHolder for each icon.
      */
@@ -179,7 +184,9 @@
                     || viewType == VIEW_TYPE_SEARCH_HERO_APP
                     || viewType == VIEW_TYPE_SEARCH_ROW_WITH_BUTTON
                     || viewType == VIEW_TYPE_SEARCH_SLICE
-                    || viewType == VIEW_TYPE_SEARCH_ROW;
+                    || viewType == VIEW_TYPE_SEARCH_ROW
+                    || viewType == VIEW_TYPE_SEARCH_PEOPLE
+                    || viewType == VIEW_TYPE_SEARCH_SHORTCUT;
         }
     }
 
@@ -190,18 +197,28 @@
      */
     public static class AdapterItemWithPayload<T> extends AdapterItem {
         private T mPayload;
-        private Runnable mSelectionHandler;
+        private AllAppsSearchPlugin mPlugin;
+        private IntConsumer mSelectionHandler;
 
-        public AdapterItemWithPayload(T payload, int type) {
-            mPayload = payload;
-            viewType = type;
+        public AllAppsSearchPlugin getPlugin() {
+            return mPlugin;
         }
 
-        public void setSelectionHandler(Runnable runnable) {
+        public void setPlugin(AllAppsSearchPlugin plugin) {
+            mPlugin = plugin;
+        }
+
+        public AdapterItemWithPayload(T payload, int type, AllAppsSearchPlugin plugin) {
+            mPayload = payload;
+            viewType = type;
+            mPlugin = plugin;
+        }
+
+        public void setSelectionHandler(IntConsumer runnable) {
             mSelectionHandler = runnable;
         }
 
-        public Runnable getSelectionHandler() {
+        public IntConsumer getSelectionHandler() {
             return mSelectionHandler;
         }
 
@@ -331,12 +348,6 @@
         mOnIconClickListener = launcher.getItemOnClickListener();
 
         setAppsPerRow(mLauncher.getDeviceProfile().inv.numAllAppsColumns);
-        if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
-            mLifecycleRegistry = new LifecycleRegistry(this);
-            mLifecycleRegistry.setCurrentState(Lifecycle.State.STARTED);
-        } else {
-            mLifecycleRegistry = null;
-        }
     }
 
     public void setAppsPerRow(int appsPerRow) {
@@ -390,10 +401,12 @@
             case VIEW_TYPE_ICON:
                 BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
                         R.layout.all_apps_icon, parent, false);
-                icon.setOnClickListener(mOnIconClickListener);
-                icon.setOnLongClickListener(mOnIconLongClickListener);
                 icon.setLongPressTimeoutFactor(1f);
                 icon.setOnFocusChangeListener(mIconFocusListener);
+                if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
+                    icon.setOnClickListener(mOnIconClickListener);
+                    icon.setOnLongClickListener(mOnIconLongClickListener);
+                }
 
                 // Ensure the all apps icon height matches the workspace icons in portrait mode.
                 icon.getLayoutParams().height = mLauncher.getDeviceProfile().allAppsCellHeightPx;
@@ -413,7 +426,6 @@
             case VIEW_TYPE_SEARCH_CORPUS_TITLE:
                 return new ViewHolder(
                         mLayoutInflater.inflate(R.layout.search_section_title, parent, false));
-
             case VIEW_TYPE_SEARCH_HERO_APP:
                 return new ViewHolder(mLayoutInflater.inflate(
                         R.layout.search_result_hero_app, parent, false));
@@ -426,6 +438,12 @@
             case VIEW_TYPE_SEARCH_SLICE:
                 return new ViewHolder(mLayoutInflater.inflate(
                         R.layout.search_result_slice, parent, false));
+            case VIEW_TYPE_SEARCH_SHORTCUT:
+                return new ViewHolder(mLayoutInflater.inflate(
+                        R.layout.search_result_shortcut, parent, false));
+            case VIEW_TYPE_SEARCH_PEOPLE:
+                return new ViewHolder(mLayoutInflater.inflate(
+                        R.layout.search_result_people_item, parent, false));
             default:
                 throw new RuntimeException("Unexpected view type");
         }
@@ -435,10 +453,36 @@
     public void onBindViewHolder(ViewHolder holder, int position) {
         switch (holder.getItemViewType()) {
             case VIEW_TYPE_ICON:
-                AppInfo info = mApps.getAdapterItems().get(position).appInfo;
+                AdapterItem adapterItem = mApps.getAdapterItems().get(position);
+                AppInfo info = adapterItem.appInfo;
                 BubbleTextView icon = (BubbleTextView) holder.itemView;
                 icon.reset();
                 icon.applyFromApplicationInfo(info);
+                if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
+                    break;
+                }
+                //TODO: replace with custom TopHitBubbleTextView with support for both shortcut
+                // and apps
+                if (adapterItem instanceof AdapterItemWithPayload) {
+                    AdapterItemWithPayload withPayload = (AdapterItemWithPayload) adapterItem;
+                    IntConsumer selectionHandler = type -> {
+                        SearchTargetEvent e = new SearchTargetEvent(SearchTarget.ItemType.APP,
+                                type);
+                        e.bundle = HeroSearchResultView.getAppBundle(info);
+                        if (withPayload.getPlugin() != null) {
+                            withPayload.getPlugin().notifySearchTargetEvent(e);
+                        }
+                    };
+                    icon.setOnClickListener(view -> {
+                        selectionHandler.accept(SearchTargetEvent.SELECT);
+                        mOnIconClickListener.onClick(view);
+                    });
+                    icon.setOnLongClickListener(view -> {
+                        selectionHandler.accept(SearchTargetEvent.LONG_PRESS);
+                        return mOnIconLongClickListener.onLongClick(view);
+                    });
+                    withPayload.setSelectionHandler(selectionHandler);
+                }
                 break;
             case VIEW_TYPE_EMPTY_SEARCH:
                 TextView emptyViewText = (TextView) holder.itemView;
@@ -456,11 +500,22 @@
                 break;
             case VIEW_TYPE_SEARCH_SLICE:
                 SliceView sliceView = (SliceView) holder.itemView;
-                Uri uri = ((AdapterItemWithPayload<Uri>) mApps.getAdapterItems().get(position))
-                        .getPayload();
+                AdapterItemWithPayload<Uri> item =
+                        (AdapterItemWithPayload<Uri>) mApps.getAdapterItems().get(position);
+                sliceView.setOnSliceActionListener((info1, s) -> {
+                    if (item.getPlugin() != null) {
+                        SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
+                                SearchTarget.ItemType.SETTINGS_SLICE,
+                                SearchTargetEvent.CHILD_SELECT);
+                        searchTargetEvent.bundle = new Bundle();
+                        searchTargetEvent.bundle.putParcelable("uri", item.getPayload());
+                        item.getPlugin().notifySearchTargetEvent(searchTargetEvent);
+                    }
+                });
                 try {
-                    LiveData<Slice> liveData = SliceLiveData.fromUri(mLauncher, uri);
-                    liveData.observe(this::getLifecycle, sliceView);
+                    LiveData<Slice> liveData = SliceLiveData.fromUri(mLauncher, item.getPayload());
+                    liveData.observe((Launcher) mLauncher, sliceView);
+                    sliceView.setTag(liveData);
                 } catch (Exception ignored) {
                 }
                 break;
@@ -468,6 +523,8 @@
             case VIEW_TYPE_SEARCH_ROW_WITH_BUTTON:
             case VIEW_TYPE_SEARCH_HERO_APP:
             case VIEW_TYPE_SEARCH_ROW:
+            case VIEW_TYPE_SEARCH_SHORTCUT:
+            case VIEW_TYPE_SEARCH_PEOPLE:
                 PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView;
                 payloadResultView.applyAdapterInfo(
                         (AdapterItemWithPayload) mApps.getAdapterItems().get(position));
@@ -479,6 +536,25 @@
     }
 
     @Override
+    public void onViewRecycled(@NonNull ViewHolder holder) {
+        super.onViewRecycled(holder);
+        if (!FeatureFlags.ENABLE_DEVICE_SEARCH.get()) return;
+        if (holder.itemView instanceof BubbleTextView) {
+            BubbleTextView icon = (BubbleTextView) holder.itemView;
+            icon.setOnClickListener(mOnIconClickListener);
+            icon.setOnLongClickListener(mOnIconLongClickListener);
+        } else if (holder.itemView instanceof SliceView) {
+            SliceView sliceView = (SliceView) holder.itemView;
+            sliceView.setOnSliceActionListener(null);
+            if (sliceView.getTag() instanceof LiveData) {
+                LiveData sliceLiveData = (LiveData) sliceView.getTag();
+                sliceLiveData.removeObservers((Launcher) mLauncher);
+            }
+        }
+    }
+
+
+    @Override
     public boolean onFailedToRecycleView(ViewHolder holder) {
         // Always recycle and we will reset the view when it is bound
         return true;
@@ -494,10 +570,4 @@
         AdapterItem item = mApps.getAdapterItems().get(position);
         return item.viewType;
     }
-
-    @NonNull
-    @Override
-    public Lifecycle getLifecycle() {
-        return mLifecycleRegistry;
-    }
 }
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 0268b96..4195a05 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -270,11 +270,7 @@
                     editText.requestFocus();
                 }
             }
-            if (Float.compare(mProgress, 1f) == 0) {
-                // Called when home gesture closes all apps container.
-                // TODO: should make the controller hide synchronously
-                mInsetController.hide();
-            }
+            // TODO: should make the controller hide synchronously
         }
     }
 }
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index 2e5ed3e..3320189 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -79,7 +79,7 @@
     public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
         if (mSearchAlgorithm instanceof PluginWrapper) {
             ((PluginWrapper) mSearchAlgorithm).runOnPluginIfConnected(
-                    AllAppsSearchPlugin::startedTyping);
+                    AllAppsSearchPlugin::startedSearchSession);
         }
     }
 
@@ -113,6 +113,7 @@
     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
         if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
             if (actionId == EditorInfo.IME_ACTION_SEARCH) {
+                // selectFocusedView should return SearchTargetEvent that is passed onto onClick
                 if (Launcher.getLauncher(mLauncher).getAppsView().selectFocusedView(v)) {
                     return true;
                 }
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index 5ed7de5..a83755e 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -60,6 +60,10 @@
             return false;
         }
 
+        if (requestSimpleFuzzySearch(query)) {
+            return title.toLowerCase().contains(query);
+        }
+
         int lastType;
         int thisType = Character.UNASSIGNED;
         int nextType = Character.getType(title.codePointAt(0));
@@ -160,4 +164,17 @@
             return new StringMatcher();
         }
     }
+
+    private static boolean requestSimpleFuzzySearch(String s) {
+        for (int i = 0; i < s.length(); ) {
+            int codepoint = s.codePointAt(i);
+            i += Character.charCount(codepoint);
+            switch (Character.UnicodeScript.of(codepoint)) {
+                case HAN:
+                    //Character.UnicodeScript.HAN: use String.contains to match
+                    return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index d8fca1d..4175280 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -149,6 +149,9 @@
     public static final BooleanFlag ENABLE_OVERVIEW_SHARE = getDebugFlag(
             "ENABLE_OVERVIEW_SHARE", false, "Show Share button in Overview Actions");
 
+    public static final BooleanFlag ENABLE_OVERVIEW_CONTENT_PUSH = getDebugFlag(
+            "ENABLE_OVERVIEW_CONTENT_PUSH", false, "Show Content Push button in Overview Actions");
+
     public static final BooleanFlag ENABLE_DATABASE_RESTORE = getDebugFlag(
             "ENABLE_DATABASE_RESTORE", true,
             "Enable database restore when new restore session is created");
@@ -174,8 +177,8 @@
             "SEPARATE_RECENTS_ACTIVITY", false,
             "Uses a separate recents activity instead of using the integrated recents+Launcher UI");
 
-    public static final BooleanFlag ENABLE_MINIMAL_DEVICE = new DeviceFlag(
-            "ENABLE_MINIMAL_DEVICE", false,
+    public static final BooleanFlag ENABLE_MINIMAL_DEVICE = getDebugFlag(
+            "ENABLE_MINIMAL_DEVICE", true,
             "Allow user to toggle minimal device mode in launcher.");
 
     public static void initialize(Context context) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index f1606ea..281598a 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -17,6 +17,7 @@
 package com.android.launcher3.folder;
 
 import static android.text.TextUtils.isEmpty;
+import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
 
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
 import static com.android.launcher3.LauncherState.NORMAL;
@@ -34,8 +35,10 @@
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Insets;
 import android.graphics.Path;
 import android.graphics.Rect;
+import android.os.Build;
 import android.text.InputType;
 import android.text.Selection;
 import android.text.TextUtils;
@@ -47,11 +50,17 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewDebug;
+import android.view.WindowInsets;
+import android.view.WindowInsetsAnimation;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.view.inputmethod.EditorInfo;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
+
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Alarm;
 import com.android.launcher3.BubbleTextView;
@@ -208,6 +217,8 @@
 
     private StatsLogManager mStatsLogManager;
 
+    @Nullable private FolderWindowInsetsAnimationCallback mFolderWindowInsetsAnimationCallback;
+
     /**
      * Used to inflate the Workspace from XML.
      *
@@ -252,6 +263,13 @@
         int measureSpec = MeasureSpec.UNSPECIFIED;
         mFooter.measure(measureSpec, measureSpec);
         mFooterHeight = mFooter.getMeasuredHeight();
+
+        if (Utilities.ATLEAST_R) {
+            mFolderWindowInsetsAnimationCallback =
+                    new FolderWindowInsetsAnimationCallback(DISPATCH_MODE_STOP, this);
+
+            setWindowInsetsAnimationCallback(mFolderWindowInsetsAnimationCallback);
+        }
     }
 
     public boolean onLongClick(View v) {
@@ -373,6 +391,26 @@
         return false;
     }
 
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
+        if (Utilities.ATLEAST_R) {
+            this.setTranslationY(0);
+
+            if (windowInsets.isVisible(WindowInsets.Type.ime())) {
+                Insets keyboardInsets = windowInsets.getInsets(WindowInsets.Type.ime());
+                int folderHeightFromBottom = getHeightFromBottom();
+
+                if (keyboardInsets.bottom > folderHeightFromBottom) {
+                    // Translate this folder above the keyboard, then add the folder name's padding
+                    this.setTranslationY(folderHeightFromBottom - keyboardInsets.bottom
+                            - mFolderName.getPaddingBottom());
+                }
+            }
+        }
+
+        return windowInsets;
+    }
+
     public FolderIcon getFolderIcon() {
         return mFolderIcon;
     }
@@ -720,11 +758,17 @@
         a.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
+                if (Utilities.ATLEAST_R) {
+                    setWindowInsetsAnimationCallback(null);
+                }
                 mIsAnimatingClosed = true;
             }
 
             @Override
             public void onAnimationEnd(Animator animation) {
+                if (Utilities.ATLEAST_R && mFolderWindowInsetsAnimationCallback != null) {
+                    setWindowInsetsAnimationCallback(mFolderWindowInsetsAnimationCallback);
+                }
                 closeComplete(true);
                 announceAccessibilityChanges();
                 mIsAnimatingClosed = false;
@@ -1646,4 +1690,64 @@
         mLauncher.getUserEventDispatcher()
                 .logLauncherEvent(mInfo.getFolderLabelStateLauncherEvent(fromState, toState));
     }
+
+    /** Returns the height of the current folder's bottom edge from the bottom of the screen. */
+    private int getHeightFromBottom() {
+        DragLayer.LayoutParams layoutParams = (DragLayer.LayoutParams) getLayoutParams();
+        int folderBottomPx = layoutParams.y + layoutParams.height;
+        int windowBottomPx = mLauncher.getDeviceProfile().heightPx;
+
+        return windowBottomPx - folderBottomPx;
+    }
+
+    /** Callback that animates a folder sliding up above the ime. */
+    @RequiresApi(api = Build.VERSION_CODES.R)
+    private static class FolderWindowInsetsAnimationCallback
+            extends WindowInsetsAnimation.Callback {
+
+        private final Folder mFolder;
+        float mFolderTranslationStart;
+        float mFolderTranslationEnd;
+
+        FolderWindowInsetsAnimationCallback(int dispatchMode, Folder folder) {
+            super(dispatchMode);
+
+            mFolder = folder;
+        }
+
+        @Override
+        public void onPrepare(@NonNull WindowInsetsAnimation animation) {
+            mFolderTranslationStart = mFolder.getTranslationY();
+        }
+
+        @NonNull
+        @Override
+        public WindowInsetsAnimation.Bounds onStart(
+                @NonNull WindowInsetsAnimation animation,
+                @NonNull WindowInsetsAnimation.Bounds bounds) {
+            mFolderTranslationEnd = mFolder.getTranslationY();
+
+            mFolder.setTranslationY(mFolderTranslationStart);
+
+            return super.onStart(animation, bounds);
+        }
+
+        @NonNull
+        @Override
+        public WindowInsets onProgress(@NonNull WindowInsets windowInsets,
+                @NonNull List<WindowInsetsAnimation> list) {
+            if (list.size() == 0) {
+                mFolder.setTranslationY(0);
+
+                return windowInsets;
+            }
+            float progress = list.get(0).getInterpolatedFraction();
+
+            mFolder.setTranslationY(
+                    Utilities.mapRange(progress, mFolderTranslationStart, mFolderTranslationEnd));
+
+            return windowInsets;
+        }
+
+    }
 }
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 30f8fb0..b2d0081 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -96,6 +96,8 @@
     public static final String REQUEST_DISABLE_DEBUG_TRACING = "disable-debug-tracing";
 
     public static final String REQUEST_OVERVIEW_SHARE_ENABLED = "overview-share-enabled";
+    public static final String REQUEST_OVERVIEW_CONTENT_PUSH_ENABLED =
+            "overview-content-push-enabled";
 
     public static boolean sDisableSensorRotation;
     public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
diff --git a/src/com/android/launcher3/util/VelocityUtils.java b/src/com/android/launcher3/util/VelocityUtils.java
new file mode 100644
index 0000000..d5962ed
--- /dev/null
+++ b/src/com/android/launcher3/util/VelocityUtils.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 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.util;
+
+/**
+ * Contains some constants and functions to standardize velocity usage.
+ */
+public class VelocityUtils {
+
+    /**
+     * Unit to pass to {@link android.view.VelocityTracker#computeCurrentVelocity(int)}.
+     */
+    public static final int PX_PER_MS = 1;
+
+}
diff --git a/src/com/android/launcher3/views/HeroSearchResultView.java b/src/com/android/launcher3/views/HeroSearchResultView.java
index 761ef0d..a8e1c6b 100644
--- a/src/com/android/launcher3/views/HeroSearchResultView.java
+++ b/src/com/android/launcher3/views/HeroSearchResultView.java
@@ -18,7 +18,9 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
 
 import android.content.Context;
+import android.content.Intent;
 import android.graphics.Point;
+import android.os.Bundle;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
@@ -41,6 +43,9 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
 import com.android.launcher3.touch.ItemLongClickListener;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
 
 import java.util.List;
 
@@ -54,6 +59,7 @@
     BubbleTextView mBubbleTextView;
     View mIconView;
     BubbleTextView[] mDeepShortcutTextViews = new BubbleTextView[2];
+    AllAppsSearchPlugin mPlugin;
 
     public HeroSearchResultView(Context context) {
         super(context);
@@ -79,7 +85,10 @@
 
 
         mBubbleTextView = findViewById(R.id.bubble_text);
-        mBubbleTextView.setOnClickListener(launcher.getItemOnClickListener());
+        mBubbleTextView.setOnClickListener(view -> {
+            handleSelection(SearchTargetEvent.SELECT);
+            launcher.getItemOnClickListener().onClick(view);
+        });
         mBubbleTextView.setOnLongClickListener(new HeroItemDragHandler(getContext(), this));
         setLayoutParams(
                 new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, grid.allAppsCellHeightPx));
@@ -91,7 +100,18 @@
             bubbleTextView.setLayoutParams(
                     new LinearLayout.LayoutParams(grid.allAppsIconSizePx,
                             grid.allAppsIconSizePx));
-            bubbleTextView.setOnClickListener(launcher.getItemOnClickListener());
+            bubbleTextView.setOnClickListener(view -> {
+                WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) bubbleTextView.getTag();
+                SearchTargetEvent event = new SearchTargetEvent(
+                        SearchTarget.ItemType.APP_HERO,
+                        SearchTargetEvent.CHILD_SELECT);
+                event.bundle = getAppBundle(itemInfo);
+                event.bundle.putString("shortcut_id", itemInfo.getDeepShortcutId());
+                if (mPlugin != null) {
+                    mPlugin.notifySearchTargetEvent(event);
+                }
+                launcher.getItemOnClickListener().onClick(view);
+            });
         }
     }
 
@@ -110,6 +130,8 @@
                 mDeepShortcutTextViews[i].applyFromItemInfoWithIcon(shorcutInfos.get(i));
             }
         }
+        mPlugin = adapterItem.getPlugin();
+        adapterItem.setSelectionHandler(this::handleSelection);
     }
 
     @Override
@@ -147,7 +169,38 @@
             mLauncher.getWorkspace().beginDragShared(mContainer.mBubbleTextView,
                     draggableView, mContainer, itemInfo, previewProvider, new DragOptions());
 
+            SearchTargetEvent event = new SearchTargetEvent(
+                    SearchTarget.ItemType.APP_HERO, SearchTargetEvent.LONG_PRESS);
+            event.bundle = getAppBundle(itemInfo);
+            if (mContainer.mPlugin != null) {
+                mContainer.mPlugin.notifySearchTargetEvent(event);
+            }
+
             return false;
         }
     }
+
+    private void handleSelection(int eventType) {
+        ItemInfo itemInfo = (ItemInfo) mBubbleTextView.getTag();
+        if (itemInfo == null) return;
+        Launcher launcher = Launcher.getLauncher(getContext());
+        launcher.startActivitySafely(this, itemInfo.getIntent(), itemInfo);
+
+        SearchTargetEvent event = new SearchTargetEvent(
+                SearchTarget.ItemType.APP_HERO, eventType);
+        event.bundle = getAppBundle(itemInfo);
+        if (mPlugin != null) {
+            mPlugin.notifySearchTargetEvent(event);
+        }
+    }
+
+    /**
+     * Helper method to generate {@link SearchTargetEvent} bundle from {@link ItemInfo}
+     */
+    public static Bundle getAppBundle(ItemInfo itemInfo) {
+        Bundle b = new Bundle();
+        b.putParcelable(Intent.EXTRA_COMPONENT_NAME, itemInfo.getTargetComponent());
+        b.putParcelable(Intent.EXTRA_USER, itemInfo.user);
+        return b;
+    }
 }
diff --git a/src/com/android/launcher3/views/SearchResultPeopleView.java b/src/com/android/launcher3/views/SearchResultPeopleView.java
new file mode 100644
index 0000000..6e45e88
--- /dev/null
+++ b/src/com/android/launcher3/views/SearchResultPeopleView.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2020 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 static android.content.Intent.URI_ALLOW_UNSAFE;
+import static android.content.Intent.URI_ANDROID_APP_SCHEME;
+
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsGridAdapter;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.util.Themes;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+
+/**
+ * A view representing a single people search result in all apps
+ */
+public class SearchResultPeopleView extends LinearLayout implements
+        AllAppsSearchBarController.PayloadResultHandler<Bundle> {
+
+    private final int mIconSize;
+    private final int mButtonSize;
+    private final PackageManager mPackageManager;
+    private View mIconView;
+    private TextView mTitleView;
+    private ImageButton[] mProviderButtons = new ImageButton[3];
+    private AllAppsSearchPlugin mPlugin;
+    private Uri mContactUri;
+
+
+    public SearchResultPeopleView(Context context) {
+        this(context, null, 0);
+    }
+
+    public SearchResultPeopleView(Context context,
+            @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public SearchResultPeopleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        DeviceProfile deviceProfile = Launcher.getLauncher(getContext()).getDeviceProfile();
+        mPackageManager = getContext().getPackageManager();
+        mIconSize = deviceProfile.iconSizePx;
+        mButtonSize = (int) (deviceProfile.iconSizePx / 1.5f);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mIconView = findViewById(R.id.icon);
+        mIconView.getLayoutParams().height = mIconSize;
+        mIconView.getLayoutParams().width = mIconSize;
+        mTitleView = findViewById(R.id.title);
+        mProviderButtons[0] = findViewById(R.id.provider_0);
+        mProviderButtons[1] = findViewById(R.id.provider_1);
+        mProviderButtons[2] = findViewById(R.id.provider_2);
+        for (ImageButton button : mProviderButtons) {
+            button.getLayoutParams().width = mButtonSize;
+            button.getLayoutParams().height = mButtonSize;
+        }
+        setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
+    }
+
+    @Override
+    public void applyAdapterInfo(
+            AllAppsGridAdapter.AdapterItemWithPayload<Bundle> adapterItemWithPayload) {
+        Bundle payload = adapterItemWithPayload.getPayload();
+        mPlugin = adapterItemWithPayload.getPlugin();
+        mTitleView.setText(payload.getString("title"));
+        mContactUri = payload.getParcelable("contact_uri");
+        Bitmap icon = payload.getParcelable("icon");
+        if (icon != null) {
+            RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create(getResources(), icon);
+            float radius = Themes.getDialogCornerRadius(getContext());
+            d.setCornerRadius(radius);
+            d.setBounds(0, 0, mIconSize, mIconSize);
+            BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(),
+                    Bitmap.createScaledBitmap(icon, mIconSize, mIconSize, false));
+            mIconView.setBackground(d);
+        }
+
+        ArrayList<Bundle> providers = payload.getParcelableArrayList("providers");
+        for (int i = 0; i < mProviderButtons.length; i++) {
+            ImageButton button = mProviderButtons[i];
+            if (providers != null && i < providers.size()) {
+                try {
+                    Bundle provider = providers.get(i);
+                    Intent intent = Intent.parseUri(provider.getString("intent_uri_str"),
+                            URI_ANDROID_APP_SCHEME | URI_ALLOW_UNSAFE);
+                    setupProviderButton(button, provider, intent);
+                    String pkg = provider.getString("package_name");
+                    UI_HELPER_EXECUTOR.post(() -> {
+                        try {
+                            ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(
+                                    pkg, 0);
+                            Drawable appIcon = applicationInfo.loadIcon(mPackageManager);
+                            MAIN_EXECUTOR.post(()-> button.setImageDrawable(appIcon));
+                        } catch (PackageManager.NameNotFoundException ignored) {
+                        }
+
+                    });
+                } catch (URISyntaxException ex) {
+                    button.setVisibility(GONE);
+                }
+            } else {
+                button.setVisibility(GONE);
+            }
+        }
+        adapterItemWithPayload.setSelectionHandler(this::handleSelection);
+    }
+
+    private void setupProviderButton(ImageButton button, Bundle provider, Intent intent) {
+        Launcher launcher = Launcher.getLauncher(getContext());
+        button.setOnClickListener(b -> {
+            launcher.startActivitySafely(b, intent, null);
+            SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
+                    SearchTarget.ItemType.PEOPLE,
+                    SearchTargetEvent.CHILD_SELECT);
+            searchTargetEvent.bundle = new Bundle();
+            searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri);
+            searchTargetEvent.bundle.putBundle("provider", provider);
+            if (mPlugin != null) {
+                mPlugin.notifySearchTargetEvent(searchTargetEvent);
+            }
+        });
+    }
+
+
+    private void handleSelection(int eventType) {
+        if (mContactUri != null) {
+            Launcher launcher = Launcher.getLauncher(getContext());
+            launcher.startActivitySafely(this, new Intent(Intent.ACTION_VIEW, mContactUri).setFlags(
+                    Intent.FLAG_ACTIVITY_NEW_TASK), null);
+            SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
+                    SearchTarget.ItemType.PEOPLE, eventType);
+            searchTargetEvent.bundle = new Bundle();
+            searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri);
+            if (mPlugin != null) {
+                mPlugin.notifySearchTargetEvent(searchTargetEvent);
+            }
+        }
+    }
+}
diff --git a/src/com/android/launcher3/views/SearchResultPlayItem.java b/src/com/android/launcher3/views/SearchResultPlayItem.java
index 19a4c5d..8624609 100644
--- a/src/com/android/launcher3/views/SearchResultPlayItem.java
+++ b/src/com/android/launcher3/views/SearchResultPlayItem.java
@@ -38,6 +38,9 @@
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
 
 import java.io.IOException;
 import java.net.URL;
@@ -54,6 +57,7 @@
     private Button mPreviewButton;
     private String mPackageName;
     private boolean mIsInstantGame;
+    private AllAppsSearchPlugin mPlugin;
 
     public SearchResultPlayItem(Context context) {
         this(context, null, 0);
@@ -84,13 +88,14 @@
         ViewGroup.LayoutParams iconParams = mIconView.getLayoutParams();
         iconParams.height = mDeviceProfile.allAppsIconSizePx;
         iconParams.width = mDeviceProfile.allAppsIconSizePx;
-        setOnClickListener(view -> handleSelection());
+        setOnClickListener(view -> handleSelection(SearchTargetEvent.SELECT));
 
     }
 
     @Override
     public void applyAdapterInfo(AdapterItemWithPayload<Bundle> adapterItemWithPayload) {
         Bundle bundle = adapterItemWithPayload.getPayload();
+        mPlugin = adapterItemWithPayload.getPlugin();
         adapterItemWithPayload.setSelectionHandler(this::handleSelection);
         if (bundle.getString("package", "").equals(mPackageName)) {
             return;
@@ -129,13 +134,14 @@
         }
     }
 
-    private void handleSelection() {
+    private void handleSelection(int eventType) {
         if (mPackageName == null) return;
         Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(
                 "https://play.google.com/store/apps/details?id="
                         + mPackageName));
         i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         getContext().startActivity(i);
+        logSearchEvent(eventType);
     }
 
     private void launchInstantGame() {
@@ -150,5 +156,16 @@
         intent.putExtra("callerId", getContext().getPackageName());
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         getContext().startActivity(intent);
+        logSearchEvent(SearchTargetEvent.CHILD_SELECT);
+    }
+
+    private void logSearchEvent(int eventType) {
+        SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
+                SearchTarget.ItemType.PLAY_RESULTS, eventType);
+        searchTargetEvent.bundle = new Bundle();
+        searchTargetEvent.bundle.putString("package_name", mPackageName);
+        if (mPlugin != null) {
+            mPlugin.notifySearchTargetEvent(searchTargetEvent);
+        }
     }
 }
diff --git a/src/com/android/launcher3/views/SearchResultShortcut.java b/src/com/android/launcher3/views/SearchResultShortcut.java
new file mode 100644
index 0000000..307cf34
--- /dev/null
+++ b/src/com/android/launcher3/views/SearchResultShortcut.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 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 static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+
+import android.content.Context;
+import android.content.pm.ShortcutInfo;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsGridAdapter;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.touch.ItemClickHandler;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
+
+/**
+ * A view representing a stand alone shortcut search result
+ */
+public class SearchResultShortcut extends FrameLayout implements
+        AllAppsSearchBarController.PayloadResultHandler<SearchTarget> {
+
+    private BubbleTextView mBubbleTextView;
+    private View mIconView;
+    private ShortcutInfo mShortcutInfo;
+    private AllAppsSearchPlugin mPlugin;
+
+    public SearchResultShortcut(@NonNull Context context) {
+        super(context);
+    }
+
+    public SearchResultShortcut(@NonNull Context context,
+            @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public SearchResultShortcut(@NonNull Context context, @Nullable AttributeSet attrs,
+            int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        Launcher launcher = Launcher.getLauncher(getContext());
+        DeviceProfile grid = launcher.getDeviceProfile();
+        mIconView = findViewById(R.id.icon);
+        ViewGroup.LayoutParams iconParams = mIconView.getLayoutParams();
+        iconParams.height = grid.allAppsIconSizePx;
+        iconParams.width = grid.allAppsIconSizePx;
+        mBubbleTextView = findViewById(R.id.bubble_text);
+        setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
+    }
+
+    @Override
+    public void applyAdapterInfo(
+            AllAppsGridAdapter.AdapterItemWithPayload<SearchTarget> adapterItemWithPayload) {
+        SearchTarget payload = adapterItemWithPayload.getPayload();
+        mPlugin = adapterItemWithPayload.getPlugin();
+        mShortcutInfo = payload.shortcuts.get(0);
+        WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(mShortcutInfo, getContext());
+        mBubbleTextView.applyFromWorkspaceItem(workspaceItemInfo);
+        mIconView.setBackground(mBubbleTextView.getIcon());
+        LauncherAppState launcherAppState = LauncherAppState.getInstance(getContext());
+        MODEL_EXECUTOR.execute(() -> {
+            launcherAppState.getIconCache().getShortcutIcon(workspaceItemInfo, mShortcutInfo);
+            mBubbleTextView.applyFromWorkspaceItem(workspaceItemInfo);
+            mIconView.setBackground(mBubbleTextView.getIcon());
+        });
+        adapterItemWithPayload.setSelectionHandler(this::handleSelection);
+    }
+
+    private void handleSelection(int eventType) {
+        WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) mBubbleTextView.getTag();
+        ItemClickHandler.onClickAppShortcut(this, itemInfo, Launcher.getLauncher(getContext()));
+
+        SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
+                SearchTarget.ItemType.SHORTCUT, eventType);
+        searchTargetEvent.shortcut = mShortcutInfo;
+        if (mPlugin != null) {
+            mPlugin.notifySearchTargetEvent(searchTargetEvent);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/views/SearchSettingsRowView.java b/src/com/android/launcher3/views/SearchSettingsRowView.java
index 08c78ff..93bcee2 100644
--- a/src/com/android/launcher3/views/SearchSettingsRowView.java
+++ b/src/com/android/launcher3/views/SearchSettingsRowView.java
@@ -31,6 +31,9 @@
 import com.android.launcher3.R;
 import com.android.launcher3.allapps.AllAppsGridAdapter;
 import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
 
 import java.util.ArrayList;
 
@@ -44,6 +47,7 @@
     private TextView mDescriptionView;
     private TextView mBreadcrumbsView;
     private Intent mIntent;
+    private AllAppsSearchPlugin mPlugin;
 
     public SearchSettingsRowView(@NonNull Context context) {
         super(context);
@@ -72,6 +76,7 @@
     public void applyAdapterInfo(
             AllAppsGridAdapter.AdapterItemWithPayload<Bundle> adapterItemWithPayload) {
         Bundle bundle = adapterItemWithPayload.getPayload();
+        mPlugin = adapterItemWithPayload.getPlugin();
         mIntent = bundle.getParcelable("intent");
         showIfAvailable(mTitleView, bundle.getString("title"));
         showIfAvailable(mDescriptionView, bundle.getString("description"));
@@ -79,7 +84,7 @@
         //TODO: implement RTL friendly breadcrumbs view
         showIfAvailable(mBreadcrumbsView, breadcrumbs != null
                 ? String.join(" > ", breadcrumbs) : null);
-        adapterItemWithPayload.setSelectionHandler(() -> onClick(this));
+        adapterItemWithPayload.setSelectionHandler(this::handleSelection);
     }
 
     private void showIfAvailable(TextView view, @Nullable String string) {
@@ -93,10 +98,22 @@
 
     @Override
     public void onClick(View view) {
+        handleSelection(SearchTargetEvent.SELECT);
+    }
+
+    private void handleSelection(int eventType) {
         if (mIntent == null) return;
         // TODO: create ItemInfo object and then use it to call startActivityForResult for proper
         //  WW logging
-        Launcher launcher = Launcher.getLauncher(view.getContext());
+        Launcher launcher = Launcher.getLauncher(getContext());
         launcher.startActivityForResult(mIntent, 0);
+
+        SearchTargetEvent searchTargetEvent = new SearchTargetEvent(
+                SearchTarget.ItemType.SETTINGS_ROW, eventType);
+        searchTargetEvent.bundle = new Bundle();
+        searchTargetEvent.bundle.putParcelable("intent", mIntent);
+        if (mPlugin != null) {
+            mPlugin.notifySearchTargetEvent(searchTargetEvent);
+        }
     }
 }
diff --git a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
index be20e2d..4fa670f 100644
--- a/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/AllAppsSearchPlugin.java
@@ -16,9 +16,12 @@
 
 package com.android.systemui.plugins;
 
-import android.os.Bundle;
+import android.app.Activity;
+import android.view.View;
 
 import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
 
 import java.util.List;
 import java.util.function.Consumer;
@@ -29,15 +32,30 @@
 @ProvidesInterface(action = AllAppsSearchPlugin.ACTION, version = AllAppsSearchPlugin.VERSION)
 public interface AllAppsSearchPlugin extends Plugin {
     String ACTION = "com.android.systemui.action.PLUGIN_ALL_APPS_SEARCH_ACTIONS";
-    int VERSION = 4;
+    int VERSION = 6;
+
+    void setup(Activity activity, View view);
 
     /**
-     * Send signal when user starts typing.
+     * Send launcher state related signals.
      */
-    void startedTyping();
+    void onStateTransitionStart(int fromState, int toState);
+    void onStateTransitionComplete(int state);
 
     /**
-     * Send over the query and get the search results.
+     * Send signal when user starts typing, perform search, when search ends
      */
-    void performSearch(String query, Consumer<List<Bundle>> results);
-}
+    void startedSearchSession();
+    void performSearch(String query, Consumer<List<SearchTarget>> results);
+
+    /**
+     * Send over search target interaction events to Plugin
+     */
+    void notifySearchTargetEvent(SearchTargetEvent event);
+
+    /**
+     * Launcher activity lifecycle callbacks
+     */
+    void onResume(int state);
+    void onStop(int state);
+}
\ No newline at end of file
diff --git a/src_plugins/com/android/systemui/plugins/OWNERS b/src_plugins/com/android/systemui/plugins/OWNERS
deleted file mode 100644
index 0514999..0000000
--- a/src_plugins/com/android/systemui/plugins/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# When changing interface for this plugin OR when increasing version code, please add Alex
-# Only add other owners if Alex is not available
-per-file AllAppsSearchPlugin.java, globs = set noparent
-per-file AllAppsSearchPlugin.java = alexmang@google.com, hyunyoungs@google.com, sunnygoyal@google.com, twickham@google.com
diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
new file mode 100644
index 0000000..c6b8300
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020 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.systemui.plugins.shared;
+
+import android.content.pm.ShortcutInfo;
+import android.os.Bundle;
+
+import java.util.List;
+
+/**
+ * Used to return all apps search targets.
+ */
+public class SearchTarget implements Comparable<SearchTarget> {
+
+    public enum ViewType {
+        TOP_HIT(0),
+        HERO(1),
+        DETAIL(2),
+        ROW(3),
+        ROW_WITH_BUTTON(4),
+        SLICE(5),
+        SHORTCUT(6),
+        PEOPLE(7);
+
+        private final int mId;
+        ViewType(int id) {
+            mId = id;
+        }
+
+        public int get() {
+            return mId;
+        }
+    }
+
+    public enum ItemType {
+        PLAY_RESULTS(0, "Play Store", ViewType.DETAIL),
+        SETTINGS_ROW(1, "Settings", ViewType.ROW),
+        SETTINGS_SLICE(2, "Settings", ViewType.SLICE),
+        APP(3, "", ViewType.TOP_HIT),
+        APP_HERO(4, "", ViewType.HERO),
+        SHORTCUT(5, "Shortcuts", ViewType.SHORTCUT),
+        PEOPLE(6, "People", ViewType.PEOPLE);
+
+        private final int mId;
+        private final String mTitle;
+        private final ViewType mViewType;
+
+        ItemType(int id, String title, ViewType type) {
+            mId = id;
+            mTitle = title;
+            mViewType = type;
+        }
+
+        public ViewType getViewType() {
+            return mViewType;
+        }
+
+        public String getTitle() {
+            return mTitle;
+        }
+
+        public int getId() {
+            return mId;
+        }
+    }
+
+    public ItemType type;
+    public List<ShortcutInfo> shortcuts;
+    public Bundle bundle;
+    public float score;
+
+    /**
+     * Constructor to create the search target. Bundle is currently temporary to hold
+     * search target primitives that cannot be expressed as java primitive objects
+     * or AOSP native objects.
+     *
+     */
+    public SearchTarget(ItemType itemType, List<ShortcutInfo> shortcuts,
+            Bundle bundle, float score) {
+        this.type = itemType;
+        this.shortcuts = shortcuts;
+        this.bundle = bundle;
+        this.score = score;
+    }
+
+    @Override
+    public int compareTo(SearchTarget o) {
+        return Float.compare(o.score, score);
+    }
+}
diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java b/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java
new file mode 100644
index 0000000..ac4bc33
--- /dev/null
+++ b/src_plugins/com/android/systemui/plugins/shared/SearchTargetEvent.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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.systemui.plugins.shared;
+
+import android.content.pm.ShortcutInfo;
+import android.os.Bundle;
+
+/**
+ * Event used for the feedback loop to the plugin. (and future aiai)
+ */
+public class SearchTargetEvent {
+    public static final int SELECT = 0;
+    public static final int QUICK_SELECT = 1;
+    public static final int LONG_PRESS = 2;
+    public static final int CHILD_SELECT = 3;
+
+    public SearchTarget.ItemType type;
+    public ShortcutInfo shortcut;
+    public int eventType;
+    public Bundle bundle;
+    public float score;
+
+    public SearchTargetEvent(SearchTarget.ItemType itemType, int eventType) {
+        this.type = itemType;
+        this.eventType = eventType;
+    }
+}
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 34ebbac..b4e45f8 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -234,7 +234,7 @@
 
         WidgetValidityCheck(LauncherAppState app) {
             mIdp = app.getInvariantDeviceProfile();
-            mAppFilter = AppFilter.newInstance(app.getContext());
+            mAppFilter = new AppFilter(app.getContext());
         }
 
         @Override
diff --git a/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java b/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
index bdf01f3..39709a9 100644
--- a/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
+++ b/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
@@ -68,8 +68,8 @@
 
         assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("电子邮件"), "电", MATCHER));
         assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("电子邮件"), "电子", MATCHER));
-        assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("电子邮件"), "子", MATCHER));
-        assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("电子邮件"), "邮件", MATCHER));
+        assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("电子邮件"), "子", MATCHER));
+        assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("电子邮件"), "邮件", MATCHER));
 
         assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("Bot"), "ba", MATCHER));
         assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("bot"), "ba", MATCHER));
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 80adf05..22833ec 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1313,6 +1313,11 @@
                 TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
+    boolean overviewContentPushEnabled() {
+        return getTestInfo(TestProtocol.REQUEST_OVERVIEW_CONTENT_PUSH_ENABLED).getBoolean(
+                TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
     private void disableSensorRotation() {
         getTestInfo(TestProtocol.REQUEST_MOCK_SENSOR_ROTATION);
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
index a30a404..e3e0f42 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
@@ -34,6 +34,27 @@
     }
 
     /**
+     * Clicks content push button.
+     */
+    @NonNull
+    public Overview clickAndDismissContentPush() {
+        if (mLauncher.overviewContentPushEnabled()) {
+            try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+                 LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                         "want to click content push button and exit screenshot ui")) {
+                UiObject2 exo = mLauncher.waitForObjectInContainer(mOverviewActions,
+                        "action_content_push");
+                mLauncher.clickLauncherObject(exo);
+                try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                        "clicked content push button")) {
+                    return new Overview(mLauncher);
+                }
+            }
+        }
+        return new Overview(mLauncher);
+    }
+
+    /**
      * Clicks screenshot button and closes screenshot ui.
      */
     @NonNull