Snap for 7374840 from 71359a1748d3e6aa672a31d3c11fa5e6730fad62 to sc-v2-release

Change-Id: Ia35c047e0db34b529ed6b459e52b07f47d6a2471
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 87a08af..d725a16 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -107,7 +107,7 @@
                        android:value="true" />
 
         <activity android:name="com.android.launcher3.dragndrop.AddItemActivity"
-            android:theme="@style/AppItemActivityTheme"
+            android:theme="@style/AddItemActivityTheme"
             android:excludeFromRecents="true"
             android:autoRemoveFromRecents="true"
             android:exported="true">
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index c459472..c52eec7 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -16,7 +16,7 @@
 
 <resources>
     <dimen name="task_thumbnail_icon_size">48dp</dimen>
-    <dimen name="task_thumbnail_icon_size_grid">32dp</dimen>
+    <dimen name="task_thumbnail_icon_size_grid">40dp</dimen>
     <!-- For screens without rounded corners -->
     <dimen name="task_corner_radius_small">2dp</dimen>
 
@@ -33,12 +33,17 @@
     <dimen name="overview_actions_horizontal_margin">16dp</dimen>
 
     <dimen name="overview_grid_top_margin">77dp</dimen>
-    <dimen name="overview_grid_bottom_margin">90dp</dimen>
+    <dimen name="overview_grid_bottom_margin">70dp</dimen>
     <dimen name="overview_grid_side_margin">54dp</dimen>
     <dimen name="overview_grid_row_spacing">42dp</dimen>
-    <dimen name="overview_grid_focus_vertical_margin">90dp</dimen>
+    <dimen name="overview_grid_focus_vertical_margin">40dp</dimen>
     <dimen name="split_placeholder_size">110dp</dimen>
 
+    <!-- These speeds are in dp/s -->
+    <dimen name="max_task_dismiss_drag_velocity">2.25dp</dimen>
+    <dimen name="default_task_dismiss_drag_velocity">1.75dp</dimen>
+    <dimen name="default_task_dismiss_drag_velocity_grid">0.75dp</dimen>
+
     <dimen name="recents_page_spacing">16dp</dimen>
     <dimen name="recents_clear_all_deadzone_vertical_margin">70dp</dimen>
 
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 6966fb6..e777ee7 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -29,10 +29,10 @@
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
 import android.app.ActivityOptions;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
-import android.content.ComponentName;
 import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -388,7 +388,7 @@
     @Override
     public float[] getNormalOverviewScaleAndOffset() {
         return SysUINavigationMode.getMode(this).hasGestures
-                ? new float[] {1, NO_OFFSET, 1} : new float[] {1.1f, NO_OFFSET, NO_OFFSET};
+                ? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET};
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 275dfda..1b8fcb3 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -75,7 +75,6 @@
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.util.ActivityOptionsWrapper;
-import com.android.launcher3.util.DynamicResource;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.launcher3.util.RunnableList;
@@ -86,8 +85,8 @@
 import com.android.quickstep.TaskViewUtils;
 import com.android.quickstep.util.MultiValueUpdateListener;
 import com.android.quickstep.util.RemoteAnimationProvider;
-import com.android.quickstep.util.StaggeredWorkspaceAnim;
 import com.android.quickstep.util.SurfaceTransactionApplier;
+import com.android.quickstep.util.WorkspaceRevealAnim;
 import com.android.quickstep.views.FloatingWidgetView;
 import com.android.quickstep.views.RecentsView;
 import com.android.systemui.shared.system.ActivityCompat;
@@ -1213,10 +1212,7 @@
                             }
                         });
                     } else {
-                        float velocityPxPerS = DynamicResource.provider(mLauncher)
-                                .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
-                        anim.play(new StaggeredWorkspaceAnim(mLauncher, velocityPxPerS, false)
-                                .getAnimators());
+                        anim.play(new WorkspaceRevealAnim(mLauncher, false).getAnimators());
                     }
                 }
             }
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
index a2ed211..14b0c5d 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java
@@ -48,7 +48,7 @@
  * User education dialog for hybrid hotseat. Allows user to migrate hotseat items to a new page in
  * the workspace and shows predictions on the whole hotseat
  */
-public class HotseatEduDialog extends AbstractSlideInView implements Insettable {
+public class HotseatEduDialog extends AbstractSlideInView<Launcher> implements Insettable {
 
     private static final int DEFAULT_CLOSE_DURATION = 200;
     protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
@@ -84,7 +84,7 @@
         mHotseatWrapper = findViewById(R.id.hotseat_wrapper);
         mSampleHotseat = findViewById(R.id.sample_prediction);
 
-        DeviceProfile grid = mLauncher.getDeviceProfile();
+        DeviceProfile grid = mActivityContext.getDeviceProfile();
         Rect padding = grid.getHotseatLayoutPadding();
 
         mSampleHotseat.getLayoutParams().height = grid.cellHeightPx;
@@ -110,13 +110,13 @@
 
         mHotseatEduController.moveHotseatItems();
         mHotseatEduController.finishOnboarding();
-        mLauncher.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_ACCEPT);
+        mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_ACCEPT);
     }
 
     private void onDismiss(View v) {
         mHotseatEduController.showDimissTip();
         mHotseatEduController.finishOnboarding();
-        mLauncher.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_DENY);
+        mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_DENY);
         handleClose(true);
     }
 
@@ -131,12 +131,12 @@
         int rightInset = insets.right - mInsets.right;
         int bottomInset = insets.bottom - mInsets.bottom;
         mInsets.set(insets);
-        if (mLauncher.getOrientation() == Configuration.ORIENTATION_PORTRAIT) {
+        if (mActivityContext.getOrientation() == Configuration.ORIENTATION_PORTRAIT) {
             setPadding(leftInset, getPaddingTop(), rightInset, 0);
             mHotseatWrapper.setPadding(mHotseatWrapper.getPaddingLeft(), getPaddingTop(),
                     mHotseatWrapper.getPaddingRight(), bottomInset);
             mHotseatWrapper.getLayoutParams().height =
-                    mLauncher.getDeviceProfile().hotseatBarSizePx + insets.bottom;
+                    mActivityContext.getDeviceProfile().hotseatBarSizePx + insets.bottom;
 
         } else {
             setPadding(0, getPaddingTop(), 0, 0);
@@ -178,7 +178,7 @@
     }
 
     private void populatePreview(List<WorkspaceItemInfo> predictions) {
-        for (int i = 0; i < mLauncher.getDeviceProfile().numShownHotseatIcons; i++) {
+        for (int i = 0; i < mActivityContext.getDeviceProfile().numShownHotseatIcons; i++) {
             WorkspaceItemInfo info = predictions.get(i);
             PredictedAppIcon icon = PredictedAppIcon.createIcon(mSampleHotseat, info);
             icon.setEnabled(false);
@@ -194,13 +194,13 @@
      */
     public void show(List<WorkspaceItemInfo> predictions) {
         if (getParent() != null
-                || predictions.size() < mLauncher.getDeviceProfile().numShownHotseatIcons
+                || predictions.size() < mActivityContext.getDeviceProfile().numShownHotseatIcons
                 || mHotseatEduController == null) {
             return;
         }
-        AbstractFloatingView.closeAllOpenViews(mLauncher);
+        AbstractFloatingView.closeAllOpenViews(mActivityContext);
         attachToContainer();
-        mLauncher.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_SEEN);
+        mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_SEEN);
         animateOpen();
         populatePreview(predictions);
     }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 814cf93..1d52315 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -25,7 +25,6 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
-import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_VERTICAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.TASK_PRIMARY_SPLIT_TRANSLATION;
@@ -65,7 +64,6 @@
         float[] scaleAndOffset = state.getOverviewScaleAndOffset(mLauncher);
         RECENTS_SCALE_PROPERTY.set(mRecentsView, scaleAndOffset[0]);
         ADJACENT_PAGE_HORIZONTAL_OFFSET.set(mRecentsView, scaleAndOffset[1]);
-        ADJACENT_PAGE_VERTICAL_OFFSET.set(mRecentsView, scaleAndOffset[2]);
         TASK_SECONDARY_TRANSLATION.set(mRecentsView, 0f);
 
         getContentAlphaProperty().set(mRecentsView, state.overviewUi ? 1f : 0);
@@ -97,8 +95,6 @@
                 config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
         setter.setFloat(mRecentsView, ADJACENT_PAGE_HORIZONTAL_OFFSET, scaleAndOffset[1],
                 config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
-        setter.setFloat(mRecentsView, ADJACENT_PAGE_VERTICAL_OFFSET, scaleAndOffset[2],
-                config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
         setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f,
                 config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
         PagedOrientationHandler orientationHandler =
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
index 0014b85..3a8de3c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -19,13 +19,13 @@
 import android.app.ActivityTaskManager;
 import android.app.PendingIntent;
 import android.content.Intent;
-import android.os.Build;
 import android.os.RemoteException;
 import android.util.Log;
 import android.util.Pair;
 import android.view.View;
 import android.widget.RemoteViews;
 
+import com.android.launcher3.Utilities;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.ActivityOptionsWrapper;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -41,6 +41,7 @@
         mLauncher = launcher;
     }
 
+    @SuppressWarnings("NewApi")
     @Override
     public boolean onInteraction(View view, PendingIntent pendingIntent,
             RemoteViews.RemoteResponse remoteResponse) {
@@ -53,7 +54,7 @@
         Pair<Intent, ActivityOptions> options = remoteResponse.getLaunchOptions(hostView);
         ActivityOptionsWrapper activityOptions = mLauncher.getAppTransitionManager()
                 .getActivityLaunchOptions(mLauncher, hostView);
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !pendingIntent.isActivity()) {
+        if (Utilities.ATLEAST_S && !pendingIntent.isActivity()) {
             // In the event this pending intent eventually launches an activity, i.e. a trampoline,
             // use the Quickstep transition animation.
             try {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index 06ffae4..01c9e76 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -19,6 +19,7 @@
 
 import android.content.Context;
 import android.graphics.Color;
+import android.os.SystemProperties;
 
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.DeviceProfile;
@@ -84,7 +85,8 @@
 
     @Override
     protected float getDepthUnchecked(Context context) {
-        return 1f;
+        //TODO revert when b/178661709 is fixed
+        return SystemProperties.getBoolean("ro.launcher.depth.appLaunch", true) ? 1 : 0;
     }
 
     @Override
@@ -96,6 +98,6 @@
             BaseDraggingActivity activity) {
         return new float[] {
                 ((RecentsView) activity.getOverviewPanel()).getMaxScaleForFullScreen(),
-                NO_OFFSET, NO_OFFSET};
+                NO_OFFSET};
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
index 1fc288f..6f084a1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
@@ -78,6 +78,6 @@
         float scale = Math.min((float) modalTaskSize.height() / taskSize.y,
                 (float) modalTaskSize.width() / taskSize.x);
 
-        return new float[] {scale, NO_OFFSET, NO_OFFSET};
+        return new float[] {scale, NO_OFFSET};
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index c9cfad3..8c128c8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.SystemProperties;
 import android.view.View;
 
 import com.android.launcher3.DeviceProfile;
@@ -59,7 +60,7 @@
 
     @Override
     public int getTransitionDuration(Context context) {
-        // In gesture modes, overview comes in all the way from the bottom, so give it more time.
+        // In gesture modes, overview comes in all the way from the side, so give it more time.
         return SysUINavigationMode.INSTANCE.get(context).getMode().hasGestures ? 380 : 250;
     }
 
@@ -78,7 +79,7 @@
 
     @Override
     public float[] getOverviewScaleAndOffset(Launcher launcher) {
-        return new float[] {NO_SCALE, NO_OFFSET, NO_OFFSET};
+        return new float[] {NO_SCALE, NO_OFFSET};
     }
 
     @Override
@@ -127,7 +128,8 @@
 
     @Override
     protected float getDepthUnchecked(Context context) {
-        return 1f;
+        //TODO revert when b/178661709 is fixed
+        return SystemProperties.getBoolean("ro.launcher.depth.overview", true) ? 1 : 0;
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index adc6b18..eb524a9 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -23,10 +23,11 @@
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.WorkspaceStateTransitionAnimation.getSpringScaleAnimator;
 import static com.android.launcher3.anim.Interpolators.ACCEL;
-import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
 import static com.android.launcher3.anim.Interpolators.DEACCEL;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
@@ -66,11 +67,11 @@
     // Scale recents takes before animating in
     private static final float RECENTS_PREPARE_SCALE = 1.33f;
     // Scale workspace takes before animating in
-    private static final float WORKSPACE_PREPARE_SCALE_GESTURES = 0.97f;
-    private static final float WORKSPACE_PREPARE_SCALE_BUTTONS = 0.92f;
-    // When the overview to home transition reaches this percentage, immediately hide overview and
-    // start animating away the scrim and animating in workspace.
-    private static final float OVERVIEW_TO_HOME_HARD_HAND_OFF = 0.4f;
+    private static final float WORKSPACE_PREPARE_SCALE = 0.92f;
+    // Constants to specify how to scroll RecentsView to the default page if it's not already there.
+    private static final int DEFAULT_PAGE = 0;
+    private static final int PER_PAGE_SCROLL_DURATION = 150;
+    private static final int MAX_PAGE_SCROLL_DURATION = 750;
 
     // Due to use of physics, duration may differ between devices so we need to calculate and
     // cache the value.
@@ -85,33 +86,32 @@
             StateAnimationConfig config) {
         RecentsView overview = mActivity.getOverviewPanel();
         if (toState == NORMAL && fromState == OVERVIEW) {
-            final float workspacePrepareScale;
+            config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, DEACCEL);
+            config.setInterpolator(ANIM_SCRIM_FADE, LINEAR);
+            config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
+            config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
+
             if (SysUINavigationMode.getMode(mActivity).hasGestures
                     && overview.getTaskViewCount() > 0) {
-                workspacePrepareScale = WORKSPACE_PREPARE_SCALE_GESTURES;
                 // Overview is going offscreen, so keep it at its current scale and opacity.
                 config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME);
-                config.setInterpolator(ANIM_OVERVIEW_FADE, clampToProgress(
-                        FINAL_FRAME, 0f, OVERVIEW_TO_HOME_HARD_HAND_OFF));
-                config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(
-                        DEACCEL, 0f, OVERVIEW_TO_HOME_HARD_HAND_OFF));
-                config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, AGGRESSIVE_EASE_IN_OUT);
-                config.setInterpolator(ANIM_SCRIM_FADE, clampToProgress(
-                        DEACCEL, OVERVIEW_TO_HOME_HARD_HAND_OFF, 1f));
-                config.setInterpolator(ANIM_WORKSPACE_SCALE, clampToProgress(
-                        DEACCEL, OVERVIEW_TO_HOME_HARD_HAND_OFF, 1f));
-                config.setInterpolator(ANIM_WORKSPACE_FADE, clampToProgress(
-                        INSTANT, OVERVIEW_TO_HOME_HARD_HAND_OFF, 1f));
+                config.setInterpolator(ANIM_OVERVIEW_FADE, FINAL_FRAME);
+                config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X,
+                        clampToProgress(FAST_OUT_SLOW_IN, 0, 0.75f));
+                config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, FINAL_FRAME);
             } else {
-                workspacePrepareScale = WORKSPACE_PREPARE_SCALE_BUTTONS;
+                config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL_DEACCEL);
                 config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
                 config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
-                config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, LINEAR);
-                config.setInterpolator(ANIM_SCRIM_FADE, LINEAR);
-                config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
-                config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
             }
 
