Merge " Migrate from Plugin SearchTarget to API search Target [3/3]"
diff --git a/Android.mk b/Android.mk
index 503f9ae..ed42039 100644
--- a/Android.mk
+++ b/Android.mk
@@ -33,7 +33,8 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     LauncherPluginLib \
-    launcher_log_protos_lite
+    launcher_log_protos_lite \
+    search_ui
 
 LOCAL_SRC_FILES := \
     $(call all-java-files-under, src_build_config) \
diff --git a/proguard.flags b/proguard.flags
index 37b8093..a450183 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -45,9 +45,10 @@
 
 # BUG(70852369): Surpress additional warnings after changing from Proguard to R8
 -dontwarn android.app.**
--dontwarn android.view.**
--dontwarn android.os.**
 -dontwarn android.graphics.**
+-dontwarn android.os.**
+-dontwarn android.view.**
+-dontwarn android.window.**
 
 # Ignore warnings for hidden utility classes referenced from the shared lib
 -dontwarn com.android.internal.util.**
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 8e6a5b6..2d9d092 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -56,6 +56,7 @@
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.Looper;
+import android.os.SystemProperties;
 import android.util.Pair;
 import android.view.View;
 
@@ -74,6 +75,7 @@
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.launcher3.views.FloatingIconView;
 import com.android.quickstep.RemoteAnimationTargets;
+import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.MultiValueUpdateListener;
 import com.android.quickstep.util.RemoteAnimationProvider;
 import com.android.quickstep.util.StaggeredWorkspaceAnim;
@@ -86,6 +88,7 @@
 import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.RemoteTransitionCompat;
 import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
@@ -99,6 +102,9 @@
 
     private static final String TAG = "QuickstepTransition";
 
+    private static final boolean ENABLE_SHELL_STARTING_SURFACE =
+            SystemProperties.getBoolean("persist.debug.shell_starting_surface", false);
+
     /** Duration of status bar animations. */
     public static final int STATUS_BAR_TRANSITION_DURATION = 120;
 
@@ -159,6 +165,9 @@
     private WrappedAnimationRunnerImpl mAppLaunchRunner;
     private WrappedAnimationRunnerImpl mKeyguardGoingAwayRunner;
 
+    private WrappedAnimationRunnerImpl mWallpaperOpenTransitionRunner;
+    private RemoteTransitionCompat mLauncherOpenTransition;
+
     private final AnimatorListenerAdapter mForceInvisibleListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationStart(Animator animation) {
@@ -442,9 +451,9 @@
             RemoteAnimationTargetCompat[] appTargets,
             RemoteAnimationTargetCompat[] wallpaperTargets,
             Rect windowTargetBounds, boolean toggleVisibility) {
-        RectF bounds = new RectF();
+        RectF launcherIconBounds = new RectF();
         FloatingIconView floatingView = FloatingIconView.getFloatingIconView(mLauncher, v,
-                toggleVisibility, bounds, true /* isOpening */);
+                toggleVisibility, launcherIconBounds, true /* isOpening */);
         Rect crop = new Rect();
         Matrix matrix = new Matrix();
 
@@ -458,11 +467,17 @@
         mDragLayer.getLocationOnScreen(dragLayerBounds);
 
         AnimOpenProperties prop = new AnimOpenProperties(mLauncher.getResources(), mDeviceProfile,
-                windowTargetBounds, bounds, v, dragLayerBounds);
+                windowTargetBounds, launcherIconBounds, v, dragLayerBounds[0], dragLayerBounds[1]);
+        int left = (int) (prop.cropCenterXStart - prop.cropWidthStart / 2);
+        int top = (int) (prop.cropCenterYStart - prop.cropHeightStart / 2);
+        int right = (int) (left + prop.cropWidthStart);
+        int bottom = (int) (top + prop.cropHeightStart);
+        // Set the crop here so we can calculate the corner radius below.
+        crop.set(left, top, right, bottom);
 
         RectF targetBounds = new RectF(windowTargetBounds);
-        RectF iconBounds = new RectF();
-        RectF temp = new RectF();
+        RectF floatingIconBounds = new RectF();
+        RectF tmpRectF = new RectF();
         Point tmpPos = new Point();
 
         AnimatorSet animatorSet = new AnimatorSet();
@@ -481,68 +496,79 @@
         });
 
         final float initialWindowRadius = supportsRoundedCornersOnWindows(mLauncher.getResources())
