Merge "Fixing LauncherAnimationRunning referring a destroyed activity" into ub-launcher3-master
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
index 71580ca..4abb86a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
@@ -213,7 +213,7 @@
     @Override
     public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTargetCompat target) {
         // TODO: Remove this once b/77875376 is fixed
-        return target.sourceContainerBounds;
+        return target.screenSpaceBounds;
     }
 
     @Override
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index 0269e4a..25a3078 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -453,8 +453,11 @@
                 // Do not change mConsumer as if there is an ongoing QuickSwitch gesture, we should
                 // not interrupt it. QuickSwitch assumes that interruption can only happen if the
                 // next gesture is also quick switch.
-                mUncheckedConsumer = new AssistantInputConsumer(this, newGestureState,
-                        InputConsumer.NO_OP, mInputMonitorCompat);
+                mUncheckedConsumer = new AssistantInputConsumer(
+                    this,
+                    newGestureState,
+                    InputConsumer.NO_OP, mInputMonitorCompat,
+                    mOverviewComponentObserver.assistantGestureIsConstrained());
             } else {
                 mUncheckedConsumer = InputConsumer.NO_OP;
             }
@@ -494,7 +497,12 @@
         }
         if (mDeviceState.isFullyGesturalNavMode()) {
             if (mDeviceState.canTriggerAssistantAction(event)) {
-                base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat);
+                base = new AssistantInputConsumer(
+                    this,
+                    newGestureState,
+                    base,
+                    mInputMonitorCompat,
+                    mOverviewComponentObserver.assistantGestureIsConstrained());
             }
 
             if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
index 94126ff..89e6931 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantInputConsumer.java
@@ -90,12 +90,18 @@
     private final float mSquaredSlop;
     private final Context mContext;
     private final GestureDetector mGestureDetector;
+    private final boolean mIsAssistGestureConstrained;
 