+            // Scroll RecentsView to page 0 as it goes offscreen, if necessary.
+            int numPagesToScroll = overview.getNextPage() - DEFAULT_PAGE;
+            long scrollDuration = Math.min(MAX_PAGE_SCROLL_DURATION,
+                    numPagesToScroll * PER_PAGE_SCROLL_DURATION);
+            config.duration = Math.max(config.duration, scrollDuration);
+            overview.snapToPage(DEFAULT_PAGE, Math.toIntExact(config.duration));
+
             Workspace workspace = mActivity.getWorkspace();
             // Start from a higher workspace scale, but only if we're invisible so we don't jump.
             boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
@@ -122,14 +122,14 @@
                         && currentChild.getShortcutsAndWidgets().getAlpha() > 0;
             }
             if (!isWorkspaceVisible) {
-                workspace.setScaleX(workspacePrepareScale);
-                workspace.setScaleY(workspacePrepareScale);
+                workspace.setScaleX(WORKSPACE_PREPARE_SCALE);
+                workspace.setScaleY(WORKSPACE_PREPARE_SCALE);
             }
             Hotseat hotseat = mActivity.getHotseat();
             boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0;
             if (!isHotseatVisible) {
-                hotseat.setScaleX(workspacePrepareScale);
-                hotseat.setScaleY(workspacePrepareScale);
+                hotseat.setScaleX(WORKSPACE_PREPARE_SCALE);
+                hotseat.setScaleY(WORKSPACE_PREPARE_SCALE);
             }
         } else if ((fromState == NORMAL || fromState == HINT_STATE
                 || fromState == HINT_STATE_TWO_BUTTON) && toState == OVERVIEW) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 62687c5..40c3e02 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -43,7 +43,6 @@
 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_HORIZONTAL_OFFSET;
-import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_VERTICAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
@@ -74,7 +73,7 @@
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.MotionPauseDetector;
-import com.android.quickstep.util.StaggeredWorkspaceAnim;
+import com.android.quickstep.util.WorkspaceRevealAnim;
 import com.android.quickstep.views.LauncherRecentsView;
 
 /**
@@ -224,7 +223,6 @@
         // Set RecentView's initial properties.
         RECENTS_SCALE_PROPERTY.set(mRecentsView, fromState.getOverviewScaleAndOffset(mLauncher)[0]);
         ADJACENT_PAGE_HORIZONTAL_OFFSET.set(mRecentsView, 1f);
-        ADJACENT_PAGE_VERTICAL_OFFSET.set(mRecentsView, 0f);
         mRecentsView.setContentAlpha(1);
         mRecentsView.setFullscreenProgress(fromState.getOverviewFullscreenProgress());
         mLauncher.getActionsView().getVisibilityAlpha().setValue(
@@ -386,8 +384,7 @@
             updateNonOverviewAnim(targetState, config);
             nonOverviewAnim = mNonOverviewAnim.getAnimationPlayer();
 
-            new StaggeredWorkspaceAnim(mLauncher, velocity.y, false /* animateOverviewScrim */)
-                    .start();
+            new WorkspaceRevealAnim(mLauncher, false /* animateOverviewScrim */).start();
         } else {
             boolean canceled = targetState == NORMAL;
             if (canceled) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index 5891d5f..f0ef9cc 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -31,7 +31,6 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
-import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_VERTICAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
@@ -113,7 +112,6 @@
         RECENTS_SCALE_PROPERTY.set(mOverviewPanel,
                 QUICK_SWITCH.getOverviewScaleAndOffset(mLauncher)[0] * 0.85f);
         ADJACENT_PAGE_HORIZONTAL_OFFSET.set(mOverviewPanel, 1f);
-        ADJACENT_PAGE_VERTICAL_OFFSET.set(mOverviewPanel, 0f);
         mOverviewPanel.setContentAlpha(1);
 
         mCurrentAnimation = mLauncher.getStateManager()
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 70b3870..c6ea953 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -28,6 +28,7 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.Interpolators;
@@ -50,6 +51,10 @@
         extends AnimatorListenerAdapter implements TouchController,
         SingleAxisSwipeDetector.Listener {
 
+    private static final float ANIMATION_PROGRESS_FRACTION_MIDPOINT = 0.5f;
+    private static final long MIN_TASK_DISMISS_ANIMATION_DURATION = 300;
+    private static final long MAX_TASK_DISMISS_ANIMATION_DURATION = 600;
+
     protected final T mActivity;
     private final SingleAxisSwipeDetector mDetector;
     private final RecentsView mRecentsView;
@@ -277,14 +282,32 @@
         } else {
             mFlingBlockCheck.onEvent();
         }
-        mCurrentAnimation.setPlayFraction(Utilities.boundToRange(
-                totalDisplacement * mProgressMultiplier, 0, 1));
+
+        // Once halfway through task dismissal interpolation, switch from reversible dragging-task
+        // animation to playing the remaining task translation animations
+        if (mCurrentAnimation.getProgressFraction() < ANIMATION_PROGRESS_FRACTION_MIDPOINT) {
+            // Halve the value as we are animating the drag across the full length for only the
+            // first half of the progress
+            mCurrentAnimation.setPlayFraction(
+                    Utilities.boundToRange(totalDisplacement * mProgressMultiplier / 2, 0, 1));
+        } else {
+            float dragVelocity = -mTaskBeingDragged.getResources().getDimension(
+                    mRecentsView.showAsGrid() ? R.dimen.default_task_dismiss_drag_velocity_grid
+                            : R.dimen.default_task_dismiss_drag_velocity);
+            onDragEnd(dragVelocity);
+            return true;
+        }
 
         return true;
     }
 
     @Override
     public void onDragEnd(float velocity) {
+        // Limit velocity, as very large scalar values make animations play too quickly
+        float maxTaskDismissDragVelocity = mTaskBeingDragged.getResources().getDimension(
+                R.dimen.max_task_dismiss_drag_velocity);
+        velocity = Utilities.boundToRange(velocity, -maxTaskDismissDragVelocity,
+                maxTaskDismissDragVelocity);
         boolean fling = mDetector.isFling(velocity);
         final boolean goingToEnd;
         boolean blockedFling = fling && mFlingBlockCheck.isBlocked();
@@ -305,6 +328,11 @@
         if (blockedFling && !goingToEnd) {
             animationDuration *= LauncherAnimUtils.blockedFlingDurationFactor(velocity);
         }
+        // Due to very high or low velocity dismissals, animation durations can be inconsistently
+        // long or short. Bound the duration for animation of task translations for a more
+        // standardized feel.
+        animationDuration = Utilities.boundToRange(animationDuration,
+                MIN_TASK_DISMISS_ANIMATION_DURATION, MAX_TASK_DISMISS_ANIMATION_DURATION);
 
         mCurrentAnimation.setEndAction(this::clearState);
         mCurrentAnimation.startWithVelocity(mActivity, goingToEnd,
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 63646d0..e0f430d 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -102,10 +102,10 @@
 import com.android.quickstep.util.ProtoTracer;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.util.StaggeredWorkspaceAnim;
 import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.SwipePipToHomeAnimator;
 import com.android.quickstep.util.TransformParams;
+import com.android.quickstep.util.WorkspaceRevealAnim;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -201,7 +201,7 @@
             STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
 
     public static final long MAX_SWIPE_DURATION = 350;
-    public static final long HOME_DURATION = StaggeredWorkspaceAnim.DURATION_MS;
+    public static final long HOME_DURATION = WorkspaceRevealAnim.DURATION_MS;
 
     public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f;
     private static final float SWIPE_DURATION_MULTIPLIER =
@@ -1126,6 +1126,7 @@
                 windowAnim.start(mContext, velocityPxPerMs);
                 mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim);
             }
+            homeAnimFactory.setSwipeVelocity(velocityPxPerMs.y);
             homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y);
             mLauncherTransitionController = null;
 
@@ -1483,6 +1484,9 @@
     private void finishCurrentTransitionToRecents() {
         if (LIVE_TILE.get()) {
             mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
+            if (mRecentsAnimationController != null) {
+                mRecentsAnimationController.getController().detachNavigationBarFromApp(true);
+            }
         } else if (!hasTargets() || mRecentsAnimationController == null) {
             // If there are no targets or the animation not started, then there is nothing to finish
             mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index c8865c4..1b1c6b4 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -23,8 +23,8 @@
 import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
 import static com.android.quickstep.SysUINavigationMode.getMode;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
-import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_Y_ANIM;
-import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_VERTICAL_OFFSET;
+import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
+import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
 import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
@@ -203,17 +203,18 @@
             Rect gridRect = new Rect();
             calculateGridSize(context, dp, gridRect);
 
-            int verticalMargin = res.getDimensionPixelSize(
-                    R.dimen.overview_grid_focus_vertical_margin);
-            float taskHeight = gridRect.height() - verticalMargin * 2;
+            int verticalMargin = Math.max(
+                    res.getDimensionPixelSize(R.dimen.overview_grid_focus_vertical_margin),
+                    res.getDimensionPixelSize(R.dimen.overview_actions_height));
+            float taskHeight =
+                    gridRect.height() - verticalMargin * 2 - dp.overviewTaskThumbnailTopMarginPx;
 
             PointF taskDimension = getTaskDimension(context, dp);
-            float scale = taskHeight / Math.max(taskDimension.x, taskDimension.y);
+            float scale = taskHeight / taskDimension.y;
             int outWidth = Math.round(scale * taskDimension.x);
             int outHeight = Math.round(scale * taskDimension.y);
 
-            int gravity = Gravity.CENTER_VERTICAL;
-            gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
+            int gravity = Gravity.CENTER;
             Gravity.apply(gravity, outWidth, outHeight, gridRect, outRect);
         } else {
             int taskMargin = dp.overviewTaskMarginPx;
@@ -302,8 +303,7 @@
         float rowHeight = (gridRect.height() - rowSpacing) / 2f;
 
         PointF taskDimension = getTaskDimension(context, dp);
-        float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / Math.max(
-                taskDimension.x, taskDimension.y);
+        float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / taskDimension.y;
         int outWidth = Math.round(scale * taskDimension.x);
         int outHeight = Math.round(scale * taskDimension.y);
 
@@ -461,17 +461,17 @@
             float fromTranslation = attached ? 1 : 0;
             float toTranslation = attached ? 0 : 1;
             mActivity.getStateManager()
-                    .cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_Y_ANIM);
+                    .cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
             if (!recentsView.isShown() && animate) {
-                ADJACENT_PAGE_VERTICAL_OFFSET.set(recentsView, fromTranslation);
+                ADJACENT_PAGE_HORIZONTAL_OFFSET.set(recentsView, fromTranslation);
             } else {
-                fromTranslation = ADJACENT_PAGE_VERTICAL_OFFSET.get(recentsView);
+                fromTranslation = ADJACENT_PAGE_HORIZONTAL_OFFSET.get(recentsView);
             }
             if (!animate) {
-                ADJACENT_PAGE_VERTICAL_OFFSET.set(recentsView, toTranslation);
+                ADJACENT_PAGE_HORIZONTAL_OFFSET.set(recentsView, toTranslation);
             } else {
                 mActivity.getStateManager().createStateElementAnimation(
-                        INDEX_RECENTS_TRANSLATE_Y_ANIM,
+                        INDEX_RECENTS_TRANSLATE_X_ANIM,
                         fromTranslation, toTranslation).start();
             }
 
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index f125063..811af7e 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -18,13 +18,14 @@
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.Utilities.boundToRange;
 import static com.android.launcher3.Utilities.dpToPx;
-import static com.android.launcher3.Utilities.mapToRange;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
 
+import static java.lang.Math.round;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
@@ -52,10 +53,12 @@
 import com.android.launcher3.util.DynamicResource;
 import com.android.launcher3.util.ObjectWrapper;
 import com.android.launcher3.views.FloatingIconView;
+import com.android.launcher3.views.FloatingView;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.quickstep.util.AppCloseConfig;
 import com.android.quickstep.util.RectFSpringAnim;
 import com.android.quickstep.util.StaggeredWorkspaceAnim;
+import com.android.quickstep.util.WorkspaceRevealAnim;
 import com.android.quickstep.views.FloatingWidgetView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
@@ -112,10 +115,6 @@
     private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) {
         final ResourceProvider rp = DynamicResource.provider(mActivity);
         final float transY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
-        float dpPerSecond = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp_per_s));
-        final float launcherAlphaMax =
-                rp.getFloat(R.dimen.swipe_up_launcher_alpha_max_progress);
-
         RectF iconLocation = new RectF();
         FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView,
                 true /* hideOriginal */, iconLocation, false /* isOpening */);
@@ -123,73 +122,25 @@
         // We want the window alpha to be 0 once this threshold is met, so that the
         // FolderIconView can be seen morphing into the icon shape.
         float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
-        return new LauncherHomeAnimationFactory() {
+
+        return new FloatingViewHomeAnimationFactory(floatingIconView) {
 
             // There is a delay in loading the icon, so we need to keep the window
             // opaque until it is ready.
             private boolean mIsFloatingIconReady = false;
 
-            private @Nullable ValueAnimator mBounceBackAnimator;
-
             @Override
             public RectF getWindowTargetRect() {
-                if (PROTOTYPE_APP_CLOSE.get()) {
-                    // We want the target rect to be at this offset position, so that all
-                    // launcher content can spring back upwards.
-                    floatingIconView.setPositionOffsetY(transY);
-                }
+                super.getWindowTargetRect();
                 return iconLocation;
             }
 
             @Override
             public void setAnimation(RectFSpringAnim anim) {
+                super.setAnimation(anim);
                 anim.addAnimatorListener(floatingIconView);
                 floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
                 floatingIconView.setFastFinishRunnable(anim::end);
-                if (PROTOTYPE_APP_CLOSE.get()) {
-                    mBounceBackAnimator = bounceBackToRestingPosition();
-                    // Use a spring to put drag layer translation back to 0.
-                    anim.addAnimatorListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            floatingIconView.setPositionOffsetY(0);
-                            mBounceBackAnimator.start();
-                        }
-                    });
-
-                    Workspace workspace = mActivity.getWorkspace();
-                    workspace.setPivotToScaleWithSelf(mActivity.getHotseat());
-                }
-            }
-
-            private ValueAnimator bounceBackToRestingPosition() {
-                DragLayer dl = mActivity.getDragLayer();
-                Workspace workspace = mActivity.getWorkspace();
-                Hotseat hotseat = mActivity.getHotseat();
-
-                final float startValue = transY;
-                final float endValue = 0;
-                // Ensures the velocity is always aligned with the direction.
-                float pixelPerSecond = Math.abs(dpPerSecond) * Math.signum(endValue - transY);
-
-                ValueAnimator springTransY = new SpringAnimationBuilder(dl.getContext())
-                        .setStiffness(rp.getFloat(R.dimen.swipe_up_trans_y_stiffness))
-                        .setDampingRatio(rp.getFloat(R.dimen.swipe_up_trans_y_damping))
-                        .setMinimumVisibleChange(1f)
-                        .setStartValue(startValue)
-                        .setEndValue(endValue)
-                        .setStartVelocity(pixelPerSecond)
-                        .build(dl, VIEW_TRANSLATE_Y);
-                springTransY.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        dl.setTranslationY(0f);
-                        dl.setAlpha(1f);
-                        SCALE_PROPERTY.set(workspace, 1f);
-                        SCALE_PROPERTY.set(hotseat, 1f);
-                    }
-                });
-                return springTransY;
             }
 
             @Override