-                ? prop.startCrop / 2f : 0f;
+                ? Math.max(crop.width(), crop.height()) / 2f
+                : 0f;
         final float finalWindowRadius = mDeviceProfile.isMultiWindowMode
                 ? 0 : getWindowCornerRadius(mLauncher.getResources());
 
         appAnimator.addUpdateListener(new MultiValueUpdateListener() {
             FloatProp mDx = new FloatProp(0, prop.dX, 0, prop.xDuration, AGGRESSIVE_EASE);
             FloatProp mDy = new FloatProp(0, prop.dY, 0, prop.yDuration, AGGRESSIVE_EASE);
-            FloatProp mScale = new FloatProp(prop.initialAppIconScale,
+
+            FloatProp mIconScaleToFitScreen = new FloatProp(prop.initialAppIconScale,
                     prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, EXAGGERATED_EASE);
             FloatProp mIconAlpha = new FloatProp(prop.iconAlphaStart, 0f,
                     APP_LAUNCH_ALPHA_START_DELAY, prop.alphaDuration, LINEAR);
-            FloatProp mCroppedSize = new FloatProp(prop.startCrop, prop.endCrop, 0, CROP_DURATION,
-                    EXAGGERATED_EASE);
+
             FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, 0,
                     RADIUS_DURATION, EXAGGERATED_EASE);
             FloatProp mShadowRadius = new FloatProp(0, mMaxShadowRadius, 0,
                     APP_LAUNCH_DURATION, EXAGGERATED_EASE);
 
+            FloatProp mCropRectCenterX = new FloatProp(prop.cropCenterXStart, prop.cropCenterXEnd,
+                    0, CROP_DURATION, EXAGGERATED_EASE);
+            FloatProp mCropRectCenterY = new FloatProp(prop.cropCenterYStart, prop.cropCenterYEnd,
+                    0, CROP_DURATION, EXAGGERATED_EASE);
+            FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd, 0,
+                    CROP_DURATION, EXAGGERATED_EASE);
+            FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, 0,
+                    CROP_DURATION, EXAGGERATED_EASE);
+
             @Override
             public void onUpdate(float percent) {
                 // Calculate the size of the scaled icon.
-                float width = bounds.width() * mScale.value;
-                float height = bounds.height() * mScale.value;
+                float iconWidth = launcherIconBounds.width() * mIconScaleToFitScreen.value;
+                float iconHeight = launcherIconBounds.height() * mIconScaleToFitScreen.value;
 
-                // Animate the crop so that it starts off as a square.
-                final int cropWidth;
-                final int cropHeight;
-                if (mDeviceProfile.isVerticalBarLayout()) {
-                    cropWidth = (int) mCroppedSize.value;
-                    cropHeight = windowTargetBounds.height();
-                } else {
-                    cropWidth = windowTargetBounds.width();
-                    cropHeight = (int) mCroppedSize.value;
-                }
-                crop.set(0, 0, cropWidth, cropHeight);
+                int left = (int) (mCropRectCenterX.value - mCropRectWidth.value / 2);
+                int top = (int) (mCropRectCenterY.value - mCropRectHeight.value / 2);
+                int right = (int) (left + mCropRectWidth.value);
+                int bottom = (int) (top + mCropRectHeight.value);
+                crop.set(left, top, right, bottom);
+
+                final int windowCropWidth = crop.width();
+                final int windowCropHeight = crop.height();
 
                 // Scale the size of the icon to match the size of the window crop.
-                float scaleX = width / cropWidth;
-                float scaleY = height / cropHeight;
+                float scaleX = iconWidth / windowCropWidth;
+                float scaleY = iconHeight / windowCropHeight;
                 float scale = Math.min(1f, Math.max(scaleX, scaleY));
 
-                float scaledCropWidth = cropWidth * scale;
-                float scaledCropHeight = cropHeight * scale;
-                float offsetX  = (scaledCropWidth - width) / 2;
-                float offsetY = (scaledCropHeight - height) / 2;
+                float scaledCropWidth = windowCropWidth * scale;
+                float scaledCropHeight = windowCropHeight * scale;
+                float offsetX  = (scaledCropWidth - iconWidth) / 2;
+                float offsetY = (scaledCropHeight - iconHeight) / 2;
 
                 // Calculate the window position to match the icon position.
-                temp.set(bounds);
-                temp.offset(dragLayerBounds[0], dragLayerBounds[1]);
-                temp.offset(mDx.value, mDy.value);
-                Utilities.scaleRectFAboutCenter(temp, mScale.value);
-                float windowTransX0 = temp.left - offsetX;
-                float windowTransY0 = temp.top - offsetY;
+                tmpRectF.set(launcherIconBounds);
+                tmpRectF.offset(dragLayerBounds[0], dragLayerBounds[1]);
+                tmpRectF.offset(mDx.value, mDy.value);
+                Utilities.scaleRectFAboutCenter(tmpRectF, mIconScaleToFitScreen.value);
+                float windowTransX0 = tmpRectF.left - offsetX;
+                float windowTransY0 = tmpRectF.top - offsetY;
+                if (ENABLE_SHELL_STARTING_SURFACE) {
+                    windowTransX0 -= crop.left * scale;
+                    windowTransY0 -= crop.top * scale;
+                }
 
                 // Calculate the icon position.
-                iconBounds.set(bounds);
-                iconBounds.offset(mDx.value, mDy.value);
-                Utilities.scaleRectFAboutCenter(iconBounds, mScale.value);
-                iconBounds.left -= offsetX;
-                iconBounds.top -= offsetY;
-                iconBounds.right += offsetX;
-                iconBounds.bottom += offsetY;
+                floatingIconBounds.set(launcherIconBounds);
+                floatingIconBounds.offset(mDx.value, mDy.value);
+                Utilities.scaleRectFAboutCenter(floatingIconBounds, mIconScaleToFitScreen.value);
+                floatingIconBounds.left -= offsetX;
+                floatingIconBounds.top -= offsetY;
+                floatingIconBounds.right += offsetX;
+                floatingIconBounds.bottom += offsetY;
 
                 SurfaceParams[] params = new SurfaceParams[appTargets.length];
                 for (int i = appTargets.length - 1; i >= 0; i--) {
@@ -553,7 +579,7 @@
                         matrix.setScale(scale, scale);
                         matrix.postTranslate(windowTransX0, windowTransY0);
 
-                        floatingView.update(iconBounds, mIconAlpha.value, percent, 0f,
+                        floatingView.update(floatingIconBounds, mIconAlpha.value, percent, 0f,
                                 mWindowRadius.value * scale, true /* isOpening */);
                         builder.withMatrix(matrix)
                                 .withWindowCrop(crop)
@@ -561,10 +587,11 @@
                                 .withCornerRadius(mWindowRadius.value)
                                 .withShadowRadius(mShadowRadius.value);
                     } else {
-                        tmpPos.set(target.position.x, target.position.y);
                         if (target.localBounds != null) {
                             final Rect localBounds = target.localBounds;
                             tmpPos.set(target.localBounds.left, target.localBounds.top);
+                        } else {
+                            tmpPos.set(target.position.x, target.position.y);
                         }
 
                         matrix.setTranslate(tmpPos.x, tmpPos.y);
@@ -636,6 +663,24 @@
     }
 
     /**
+     * Registers remote animations used when closing apps to home screen.
+     */
+    @Override
+    public void registerRemoteTransitions() {
+        if (SEPARATE_RECENTS_ACTIVITY.get()) {
+            return;
+        }
+        if (hasControlRemoteAppTransitionPermission()) {
+            mWallpaperOpenTransitionRunner = createWallpaperOpenRunner(false /* fromUnlock */);
+            mLauncherOpenTransition = RemoteAnimationAdapterCompat.buildRemoteTransition(
+                    new WrappedLauncherAnimationRunner<>(mWallpaperOpenTransitionRunner,
+                            false /* startAtFrontOfQueue */));
+            mLauncherOpenTransition.addHomeOpenCheck();
+            SystemUiProxy.INSTANCE.getNoCreate().registerRemoteTransition(mLauncherOpenTransition);
+        }
+    }
+
+    /**
      * Unregisters all remote animations.
      */
     @Override
@@ -654,6 +699,20 @@
         }
     }
 