-    public AssistantInputConsumer(Context context, GestureState gestureState,
-            InputConsumer delegate, InputMonitorCompat inputMonitor) {
+    public AssistantInputConsumer(
+            Context context,
+            GestureState gestureState,
+            InputConsumer delegate,
+            InputMonitorCompat inputMonitor,
+            boolean isAssistGestureConstrained) {
         super(delegate, inputMonitor);
         final Resources res = context.getResources();
         mContext = context;
+        mIsAssistGestureConstrained = isAssistGestureConstrained;
         mDragDistThreshold = res.getDimension(R.dimen.gestures_assistant_drag_threshold);
         mFlingDistThreshold = res.getDimension(R.dimen.gestures_assistant_fling_threshold);
         mTimeThreshold = res.getInteger(R.integer.assistant_gesture_min_time_threshold);
@@ -258,7 +264,8 @@
     private class AssistantGestureListener extends SimpleOnGestureListener {
         @Override
         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
-            if (isValidAssistantGestureAngle(velocityX, -velocityY)
+            if (!mIsAssistGestureConstrained
+                && isValidAssistantGestureAngle(velocityX, -velocityY)
                     && mDistance >= mFlingDistThreshold
                     && !mLaunchedAssistant
                     && mState != STATE_DELEGATE_ACTIVE) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
index 681ce02..d9e9cc7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/AppWindowAnimationHelper.java
@@ -50,6 +50,7 @@
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
 import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
 import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
 import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
 
@@ -119,7 +120,7 @@
 
     private void updateSourceStack(RemoteAnimationTargetCompat target) {
         mSourceInsets.set(target.contentInsets);
-        mSourceStackBounds.set(target.sourceContainerBounds);
+        mSourceStackBounds.set(target.screenSpaceBounds);
 
         // TODO: Should sourceContainerBounds already have this offset?
         mSourceStackBounds.offsetTo(target.position.x, target.position.y);
@@ -199,9 +200,17 @@
         for (int i = 0; i < params.mTargetSet.unfilteredApps.length; i++) {
             RemoteAnimationTargetCompat app = params.mTargetSet.unfilteredApps[i];
             SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
-            mTmpMatrix.setTranslate(app.position.x, app.position.y);
+            if (app.localBounds != null) {
+                mTmpMatrix.setTranslate(0, 0);
+                if (app.activityType == ACTIVITY_TYPE_HOME && app.mode == MODE_CLOSING) {
+                    mTmpMatrix.setTranslate(app.localBounds.left, app.localBounds.top);
+                }
+            } else {
+                mTmpMatrix.setTranslate(app.position.x, app.position.y);
+            }
+
             Rect crop = mTmpRect;
-            crop.set(app.sourceContainerBounds);
+            crop.set(app.screenSpaceBounds);
             crop.offsetTo(0, 0);
             float alpha;
             float cornerRadius = 0f;
@@ -211,7 +220,11 @@
                 alpha = mTaskAlphaCallback.getAlpha(app, params.mTargetAlpha);
                 if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
                     mTmpMatrix.setRectToRect(mSourceRect, mCurrentRect, ScaleToFit.FILL);
-                    mTmpMatrix.postTranslate(app.position.x, app.position.y);
+                    if (app.localBounds != null) {
+                        mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top);
+                    } else {
+                        mTmpMatrix.postTranslate(app.position.x, app.position.y);
+                    }
                     mCurrentClipRectF.roundOut(crop);
                     if (mSupportsRoundedCornersOnWindows) {
                         if (params.mCornerRadius > -1) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 34d8adf..b5e6af4 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -169,7 +169,6 @@
                 }
             };
 
-    private final OrientationEventListener mOrientationListener;
     private int mPreviousRotation;
     protected RecentsAnimationController mRecentsAnimationController;
     protected RecentsAnimationTargets mRecentsAnimationTargets;
@@ -377,22 +376,6 @@
 
         // Initialize quickstep specific cache params here, as this is constructed only once
         mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
-        mOrientationListener = new OrientationEventListener(getContext()) {
-            @Override
-            public void onOrientationChanged(int i) {
-                int rotation = RotationHelper.getRotationFromDegrees(i);
-                if (mPreviousRotation != rotation) {
-                    animateRecentsRotationInPlace(rotation);
-                    if (rotation == 0) {
-                        showActionsView();
-                    } else {
-                        hideActionsView();
-                    }
-                    mPreviousRotation = rotation;
-                }
-            }
-        };
-
     }
 
     public OverScroller getScroller() {
@@ -521,13 +504,6 @@
     }
 
     public void setOverviewStateEnabled(boolean enabled) {
-        if (supportsVerticalLandscape() && mOrientationListener.canDetectOrientation()) {
-            if (enabled) {
-                mOrientationListener.enable();
-            } else {
-                mOrientationListener.disable();
-            }
-        }
         mOverviewStateEnabled = enabled;
         updateTaskStackListenerState();
         if (!enabled) {
@@ -968,35 +944,6 @@
         setSwipeDownShouldLaunchApp(true);
     }
 
-    private void animateRecentsRotationInPlace(int newRotation) {
-        if (!supportsVerticalLandscape()) {
-            return;
-        }
-
-        AnimatorSet pa = setRecentsChangedOrientation(true);
-        pa.addListener(AnimationSuccessListener.forRunnable(() -> {
-            updateLayoutRotation(newRotation);
-            ((DragLayer) mActivity.getDragLayer()).recreateControllers();
-            rotateAllChildTasks();
-            setRecentsChangedOrientation(false).start();
-        }));
-        pa.start();
-    }
-
-    public AnimatorSet setRecentsChangedOrientation(boolean fadeInChildren) {
-        getRunningTaskIndex();
-        int runningIndex = getCurrentPage();
-        AnimatorSet as = new AnimatorSet();
-        for (int i = 0; i < getTaskViewCount(); i++) {
-            if (runningIndex == i) {
-                continue;
-            }
-            View taskView = getTaskViewAt(i);
-            as.play(ObjectAnimator.ofFloat(taskView, View.ALPHA, fadeInChildren ? 0 : 1));
-        }
-        return as;
-    }
-
     abstract protected boolean supportsVerticalLandscape();
 
     private void rotateAllChildTasks() {
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index 8d4e727..b9bd6b1 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -49,6 +49,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Matrix;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
@@ -297,8 +298,12 @@
         if (mLauncher.isInMultiWindowMode()) {
             for (RemoteAnimationTargetCompat target : appTargets) {
                 if (target.mode == MODE_OPENING) {
-                    bounds.set(target.sourceContainerBounds);
-                    bounds.offsetTo(target.position.x, target.position.y);
+                    bounds.set(target.screenSpaceBounds);
+                    if (target.localBounds != null) {
+                        bounds.set(target.localBounds);
+                    } else {
+                        bounds.offsetTo(target.position.x, target.position.y);
+                    }
                     return bounds;
                 }
             }
@@ -458,6 +463,7 @@
         RectF targetBounds = new RectF(windowTargetBounds);
         RectF currentBounds = new RectF();
         RectF temp = new RectF();
+        Point tmpPos = new Point();
 
         AnimatorSet animatorSet = new AnimatorSet();
         ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
@@ -545,6 +551,13 @@
                 for (int i = appTargets.length - 1; i >= 0; i--) {
                     RemoteAnimationTargetCompat target = appTargets[i];
                     SurfaceParams.Builder builder = new SurfaceParams.Builder(target.leash);
+
+                    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);
+                    }
+
                     if (target.mode == MODE_OPENING) {
                         matrix.setScale(scale, scale);
                         matrix.postTranslate(transX0, transY0);
@@ -561,9 +574,9 @@
                                 .withAlpha(1f - mIconAlpha.value)
                                 .withCornerRadius(mWindowRadius.value);
                     } else {
-                        matrix.setTranslate(target.position.x, target.position.y);
+                        matrix.setTranslate(tmpPos.x, tmpPos.y);
                         builder.withMatrix(matrix)
-                                .withWindowCrop(target.sourceContainerBounds)
+                                .withWindowCrop(target.screenSpaceBounds)
                                 .withAlpha(1f);
                     }
                     builder.withLayer(RemoteAnimationProvider.getLayer(target, MODE_OPENING));
@@ -660,7 +673,7 @@
                     RemoteAnimationTargetCompat target = appTargets[i];
                     params[i] = new SurfaceParams.Builder(target.leash)
                             .withAlpha(1f)
-                            .withWindowCrop(target.sourceContainerBounds)
+                            .withWindowCrop(target.screenSpaceBounds)
                             .withLayer(RemoteAnimationProvider.getLayer(target, MODE_OPENING))
                             .withCornerRadius(cornerRadius)
                             .build();
@@ -679,6 +692,7 @@
         SyncRtSurfaceTransactionApplierCompat surfaceApplier =
                 new SyncRtSurfaceTransactionApplierCompat(mDragLayer);
         Matrix matrix = new Matrix();
+        Point tmpPos = new Point();
         ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1);
         int duration = CLOSING_TRANSITION_DURATION_MS;
         float windowCornerRadius = mDeviceProfile.isMultiWindowMode
@@ -695,22 +709,28 @@
                 for (int i = appTargets.length - 1; i >= 0; i--) {
                     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);
+                    }
+
                     if (target.mode == MODE_CLOSING) {
                         matrix.setScale(mScale.value, mScale.value,
-                                target.sourceContainerBounds.centerX(),
-                                target.sourceContainerBounds.centerY());
+                                target.screenSpaceBounds.centerX(),
+                                target.screenSpaceBounds.centerY());
                         matrix.postTranslate(0, mDy.value);
-                        matrix.postTranslate(target.position.x, target.position.y);
+                        matrix.postTranslate(tmpPos.x, tmpPos.y);
                         builder.withMatrix(matrix)
                                 .withAlpha(mAlpha.value)
                                 .withCornerRadius(windowCornerRadius);
                     } else {
-                        matrix.setTranslate(target.position.x, target.position.y);
+                        matrix.setTranslate(tmpPos.x, tmpPos.y);
                         builder.withMatrix(matrix)
                                 .withAlpha(1f);
                     }
                     params[i] = builder
-                            .withWindowCrop(target.sourceContainerBounds)
+                            .withWindowCrop(target.screenSpaceBounds)
                             .withLayer(RemoteAnimationProvider.getLayer(target, MODE_CLOSING))
                             .build();
                 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java b/quickstep/src/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java
new file mode 100644
index 0000000..548223a
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java
@@ -0,0 +1,45 @@
+/*
+ * 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.uioverrides;
+
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Size;
+import android.view.View;
+
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.graphics.LauncherPreviewRenderer;
+import com.android.systemui.shared.system.SurfaceViewRequestReceiver;
+
+/** Render preview using surface view. */
+public class PreviewSurfaceRenderer {
+
+    /** Handle a received surface view request. */
+    public static void render(Context context, Bundle bundle) {
+        final String gridName = bundle.getString("name");
+        bundle.remove("name");
+        final InvariantDeviceProfile idp = new InvariantDeviceProfile(context, gridName);
+
+        MAIN_EXECUTOR.execute(() -> {
+            View view = new LauncherPreviewRenderer(context, idp).getRenderedView();
+            new SurfaceViewRequestReceiver().onReceive(context, bundle, view,
+                    new Size(view.getMeasuredWidth(), view.getMeasuredHeight()));
+        });
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 866836e..9edc86e 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -22,6 +22,7 @@
 
 import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter;
 import static com.android.systemui.shared.system.PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED;
 
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -104,6 +105,10 @@
         updateOverviewTargets();
     }
 
+    public boolean assistantGestureIsConstrained() {
+        return (mDeviceState.getSystemUiStateFlags() & SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED) != 0;
+    }
+
     /**
      * Update overview intent and {@link BaseActivityInterface} based off the current launcher home
      * component.
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 4ac815e..0afe4a8 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -166,12 +166,9 @@
             return false;
         }
 
-        setOverlayPackageEnabled(NAV_BAR_MODE_3BUTTON_OVERLAY,
-                overlayPackage == NAV_BAR_MODE_3BUTTON_OVERLAY);
-        setOverlayPackageEnabled(NAV_BAR_MODE_2BUTTON_OVERLAY,
-                overlayPackage == NAV_BAR_MODE_2BUTTON_OVERLAY);
-        setOverlayPackageEnabled(NAV_BAR_MODE_GESTURAL_OVERLAY,
-                overlayPackage == NAV_BAR_MODE_GESTURAL_OVERLAY);
+        Log.d(TAG, "setActiveOverlay: " + overlayPackage + "...");
+        UiDevice.getInstance(getInstrumentation()).executeShellCommand(
+                "cmd overlay enable-exclusive " + overlayPackage);
 
         if (currentSysUiNavigationMode() != expectedMode) {
             final CountDownLatch latch = new CountDownLatch(1);
@@ -210,14 +207,6 @@
         return true;
     }
 
-    private static void setOverlayPackageEnabled(String overlayPackage, boolean enable)
-            throws Exception {
-        Log.d(TAG, "setOverlayPackageEnabled: " + overlayPackage + " " + enable);
-        final String action = enable ? "enable" : "disable";
-        UiDevice.getInstance(getInstrumentation()).executeShellCommand(
-                "cmd overlay " + action + " " + overlayPackage);
-    }
-
     private static boolean packageExists(String packageName) {
         try {
             PackageManager pm = getInstrumentation().getContext().getPackageManager();
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 471a743..8453c41 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -100,11 +100,11 @@
             "Suggests folder names instead of blank text.");
 
     public static final BooleanFlag APP_SEARCH_IMPROVEMENTS = new DeviceFlag(
-            "APP_SEARCH_IMPROVEMENTS", false,
+            "APP_SEARCH_IMPROVEMENTS", true,
             "Adds localized title and keyword search and ranking");
 
-    public static final BooleanFlag ENABLE_PREDICTION_DISMISS = new DeviceFlag(
-            "ENABLE_PREDICTION_DISMISS", true, "Allow option to dimiss apps from predicted list");
+    public static final BooleanFlag ENABLE_PREDICTION_DISMISS = getDebugFlag(
+            "ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list");
 
     public static final BooleanFlag ENABLE_QUICK_CAPTURE_GESTURE = getDebugFlag(
             "ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
@@ -117,11 +117,11 @@
             "ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
             "Allow Launcher to handle nav bar gestures while Assistant is running over it");
 
-    public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = new DeviceFlag(
+    public static final BooleanFlag ENABLE_HYBRID_HOTSEAT = getDebugFlag(
             "ENABLE_HYBRID_HOTSEAT", false, "Fill gaps in hotseat with predicted apps");
 
-    public static final BooleanFlag HOTSEAT_MIGRATE_NEW_PAGE = new DeviceFlag(
-            "HOTSEAT_MIGRATE_NEW_PAGE", true,
+    public static final BooleanFlag HOTSEAT_MIGRATE_NEW_PAGE = getDebugFlag(
+            "HOTSEAT_MIGRATE_NEW_PAGE", false,
             "Migrates hotseat to a new workspace page instead of same page");
 
     public static final BooleanFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = getDebugFlag(
@@ -131,13 +131,18 @@
             "MULTI_DB_GRID_MIRATION_ALGO", false, "Use the multi-db grid migration algorithm");
 
     public static final BooleanFlag ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER = getDebugFlag(
-            "ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", true,
-            "Show launcher preview in grid picker");
+            "ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER", true, "Show launcher preview in grid picker");
+
+    public static final BooleanFlag USE_SURFACE_VIEW_FOR_GRID_PREVIEW = getDebugFlag(
+            "USE_SURFACE_VIEW_FOR_GRID_PREVIEW", false, "Use surface view for grid preview");
 
     public static final BooleanFlag ENABLE_OVERVIEW_ACTIONS = getDebugFlag(
             "ENABLE_OVERVIEW_ACTIONS", true, "Show app actions instead of the shelf in Overview."
             + " As part of this decoupling, also distinguish swipe up from nav bar vs above it.");
 
+    public static final BooleanFlag ENABLE_SELECT_MODE = getDebugFlag(
+            "ENABLE_SELECT_MODE", true, "Show Select Mode 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");
diff --git a/src/com/android/launcher3/graphics/GridOptionsProvider.java b/src/com/android/launcher3/graphics/GridOptionsProvider.java
index 71b4366..607aba9 100644
--- a/src/com/android/launcher3/graphics/GridOptionsProvider.java
+++ b/src/com/android/launcher3/graphics/GridOptionsProvider.java
@@ -1,5 +1,6 @@
 package com.android.launcher3.graphics;
 
+import static com.android.launcher3.config.FeatureFlags.USE_SURFACE_VIEW_FOR_GRID_PREVIEW;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
 import android.content.ContentProvider;
@@ -19,6 +20,7 @@
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.InvariantDeviceProfile.GridOption;
 import com.android.launcher3.R;
+import com.android.launcher3.uioverrides.PreviewSurfaceRenderer;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -62,6 +64,11 @@
     private static final String KEY_PREVIEW = "preview";
     private static final String MIME_TYPE_PNG = "image/png";
 
+    private static final String METHOD_GET_PREVIEW = "get_preview";
+    private static final String METADATA_KEY_PREVIEW_VERSION = "preview_version";
+
+
+
     public static final PipeDataWriter<Future<Bitmap>> BITMAP_WRITER =
             new PipeDataWriter<Future<Bitmap>>() {
                 @Override
@@ -98,6 +105,10 @@
                     .add(KEY_IS_DEFAULT, idp.numColumns == gridOption.numColumns
                             && idp.numRows == gridOption.numRows);
         }
+        Bundle metadata = new Bundle();
+        metadata.putString(METADATA_KEY_PREVIEW_VERSION,
+                USE_SURFACE_VIEW_FOR_GRID_PREVIEW.get() ? "V2" : "V1");
+        cursor.setExtras(metadata);
         return cursor;
     }
 
@@ -188,4 +199,14 @@
             throw new FileNotFoundException(e.getMessage());
         }
     }
+
+    @Override
+    public Bundle call(String method, String arg, Bundle extras)  {
+        if (!METHOD_GET_PREVIEW.equals(method)) {
+            return null;
+        }
+
+        PreviewSurfaceRenderer.render(getContext(), extras);
+        return null;
+    }
 }
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 02e98e8..5bc6610 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -262,6 +262,13 @@
         });
     }
 
+    /** Populate preview and render it. */
+    public View getRenderedView() {
+        MainThreadRenderer renderer = new MainThreadRenderer(mContext);
+        renderer.populate();
+        return renderer.mRootView;
+    }
+
     private class MainThreadRenderer extends ContextThemeWrapper
             implements ActivityContext, WorkspaceLayoutManager, LayoutInflater.Factory2 {
 
@@ -388,7 +395,7 @@
             }
         }
 
-        private void renderScreenShot(Canvas canvas) {
+        private void populate() {
             if (ENABLE_LAUNCHER_PREVIEW_IN_GRID_PICKER.get()) {
                 boolean needsToMigrate = needsToMigrate(mContext, mIdp);
                 boolean success = false;
@@ -499,7 +506,10 @@
             measureView(mRootView, mDp.widthPx, mDp.heightPx);
             // Additional measure for views which use auto text size API
             measureView(mRootView, mDp.widthPx, mDp.heightPx);
+        }
 
+        private void renderScreenShot(Canvas canvas) {
+            populate();
             mRootView.draw(canvas);
             dispatchVisibilityAggregated(mRootView, false);
         }
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java b/src_ui_overrides/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java
new file mode 100644
index 0000000..4913cad
--- /dev/null
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/PreviewSurfaceRenderer.java
@@ -0,0 +1,27 @@
+/*
+ * 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.uioverrides;
+
+import android.content.Context;
+import android.os.Bundle;
+
+/** Render preview using surface view. */
+public class PreviewSurfaceRenderer {
+
+    /** Handle a received surface view request. */
+    public static void render(Context context, Bundle bundle) { }
+}