@@ -204,34 +155,15 @@
             @Override
             public void update(@Nullable AppCloseConfig config, RectF currentRect,
                     float progress, float radius) {
+                super.update(config, currentRect, progress, radius);
                 int fgAlpha = 255;
                 if (config != null && PROTOTYPE_APP_CLOSE.get()) {
-                    DragLayer dl = mActivity.getDragLayer();
-                    float translationY = config.getWorkspaceTransY();
-                    dl.setTranslationY(translationY);
-
-                    float alpha = mapToRange(progress, 0, launcherAlphaMax, 0, 1f, LINEAR);
-                    dl.setAlpha(Math.min(alpha, 1f));
-
-                    float scale = Math.min(1f, config.getWorkspaceScale());
-                    SCALE_PROPERTY.set(mActivity.getWorkspace(), scale);
-                    SCALE_PROPERTY.set(mActivity.getHotseat(), scale);
-                    SCALE_PROPERTY.set(mActivity.getAppsView(), scale);
-
                     progress = config.getInterpolatedProgress();
                     fgAlpha = config.getFgAlpha();
                 }
                 floatingIconView.update(1f, fgAlpha, currentRect, progress,
                         windowAlphaThreshold, radius, false);
             }
-
-            @Override
-            public void onCancel() {
-                floatingIconView.fastFinish();
-                if (mBounceBackAnimator != null) {
-                    mBounceBackAnimator.cancel();
-                }
-            }
         };
     }
 
@@ -246,10 +178,11 @@
                 hostView, backgroundLocation, windowSize,
                 mTaskViewSimulator.getCurrentCornerRadius(), isTargetTranslucent);
 
-        return new LauncherHomeAnimationFactory() {
+        return new FloatingViewHomeAnimationFactory(floatingWidgetView) {
 
             @Override
             public RectF getWindowTargetRect() {
+                super.getWindowTargetRect();
                 return backgroundLocation;
             }
 
@@ -260,6 +193,8 @@
 
             @Override
             public void setAnimation(RectFSpringAnim anim) {
+                super.setAnimation(anim);
+
                 anim.addAnimatorListener(floatingWidgetView);
                 floatingWidgetView.setOnTargetChangeListener(anim::onTargetPositionChanged);
                 floatingWidgetView.setFastFinishRunnable(anim::end);
@@ -273,15 +208,11 @@
             @Override
             public void update(@Nullable AppCloseConfig config, RectF currentRect,
                     float progress, float radius) {
+                super.update(config, currentRect, progress, radius);
                 floatingWidgetView.update(currentRect, 1 /* floatingWidgetAlpha */,
                         config != null ? config.getFgAlpha() : 1f /* foregroundAlpha */,
                         0 /* fallbackBackgroundAlpha */, 1 - progress);
             }
-
-            @Override
-            public void onCancel() {
-                floatingWidgetView.fastFinish();
-            }
         };
     }
 
@@ -323,6 +254,120 @@
                 true /* toRecents */, callback, true /* sendUserLeaveHint */);
     }
 