+    @Override
+    public void unregisterRemoteTransitions() {
+        if (SEPARATE_RECENTS_ACTIVITY.get()) {
+            return;
+        }
+        if (hasControlRemoteAppTransitionPermission()) {
+            if (mLauncherOpenTransition == null) return;
+            SystemUiProxy.INSTANCE.getNoCreate().unregisterRemoteTransition(
+                    mLauncherOpenTransition);
+            mLauncherOpenTransition = null;
+            mWallpaperOpenTransitionRunner = null;
+        }
+    }
+
     private boolean launcherIsATargetWithMode(RemoteAnimationTargetCompat[] targets, int mode) {
         return taskIsATargetWithMode(targets, mLauncher.getTaskId(), mode);
     }
@@ -721,9 +780,10 @@
                     RemoteAnimationTargetCompat target = appTargets[i];
                     SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash);
 
-                    tmpPos.set(target.position.x, target.position.y);
                     if (target.localBounds != null) {
                         tmpPos.set(target.localBounds.left, target.localBounds.top);
+                    } else {
+                        tmpPos.set(target.position.x, target.position.y);
                     }
 
                     if (target.mode == MODE_CLOSING) {
@@ -932,8 +992,15 @@
      */
     static class AnimOpenProperties {
 
-        public final float startCrop;
-        public final float endCrop;
+        public final int cropCenterXStart;
+        public final int cropCenterYStart;
+        public final int cropWidthStart;
+        public final int cropHeightStart;
+
+        public final int cropCenterXEnd;
+        public final int cropCenterYEnd;
+        public final int cropWidthEnd;
+        public final int cropHeightEnd;
 
         public final float dX;
         public final float dY;
@@ -948,7 +1015,7 @@
         public final float iconAlphaStart;
 
         AnimOpenProperties(Resources r, DeviceProfile dp, Rect windowTargetBounds,
-                RectF launcherIconBounds, View view, int[] dragLayerBounds) {
+                RectF launcherIconBounds, View view, int dragLayerLeft, int dragLayerTop) {
             // Scale the app icon to take up the entire screen. This simplifies the math when
             // animating the app window position / scale.
             float smallestSize = Math.min(windowTargetBounds.height(), windowTargetBounds.width());
@@ -966,8 +1033,8 @@
             finalAppIconScale = Math.max(maxScaleX, maxScaleY);
 
             // Animate the app icon to the center of the window bounds in screen coordinates.
-            float centerX = windowTargetBounds.centerX() - dragLayerBounds[0];
-            float centerY = windowTargetBounds.centerY() - dragLayerBounds[1];
+            float centerX = windowTargetBounds.centerX() - dragLayerLeft;
+            float centerY = windowTargetBounds.centerY() - dragLayerTop;
 
             dX = centerX - launcherIconBounds.centerX();
             dY = centerY - launcherIconBounds.centerY();
@@ -981,15 +1048,31 @@
             alphaDuration = useUpwardAnimation ? APP_LAUNCH_ALPHA_DURATION
                     : APP_LAUNCH_ALPHA_DOWN_DURATION;
 
-            if (dp.isVerticalBarLayout()) {
-                startCrop = windowTargetBounds.height();
-                endCrop = windowTargetBounds.width();
+            if (ENABLE_SHELL_STARTING_SURFACE) {
+                iconAlphaStart = 0;
+
+                // TOOD: Share value from shell when available.
+                final float windowIconSize = Utilities.pxFromSp(108, r.getDisplayMetrics());
+
+                cropCenterXStart = windowTargetBounds.centerX();
+                cropCenterYStart = windowTargetBounds.centerY();
+
+                cropWidthStart = (int) windowIconSize;
+                cropHeightStart = (int) windowIconSize;
             } else {
-                startCrop = windowTargetBounds.width();
-                endCrop = windowTargetBounds.height();
+                iconAlphaStart = 1;
+
+                cropWidthStart = cropHeightStart =
+                        Math.min(windowTargetBounds.width(), windowTargetBounds.height());
+                cropCenterXStart = cropCenterYStart =
+                        Math.min(windowTargetBounds.centerX(), windowTargetBounds.centerY());
             }
 
-            iconAlphaStart = 1f;
+            cropWidthEnd = windowTargetBounds.width();
+            cropHeightEnd = windowTargetBounds.height();
+
+            cropCenterXEnd = windowTargetBounds.centerX();
+            cropCenterYEnd = windowTargetBounds.centerY();
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index a7e4741..3d5b1c6 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -721,10 +721,11 @@
 
     @UiThread
     public void onGestureStarted(boolean isLikelyToStartNewTask) {
-        InteractionJankMonitorWrapper.begin(mRecentsView,
-                InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH, 2000 /* ms timeout */);
-        InteractionJankMonitorWrapper.begin(mRecentsView,
-                InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
+        // Temporarily disable this until we have a view that we can use
+        // InteractionJankMonitorWrapper.begin(mRecentsView,
+        //         InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH, 2000 /* ms timeout */);
+        // InteractionJankMonitorWrapper.begin(mRecentsView,
+        //         InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME);
         notifyGestureStartedAsync();
         setIsLikelyToStartNewTask(isLikelyToStartNewTask, false /* animate */);
         mStateCallback.setStateOnUiThread(STATE_GESTURE_STARTED);
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index b4f20d1..5bed929 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -396,4 +396,9 @@
             pa.addFloat(recentsView, FULLSCREEN_PROGRESS, 1, 0, LINEAR);
         }
     }
+
+    /** Called when OverviewService is bound to this process */
+    void onOverviewServiceBound() {
+        // Do nothing
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 901040d..a80c111 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -22,12 +22,14 @@
 import static com.android.launcher3.GestureNavContract.EXTRA_ICON_POSITION;
 import static com.android.launcher3.GestureNavContract.EXTRA_ICON_SURFACE;
 import static com.android.launcher3.GestureNavContract.EXTRA_REMOTE_CALLBACK;
+import static com.android.launcher3.Utilities.createHomeIntent;
 import static com.android.launcher3.anim.Interpolators.ACCEL;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
 
 import android.animation.ObjectAnimator;
 import android.annotation.TargetApi;
 import android.app.ActivityOptions;
+import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Matrix;
@@ -126,7 +128,11 @@
         ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
         Intent intent = new Intent(mGestureState.getHomeIntent());
         mActiveAnimationFactory.addGestureContract(intent);
-        mContext.startActivity(intent, options.toBundle());
+        try {
+            mContext.startActivity(intent, options.toBundle());
+        } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
+            mContext.startActivity(createHomeIntent());
+        }
         return mActiveAnimationFactory;
     }
 
diff --git a/quickstep/src/com/android/quickstep/ImageActionsApi.java b/quickstep/src/com/android/quickstep/ImageActionsApi.java
index ba8ba33..b04905c 100644
--- a/quickstep/src/com/android/quickstep/ImageActionsApi.java
+++ b/quickstep/src/com/android/quickstep/ImageActionsApi.java
@@ -22,11 +22,14 @@
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.quickstep.util.ImageActionUtils.persistBitmapAndStartActivity;
 
+import android.app.prediction.AppTarget;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ShortcutInfo;
 import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.util.Log;
 
 import androidx.annotation.Nullable;
@@ -96,4 +99,12 @@
         ImageActionUtils.saveScreenshot(mSystemUiProxy, screenshot, screenshotBounds, visibleInsets,
                 task);
     }
+
+    /**
+     * Share the image when user taps on overview share targets.
+     */
+    @UiThread
+    public void shareImage(RectF rectF, ShortcutInfo shortcutInfo, AppTarget appTarget) {
+        ImageActionUtils.shareImage(mContext, mBitmapSupplier, rectF, shortcutInfo, appTarget, TAG);
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 9f435f5..7630bc4 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -270,4 +270,11 @@
                 + res.getDimensionPixelSize(R.dimen.overview_actions_height);
         return actionsHeight;
     }
-}
\ No newline at end of file
+
+    @Override
+    void onOverviewServiceBound() {
+        final BaseQuickstepLauncher activity = getCreatedActivity();
+        if (activity == null) return;
+        activity.getAppTransitionManager().registerRemoteTransitions();
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index ec6e303..985389e 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -175,9 +175,12 @@
                 return;
             }
 
-            InteractionJankMonitorWrapper.begin(
-                    mActivityInterface.getCreatedActivity().getRootView(),
-                    InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
+            final T activity = mActivityInterface.getCreatedActivity();
+            if (activity != null) {
+                InteractionJankMonitorWrapper.begin(
+                        activity.getRootView(),
+                        InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
+            }
 
             // Otherwise, start overview.
             mListener = mActivityInterface.createActivityInitListener(this::onActivityReady);
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 7bf7712..fb8f9fe 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -20,6 +20,7 @@
 import static android.content.Intent.ACTION_PACKAGE_CHANGED;
 import static android.content.Intent.ACTION_PACKAGE_REMOVED;
 
+import static com.android.launcher3.Utilities.createHomeIntent;
 import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
 import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter;
 import static com.android.systemui.shared.system.PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED;
@@ -74,9 +75,7 @@
     public OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState) {
         mContext = context;
         mDeviceState = deviceState;
-        mCurrentHomeIntent = new Intent(Intent.ACTION_MAIN)
-                .addCategory(Intent.CATEGORY_HOME)
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mCurrentHomeIntent = createHomeIntent();
         mMyHomeIntent = new Intent(mCurrentHomeIntent).setPackage(mContext.getPackageName());
         ResolveInfo info = context.getPackageManager().resolveActivity(mMyHomeIntent, 0);
         ComponentName myHomeComponent =
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index c37fd84..7beeae2 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -21,6 +21,7 @@
 import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
 import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_DURATION;
 import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_PRE_DELAY;
+import static com.android.launcher3.Utilities.createHomeIntent;
 import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
 import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
 import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
@@ -309,9 +310,7 @@
     }
 
     public void startHome() {
-        startActivity(new Intent(Intent.ACTION_MAIN)
-                .addCategory(Intent.CATEGORY_HOME)
-                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+        startActivity(createHomeIntent());
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index a214d81..ca55468 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -35,6 +35,7 @@
 import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
 import com.android.systemui.shared.recents.ISystemUiProxy;
 import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.system.RemoteTransitionCompat;
 
 /**
  * Holds the reference to SystemUI.
@@ -408,4 +409,26 @@
             }
         }
     }
+
+    @Override
+    public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.registerRemoteTransition(remoteTransition);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call registerRemoteTransition");
+            }
+        }
+    }
+
+    @Override
+    public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.unregisterRemoteTransition(remoteTransition);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call registerRemoteTransition");
+            }
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index e59035c..1f7cec5 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -136,6 +136,12 @@
                 SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy);
                 TouchInteractionService.this.initInputMonitor();
                 preloadOverview(true /* fromInit */);
+                mDeviceState.runOnUserUnlocked(() -> {
+                    final BaseActivityInterface ai =
+                            mOverviewComponentObserver.getActivityInterface();
+                    if (ai == null) return;
+                    ai.onOverviewServiceBound();
+                });
             });
             sIsInitialized = true;
         }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 5aaea00..85ecab1 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -19,6 +19,7 @@
 import static android.view.MotionEvent.ACTION_POINTER_DOWN;
 import static android.view.MotionEvent.ACTION_UP;
 