+    private class FloatingViewHomeAnimationFactory extends LauncherHomeAnimationFactory {
+
+        private final float mTransY;
+        private final FloatingView mFloatingView;
+        private ValueAnimator mBounceBackAnimator;
+        private final AnimatorSet mWorkspaceReveal;
+
+        FloatingViewHomeAnimationFactory(FloatingView floatingView) {
+            mFloatingView = floatingView;
+
+            ResourceProvider rp = DynamicResource.provider(mActivity);
+            mTransY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
+
+            mWorkspaceReveal = PROTOTYPE_APP_CLOSE.get()
+                    ? new WorkspaceRevealAnim(mActivity, true /* animateScrim */).getAnimators()
+                    : null;
+        }
+
+        @Override
+        public @NonNull RectF getWindowTargetRect() {
+            if (PROTOTYPE_APP_CLOSE.get()) {
+                // We want the target rect to be at this offset position, so that all
+                // launcher content can spring back upwards.
+                mFloatingView.setPositionOffsetY(mTransY);
+            }
+            return super.getWindowTargetRect();
+        }
+
+        @Override
+        public boolean shouldPlayAtomicWorkspaceReveal() {
+            return false;
+        }
+
+        @Override
+        public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
+                float radius) {
+            if (config != null && PROTOTYPE_APP_CLOSE.get()) {
+                DragLayer dl = mActivity.getDragLayer();
+                float translationY = config.getWorkspaceTransY();
+                dl.setTranslationY(translationY);
+
+                long duration = mWorkspaceReveal.getDuration();
+                long playTime = boundToRange(round(duration * progress), 0, duration);
+                mWorkspaceReveal.setCurrentPlayTime(playTime);
+            }
+        }
+
+        protected void bounceBackToRestingPosition() {
+            final float startValue = mTransY;
+            final float endValue = 0;
+            // Ensures the velocity is always aligned with the direction.
+            float pixelPerSecond = Math.abs(mSwipeVelocity) * Math.signum(endValue - mTransY);
+
+            DragLayer dl = mActivity.getDragLayer();
+            Workspace workspace = mActivity.getWorkspace();
+            Hotseat hotseat = mActivity.getHotseat();
+
+            ResourceProvider rp = DynamicResource.provider(mActivity);
+            ValueAnimator springTransY = new SpringAnimationBuilder(dl.getContext())
+                    .setStiffness(rp.getFloat(R.dimen.swipe_up_trans_y_stiffness))
+                    .setDampingRatio(rp.getFloat(R.dimen.swipe_up_trans_y_damping))
+                    .setMinimumVisibleChange(1f)
+                    .setStartValue(startValue)
+                    .setEndValue(endValue)
+                    .setStartVelocity(pixelPerSecond)
+                    .build(dl, VIEW_TRANSLATE_Y);
+            springTransY.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    dl.setTranslationY(0f);
+                    dl.setAlpha(1f);
+                    SCALE_PROPERTY.set(workspace, 1f);
+                    SCALE_PROPERTY.set(hotseat, 1f);
+                }
+            });
+
+            mBounceBackAnimator = springTransY;
+            mBounceBackAnimator.start();
+        }
+
+        @Override
+        public void setAnimation(RectFSpringAnim anim) {
+            if (PROTOTYPE_APP_CLOSE.get()) {
+                // Use a spring to put drag layer translation back to 0.
+                anim.addAnimatorListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mFloatingView.setPositionOffsetY(0);
+                        bounceBackToRestingPosition();
+                    }
+                });
+
+                // Will be updated manually below so that the two animations are in sync.
+                mWorkspaceReveal.start();
+                mWorkspaceReveal.pause();
+
+                anim.addAnimatorListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mWorkspaceReveal.end();
+                    }
+                });
+            }
+        }
+
+        @Override
+        public void onCancel() {
+            mFloatingView.fastFinish();
+            if (mBounceBackAnimator != null) {
+                mBounceBackAnimator.cancel();
+            }
+        }
+    }
+
     private class LauncherHomeAnimationFactory extends HomeAnimationFactory {
         @NonNull
         @Override
@@ -336,8 +381,12 @@
 
         @Override
         public void playAtomicAnimation(float velocity) {
-            new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
-                    !PROTOTYPE_APP_CLOSE.get()).start();
+            if (!PROTOTYPE_APP_CLOSE.get()) {
+                new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */)
+                        .start();
+            } else if (shouldPlayAtomicWorkspaceReveal()) {
+                new WorkspaceRevealAnim(mActivity, true).start();
+            }
         }
 
         @Override
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 29a00d1..b79e934 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -129,6 +129,7 @@
     }
 
     protected abstract class HomeAnimationFactory {
+        protected float mSwipeVelocity;
 
         public @NonNull RectF getWindowTargetRect() {
             PagedOrientationHandler orientationHandler = getOrientationHandler();
@@ -152,10 +153,18 @@
 
         public abstract @NonNull AnimatorPlaybackController createActivityAnimationToHome();
 
+        public void setSwipeVelocity(float velocity) {
+            mSwipeVelocity = velocity;
+        }
+
         public void playAtomicAnimation(float velocity) {
             // No-op
         }
 
+        public boolean shouldPlayAtomicWorkspaceReveal() {
+            return true;
+        }
+
         public void setAnimation(RectFSpringAnim anim) { }
 
         public boolean keepWindowOpaque() { return false; }
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 6fb938a..acf9992 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -107,6 +107,17 @@
     }
 
     @Override
+    public void setHomeRotationEnabled(boolean enabled) {
+        if (mSystemUiProxy != null) {
+            try {
+                mSystemUiProxy.setHomeRotationEnabled(enabled);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call onBackPressed", e);
+            }
+        }
+    }
+
+    @Override
     public IBinder asBinder() {
         // Do nothing
         return null;
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 4d776ba..f0364eb 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -23,7 +23,6 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
-import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_VERTICAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_GRID_PROGRESS;
 import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
@@ -89,8 +88,6 @@
                 config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
         setter.setFloat(mRecentsView, ADJACENT_PAGE_HORIZONTAL_OFFSET, scaleAndOffset[1],
                 config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
-        setter.setFloat(mRecentsView, ADJACENT_PAGE_VERTICAL_OFFSET, scaleAndOffset[2],
-                config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
         setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f,
                 config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
 
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
index 532f219..b6cfdce 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -126,7 +126,7 @@
     }
 
     public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
-        return new float[] { NO_SCALE, NO_OFFSET, NO_OFFSET };
+        return new float[] { NO_SCALE, NO_OFFSET };
     }
 
     /**
@@ -170,7 +170,7 @@
 
         @Override
         public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
-            return new float[] { NO_SCALE, NO_OFFSET, 1 };
+            return new float[] { NO_SCALE, 1 };
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 76f43c9..6f681b3 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -45,8 +45,8 @@
     private static final String LOG_TAG = "AllSetActivity";
     private static final String URI_SYSTEM_NAVIGATION_SETTING =
             "#Intent;action=com.android.settings.SEARCH_RESULT_TRAMPOLINE;S.:settings:fragment_args_key=gesture_system_navigation_input_summary;S.:settings:show_fragment=com.android.settings.gestures.SystemNavigationGestureSettings;end";
-    private static final String EXTRA_ACCENT_COLOR_DARK_MODE = "accent_color_dark_mode";
-    private static final String EXTRA_ACCENT_COLOR_LIGHT_MODE = "accent_color_light_mode";
+    private static final String EXTRA_ACCENT_COLOR_DARK_MODE = "suwColorAccentDark";
+    private static final String EXTRA_ACCENT_COLOR_LIGHT_MODE = "suwColorAccentLight";
 
     private int mAccentColor;
 
diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
index 10b7662..badb41a 100644
--- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
+++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -30,7 +30,7 @@
 
 /**
  * Runs an animation from overview to home. Currently, this animation is just a wrapper around the
- * normal state transition and may play a {@link StaggeredWorkspaceAnim} if we're starting from an
+ * normal state transition and may play a {@link WorkspaceRevealAnim} if we're starting from an
  * upward fling.
  */
 public class OverviewToHomeAnim {
@@ -51,7 +51,7 @@
 
     /**
      * Starts the animation. If velocity < 0 (i.e. upwards), also plays a
-     * {@link StaggeredWorkspaceAnim}.
+     * {@link WorkspaceRevealAnim}.
      */
     public void animateWithVelocity(float velocity) {
         StateManager<LauncherState> stateManager = mLauncher.getStateManager();
@@ -61,18 +61,18 @@
         }
         AnimatorSet anim = new AnimatorSet();
 
-        boolean playStaggeredWorkspaceAnim = velocity < 0;
-        if (playStaggeredWorkspaceAnim) {
-            StaggeredWorkspaceAnim staggeredWorkspaceAnim = new StaggeredWorkspaceAnim(
-                    mLauncher, velocity, false /* animateOverviewScrim */);
-            staggeredWorkspaceAnim.addAnimatorListener(new AnimationSuccessListener() {
+        boolean playWorkspaceRevealAnim = velocity < 0;
+        if (playWorkspaceRevealAnim) {
+            WorkspaceRevealAnim workspaceRevealAnim = new WorkspaceRevealAnim(mLauncher,
+                    false /* animateOverviewScrim */);
+            workspaceRevealAnim.addAnimatorListener(new AnimationSuccessListener() {
                 @Override
                 public void onAnimationSuccess(Animator animator) {
                     mIsHomeStaggeredAnimFinished = true;
                     maybeOverviewToHomeAnimComplete();
                 }
             });
-            anim.play(staggeredWorkspaceAnim.getAnimators());
+            anim.play(workspaceRevealAnim.getAnimators());
         } else {
             mIsHomeStaggeredAnimFinished = true;
         }
diff --git a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
index c1ca060..5c72c8f 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
@@ -15,7 +15,7 @@
  */
 package com.android.quickstep.util;
 
-import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_VERTICAL_OFFSET;
+import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
 
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
@@ -31,7 +31,7 @@
         extends AtomicAnimationFactory<STATE_TYPE> {
 
     public static final int INDEX_RECENTS_FADE_ANIM = AtomicAnimationFactory.NEXT_INDEX + 0;
-    public static final int INDEX_RECENTS_TRANSLATE_Y_ANIM = AtomicAnimationFactory.NEXT_INDEX + 1;
+    public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = AtomicAnimationFactory.NEXT_INDEX + 1;
 
     private static final int MY_ANIM_COUNT = 2;
 
@@ -48,14 +48,14 @@
             case INDEX_RECENTS_FADE_ANIM:
                 return ObjectAnimator.ofFloat(mActivity.getOverviewPanel(),
                         RecentsView.CONTENT_ALPHA, values);
-            case INDEX_RECENTS_TRANSLATE_Y_ANIM: {
+            case INDEX_RECENTS_TRANSLATE_X_ANIM: {
                 RecentsView rv = mActivity.getOverviewPanel();
                 return new SpringAnimationBuilder(mActivity)
                         .setMinimumVisibleChange(DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE)
                         .setDampingRatio(0.8f)
                         .setStiffness(250)
                         .setValues(values)
-                        .build(rv, ADJACENT_PAGE_VERTICAL_OFFSET);
+                        .build(rv, ADJACENT_PAGE_HORIZONTAL_OFFSET);
             }
             default:
                 return super.createStateElementAnimation(index, values);
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index e983f46..bfd9008 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -51,6 +51,7 @@
 import com.android.launcher3.util.SettingsCache;
 import com.android.launcher3.util.WindowBounds;
 import com.android.quickstep.BaseActivityInterface;
+import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.views.TaskView;
 
 import java.lang.annotation.Retention;
@@ -287,8 +288,9 @@
     }
 
     private void updateHomeRotationSetting() {
-        setFlag(FLAG_HOME_ROTATION_ALLOWED_IN_PREFS,
-                mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY, false));
+        boolean homeRotationEnabled = mSharedPrefs.getBoolean(ALLOW_ROTATION_PREFERENCE_KEY, false);
+        setFlag(FLAG_HOME_ROTATION_ALLOWED_IN_PREFS, homeRotationEnabled);
+        SystemUiProxy.INSTANCE.get(mContext).setHomeRotationEnabled(homeRotationEnabled);
     }
 
     private void initFlags() {
diff --git a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
new file mode 100644
index 0000000..50da93b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherState.BACKGROUND_APP;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
+import static com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER;
+import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
+import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.view.View;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.util.DynamicResource;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.plugins.ResourceProvider;
+
+/**
+ * Creates an animation that reveals the workspace.
+ * This is used in conjunction with the swipe up to home animation.
+ */
+public class WorkspaceRevealAnim {
+
+    // Should be used for animations running alongside this WorkspaceRevealAnim.
+    public static final int DURATION_MS = 350;
+
+    private final float mScaleStart;
+    private final AnimatorSet mAnimators = new AnimatorSet();
+
+    public WorkspaceRevealAnim(Launcher launcher, boolean animateOverviewScrim) {
+        prepareToAnimate(launcher, animateOverviewScrim);
+
+        ResourceProvider rp = DynamicResource.provider(launcher);
+        mScaleStart = rp.getFloat(R.dimen.swipe_up_scale_start);
+
+        Workspace workspace = launcher.getWorkspace();
+        workspace.setPivotToScaleWithSelf(launcher.getHotseat());
+
+        // Add reveal animations.
+        addRevealAnimatorsForView(workspace);
+        addRevealAnimatorsForView(launcher.getHotseat());
+
+        // Add overview scrim animation.
+        if (animateOverviewScrim) {
+            PendingAnimation overviewScrimBuilder = new PendingAnimation(DURATION_MS);
+            launcher.getWorkspace().getStateTransitionAnimation()
+                    .setScrim(overviewScrimBuilder, NORMAL, new StateAnimationConfig());
+            mAnimators.play(overviewScrimBuilder.buildAnim());
+        }
+
+        // Add depth controller animation.
+        if (launcher instanceof BaseQuickstepLauncher) {
+            PendingAnimation depthBuilder = new PendingAnimation(DURATION_MS);
+            DepthController depth = ((BaseQuickstepLauncher) launcher).getDepthController();
+            depth.setStateWithAnimation(NORMAL, new StateAnimationConfig(), depthBuilder);
+            mAnimators.play(depthBuilder.buildAnim());
+        }
+
+        // Add sysui scrim animation.
+        mAnimators.play(launcher.getRootView().getSysUiScrim().createSysuiMultiplierAnim(0f, 1f));
+
+        mAnimators.setDuration(DURATION_MS);
+        mAnimators.setInterpolator(Interpolators.DECELERATED_EASE);
+    }
+
+    private void addRevealAnimatorsForView(View v) {
+        ObjectAnimator scale = ObjectAnimator.ofFloat(v, SCALE_PROPERTY, mScaleStart, 1f);
+        scale.setDuration(DURATION_MS);
+        scale.setInterpolator(Interpolators.DECELERATED_EASE);
+        mAnimators.play(scale);
+
+        ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0, 1f);
+        alpha.setDuration(DURATION_MS);
+        alpha.setInterpolator(Interpolators.DECELERATED_EASE);
+        mAnimators.play(alpha);
+    }
+
+    /**
+     * Setup workspace with 0 duration.
+     */
+    private void prepareToAnimate(Launcher launcher, boolean animateOverviewScrim) {
+        StateAnimationConfig config = new StateAnimationConfig();
+        config.animFlags = SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER | SKIP_SCRIM;
+        config.duration = 0;
+        // setRecentsAttachedToAppWindow() will animate recents out.
+        launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start();
+
+        // Stop scrolling so that it doesn't interfere with the translation offscreen.
+        launcher.<RecentsView>getOverviewPanel().getScroller().forceFinished(true);
+
+        if (animateOverviewScrim) {
+            launcher.getWorkspace().getStateTransitionAnimation()
+                    .setScrim(NO_ANIM_PROPERTY_SETTER, BACKGROUND_APP, config);
+        }
+    }
+
+    public AnimatorSet getAnimators() {
+        return mAnimators;
+    }
+
+    public WorkspaceRevealAnim addAnimatorListener(Animator.AnimatorListener listener) {
+        mAnimators.addListener(listener);
+        return this;
+    }
+
+    /**
+     * Starts the animation.
+     */
+    public void start() {
+        mAnimators.start();
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
index 121e094..0012dd8 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
@@ -34,6 +34,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.views.FloatingView;
 import com.android.launcher3.views.ListenerView;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
 import com.android.launcher3.widget.RoundedCornerEnforcement;
@@ -41,7 +42,7 @@
 /** A view that mimics an App Widget through a launch animation. */
 @TargetApi(Build.VERSION_CODES.S)
 public class FloatingWidgetView extends FrameLayout implements AnimatorListener,
-        OnGlobalLayoutListener {
+        OnGlobalLayoutListener, FloatingView {
     private static final Matrix sTmpMatrix = new Matrix();
 
     private final Launcher mLauncher;
@@ -59,6 +60,8 @@
     private Runnable mOnTargetChangeRunnable;
     private boolean mAppTargetIsTranslucent;
 
+    private float mIconOffsetY;
+
     public FloatingWidgetView(Context context) {
         this(context, null);
     }
@@ -129,6 +132,7 @@
     }
 
     /** Callback at the end or early exit of the animation. */
+    @Override
     public void fastFinish() {
         if (isUninitialized()) return;
         Runnable fastFinishRunnable = mFastFinishRunnable;
@@ -192,6 +196,12 @@
         positionViews();
     }
 
+    @Override
+    public void setPositionOffsetY(float y) {
+        mIconOffsetY = y;
+        onGlobalLayout();
+    }
+
     /** Sets the layout parameters of the floating view and its background view child. */
     private void positionViews() {
         LayoutParams layoutParams = (LayoutParams) getLayoutParams();
@@ -200,7 +210,7 @@
 
         // FloatingWidgetView layout is forced LTR
         mBackgroundView.setTranslationX(mBackgroundPosition.left);
-        mBackgroundView.setTranslationY(mBackgroundPosition.top);
+        mBackgroundView.setTranslationY(mBackgroundPosition.top + mIconOffsetY);
         LayoutParams backgroundParams = (LayoutParams) mBackgroundView.getLayoutParams();
         backgroundParams.leftMargin = 0;
         backgroundParams.topMargin = 0;
@@ -215,7 +225,8 @@
             sTmpMatrix.setTranslate(-mBackgroundOffset.left - mAppWidgetView.getLeft(),
                     -mBackgroundOffset.top - mAppWidgetView.getTop());
             sTmpMatrix.postScale(foregroundScale, foregroundScale);
-            sTmpMatrix.postTranslate(mBackgroundPosition.left, mBackgroundPosition.top);
+            sTmpMatrix.postTranslate(mBackgroundPosition.left, mBackgroundPosition.top
+                    + mIconOffsetY);
             mForegroundOverlayView.setMatrix(sTmpMatrix);
         }
     }
@@ -240,6 +251,7 @@
     }
 
     private void recycle() {
+        mIconOffsetY = 0;
         mEndRunnable = null;
         mFastFinishRunnable = null;
         mOnTargetChangeRunnable = null;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 5bad5e8..84d0444 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -32,11 +32,12 @@
 import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.Utilities.squaredTouchSlop;
 import static com.android.launcher3.anim.Interpolators.ACCEL;
+import static com.android.launcher3.anim.Interpolators.ACCEL_0_5;
 import static com.android.launcher3.anim.Interpolators.ACCEL_0_75;
-import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.clampToProgress;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_CLEAR_ALL;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
@@ -231,22 +232,6 @@
                 }
             };
 
-    public static final FloatProperty<RecentsView> ADJACENT_PAGE_VERTICAL_OFFSET =
-            new FloatProperty<RecentsView>("adjacentPageVerticalOffset") {
-                @Override
-                public void setValue(RecentsView recentsView, float v) {
-                    if (recentsView.mAdjacentPageVerticalOffset != v) {
-                        recentsView.mAdjacentPageVerticalOffset = v;
-                        recentsView.updateVerticalPageOffsets();
-                    }
-                }
-
-                @Override
-                public Float get(RecentsView recentsView) {
-                    return recentsView.mAdjacentPageVerticalOffset;
-                }
-            };
-
     /**
      * Can be used to tint the color of the RecentsView to simulate a scrim that can views
      * excluded from. Really should be a proper scrim.
@@ -276,8 +261,6 @@
                 @Override
                 public void setValue(RecentsView recentsView, float v) {
                     recentsView.setTaskViewsResistanceTranslation(v);
-                    recentsView.mLastComputedTaskBottomPushOutDistance = null;
-                    recentsView.updateVerticalPageOffsets();
                 }
 
                 @Override
@@ -327,11 +310,9 @@
                     view.setScaleY(scale);
                     view.mLastComputedTaskStartPushOutDistance = null;
                     view.mLastComputedTaskEndPushOutDistance = null;
-                    view.mLastComputedTaskBottomPushOutDistance = null;
                     view.mLiveTileTaskViewSimulator.recentsViewScale.value = scale;
                     view.setTaskViewsResistanceTranslation(view.mTaskViewsSecondaryTranslation);
                     view.updatePageOffsets();
-                    view.updateVerticalPageOffsets();
                 }
 
                 @Override
@@ -356,6 +337,11 @@
     // OverScroll constants
     private static final int OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION = 270;
 
+    private static final int DISMISS_TASK_DURATION = 300;
+    private static final int ADDITION_TASK_DURATION = 200;
+    private static final float INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.55f;
+    private static final float ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET = 0.05f;
+
     protected final RecentsOrientedState mOrientationState;
     protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
     protected RecentsAnimationController mRecentsAnimationController;
@@ -370,7 +356,6 @@
     // How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot.
     protected Float mLastComputedTaskStartPushOutDistance = null;
     protected Float mLastComputedTaskEndPushOutDistance = null;
-    protected Float mLastComputedTaskBottomPushOutDistance = null;
     protected boolean mEnableDrawingLiveTile = false;
     protected final Rect mTempRect = new Rect();
     protected final RectF mTempRectF = new RectF();
@@ -379,10 +364,6 @@
     private final List<OnScrollChangedListener> mScrollListeners = new ArrayList<>();
     private float mFullscreenScale;
 
-    private static final int DISMISS_TASK_DURATION = 300;
-    private static final int DISMISS_TASK_TRANSLATION_DURATION = 200;
-    private static final int ADDITIONAL_DISMISS_TASK_TRANSLATION_DURATION = 75;
-    private static final int ADDITION_TASK_DURATION = 200;
     // The threshold at which we update the SystemUI flags when animating from the task into the app
     public static final float UPDATE_SYSUI_FLAGS_THRESHOLD = 0.85f;
 
@@ -415,7 +396,6 @@
     private boolean mOverviewFullscreenEnabled;
 
     private float mAdjacentPageHorizontalOffset = 0;
-    private float mAdjacentPageVerticalOffset = 0;
     protected float mTaskViewsSecondaryTranslation = 0;
     protected float mTaskViewsPrimarySplitTranslation = 0;
     protected float mTaskViewsSecondarySplitTranslation = 0;
@@ -506,7 +486,6 @@
     protected boolean mRunningTaskTileHidden;
     private Task mTmpRunningTask;
     protected int mFocusedTaskId = -1;
-    private float mFocusedTaskRatio;
 
     private boolean mRunningTaskIconScaledDown = false;
 
@@ -1214,7 +1193,6 @@
         // Update the set of visible task's data
         loadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
         setTaskModalness(0);
-        updateVerticalPageOffsets();
         setColorTint(0);
     }
 
@@ -1372,19 +1350,7 @@
     public Point getSelectedTaskSize() {
         mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), mTempRect,
                 mOrientationHandler);
-        int taskWidth = mTempRect.width();
-        int taskHeight = mTempRect.height();
-        if (mRunningTaskId != -1) {
-            int boxLength = Math.max(taskWidth, taskHeight);
-            if (mFocusedTaskRatio > 1) {
-                taskWidth = boxLength;
-                taskHeight = (int) (boxLength / mFocusedTaskRatio);
-            } else {
-                taskWidth = (int) (boxLength * mFocusedTaskRatio);
-                taskHeight = boxLength;
-            }
-        }
-        return new Point(taskWidth, taskHeight);
+        return new Point(mTempRect.width(), mTempRect.height());
     }
 
     /** Gets the last computed task size */
@@ -1614,13 +1580,6 @@
     }
 
     /**
-     * Returns the width to height ratio of the focused {@link TaskView}.
-     */
-    public float getFocusedTaskRatio() {
-        return mFocusedTaskRatio;
-    }
-
-    /**
      * Get the index of the task view whose id matches {@param taskId}.
      * @return -1 if there is no task view for the task id, else the index of the task view.
      */
@@ -1799,7 +1758,7 @@
         int runningTaskId = runningTaskInfo == null ? -1 : runningTaskInfo.taskId;
         setCurrentTask(runningTaskId);
         if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
-            setFocusedTask(runningTaskId);
+            mFocusedTaskId = runningTaskId;
         }
         setCurrentPage(getRunningTaskIndex());
         setRunningTaskViewShowScreenshot(false);
@@ -1829,15 +1788,6 @@
     }
 
     /**
-     * Sets the focused task id and store the width to height ratio of the focused task.
-     */
-    protected void setFocusedTask(int focusedTaskId) {
-        mFocusedTaskId = focusedTaskId;
-        mFocusedTaskRatio =
-                mLastComputedTaskSize.width() / (float) mLastComputedTaskSize.height();
-    }
-
-    /**
      * Hides the tile associated with {@link #mRunningTaskId}
      */
     public void setRunningTaskHidden(boolean isHidden) {
@@ -1909,28 +1859,23 @@
      * This method is used when no task dismissal has occurred.
      */
     private void updateGridProperties() {
-        updateGridProperties(null, -1);
+        updateGridProperties(false);
     }
 
     /**
      * Updates TaskView and ClearAllButton scaling and translation required to turn into grid
      * layout.
      * This method only calculates the potential position and depends on {@link #setGridProgress} to
-     * apply the actual scaling and translation. This adds task translation animations in the case
-     * of task dismissals: e.g. when dismissedTask is not null.
+     * apply the actual scaling and translation.
      *
-     * @param dismissedTask the TaskView dismissed, possibly null
-     * @param dismissedIndex the index at which the dismissedTask was prior to dismissal, if no
-     *                       dismissal occurred, this is unused
+     * @param isTaskDismissal indicates if update was called due to task dismissal
      */
-    private void updateGridProperties(TaskView dismissedTask, int dismissedIndex) {
+    private void updateGridProperties(boolean isTaskDismissal) {
         int taskCount = getTaskViewCount();
         if (taskCount == 0) {
             return;
         }
 
-        final int boxLength = Math.max(mLastComputedGridTaskSize.width(),
-                mLastComputedGridTaskSize.height());
         int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
 
         /*
@@ -1941,7 +1886,8 @@
          */
         final float taskGridVerticalDiff =
                 mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
-        final float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
+        final float heightOffset =
+                (mLastComputedGridTaskSize.height() + taskTopMargin) + mRowSpacing;
 
         int topRowWidth = 0;
         int bottomRowWidth = 0;
@@ -1963,10 +1909,6 @@
         int snappedPage = getNextPage();
         TaskView snappedTaskView = getTaskViewAtByAbsoluteIndex(snappedPage);
 
-        boolean isTaskDismissal = dismissedTask != null;
-        float dismissedTaskWidth =
-                isTaskDismissal ? dismissedTask.getLayoutParams().width + mPageSpacing : 0;
-
         if (!isTaskDismissal) {
             mTopRowIdSet.clear();
         }
@@ -2062,34 +2004,13 @@
             snappedTaskGridTranslationX = gridTranslations[snappedPage - mTaskViewStartIndex];
         }
 
-        // Animate task dismissTranslationX for tasks with index >= dismissed index and in the
-        // same row as the dismissed index, or if the dismissed task was the focused task. Offset
-        // successive task dismissal durations for a staggered effect.
-        ArrayList<Animator> gridTranslationAnimators = new ArrayList<>();
-        boolean isFocusedTaskDismissed =
-                isTaskDismissal && dismissedTask.getTask().key.id == mFocusedTaskId;
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = getTaskViewAt(i);
-            if (isFocusedTaskDismissed || (i >= dismissedIndex && isSameGridRow(dismissedTask,
-                    taskView))) {
-                Animator taskDismissAnimator = ObjectAnimator.ofFloat(taskView,
-                        taskView.getPrimaryDismissTranslationProperty(),
-                        mIsRtl ? -dismissedTaskWidth : dismissedTaskWidth, 0f);
-                int additionalTranslationDuration =
-                        i >= dismissedIndex ? (ADDITIONAL_DISMISS_TASK_TRANSLATION_DURATION * (
-                                (i - dismissedIndex) / 2)) : 0;
-                taskDismissAnimator.setDuration(
-                        DISMISS_TASK_TRANSLATION_DURATION + additionalTranslationDuration);
-                gridTranslationAnimators.add(taskDismissAnimator);
-            }
             taskView.setGridTranslationX(gridTranslations[i] - snappedTaskGridTranslationX);
             taskView.getPrimaryNonFullscreenTranslationProperty().set(taskView,
                     snappedTaskFullscreenScrollAdjustment);
             taskView.getSecondaryNonFullscreenTranslationProperty().set(taskView, 0f);
         }
-        AnimatorSet gridTranslationAnimatorSet = new AnimatorSet();
-        gridTranslationAnimatorSet.playTogether(gridTranslationAnimators);
-        gridTranslationAnimatorSet.start();
 
         // Use the accumulated translation of the row containing the last task.
         float clearAllAccumulatedTranslation = topSet.contains(taskCount - 1)
@@ -2110,20 +2031,9 @@
         float clearAllShorterRowCompensation =
                 mIsRtl ? -shorterRowCompensation : shorterRowCompensation;
 
-        // If the total width is shorter than one grid's width, move ClearAllButton further away
-        // accordingly. Update longRowWidth if ClearAllButton has been moved.
-        float clearAllShortTotalCompensation = 0;
-        int longRowWidth = Math.max(topRowWidth, bottomRowWidth);
-        if (longRowWidth < mLastComputedGridSize.width()) {
-            float shortTotalCompensation = mLastComputedGridSize.width() - longRowWidth;
-            clearAllShortTotalCompensation =
-                    mIsRtl ? -shortTotalCompensation : shortTotalCompensation;
-            longRowWidth = mLastComputedGridSize.width();
-        }
-
         float clearAllTotalTranslationX =
                 clearAllAccumulatedTranslation + clearAllShorterRowCompensation
-                        + clearAllShortTotalCompensation + snappedTaskFullscreenScrollAdjustment;
+                        + snappedTaskFullscreenScrollAdjustment;
         if (focusedTaskIndex < taskCount) {
             // Shift by focused task's width and spacing if a task is focused.
             clearAllTotalTranslationX +=
@@ -2133,9 +2043,12 @@
         // Make sure there are enough space between snapped page and ClearAllButton, for the case
         // of swiping up after quick switch.
         if (snappedTaskView != null) {
+            int longRowWidth = Math.max(topRowWidth, bottomRowWidth);
             int distanceFromClearAll = longRowWidth - snappedTaskRowWidth;
+            // ClearAllButton should be off screen when snapped task is in its snapped position.
             int minimumDistance =
-                    mLastComputedGridSize.width() - snappedTaskView.getLayoutParams().width;
+                    mTaskWidth - snappedTaskView.getLayoutParams().width
+                            + (mLastComputedGridSize.width() - mTaskWidth) / 2;
             if (distanceFromClearAll < minimumDistance) {
                 int distanceDifference = minimumDistance - distanceFromClearAll;
                 clearAllTotalTranslationX += mIsRtl ? -distanceDifference : distanceDifference;
@@ -2233,7 +2146,7 @@
             PendingAnimation anim) {
         // Use setFloat instead of setViewAlpha as we want to keep the view visible even when it's
         // alpha is set to 0 so that it can be recycled in the view pool properly
-        anim.setFloat(taskView, VIEW_ALPHA, 0, ACCEL_2);
+        anim.setFloat(taskView, VIEW_ALPHA, 0, clampToProgress(ACCEL, 0, 0.5f));
         SplitSelectStateController splitController = mSplitPlaceholderView.getSplitController();
 
         ResourceProvider rp = DynamicResource.provider(mActivity);
@@ -2269,8 +2182,10 @@
                     throw new IllegalStateException("Invalid split task translation: " + dir);
             }
         }
+        // Double translation distance so dismissal drag is the full height, as we only animate
+        // the drag for the first half of the progress.
         anim.add(ObjectAnimator.ofFloat(taskView, dismissingTaskViewTranslate,
-                positiveNegativeFactor * translateDistance).setDuration(duration), LINEAR, sp);
+                positiveNegativeFactor * translateDistance * 2).setDuration(duration), LINEAR, sp);
 
         if (LIVE_TILE.get() && taskView.isRunningTask()) {
             anim.addOnFrameCallback(() -> {
@@ -2306,6 +2221,11 @@
         }
         int draggedIndex = indexOfChild(taskView);
 
+        boolean isFocusedTaskDismissed = taskView.getTask().key.id == mFocusedTaskId;
+        if (isFocusedTaskDismissed && showAsGrid()) {
+            anim.setFloat(mActionsView, VIEW_ALPHA, 0, clampToProgress(ACCEL_0_5, 0, 0.5f));
+        }
+        float dismissedTaskWidth = taskView.getLayoutParams().width + mPageSpacing;
         boolean needsCurveUpdates = false;
         for (int i = 0; i < count; i++) {
             View child = getChildAt(i);
@@ -2314,7 +2234,7 @@
                     addDismissedTaskAnimations(taskView, duration, anim);
                 }
             } else if (!showAsGrid()) {
-                // For grid layout, don't animate other tasks when dismissing in grid for now.
+                // Compute scroll offsets from task dismissal for animation.
                 // If we just take newScroll - oldScroll, everything to the right of dragged task
                 // translates to the left. We need to offset this in some cases:
                 // - In RTL, add page offset to all pages, since we want pages to move to the right
@@ -2341,15 +2261,31 @@
                             ? ((TaskView) child).getPrimaryDismissTranslationProperty()
                             : mOrientationHandler.getPrimaryViewTranslate();
 
-                    ResourceProvider rp = DynamicResource.provider(mActivity);
-                    SpringProperty sp = new SpringProperty(SpringProperty.FLAG_CAN_SPRING_ON_END)
-                            .setDampingRatio(
-                                    rp.getFloat(R.dimen.dismiss_task_trans_x_damping_ratio))
-                            .setStiffness(rp.getFloat(R.dimen.dismiss_task_trans_x_stiffness));
-                    anim.add(ObjectAnimator.ofFloat(child, translationProperty, scrollDiff)
-                            .setDuration(duration), ACCEL, sp);
+                    float additionalDismissDuration =
+                            ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(
+                                    i - draggedIndex);
+                    anim.setFloat(child, translationProperty, scrollDiff, clampToProgress(LINEAR,
+                            Utilities.boundToRange(INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
+                                    + additionalDismissDuration, 0f, 1f), 1));
                     needsCurveUpdates = true;
                 }
+            } else if (child instanceof TaskView) {
+                // Animate task with index >= dismissed index and in the same row as the
+                // dismissed index, or if the dismissed task was the focused task. Offset
+                // successive task dismissal durations for a staggered effect.
+                if (isFocusedTaskDismissed || (i >= draggedIndex && isSameGridRow((TaskView) child,
+                        taskView))) {
+                    FloatProperty translationProperty =
+                            ((TaskView) child).getPrimaryDismissTranslationProperty();
+                    float additionalDismissDuration =
+                            ADDITIONAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET * Math.abs(
+                                    i - draggedIndex);
+                    anim.setFloat(child, translationProperty,
+                            !mIsRtl ? -dismissedTaskWidth : dismissedTaskWidth,
+                            clampToProgress(LINEAR, Utilities.boundToRange(
+                                    INITIAL_DISMISS_TRANSLATION_INTERPOLATION_OFFSET
+                                            + additionalDismissDuration, 0f, 1f), 1));
+                }
             }
         }
 
@@ -2387,6 +2323,10 @@
                         }
                     }
 
+                    // Reset task translations as they may have updated via animations in
+                    // createTaskDismissAnimation
+                    resetTaskVisuals();
+
                     int pageToSnapTo = mCurrentPage;
                     // Snap to start if focused task was dismissed, as after quick switch it could
                     // be at any page but the focused task always displays at the start.
@@ -2404,7 +2344,7 @@
                     } else {
                         snapToPageImmediately(pageToSnapTo);
                         // Grid got messed up, reapply.
-                        updateGridProperties(taskView, draggedIndex - mTaskViewStartIndex);
+                        updateGridProperties(true);
                         if (showAsGrid() && getFocusedTaskView() == null
                                 && mActionsView.getVisibilityAlpha().getValue() == 1) {
                             animateActionsViewOut();
@@ -2414,9 +2354,6 @@
                     // immediately available.
                     onLayout(false /*  changed */, getLeft(), getTop(), getRight(), getBottom());
                 }
-                if (!showAsGrid()) {
-                    resetTaskVisuals();
-                }
                 onDismissAnimationEnds();
                 mPendingAnimation = null;
             }
@@ -2640,6 +2577,16 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
+        if (LIVE_TILE.get()) {
+            switchToScreenshot(
+                    () -> finishRecentsAnimation(true /* toRecents */,
+                            this::onConfigurationChangedInternal));
+        } else {
+            onConfigurationChangedInternal();
+        }
+    }
+
+    private void onConfigurationChangedInternal() {
         final int rotation = mActivity.getDisplay().getRotation();
         if (mOrientationState.setRecentsRotation(rotation)) {
             updateOrientationHandler();
@@ -2733,9 +2680,7 @@
         setTaskModalness(mTaskModalness);
         mLastComputedTaskStartPushOutDistance = null;
         mLastComputedTaskEndPushOutDistance = null;
-        mLastComputedTaskBottomPushOutDistance = null;
         updatePageOffsets();
-        updateVerticalPageOffsets();
         setImportantForAccessibility(isModal() ? IMPORTANT_FOR_ACCESSIBILITY_NO
                 : IMPORTANT_FOR_ACCESSIBILITY_AUTO);
     }
@@ -2752,7 +2697,7 @@
 
         float midpointOffsetSize = 0;
         float leftOffsetSize = midpoint - 1 >= 0
-                ? -getHorizontalOffsetSize(midpoint - 1, midpoint, offset)
+                ? getHorizontalOffsetSize(midpoint - 1, midpoint, offset)
                 : 0;
         float rightOffsetSize = midpoint + 1 < count
                 ? getHorizontalOffsetSize(midpoint + 1, midpoint, offset)
@@ -2889,64 +2834,6 @@
         return distanceToOffscreen * offsetProgress;
     }
 