+import static com.android.launcher3.Utilities.createHomeIntent;
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.Utilities.squaredTouchSlop;
 import static com.android.launcher3.util.VelocityUtils.PX_PER_MS;
@@ -203,9 +204,7 @@
                 public void onAnimationEnd(Animator animation) {
                     if (dismissTask) {
                         // For now, just start the home intent so user is prompted to unlock the device.
-                        mContext.startActivity(new Intent(Intent.ACTION_MAIN)
-                                .addCategory(Intent.CATEGORY_HOME)
-                                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+                        mContext.startActivity(createHomeIntent());
                         mHomeLaunched = true;
                     }
                     mStateCallback.setState(STATE_HANDLER_INVALIDATED);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
index 924b32c..864e08d 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
@@ -15,10 +15,12 @@
  */
 package com.android.quickstep.inputconsumers;
 
+import static com.android.launcher3.Utilities.createHomeIntent;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
 
+import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.graphics.PointF;
 import android.view.MotionEvent;
@@ -77,7 +79,11 @@
 
     @Override
     public void onSwipeUp(boolean wasFling, PointF finalVelocity) {
-        mContext.startActivity(mGestureState.getHomeIntent());
+        try {
+            mContext.startActivity(mGestureState.getHomeIntent());
+        } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
+            mContext.startActivity(createHomeIntent());
+        }
         ActiveGestureLog.INSTANCE.addLog("startQuickstep");
         BaseActivity activity = BaseDraggingActivity.fromContext(mContext);
         int state = (mGestureState != null && mGestureState.getEndTarget() != null)
diff --git a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
index e998e9a..d022085 100644
--- a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
+++ b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
@@ -22,15 +22,19 @@
 import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
+import android.app.prediction.AppTarget;
 import android.content.ClipData;
 import android.content.ClipDescription;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ShortcutInfo;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Insets;
 import android.graphics.Picture;
 import android.graphics.Rect;
+import android.graphics.RectF;
 import android.net.Uri;
 import android.util.Log;
 
@@ -71,6 +75,34 @@
     }
 
     /**
+     * Launch the activity to share image for overview sharing. This is to share cropped bitmap
+     * with specific share targets (with shortcutInfo and appTarget) rendered in overview.
+     */
+    @UiThread
+    public static void shareImage(Context context, Supplier<Bitmap> bitmapSupplier, RectF rectF,
+            ShortcutInfo shortcutInfo, AppTarget appTarget, String tag) {
+        if (bitmapSupplier.get() == null) {
+            return;
+        }
+        Rect crop = new Rect();
+        rectF.round(crop);
+        Intent intent = new Intent();
+        Uri uri =  getImageUri(bitmapSupplier.get(), crop, context, tag);
+        ClipData clipdata = new ClipData(new ClipDescription("content",
+                new String[]{"image/png"}),
+                new ClipData.Item(uri));
+        intent.setAction(Intent.ACTION_SEND)
+            .setComponent(new ComponentName(appTarget.getPackageName(), appTarget.getClassName()))
+            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+            .addFlags(FLAG_GRANT_READ_URI_PERMISSION)
+            .setType("image/png")
+            .putExtra(Intent.EXTRA_STREAM, uri)
+            .putExtra(Intent.EXTRA_SHORTCUT_ID, shortcutInfo.getId())
+            .setClipData(clipdata);
+        context.startActivity(intent);
+    }
+
+    /**
      * Launch the activity to share image.
      */
     @UiThread
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index dd3e31f..a89aaf4 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -49,6 +49,7 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.touch.PagedOrientationHandler;
@@ -156,7 +157,8 @@
         Resources res = context.getResources();
         int originalSmallestWidth = res.getConfiguration().smallestScreenWidthDp
                 * res.getDisplayMetrics().densityDpi / DENSITY_DEVICE_STABLE;
-        if (originalSmallestWidth < 600) {
+        if (originalSmallestWidth < 600 && !mContext.getResources().getBoolean(
+                R.bool.allow_rotation)) {
             mFlags |= FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_DENSITY;
         }
         mFlags |= FLAG_SWIPE_UP_NOT_RUNNING;
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index b9e0f62..475953b 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -23,6 +23,7 @@
 import static com.android.launcher3.tapl.TestHelpers.getHomeIntentInPackage;
 import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_ACTIVITY_TIMEOUT;
+import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_BROADCAST_TIMEOUT_SECS;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.resolveSystemApp;
 import static com.android.launcher3.ui.AbstractLauncherUiTest.startAppFast;
@@ -66,6 +67,8 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.model.Statement;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import java.util.function.Function;
 
@@ -112,11 +115,16 @@
             @Override
             public void evaluate() throws Throwable {
                 TestCommandReceiver.callCommand(TestCommandReceiver.ENABLE_TEST_LAUNCHER);
+                OverviewUpdateHandler updateHandler =
+                        MAIN_EXECUTOR.submit(OverviewUpdateHandler::new).get();
                 UiDevice.getInstance(getInstrumentation()).executeShellCommand(
                         getLauncherCommand(mOtherLauncherActivity));
+                updateHandler.mChangeCounter
+                        .await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS);
                 try {
                     base.evaluate();
                 } finally {
+                    MAIN_EXECUTOR.submit(updateHandler::destroy).get();
                     TestCommandReceiver.callCommand(TestCommandReceiver.DISABLE_TEST_LAUNCHER);
                     UiDevice.getInstance(getInstrumentation()).executeShellCommand(
                             getLauncherCommand(getLauncherInMyProcess()));
@@ -241,4 +249,30 @@
     private int getTaskCount(RecentsActivity recents) {
         return recents.<RecentsView>getOverviewPanel().getTaskViewCount();
     }
+
+    private class OverviewUpdateHandler {
+
+        final RecentsAnimationDeviceState mRads;
+        final OverviewComponentObserver mObserver;
+        final CountDownLatch mChangeCounter;
+
+        OverviewUpdateHandler() {
+            Context ctx = getInstrumentation().getTargetContext();
+            mRads = new RecentsAnimationDeviceState(ctx);
+            mObserver = new OverviewComponentObserver(ctx, mRads);
+            mChangeCounter = new CountDownLatch(1);
+            if (mObserver.getHomeIntent().getComponent()
+                    .getPackageName().equals(mOtherLauncherActivity.packageName)) {
+                // Home already same
+                mChangeCounter.countDown();
+            } else {
+                mObserver.setOverviewChangeListener(b -> mChangeCounter.countDown());
+            }
+        }
+
+        void destroy() {
+            mObserver.onDestroy();
+            mRads.destroy();
+        }
+    }
 }
diff --git a/res/layout/launcher_preview_layout.xml b/res/layout/launcher_preview_layout.xml
index 4a20c70..1691680 100644
--- a/res/layout/launcher_preview_layout.xml
+++ b/res/layout/launcher_preview_layout.xml
@@ -29,23 +29,8 @@
         launcher:containerType="workspace"
         launcher:pageIndicator="@+id/page_indicator"/>
 
-    <com.android.launcher3.Hotseat
+    <include
         android:id="@+id/hotseat"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:importantForAccessibility="no"
-        android:theme="@style/HomeScreenElementTheme"
-        launcher:containerType="hotseat" />
-
-    <com.android.launcher3.InsettableFrameLayout
-        android:id="@+id/apps_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" >
-
-        <include
-            android:id="@id/search_container_all_apps"
-            layout="@layout/search_container_all_apps"/>
-
-    </com.android.launcher3.InsettableFrameLayout>
+        layout="@layout/hotseat" />
 
 </com.android.launcher3.InsettableFrameLayout>
\ No newline at end of file
diff --git a/robolectric_tests/src/com/android/launcher3/util/LauncherUIHelper.java b/robolectric_tests/src/com/android/launcher3/util/LauncherUIHelper.java
index f019a20..fdddab4 100644
--- a/robolectric_tests/src/com/android/launcher3/util/LauncherUIHelper.java
+++ b/robolectric_tests/src/com/android/launcher3/util/LauncherUIHelper.java
@@ -18,6 +18,8 @@
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.makeMeasureSpec;
 
+import static com.android.launcher3.Utilities.createHomeIntent;
+
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
@@ -46,10 +48,7 @@
      */
     public static String getLauncherClassName() {
         Context context = RuntimeEnvironment.application;
-        Intent homeIntent = new Intent(Intent.ACTION_MAIN)
-                .addCategory(Intent.CATEGORY_HOME)
-                .setPackage(context.getPackageName())
-                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        Intent homeIntent = createHomeIntent().setPackage(context.getPackageName());
 
         List<ResolveInfo> launchers = context.getPackageManager()
                 .queryIntentActivities(homeIntent, 0);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5b55c4b..0274775 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1596,6 +1596,7 @@
 
         mOverlayManager.onActivityDestroyed(this);
         mAppTransitionManager.unregisterRemoteAnimations();
+        mAppTransitionManager.unregisterRemoteTransitions();
         mUserChangedCallbackCloseable.close();
         mLifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED);
         mLiveSearchManager.stop();
diff --git a/src/com/android/launcher3/LauncherAppTransitionManager.java b/src/com/android/launcher3/LauncherAppTransitionManager.java
index 24e0d14..ac3ad9f 100644
--- a/src/com/android/launcher3/LauncherAppTransitionManager.java
+++ b/src/com/android/launcher3/LauncherAppTransitionManager.java
@@ -67,4 +67,18 @@
     public void unregisterRemoteAnimations() {
         // Do nothing
     }
+
+    /**
+     * Registers remote transitions for certain system transitions.
+     */
+    public void registerRemoteTransitions() {
+        // Do nothing
+    }
+
+    /**
+     * Unregisters all remote transitions.
+     */
+    public void unregisterRemoteTransitions() {
+        // Do nothing
+    }
 }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index df5d234..8066aa6 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -461,6 +461,15 @@
     }
 
     /**
+     * Returns an intent for starting the default home activity
+     */
+    public static Intent createHomeIntent() {
+        return new Intent(Intent.ACTION_MAIN)
+                .addCategory(Intent.CATEGORY_HOME)
+                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+    }
+
+    /**
      * Wraps a message with a TTS span, so that a different message is spoken than
      * what is getting displayed.
      * @param msg original message
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index efc1201..3a9986e 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -64,7 +64,6 @@
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.R;
 import com.android.launcher3.WorkspaceLayoutManager;
-import com.android.launcher3.allapps.SearchUiManager;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.icons.BaseIconFactory;
@@ -512,16 +511,6 @@
             mWorkspace.addViewToCellLayout(qsb, 0, R.id.search_container_workspace, lp, true);
         }
 
-        // Setup search view
-        SearchUiManager searchUiManager = mRootView.findViewById(R.id.search_container_all_apps);
-        mRootView.findViewById(R.id.apps_view).setTranslationY(
-                mDp.heightPx - searchUiManager.getScrollRangeDelta(mInsets));
-        ViewGroup searchView = (ViewGroup) searchUiManager;
-        searchView.setEnabled(false);
-        for (int i = 0; i < searchView.getChildCount(); i++) {
-            searchView.getChildAt(i).setEnabled(false);
-        }
-
         measureView(mRootView, mDp.widthPx, mDp.heightPx);
         dispatchVisibilityAggregated(mRootView, true);
         measureView(mRootView, mDp.widthPx, mDp.heightPx);
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index ecf4f36..ba28e82 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -51,7 +51,7 @@
     public static final int REQUEST_ROTATE = 1;
     public static final int REQUEST_LOCK = 2;
 
-    private final Activity mActivity;
+    private Activity mActivity;
     private final SharedPreferences mSharedPrefs;
 
     private boolean mIgnoreAutoRotateSettings;
@@ -95,6 +95,7 @@
 
     @Override
     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
+        if (mDestroyed) return;
         boolean wasRotationEnabled = mHomeRotationEnabled;
         mHomeRotationEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY,
                 getAllowRotationDefaultValue());
@@ -141,6 +142,7 @@
     public void destroy() {
         if (!mDestroyed) {
             mDestroyed = true;
+            mActivity = null;
             if (mSharedPrefs != null) {
                 mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
             }
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index d3fc89e..37dd4d2 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -150,7 +150,7 @@
         return "Activity leak detector has found leaked activities, " + dumpHprofData() + ".";
     }
 
-    private static String dumpHprofData() {
+    public static String dumpHprofData() {
         try {
             final String fileName = getInstrumentation().getTargetContext().getFilesDir().getPath()
                     + "/ActivityLeakHeapDump.hprof";