-    private void updateVerticalPageOffsets() {
-        float offset = mAdjacentPageVerticalOffset;
-        int count = getTaskViewCount();
-
-        TaskView runningTask = mRunningTaskId == -1 || !mRunningTaskTileHidden
-                ? null : getTaskView(mRunningTaskId);
-        int midpoint = runningTask == null ? -1 : indexOfChild(runningTask);
-
-        float offsetSize = getVerticalOffsetSize(offset);
-        float midpointOffsetSize = 0;
-
-        for (int i = 0; i < count; i++) {
-            float translation = i == midpoint
-                    ? midpointOffsetSize
-                    : offsetSize;
-            int directionFactor = mOrientationHandler.getSecondaryTranslationDirectionFactor() * -1;
-            translation *= directionFactor;
-            TaskView child = getTaskViewAt(i);
-            FloatProperty translationProperty = child.getSecondaryTaskOffsetTranslationProperty();
-            translationProperty.set(child, translation);
-            if (LIVE_TILE.get() && mEnableDrawingLiveTile && i == getRunningTaskIndex()) {
-                mLiveTileTaskViewSimulator.taskSecondaryTranslation.value = translation;
-                redrawLiveTile();
-            }
-        }
-    }
-
-    /**
-     * Computes the distance to offset the given child such that it is completely offscreen when
-     * translating away from its position in overview.
-     * @param offsetProgress From 0 to 1 where 0 means no offset and 1 means offset offscreen.
-     */
-    private float getVerticalOffsetSize(float offsetProgress) {
-        if (offsetProgress == 0) {
-            // Don't bother calculating everything below if we won't offset anyway.
-            return 0;
-        }
-        // First, find the distance to offscreen from the normal (centered) task position.
-        mTempRectF.set(mLastComputedTaskSize);
-        RectF taskPosition = mTempRectF;
-        float desiredTop = getHeight();
-        float distanceToOffscreen = desiredTop - taskPosition.top;
-        // Next, we need to account for the resistance translation if any (e.g. long swipe up).
-        float translationY = mTaskViewsSecondaryTranslation;
-        distanceToOffscreen -= translationY;
-        // Finally, we need to account for RecentsView scale, because it moves tasks based on its
-        // pivot. To do this, we move the task position to where it would be offscreen at scale = 1
-        // (computed above), then we apply the scale via getMatrix() to determine how much that
-        // moves the task from its desired position, and adjust the computed distance accordingly.
-        if (mLastComputedTaskBottomPushOutDistance == null) {
-            taskPosition.offsetTo(0, desiredTop + translationY);
-            getMatrix().mapRect(taskPosition);
-            mLastComputedTaskBottomPushOutDistance = (taskPosition.top - desiredTop) / getScaleY();
-        }
-        distanceToOffscreen -= mLastComputedTaskBottomPushOutDistance;
-        return distanceToOffscreen * offsetProgress;
-    }
-
     protected void setTaskViewsResistanceTranslation(float translation) {
         mTaskViewsSecondaryTranslation = translation;
         for (int i = 0; i < getTaskViewCount(); i++) {
@@ -3598,11 +3485,11 @@
         }
 
         int overScrollShift = getOverScrollShift();
-        if (mAdjacentPageVerticalOffset > 0) {
+        if (mAdjacentPageHorizontalOffset > 0) {
             // Don't dampen the scroll (due to overscroll) if the adjacent tasks are offscreen, so
             // that the page can move freely given there's no visual indication why it shouldn't.
-            overScrollShift = (int) Utilities.mapRange(mAdjacentPageVerticalOffset, overScrollShift,
-                    getUndampedOverScrollShift());
+            overScrollShift = (int) Utilities.mapRange(mAdjacentPageHorizontalOffset,
+                    overScrollShift, getUndampedOverScrollShift());
         }
         return getScrollForPage(pageIndex) - mOrientationHandler.getPrimaryScroll(this)
                 + overScrollShift;
@@ -3794,7 +3681,8 @@
         return mColorTint;
     }
 
-    private boolean showAsGrid() {
+    /** Returns {@code true} if the overview tasks are displayed as a grid. */
+    public boolean showAsGrid() {
         return mOverviewGridEnabled || (mCurrentGestureEndTarget != null
                 && mSizeStrategy.stateFromGestureEndTarget(
                 mCurrentGestureEndTarget).displayOverviewTasksAsGrid(mActivity.getDeviceProfile()));
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 32cd367..bff1013 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -215,6 +215,7 @@
                 RecentsView recentsView = mTaskView.getRecentsView();
                 recentsView.switchToScreenshot(null,
                         () -> recentsView.finishRecentsAnimation(true /* toRecents */,
+                                false /* shouldPip */,
                                 () -> menuOption.onClick(view)));
             } else {
                 menuOption.onClick(view);
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 02888a1..1bfd430 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -411,7 +411,9 @@
      */
     public static class PreviewPositionHelper {
 
-        // Contains the portion of the thumbnail that is clipped when fullscreen progress = 0.
+        private static final RectF EMPTY_RECT_F = new RectF();
+
+        // Contains the portion of the thumbnail that is unclipped when fullscreen progress = 1.
         private final RectF mClippedInsets = new RectF();
         private final Matrix mMatrix = new Matrix();
         private boolean mIsOrientationChanged;
@@ -616,15 +618,17 @@
                     break;
             }
             mClippedInsets.offsetTo(newLeftInset * scale, newTopInset * scale);
-            mMatrix.postTranslate(translateX - mClippedInsets.left,
-                    translateY - mClippedInsets.top);
+            mMatrix.postTranslate(translateX, translateY);
+            if (TaskView.FULL_THUMBNAIL) {
+                mMatrix.postTranslate(-mClippedInsets.left, -mClippedInsets.top);
+            }
         }
 
         /**
          * Insets to used for clipping the thumbnail (in case it is drawing outside its own space)
          */
         public RectF getInsetsToDrawInFullscreen() {
-            return mClippedInsets;
+            return TaskView.FULL_THUMBNAIL ? mClippedInsets : EMPTY_RECT_F;
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index f8be5b6..55a32ea 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -141,6 +141,11 @@
      */
     public static final boolean CLIP_STATUS_AND_NAV_BARS = false;
 
+    /**
+     * Should the TaskView scale down to fit whole thumbnail in fullscreen.
+     */
+    public static final boolean FULL_THUMBNAIL = false;
+
     private static final float EDGE_SCALE_DOWN_FACTOR_CAROUSEL = 0.03f;
     private static final float EDGE_SCALE_DOWN_FACTOR_GRID = 0.00f;
 
@@ -1133,11 +1138,6 @@
                 TASK_OFFSET_TRANSLATION_X, TASK_OFFSET_TRANSLATION_Y);
     }
 
-    public FloatProperty<TaskView> getSecondaryTaskOffsetTranslationProperty() {
-        return getPagedOrientationHandler().getSecondaryValue(
-                TASK_OFFSET_TRANSLATION_X, TASK_OFFSET_TRANSLATION_Y);
-    }
-
     public FloatProperty<TaskView> getTaskResistanceTranslationProperty() {
         return getPagedOrientationHandler().getSecondaryValue(
                 TASK_RESISTANCE_TRANSLATION_X, TASK_RESISTANCE_TRANSLATION_Y);
@@ -1348,46 +1348,26 @@
 
             int boxWidth;
             int boxHeight;
-            float thumbnailRatio;
             boolean isFocusedTask = isFocusedTask();
             if (isFocusedTask) {
                 // Task will be focused and should use focused task size. Use focusTaskRatio
                 // that is associated with the original orientation of the focused task.
                 boxWidth = taskWidth;
                 boxHeight = taskHeight;
-                thumbnailRatio = getRecentsView().getFocusedTaskRatio();
             } else {
                 // Otherwise task is in grid, and should use lastComputedGridTaskSize.
                 Rect lastComputedGridTaskSize = getRecentsView().getLastComputedGridTaskSize();
                 boxWidth = lastComputedGridTaskSize.width();
                 boxHeight = lastComputedGridTaskSize.height();
-                thumbnailRatio = mTask != null ? mTask.getVisibleThumbnailRatio(
-                        TaskView.CLIP_STATUS_AND_NAV_BARS) : 0f;
             }
-            int boxLength = Math.max(boxWidth, boxHeight);
 
             // Bound width/height to the box size.
-            if (thumbnailRatio == 0f) {
-                expectedWidth = boxWidth;
-                expectedHeight = boxHeight + thumbnailPadding;
-            } else if (thumbnailRatio > 1) {
-                expectedWidth = boxLength;
-                expectedHeight = (int) (boxLength / thumbnailRatio) + thumbnailPadding;
-            } else {
-                expectedWidth = (int) (boxLength * thumbnailRatio);
-                expectedHeight = boxLength + thumbnailPadding;
-            }
+            expectedWidth = boxWidth;
+            expectedHeight = boxHeight + thumbnailPadding;
 
             // Scale to to fit task Rect.
             fullscreenScale = taskWidth / (float) boxWidth;
 
-            // In full screen, scale back TaskView to original size.
-            if (expectedWidth > boxWidth) {
-                fullscreenScale *= boxWidth / (float) expectedWidth;
-            } else if (expectedHeight - thumbnailPadding > boxHeight) {
-                fullscreenScale *= boxHeight / (float) (expectedHeight - thumbnailPadding);
-            }
-
             // Align to top of task Rect.
             boxTranslationY = (expectedHeight - thumbnailPadding - taskHeight) / 2.0f;
         } else {
diff --git a/res/drawable/bg_widgets_picker_handle.xml b/res/drawable/bg_widgets_picker_handle.xml
new file mode 100644
index 0000000..68681a6
--- /dev/null
+++ b/res/drawable/bg_widgets_picker_handle.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="?android:attr/colorBackground" />
+            <padding android:top="16dp"/>
+        </shape>
+    </item>
+    <item android:gravity="center">
+        <shape android:shape="rectangle">
+            <solid android:color="?android:attr/textColorSecondary" />
+            <size android:width="48dp" android:height="2dp" />
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/personal_work_tabs_ripple.xml b/res/drawable/personal_work_tabs_ripple.xml
new file mode 100644
index 0000000..2e57b80
--- /dev/null
+++ b/res/drawable/personal_work_tabs_ripple.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="?android:attr/colorControlHighlight">
+    <shape android:shape="rectangle">
+        <solid android:color="@android:color/transparent" />
+        <corners android:radius="@dimen/all_apps_header_pill_corner_radius" />
+    </shape>
+</ripple>
\ No newline at end of file
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index 00d148f..0a3fbbc 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -16,69 +16,85 @@
 ** limitations under the License.
 */
 -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/add_item_confirmation"
+<com.android.launcher3.dragndrop.AddItemDragLayer
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/add_item_drag_layer"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:padding="24dp"
-    android:theme="?attr/widgetsTheme"
-    android:orientation="vertical">
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:importantForAccessibility="no">
 
-    <TextView
-        style="@style/TextHeadline"
-        android:id="@+id/widget_appName"
+    <com.android.launcher3.widget.AddItemWidgetsBottomSheet
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/add_item_bottom_sheet"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:gravity="center_horizontal"
-        android:textColor="?android:attr/textColorPrimary"
-        android:textSize="24sp"
-        android:ellipsize="end"
-        android:fadingEdge="horizontal"
-        android:singleLine="true"
-        android:maxLines="1" />
+        android:background="@drawable/add_item_dialog_background"
+        android:padding="24dp"
+        android:theme="?attr/widgetsTheme"
+        android:layout_gravity="bottom"
+        android:orientation="vertical">
 
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center_horizontal"
-        android:paddingVertical="8dp"
-        android:text="@string/add_item_request_drag_hint"
-        android:textSize="14sp"
-        android:textColor="?android:attr/textColorSecondary"
-        android:alpha="0.7"
-        android:importantForAccessibility="no"/>
-
-    <include layout="@layout/widget_cell"
-        android:id="@+id/widget_cell"
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1"
-        android:layout_marginVertical="16dp" />
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="end"
-        android:padding="8dp"
-        android:orientation="horizontal">
-        <Button
-            style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
-            android:layout_width="wrap_content"
+        <TextView
+            style="@style/TextHeadline"
+            android:id="@+id/widget_appName"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingHorizontal="16dp"
-            android:onClick="onCancelClick"
-            android:text="@android:string/cancel" />
+            android:gravity="center_horizontal"
+            android:textColor="?android:attr/textColorPrimary"
+            android:textSize="24sp"
+            android:ellipsize="end"
+            android:fadingEdge="horizontal"
+            android:singleLine="true"
+            android:maxLines="1" />
 
-        <Space
-            android:layout_width="4dp"
-            android:layout_height="wrap_content" />
-
-        <Button
-            style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
-            android:layout_width="wrap_content"
+        <TextView
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingHorizontal="16dp"
-            android:onClick="onPlaceAutomaticallyClick"
-            android:text="@string/add_to_home_screen" />
-    </LinearLayout>
-</LinearLayout>
+            android:gravity="center_horizontal"
+            android:paddingVertical="8dp"
+            android:text="@string/add_item_request_drag_hint"
+            android:textSize="14sp"
+            android:textColor="?android:attr/textColorSecondary"
+            android:alpha="0.7"
+            android:importantForAccessibility="no"/>
+
+        <include layout="@layout/widget_cell"
+            android:id="@+id/widget_cell"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:layout_marginVertical="16dp" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="end"
+            android:padding="8dp"
+            android:orientation="horizontal">
+            <Button
+                style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingHorizontal="16dp"
+                android:onClick="onCancelClick"
+                android:text="@android:string/cancel" />
+
+            <Space
+                android:layout_width="4dp"
+                android:layout_height="wrap_content" />
+
+            <Button
+                style="@style/Widget.DeviceDefault.Button.Rounded.Colored"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingHorizontal="16dp"
+                android:onClick="onPlaceAutomaticallyClick"
+                android:text="@string/add_to_home_screen"/>
+        </LinearLayout>
+    </com.android.launcher3.widget.AddItemWidgetsBottomSheet>
+
+</com.android.launcher3.dragndrop.AddItemDragLayer>
+
+
diff --git a/res/layout/all_apps_personal_work_tabs.xml b/res/layout/all_apps_personal_work_tabs.xml
index 750e101..31fa5cf 100644
--- a/res/layout/all_apps_personal_work_tabs.xml
+++ b/res/layout/all_apps_personal_work_tabs.xml
@@ -32,7 +32,7 @@
         android:layout_width="0dp"
         android:layout_height="match_parent"
         android:layout_weight="1"
-        android:background="?android:attr/selectableItemBackground"
+        android:background="@drawable/personal_work_tabs_ripple"
         android:text="@string/all_apps_personal_tab"
         android:textColor="@color/all_apps_tab_text"
         android:textSize="16sp" />
@@ -42,7 +42,7 @@
         android:layout_width="0dp"
         android:layout_height="match_parent"
         android:layout_weight="1"
-        android:background="?android:attr/selectableItemBackground"
+        android:background="@drawable/personal_work_tabs_ripple"
         android:text="@string/all_apps_work_tab"
         android:textColor="@color/all_apps_tab_text"
         android:textSize="16sp" />
diff --git a/res/layout/widgets_full_sheet_search_and_recommendations.xml b/res/layout/widgets_full_sheet_search_and_recommendations.xml
index ce7a682..a89f85f 100644
--- a/res/layout/widgets_full_sheet_search_and_recommendations.xml
+++ b/res/layout/widgets_full_sheet_search_and_recommendations.xml
@@ -18,35 +18,44 @@
     android:id="@+id/search_and_recommendations_container"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:paddingHorizontal="16dp"
     android:layout_marginBottom="16dp"
-    android:orientation="vertical"
-    android:clipToPadding="false">
+    android:orientation="vertical">
+
     <View
         android:id="@+id/collapse_handle"
-        android:layout_width="48dp"
-        android:layout_height="2dp"
-        android:layout_marginTop="16dp"
-        android:elevation="2dp"
-        android:layout_gravity="center_horizontal"
-        android:background="?android:attr/textColorSecondary"/>
+        android:layout_width="match_parent"
+        android:layout_height="18dp"
+        android:elevation="0.1dp"
+        android:background="@drawable/bg_widgets_picker_handle"/>
+
     <TextView
         android:id="@+id/title"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center_horizontal"
         android:textSize="24sp"
-        android:layout_marginTop="16dp"
+        android:layout_marginTop="24dp"
         android:textColor="?android:attr/textColorSecondary"
         android:text="@string/widget_button_text"/>
-    <include layout="@layout/widgets_search_bar"/>
+
+    <FrameLayout
+        android:id="@+id/search_bar_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:elevation="0.1dp"
+        android:background="?android:attr/colorBackground"
+        android:paddingBottom="8dp"
+        android:clipToPadding="false">
+        <include layout="@layout/widgets_search_bar" />
+    </FrameLayout>
 
     <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
         android:id="@+id/recommended_widget_table"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:layout_marginHorizontal="16dp"
+        android:layout_marginTop="8dp"
         android:background="@drawable/widgets_recommendation_background"
         android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
-        android:layout_marginTop="16dp"
-        android:visibility="gone"/>
+        android:visibility="gone" />
 </com.android.launcher3.widget.picker.SearchAndRecommendationsView>
diff --git a/res/layout/widgets_personal_work_tabs.xml b/res/layout/widgets_personal_work_tabs.xml
index f835b52..72d83e8 100644
--- a/res/layout/widgets_personal_work_tabs.xml
+++ b/res/layout/widgets_personal_work_tabs.xml
@@ -22,6 +22,7 @@
     android:layout_height="@dimen/all_apps_header_pill_height"
     android:layout_marginHorizontal="16dp"
     android:orientation="horizontal"
+    android:background="@drawable/all_apps_tabs_background"
     android:elevation="2dp"
     style="@style/TextHeadline">
 
@@ -30,7 +31,7 @@
         android:layout_width="0dp"
         android:layout_height="match_parent"
         android:layout_weight="1"
-        android:background="?android:attr/selectableItemBackground"
+        android:background="@drawable/personal_work_tabs_ripple"
         android:text="@string/widgets_full_sheet_personal_tab"
         android:textColor="@color/all_apps_tab_text"
         android:textSize="14sp" />
@@ -40,7 +41,7 @@
         android:layout_width="0dp"
         android:layout_height="match_parent"
         android:layout_weight="1"
-        android:background="?android:attr/selectableItemBackground"
+        android:background="@drawable/personal_work_tabs_ripple"
         android:text="@string/widgets_full_sheet_work_tab"
         android:textColor="@color/all_apps_tab_text"
         android:textSize="14sp" />
diff --git a/res/layout/widgets_search_bar.xml b/res/layout/widgets_search_bar.xml
index 2467156..6a4bb4d 100644
--- a/res/layout/widgets_search_bar.xml
+++ b/res/layout/widgets_search_bar.xml
@@ -5,10 +5,9 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal"
-    android:layout_marginTop="16dp"
-    android:layout_marginBottom="1dp"
-    android:background="@drawable/bg_widgets_searchbox"
-    android:elevation="2dp">
+    android:layout_marginTop="24dp"
+    android:layout_marginHorizontal="16dp"
+    android:background="@drawable/bg_widgets_searchbox">
 
     <com.android.launcher3.ExtendedEditText
         android:id="@+id/widgets_search_bar_edit_text"
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index 07a5096..427525b 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
 /*
-* Copyright (C) 2018 The Android Open Source Project
+* Copyright (C) 2008 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.
@@ -18,11 +18,7 @@
 -->
 
 <resources>
-
-    <style name="AppItemActivityTheme" parent="@android:style/Theme.DeviceDefault.Dialog.Alert">
+    <style name="AddItemActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
         <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
-        <item name="android:windowBackground">@drawable/add_item_dialog_background</item>
-        <item name="android:windowNoTitle">true</item>
     </style>
-
-</resources>
\ No newline at end of file
+</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 102d4e0..77c7e98 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -126,7 +126,7 @@
 
     <item name="swipe_up_rect_xy_fling_friction" type="dimen" format="float">1.5</item>
 
-    <item name="swipe_up_scale_start"  type="dimen" format="float">0.98</item>
+    <item name="swipe_up_scale_start"  type="dimen" format="float">0.88</item>
     <item name="swipe_up_duration"  type="dimen" format="float">400</item>
 
     <item name="swipe_up_trans_y_dp"  type="dimen" format="float">4.5</item>
diff --git a/res/values/id.xml b/res/values/id.xml
index 39c49bd..1bd40ce 100644
--- a/res/values/id.xml
+++ b/res/values/id.xml
@@ -15,6 +15,7 @@
     limitations under the License.
 -->
 <resources>
+    <item type="id" name="apps_list_view_work" />
     <item type="id" name="view_type_widgets_list" />
     <item type="id" name="view_type_widgets_header" />
     <item type="id" name="view_type_widgets_search_header" />
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 7078feb..6d22951 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -149,12 +149,6 @@
     <style name="AppTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark.DarkMainColor" />
     <style name="AppTheme.Dark.DarkText" parent="@style/LauncherTheme.Dark.DarkText" />
 
-    <style name="AppItemActivityTheme" parent="@android:style/Theme.DeviceDefault.Light.Dialog.Alert">
-        <item name="widgetsTheme">@style/WidgetContainerTheme</item>
-        <item name="android:windowBackground">@drawable/add_item_dialog_background</item>
-        <item name="android:windowNoTitle">true</item>
-    </style>
-
     <style name="HomeSettingsTheme" parent="@android:style/Theme.DeviceDefault.Settings">
         <item name="android:navigationBarColor">?android:colorPrimaryDark</item>
         <item name="preferenceTheme">@style/HomeSettingsPreferenceTheme</item>
@@ -291,4 +285,8 @@
     <style name="Widget.DeviceDefault.Button.Rounded.Colored" parent="@android:style/Widget.DeviceDefault.Button.Colored">
         <item name="android:background">@drawable/add_item_dialog_button_background</item>
     </style>
+
+    <style name="AddItemActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
+        <item name="widgetsTheme">@style/WidgetContainerTheme</item>
+    </style>
 </resources>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 32b2c9a..b3952ca 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -63,7 +63,8 @@
             TYPE_DRAG_DROP_POPUP,
             TYPE_TASK_MENU,
             TYPE_OPTIONS_POPUP,
-            TYPE_ICON_SURFACE
+            TYPE_ICON_SURFACE,
+            TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface FloatingViewType {}
@@ -84,11 +85,13 @@
     public static final int TYPE_OPTIONS_POPUP = 1 << 12;
     public static final int TYPE_ICON_SURFACE = 1 << 13;
 
+    public static final int TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP = 1 << 14;
+
     public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
             | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
             | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
             | TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER | TYPE_ALL_APPS_EDU
-            | TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP;
+            | TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP | TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP;
 
     // Type of popups which should be kept open during launcher rebind
     public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 16ffd7a..cf90216 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2804,7 +2804,7 @@
      * @see LauncherState#getOverviewScaleAndOffset(Launcher)
      */
     public float[] getNormalOverviewScaleAndOffset() {
-        return new float[] {NO_SCALE, NO_OFFSET, NO_OFFSET};
+        return new float[] {NO_SCALE, NO_OFFSET};
     }
 
     /**
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 8432f4b..3399ce9 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -172,12 +172,10 @@
     }
 
     /**
-     * Returns an array of three elements.
+     * Returns an array of two elements.
      * The first specifies the scale for the overview
      * The second is the factor ([0, 1], 0 => center-screen; 1 => offscreen) by which overview
      * should be shifted horizontally.
-     * The third is the factor ([0, 1], 0 => center-screen; 1 => offscreen) by which overview
-     * should be shifted vertically.
      */
     public float[] getOverviewScaleAndOffset(Launcher launcher) {
         return launcher.getNormalOverviewScaleAndOffset();
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 3fdcea5..1620d08 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -30,11 +30,13 @@
 import android.graphics.Paint;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.Parcelable;
 import android.os.Process;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.SparseArray;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -133,6 +135,7 @@
     private int mHeaderColor;
 
 
+
     public AllAppsContainerView(Context context) {
         this(context, null);
     }
@@ -169,6 +172,19 @@
         mAllAppsStore.addUpdateListener(this::onAppsUpdated);
     }
 
+    @Override
+    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> sparseArray) {
+        try {
+            // Many slice view id is not properly assigned, and hence throws null
+            // pointer exception in the underneath method. Catching the exception
+            // simply doesn't restore these slice views. This doesn't have any
+            // user visible effect because because we query them again.
+            super.dispatchRestoreInstanceState(sparseArray);
+        } catch (Exception e) {
+            Log.e("AllAppsContainerView", "restoreInstanceState viewId = 0", e);
+        }
+    }
+
     /**
      * Sets the long click listener for icons
      */
@@ -436,6 +452,7 @@
             setupWorkToggle();
             mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
             mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
+            mAH[AdapterHolder.WORK].recyclerView.setId(R.id.apps_list_view_work);
             mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.MAIN);
             findViewById(R.id.tab_personal)
                     .setOnClickListener((View view) -> {
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 9d73bba..1e7b224 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -35,6 +35,7 @@
     public static final Interpolator LINEAR = new LinearInterpolator();
 
     public static final Interpolator ACCEL = new AccelerateInterpolator();
+    public static final Interpolator ACCEL_0_5 = new AccelerateInterpolator(0.5f);
     public static final Interpolator ACCEL_0_75 = new AccelerateInterpolator(0.75f);
     public static final Interpolator ACCEL_1_5 = new AccelerateInterpolator(1.5f);
     public static final Interpolator ACCEL_2 = new AccelerateInterpolator(2);
@@ -149,11 +150,15 @@
      */
     public static Interpolator clampToProgress(Interpolator interpolator, float lowerBound,
             float upperBound) {
-        if (upperBound <= lowerBound) {
-            throw new IllegalArgumentException(String.format(
-                    "lowerBound (%f) must be less than upperBound (%f)", lowerBound, upperBound));
+        if (upperBound < lowerBound) {
+            throw new IllegalArgumentException(
+                    String.format("upperBound (%f) must be greater than lowerBound (%f)",
+                            upperBound, lowerBound));
         }
         return t -> {
+            if (t == lowerBound && t == upperBound) {
+                return t == 0f ? 0 : 1;
+            }
             if (t < lowerBound) {
                 return 0;
             }
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 5ba36f2..5dae5a6 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -30,6 +30,7 @@
 import android.content.ClipDescription;
 import android.content.Intent;
 import android.content.pm.LauncherApps.PinItemRequest;
+import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -37,7 +38,6 @@
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
-import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.DragShadowBuilder;
@@ -56,6 +56,8 @@
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.PinRequestHelper;
+import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.views.AbstractSlideInView;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.launcher3.widget.LauncherAppWidgetHost;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
@@ -69,8 +71,12 @@
 
 import java.util.function.Supplier;
 
+/**
+ * Activity to show pin widget dialog.
+ */
 @TargetApi(Build.VERSION_CODES.O)
-public class AddItemActivity extends BaseActivity implements OnLongClickListener, OnTouchListener {
+public class AddItemActivity extends BaseActivity
+        implements OnLongClickListener, OnTouchListener, AbstractSlideInView.OnCloseListener {
 
     private static final int SHADOW_SIZE = 10;
 
@@ -82,6 +88,7 @@
     private PinItemRequest mRequest;
     private LauncherAppState mApp;
     private InvariantDeviceProfile mIdp;
+    private BaseDragLayer<AddItemActivity> mDragLayer;
 
     private WidgetCell mWidgetCell;
 
@@ -111,6 +118,14 @@
         mDeviceProfile = mIdp.getDeviceProfile(getApplicationContext());
 
         setContentView(R.layout.add_item_confirmation_activity);
+        // Set flag to allow activity to draw over navigation and status bar.
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
+                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+        mDragLayer = findViewById(R.id.add_item_drag_layer);
+        mDragLayer.recreateControllers();
+        mDragLayer.setInsets(mDeviceProfile.getInsets());
+        AbstractSlideInView<AddItemActivity> slideInView = findViewById(R.id.add_item_bottom_sheet);
+        slideInView.addOnCloseListener(this);
         mWidgetCell = findViewById(R.id.widget_cell);
 
         if (mRequest.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT) {
@@ -135,6 +150,8 @@
 
         TextView widgetAppName = findViewById(R.id.widget_appName);
         widgetAppName.setText(getApplicationInfo().labelRes);
+
+        setupNavBarColor();
     }
 
     @Override
@@ -338,7 +355,20 @@
 
     @Override
     public BaseDragLayer getDragLayer() {
-        throw new UnsupportedOperationException();
+        return mDragLayer;
+    }
+
+    @Override
+    public void onSlideInViewClosed() {
+        finish();
+    }
+
+    protected void setupNavBarColor() {
+        boolean isSheetDark = (getApplicationContext().getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+        getSystemUiController().updateUiState(
+                SystemUiController.UI_STATE_BASE_WINDOW,
+                isSheetDark ? SystemUiController.FLAG_DARK_NAV : SystemUiController.FLAG_LIGHT_NAV);
     }
 
     private void logCommand(StatsLogManager.EventEnum command) {
@@ -346,15 +376,4 @@
                 .withItemInfo((ItemInfo) mWidgetCell.getWidgetView().getTag())
                 .log(command);
     }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        View view = getWindow().getDecorView();
-        WindowManager.LayoutParams layoutParams =
-                (WindowManager.LayoutParams) view.getLayoutParams();
-        layoutParams.gravity = Gravity.BOTTOM;
-        layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
-        getWindowManager().updateViewLayout(view, layoutParams);
-    }
 }
diff --git a/src/com/android/launcher3/dragndrop/AddItemDragLayer.java b/src/com/android/launcher3/dragndrop/AddItemDragLayer.java
new file mode 100644
index 0000000..5b52c3d
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/AddItemDragLayer.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.dragndrop;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.BaseDragLayer;
+
+/**
+ * Drag layer for {@link AddItemActivity}.
+ */
+public class AddItemDragLayer extends BaseDragLayer<AddItemActivity> {
+
+    public AddItemDragLayer(Context context, AttributeSet attrs) {
+        this(context, attrs, /*alphaChannelCount= */ 1);
+    }
+
+    public AddItemDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) {
+        super(context, attrs, alphaChannelCount);
+    }
+
+    @Override
+    public void recreateControllers() {
+        mControllers = new TouchController[] {};
+    }
+}
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index f79313f..92ca8a1 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -31,17 +31,21 @@
 import android.view.animation.Interpolator;
 
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.touch.BaseSwipeDetector;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
- * Extension of AbstractFloatingView with common methods for sliding in from bottom
+ * Extension of {@link AbstractFloatingView} with common methods for sliding in from bottom.
+ *
+ * @param <T> Type of ActivityContext inflating this view.
  */
-public abstract class AbstractSlideInView extends AbstractFloatingView
-        implements SingleAxisSwipeDetector.Listener {
+public abstract class AbstractSlideInView<T extends Context & ActivityContext>
+        extends AbstractFloatingView implements SingleAxisSwipeDetector.Listener {
 
     protected static final Property<AbstractSlideInView, Float> TRANSLATION_SHIFT =
             new Property<AbstractSlideInView, Float>(Float.class, "translationShift") {
@@ -59,7 +63,8 @@
     protected static final float TRANSLATION_SHIFT_CLOSED = 1f;
     protected static final float TRANSLATION_SHIFT_OPENED = 0f;
 
-    protected final Launcher mLauncher;
+    protected final T mActivityContext;
+
     protected final SingleAxisSwipeDetector mSwipeDetector;
     protected final ObjectAnimator mOpenCloseAnimator;
 
@@ -71,10 +76,11 @@
     protected float mTranslationShift = TRANSLATION_SHIFT_CLOSED;
 
     protected boolean mNoIntercept;
+    protected List<OnCloseListener> mOnCloseListeners = new ArrayList<>();
 
     public AbstractSlideInView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mLauncher = Launcher.getLauncher(context);
+        mActivityContext = ActivityContext.lookupContext(context);
 
         mScrollInterpolator = Interpolators.SCROLL_CUBIC;
         mSwipeDetector = new SingleAxisSwipeDetector(context, this,
@@ -88,8 +94,8 @@
                 announceAccessibilityChanges();
             }
         });
-        int scrimColor = getScrimColor(mLauncher);
-        mColorScrim = scrimColor != -1 ? createColorScrim(mLauncher, scrimColor) : null;
+        int scrimColor = getScrimColor(context);
+        mColorScrim = scrimColor != -1 ? createColorScrim(context, scrimColor) : null;
     }
 
     protected void attachToContainer() {
@@ -120,8 +126,8 @@
             return false;
         }
 
-        int directionsToDetectScroll = mSwipeDetector.isIdleState() ?
-                SingleAxisSwipeDetector.DIRECTION_NEGATIVE : 0;
+        int directionsToDetectScroll = mSwipeDetector.isIdleState()
+                ? SingleAxisSwipeDetector.DIRECTION_NEGATIVE : 0;
         mSwipeDetector.setDetectableScrollConditions(
                 directionsToDetectScroll, false);
         mSwipeDetector.onTouchEvent(ev);
@@ -176,6 +182,11 @@
         }
     }
 
+    /** Registers an {@link OnCloseListener}. */
+    public void addOnCloseListener(OnCloseListener listener) {
+        mOnCloseListeners.add(listener);
+    }
+
     protected void handleClose(boolean animate, long defaultDuration) {
         if (!mIsOpen) {
             return;
@@ -210,10 +221,11 @@
         if (mColorScrim != null) {
             getPopupContainer().removeView(mColorScrim);
         }
+        mOnCloseListeners.forEach(OnCloseListener::onSlideInViewClosed);
     }
 
     protected BaseDragLayer getPopupContainer() {
-        return mLauncher.getDragLayer();
+        return mActivityContext.getDragLayer();
     }
 
     protected View createColorScrim(Context context, int bgColor) {
@@ -227,4 +239,15 @@
 
         return view;
     }
+
+    /**
+     * Interface to report that the {@link AbstractSlideInView} has closed.
+     */
+    public interface OnCloseListener {
+
+        /**
+         * Called when {@link AbstractSlideInView} closes.
+         */
+        void onSlideInViewClosed();
+    }
 }
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 81581fa..f973c2b 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -63,7 +63,7 @@
  */
 @TargetApi(Build.VERSION_CODES.Q)
 public class FloatingIconView extends FrameLayout implements
-        Animator.AnimatorListener, OnGlobalLayoutListener {
+        Animator.AnimatorListener, OnGlobalLayoutListener, FloatingView {
 
     private static final String TAG = FloatingIconView.class.getSimpleName();
 
@@ -443,6 +443,7 @@
         mFastFinishRunnable = runnable;
     }
 
+    @Override
     public void fastFinish() {
         if (mFastFinishRunnable != null) {
             mFastFinishRunnable.run();
@@ -475,9 +476,7 @@
     @Override
     public void onAnimationRepeat(Animator animator) {}
 
-    /**
-     * Offsets and updates the position of this view by {@param y}.
-     */
+    @Override
     public void setPositionOffsetY(float y) {
         mIconOffsetY = y;
         onGlobalLayout();
diff --git a/src/com/android/launcher3/views/FloatingView.java b/src/com/android/launcher3/views/FloatingView.java
new file mode 100644
index 0000000..ea4fd15
--- /dev/null
+++ b/src/com/android/launcher3/views/FloatingView.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.views;
+
+/**
+ * Shared interface for floating views.
+ */
+public interface FloatingView {
+
+    /**
+     * Offsets and updates the position of this view by {@param y}.
+     */
+    void setPositionOffsetY(float y);
+
+    /**
+     * Fast finish the animation.
+     */
+    void fastFinish();
+}
diff --git a/src/com/android/launcher3/views/WorkEduView.java b/src/com/android/launcher3/views/WorkEduView.java
index c8cf627..6be0c23 100644
--- a/src/com/android/launcher3/views/WorkEduView.java
+++ b/src/com/android/launcher3/views/WorkEduView.java
@@ -42,7 +42,7 @@
 /**
  * On boarding flow for users right after setting up work profile
  */
-public class WorkEduView extends AbstractSlideInView
+public class WorkEduView extends AbstractSlideInView<Launcher>
         implements Insettable, StateListener<LauncherState> {
 
     private static final int DEFAULT_CLOSE_DURATION = 200;
@@ -76,14 +76,15 @@
 
     @Override
     protected void handleClose(boolean animate) {
-        mLauncher.getSharedPrefs().edit().putInt(KEY_WORK_EDU_STEP, mNextWorkEduStep).apply();
+        mActivityContext.getSharedPrefs().edit()
+                .putInt(KEY_WORK_EDU_STEP, mNextWorkEduStep).apply();
         handleClose(true, DEFAULT_CLOSE_DURATION);
     }
 
     @Override
     protected void onCloseComplete() {
         super.onCloseComplete();
-        mLauncher.getStateManager().removeStateListener(this);
+        mActivityContext.getStateManager().removeStateListener(this);
     }
 
     @Override
@@ -116,13 +117,14 @@
             animator.addListener(new AnimationSuccessListener() {
                 @Override
                 public void onAnimationSuccess(Animator animator) {
-                    mContentText.setText(mLauncher.getString(R.string.work_profile_edu_work_apps));
+                    mContentText.setText(
+                            mActivityContext.getString(R.string.work_profile_edu_work_apps));
                     ObjectAnimator.ofFloat(mContentText, ALPHA, 1).start();
                 }
             });
             animator.start();
         } else {
-            mContentText.setText(mLauncher.getString(R.string.work_profile_edu_work_apps));
+            mContentText.setText(mActivityContext.getString(R.string.work_profile_edu_work_apps));
         }
         mNextWorkEduStep = WORK_EDU_WORK_APPS;
         mProceedButton.setOnClickListener(v -> handleClose(true));
@@ -142,7 +144,7 @@
     private void show() {
         attachToContainer();
         animateOpen();
-        mLauncher.getStateManager().addStateListener(this);
+        mActivityContext.getStateManager().addStateListener(this);
     }
 
     @Override
@@ -168,7 +170,7 @@
     }
 
     private AllAppsPagedView getAllAppsPagedView() {
-        View v = mLauncher.getAppsView().getContentView();
+        View v = mActivityContext.getAppsView().getContentView();
         return (v instanceof AllAppsPagedView) ? (AllAppsPagedView) v : null;
     }
 
diff --git a/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
new file mode 100644
index 0000000..9e08303
--- /dev/null
+++ b/src/com/android/launcher3/widget/AddItemWidgetsBottomSheet.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+
+import com.android.launcher3.Insettable;
+import com.android.launcher3.dragndrop.AddItemActivity;
+import com.android.launcher3.views.AbstractSlideInView;
+
+/**
+ * Bottom sheet for the pin widget.
+ */
+public class AddItemWidgetsBottomSheet extends AbstractSlideInView<AddItemActivity>
+        implements Insettable {
+
+    private static final int DEFAULT_CLOSE_DURATION = 200;
+
+    private Rect mInsets;
+    private Configuration mCurrentConfiguration;
+
+    public AddItemWidgetsBottomSheet(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AddItemWidgetsBottomSheet(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mContent = this;
+        mInsets = new Rect();
+        mCurrentConfiguration = new Configuration(getResources().getConfiguration());
+        animateOpen();
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        setTranslationShift(mTranslationShift);
+    }
+
+    private void animateOpen() {
+        if (mIsOpen || mOpenCloseAnimator.isRunning()) {
+            return;
+        }
+        mIsOpen = true;
+        mOpenCloseAnimator.setValues(
+                PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+        mOpenCloseAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+        mOpenCloseAnimator.start();
+    }
+
+    @Override
+    protected void handleClose(boolean animate) {
+        handleClose(animate, DEFAULT_CLOSE_DURATION);
+    }
+
+    @Override
+    protected boolean isOfType(@FloatingViewType int type) {
+        return (type & TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP) != 0;
+    }
+
+    @Override
+    public void setInsets(Rect insets) {
+        // Extend behind left, right, and bottom insets.
+        int leftInset = insets.left - mInsets.left;
+        int rightInset = insets.right - mInsets.right;
+        int bottomInset = insets.bottom - mInsets.bottom;
+        mInsets.set(insets);
+        setPadding(leftInset, getPaddingTop(), rightInset, bottomInset);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        if (mCurrentConfiguration.orientation != newConfig.orientation) {
+            mInsets.setEmpty();
+        }
+        mCurrentConfiguration.updateFrom(newConfig);
+    }
+}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index a7ecb07..f7e295e 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -28,6 +28,7 @@
 
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.dragndrop.DragOptions;
@@ -42,11 +43,10 @@
 /**
  * Base class for various widgets popup
  */
-public abstract class BaseWidgetSheet extends AbstractSlideInView
+public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
         implements OnClickListener, OnLongClickListener, DragSource,
         PopupDataProvider.PopupDataChangeListener {
 
-
     /* Touch handling related member variables. */
     private Toast mWidgetInstructionToast;
 
@@ -62,13 +62,13 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mLauncher.getPopupDataProvider().setChangeListener(this);
+        mActivityContext.getPopupDataProvider().setChangeListener(this);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mLauncher.getPopupDataProvider().setChangeListener(null);
+        mActivityContext.getPopupDataProvider().setChangeListener(null);
     }
 
     @Override
@@ -91,7 +91,7 @@
     public boolean onLongClick(View v) {
         TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick");
         v.cancelLongPress();
-        if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
+        if (!ItemLongClickListener.canStartDrag(mActivityContext)) return false;
 
         if (v instanceof WidgetCell) {
             return beginDraggingWidget((WidgetCell) v);
@@ -160,7 +160,7 @@
     }
 
     protected SystemUiController getSystemUiController() {
-        return mLauncher.getSystemUiController();
+        return mActivityContext.getSystemUiController();
     }
 
     /**
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 995ac47..787a2d1 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -83,7 +83,7 @@
         setWillNotDraw(false);
         mInsets = new Rect();
         mContent = this;
-        DeviceProfile deviceProfile = mLauncher.getDeviceProfile();
+        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         // Set the max table height to 2 / 3 of the grid height so that the bottom picker won't
         // take over the entire view vertically.
         mMaxTableHeight = deviceProfile.inv.numRows * 2 / 3  * deviceProfile.cellHeightPx;
@@ -97,7 +97,7 @@
         int paddingPx = 2 * getResources().getDimensionPixelOffset(
                 R.dimen.widget_cell_horizontal_padding);
         int maxHorizontalSpan = findViewById(R.id.widgets_table).getMeasuredWidth()
-                / (mLauncher.getDeviceProfile().cellWidthPx + paddingPx);
+                / (mActivityContext.getDeviceProfile().cellWidthPx + paddingPx);
 
         if (mMaxHorizontalSpan != maxHorizontalSpan) {
             // Ensure the table layout is showing widgets in the right column after measure.
@@ -134,7 +134,7 @@
 
     @Override
     public void onWidgetsBound() {
-        List<WidgetItem> widgets = mLauncher.getPopupDataProvider().getWidgetsForPackageUser(
+        List<WidgetItem> widgets = mActivityContext.getPopupDataProvider().getWidgetsForPackageUser(
                 new PackageUserKey(
                         mOriginalItemInfo.getTargetComponent().getPackageName(),
                         mOriginalItemInfo.user));
@@ -148,7 +148,7 @@
             row.forEach(widgetItem -> {
                 WidgetCell widget = addItemCell(tableRow);
                 widget.setPreviewSize(widgetItem.spanX, widgetItem.spanY);
-                widget.applyFromCellItem(widgetItem, LauncherAppState.getInstance(mLauncher)
+                widget.applyFromCellItem(widgetItem, LauncherAppState.getInstance(mActivityContext)
                         .getWidgetCache());
                 widget.ensurePreview();
                 widget.setVisibility(View.VISIBLE);
diff --git a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
index 317fd03..34346ab 100644
--- a/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
+++ b/src/com/android/launcher3/widget/picker/SearchAndRecommendationsScrollController.java
@@ -101,7 +101,7 @@
         mCurrentRecyclerView.setOnContentChangeListener(mOnContentChangeListener);
         mViewHolder.mHeaderTitle.setTranslationY(0);
         mViewHolder.mRecommendedWidgetsTable.setTranslationY(0);
-        mViewHolder.mSearchBar.setTranslationY(0);
+        mViewHolder.mSearchBarContainer.setTranslationY(0);
 
         if (mHasWorkProfile) {
             mPrimaryWorkTabsView.setTranslationY(0);
@@ -120,7 +120,7 @@
         mCollapsibleHeightForRecommendation =
                 measureHeightWithVerticalMargins(mViewHolder.mHeaderTitle)
                         + measureHeightWithVerticalMargins(mViewHolder.mCollapseHandle)
-                        + measureHeightWithVerticalMargins((View) mViewHolder.mSearchBar)
+                        + measureHeightWithVerticalMargins((View) mViewHolder.mSearchBarContainer)
                         + measureHeightWithVerticalMargins(mViewHolder.mRecommendedWidgetsTable);
 
         int topContainerHeight = measureHeightWithVerticalMargins(mViewHolder.mContainer);
@@ -243,7 +243,7 @@
 
         if (mCollapsibleHeightForSearch > 0) {
             int searchYDisplacement = Math.max(-recyclerViewYOffset, -mCollapsibleHeightForSearch);
-            mViewHolder.mSearchBar.setTranslationY(searchYDisplacement);
+            mViewHolder.mSearchBarContainer.setTranslationY(searchYDisplacement);
         }
 
         if (mHasWorkProfile && mCollapsibleHeightForTabs > 0) {
@@ -255,7 +255,7 @@
     /** Resets any previous view translation. */
     public void reset() {
         mViewHolder.mHeaderTitle.setTranslationY(0);
-        mViewHolder.mSearchBar.setTranslationY(0);
+        mViewHolder.mSearchBarContainer.setTranslationY(0);
         if (mHasWorkProfile) {
             mPrimaryWorkTabsView.setTranslationY(0);
         }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 4d8c1ca..e44acc3 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -207,7 +207,7 @@
         onWidgetsBound();
 
         mSearchAndRecommendationViewHolder.mSearchBar.initialize(
-                mLauncher.getPopupDataProvider(), /* searchModeListener= */ this);
+                mActivityContext.getPopupDataProvider(), /* searchModeListener= */ this);
 
         if (!hasSeenEducationTip()) {
             addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
@@ -271,7 +271,7 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mLauncher.getAppWidgetHost().addProviderChangeListener(this);
+        mActivityContext.getAppWidgetHost().addProviderChangeListener(this);
         notifyWidgetProvidersChanged();
         onRecommendedWidgetsBound();
     }
@@ -279,7 +279,7 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mLauncher.getAppWidgetHost().removeProviderChangeListener(this);
+        mActivityContext.getAppWidgetHost().removeProviderChangeListener(this);
     }
 
     @Override
@@ -327,7 +327,7 @@
     }
 
     private void doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        DeviceProfile deviceProfile = mLauncher.getDeviceProfile();
+        DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         int widthUsed;
         if (mInsets.bottom > 0) {
             widthUsed = mInsets.left + mInsets.right;
@@ -350,7 +350,7 @@
 
         int previousMaxSpansPerRow = mMaxSpansPerRow;
         mMaxSpansPerRow = getMeasuredWidth()
-                / (mLauncher.getDeviceProfile().cellWidthPx + mWidgetCellHorizontalPadding);
+                / (mActivityContext.getDeviceProfile().cellWidthPx + mWidgetCellHorizontalPadding);
 
         if (previousMaxSpansPerRow != mMaxSpansPerRow) {
             mAdapters.get(AdapterHolder.PRIMARY).mWidgetsListAdapter.setMaxHorizontalSpansPerRow(
@@ -383,7 +383,7 @@
 
     @Override
     public void notifyWidgetProvidersChanged() {
-        mLauncher.refreshAndBindWidgetsForPackageUser(null);
+        mActivityContext.refreshAndBindWidgetsForPackageUser(null);
     }
 
     @Override
@@ -391,7 +391,8 @@
         if (mIsInSearchMode) {
             return;
         }
-        List<WidgetsListBaseEntry> allWidgets = mLauncher.getPopupDataProvider().getAllWidgets();
+        List<WidgetsListBaseEntry> allWidgets =
+                mActivityContext.getPopupDataProvider().getAllWidgets();
 
         AdapterHolder primaryUserAdapterHolder = mAdapters.get(AdapterHolder.PRIMARY);
         primaryUserAdapterHolder.mWidgetsListAdapter.setWidgets(allWidgets);
@@ -468,12 +469,12 @@
             return;
         }
         List<WidgetItem> recommendedWidgets =
-                mLauncher.getPopupDataProvider().getRecommendedWidgets();
+                mActivityContext.getPopupDataProvider().getRecommendedWidgets();
         WidgetsRecommendationTableLayout table =
                 mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable;
         if (recommendedWidgets.size() > 0) {
             float maxTableHeight =
-                    (mLauncher.getDeviceProfile().availableHeightPx - mTabsHeight
+                    (mActivityContext.getDeviceProfile().availableHeightPx - mTabsHeight
                             - getHeaderViewHeight()) * RECOMMENDATION_TABLE_HEIGHT_RATIO;
             List<ArrayList<WidgetItem>> recommendedWidgetsInTable =
                     WidgetsTableUtils.groupWidgetItemsIntoTable(recommendedWidgets,
@@ -614,10 +615,11 @@
     }
 
     private void showEducationTipOnView(View view) {
-        mLauncher.getSharedPrefs().edit().putBoolean(WIDGETS_EDUCATION_TIP_SEEN, true).apply();
+        mActivityContext.getSharedPrefs().edit()
+                .putBoolean(WIDGETS_EDUCATION_TIP_SEEN, true).apply();
         int[] coords = new int[2];
         view.getLocationOnScreen(coords);
-        ArrowTipView arrowTipView = new ArrowTipView(mLauncher);
+        ArrowTipView arrowTipView = new ArrowTipView(mActivityContext);
         arrowTipView.showAtLocation(
                 getContext().getString(R.string.long_press_widget_to_add),
                 /* arrowXCoord= */coords[0] + view.getWidth() / 2,
@@ -653,7 +655,7 @@
     }
 
     private boolean hasSeenEducationTip() {
-        return mLauncher.getSharedPrefs().getBoolean(WIDGETS_EDUCATION_TIP_SEEN, false)
+        return mActivityContext.getSharedPrefs().getBoolean(WIDGETS_EDUCATION_TIP_SEEN, false)
                 || Utilities.IS_RUNNING_IN_TEST_HARNESS;
     }
 
@@ -711,6 +713,7 @@
     final class SearchAndRecommendationViewHolder {
         final SearchAndRecommendationsView mContainer;
         final View mCollapseHandle;
+        final View mSearchBarContainer;
         final WidgetsSearchBar mSearchBar;
         final TextView mHeaderTitle;
         final WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
@@ -719,6 +722,7 @@
                 SearchAndRecommendationsView searchAndRecommendationContainer) {
             mContainer = searchAndRecommendationContainer;
             mCollapseHandle = mContainer.findViewById(R.id.collapse_handle);
+            mSearchBarContainer = mContainer.findViewById(R.id.search_bar_container);
             mSearchBar = mContainer.findViewById(R.id.widgets_search_bar);
             mHeaderTitle = mContainer.findViewById(R.id.title);
             mRecommendedWidgetsTable = mContainer.findViewById(R.id.recommended_widget_table);
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index ca463e6..cbd9480 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -247,12 +247,26 @@
         return mDevice;
     }
 
+    private boolean hasSystemUiObject(String resId) {
+        return mDevice.hasObject(By.res(SYSTEMUI_PACKAGE, resId));
+    }
+
     @Before
     public void setUp() throws Exception {
         mLauncher.onTestStart();
-        Assert.assertTrue("Keyguard is visible, which is likely caused by a crash in SysUI",
+        Log.d(TAG, "Before disabling battery defender");
+        mDevice.executeShellCommand("setprop vendor.battery.defender.disable 1");
+        Log.d(TAG, "Before enabling stay awake");
+        mDevice.executeShellCommand("settings put global stay_on_while_plugged_in 3");
+        for (int i = 0; i < 10 && hasSystemUiObject("keyguard_status_view"); ++i) {
+            Log.d(TAG, "Before unlocking the phone");
+            mDevice.executeShellCommand("input keyevent 82");
+            mDevice.waitForIdle();
+        }
+        Assert.assertTrue("Keyguard still visible",
                 TestHelpers.wait(
                         Until.gone(By.res(SYSTEMUI_PACKAGE, "keyguard_status_view")), 60000));
+        Log.d(TAG, "Keyguard is not visible");
 
         final String launcherPackageName = mDevice.getLauncherPackageName();
         try {