Merge "Fix activity NPE when clearing flags" into sc-dev
diff --git a/go/quickstep/res/values/strings.xml b/go/quickstep/res/values/strings.xml
index 71e2f3a..61c8cd9 100644
--- a/go/quickstep/res/values/strings.xml
+++ b/go/quickstep/res/values/strings.xml
@@ -10,5 +10,5 @@
     <!-- Label for a button that translates a screenshot of the current app. [CHAR_LIMIT=40] -->
     <string name="action_translate">Translate</string>
     <!-- Label for a button that triggers Search on a screenshot of the current app. [CHAR_LIMIT=40] -->
-    <string name="action_search">Search</string>
+    <string name="action_search">Lens</string>
 </resources>
diff --git a/quickstep/res/layout/overview_clear_all_button.xml b/quickstep/res/layout/overview_clear_all_button.xml
index 34ff91d..c61610a 100644
--- a/quickstep/res/layout/overview_clear_all_button.xml
+++ b/quickstep/res/layout/overview_clear_all_button.xml
@@ -22,5 +22,4 @@
     android:layout_height="wrap_content"
     android:text="@string/recents_clear_all"
     android:textColor="?attr/workspaceTextColor"
-    android:textSize="14sp"
-    android:translationY="@dimen/task_thumbnail_half_top_margin" />
\ No newline at end of file
+    android:textSize="14sp" />
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 0f9a6aa..7e5b85c 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -13,6 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+<!-- NOTE! don't add dimensions for margins / paddings / sizes that change per orientation to this
+     file, they need to be loaded at runtime. -->
 <com.android.quickstep.views.TaskView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
@@ -24,8 +26,7 @@
     <com.android.quickstep.views.TaskThumbnailView
         android:id="@+id/snapshot"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:layout_marginTop="@dimen/task_thumbnail_top_margin"/>
+        android:layout_height="match_parent"/>
 
     <com.android.quickstep.views.IconView
         android:id="@+id/icon"
diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml
index c03eaa2..7cb01f6 100644
--- a/quickstep/res/values-land/dimens.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -16,4 +16,6 @@
 -->
 <resources>
     <dimen name="task_card_menu_horizontal_padding">24dp</dimen>
+
+    <dimen name="overview_task_margin">8dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 755bce8..3036341 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -15,11 +15,8 @@
 -->
 
 <resources>
-
-    <dimen name="task_thumbnail_top_margin">80dp</dimen>
-    <dimen name="task_thumbnail_half_top_margin">40dp</dimen>
     <dimen name="task_thumbnail_icon_size">48dp</dimen>
-    <dimen name="task_icon_top_margin">16dp</dimen>
+    <dimen name="task_thumbnail_icon_size_grid">32dp</dimen>
     <!-- For screens without rounded corners -->
     <dimen name="task_corner_radius_small">2dp</dimen>
 
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 9ab49ce..6ba7414 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -338,10 +338,6 @@
     @Override
     public void onDragLayerHierarchyChanged() {
         onLauncherStateOrFocusChanged();
-
-        if (mTaskbarController != null) {
-            mTaskbarController.onLauncherDragLayerHierarchyChanged();
-        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index fc5e2c1..5513c16 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -35,14 +35,13 @@
     private final DeviceProfile mDeviceProfile;
     private final LayoutInflater mLayoutInflater;
     private final TaskbarContainerView mTaskbarContainerView;
-    private final float mIconScale;
 
     public TaskbarActivityContext(BaseQuickstepLauncher launcher) {
         super(launcher);
         mDeviceProfile = launcher.getDeviceProfile().copy(this);
         float taskbarIconSize = getResources().getDimension(R.dimen.taskbar_icon_size);
-        mIconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
-        mDeviceProfile.updateIconSize(mIconScale, getResources());
+        float iconScale = taskbarIconSize / mDeviceProfile.iconSizePx;
+        mDeviceProfile.updateIconSize(iconScale, getResources());
 
         mLayoutInflater = LayoutInflater.from(this).cloneInContext(this);
 
@@ -73,11 +72,4 @@
     public Rect getFolderBoundingBox() {
         return mTaskbarContainerView.getFolderBoundingBox();
     }
-
-    /**
-     * @return The ratio of taskbar icon size vs normal workspace/hotseat icon size.
-     */
-    public float getTaskbarIconScale() {
-        return mIconScale;
-    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
index abf6d54..eccc41b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarController.java
@@ -151,13 +151,22 @@
                         ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
                                 ActivityOptions.makeBasic());
                     } else if (tag instanceof FolderInfo) {
-                        if (mLauncher.hasBeenResumed()) {
-                            FolderInfo folderInfo = (FolderInfo) tag;
-                            onClickedOnFolderFromHome(folderInfo);
-                        } else {
-                            FolderIcon folderIcon = (FolderIcon) view;
-                            onClickedOnFolderInApp(folderIcon);
-                        }
+                        FolderIcon folderIcon = (FolderIcon) view;
+                        Folder folder = folderIcon.getFolder();
+
+                        setTaskbarWindowFullscreen(true);
+
+                        mTaskbarContainerView.post(() -> {
+                            folder.animateOpen();
+
+                            folder.iterateOverItems((itemInfo, itemView) -> {
+                                itemView.setOnClickListener(getItemOnClickListener());
+                                itemView.setOnLongClickListener(getItemOnLongClickListener());
+                                // To play haptic when dragging, like other Taskbar items do.
+                                itemView.setHapticFeedbackEnabled(true);
+                                return false;
+                            });
+                        });
                     } else {
                         ItemClickHandler.INSTANCE.onClick(view);
                     }
@@ -167,44 +176,9 @@
                 };
             }
 
-            // Open the real folder in Launcher.
-            private void onClickedOnFolderFromHome(FolderInfo folderInfo) {
-                alignRealHotseatWithTaskbar();
-
-                FolderIcon folderIcon = (FolderIcon) mLauncher.getHotseat()
-                        .getFirstItemMatch((info, v) -> info == folderInfo);
-                folderIcon.post(folderIcon::performClick);
-            }
-
-            // Open the Taskbar folder, and handle clicks on folder items.
-            private void onClickedOnFolderInApp(FolderIcon folderIcon) {
-                Folder folder = folderIcon.getFolder();
-
-                setTaskbarWindowFullscreen(true);
-
-                mTaskbarContainerView.post(() -> {
-                    folder.animateOpen();
-
-                    folder.iterateOverItems((itemInfo, itemView) -> {
-                        itemView.setOnClickListener(getItemOnClickListener());
-                        itemView.setOnLongClickListener(getItemOnLongClickListener());
-                        // To play haptic when dragging, like other Taskbar items do.
-                        itemView.setHapticFeedbackEnabled(true);
-                        return false;
-                    });
-                });
-            }
-
             @Override
             public View.OnLongClickListener getItemOnLongClickListener() {
-                return view -> {
-                    if (mLauncher.hasBeenResumed() && view.getTag() instanceof ItemInfo) {
-                        // TODO: remove this path
-                        return mDragController.startWorkspaceDragOnLongClick(view);
-                    } else {
-                        return mDragController.startSystemDragOnLongClick(view);
-                    }
-                };
+                return mDragController::startSystemDragOnLongClick;
             }
 
             @Override
@@ -509,14 +483,6 @@
                 mTaskbarViewOnHome.getHeight() - hotseatBounds.bottom);
     }
 
-    /**
-     * A view was added or removed from DragLayer, check if we need to hide our hotseat copy and
-     * show the real one instead.
-     */
-    public void onLauncherDragLayerHierarchyChanged() {
-        // TODO: remove, as this is a no-op now
-    }
-
     private void updateWhichTaskbarViewIsVisible() {
         boolean isInApp = !mLauncher.hasBeenResumed() || mIsAnimatingToLauncher
                 || mIsAnimatingToApp;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index f51e498..5eb34cb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -33,7 +33,6 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
-import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.system.ClipDescriptionCompat;
@@ -126,38 +125,6 @@
     }
 
     /**
-     * Starts a drag and drop operation that controls a real Workspace (Hotseat) view.
-     * @param view The Taskbar item that was long clicked.
-     * @return Whether {@link View#startDragAndDrop} started successfully.
-     */
-    protected boolean startWorkspaceDragOnLongClick(View view) {
-        View.DragShadowBuilder transparentShadowBuilder = new View.DragShadowBuilder(view) {
-            private static final int ARBITRARY_SHADOW_SIZE = 10;
-
-            @Override
-            public void onDrawShadow(Canvas canvas) {
-            }
-
-            @Override
-            public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) {
-                outShadowSize.set(ARBITRARY_SHADOW_SIZE, ARBITRARY_SHADOW_SIZE);
-                outShadowTouchPoint.set(ARBITRARY_SHADOW_SIZE / 2, ARBITRARY_SHADOW_SIZE / 2);
-            }
-        };
-
-        TaskbarDragListener taskbarDragListener = new TaskbarDragListener(mLauncher,
-                (ItemInfo) view.getTag());
-        if (view.startDragAndDrop(new ClipData("", new String[] {taskbarDragListener.getMimeType()},
-                        new ClipData.Item("")),
-                transparentShadowBuilder, null /* localState */, View.DRAG_FLAG_GLOBAL)) {
-            view.setOnDragListener(getDraggedViewDragListener());
-            taskbarDragListener.init(mLauncher.getDragLayer());
-            return true;
-        }
-        return false;
-    }
-
-    /**
      * Hide the original Taskbar item while it is being dragged.
      */
     private View.OnDragListener getDraggedViewDragListener() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragListener.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragListener.java
deleted file mode 100644
index dc27df1..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragListener.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.launcher3.taskbar;
-
-import android.content.ClipDescription;
-import android.graphics.Point;
-import android.view.DragEvent;
-import android.view.View;
-
-import com.android.launcher3.BaseQuickstepLauncher;
-import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.model.data.ItemInfo;
-
-import java.util.UUID;
-
-/**
- * Listens to system drag and drop events initated by the Taskbar, and forwards them to Launcher's
- * internal DragController to move Hotseat items.
- */
-public class TaskbarDragListener implements View.OnDragListener {
-
-    private static final String MIME_TYPE_PREFIX = "com.android.launcher3.taskbar.drag_and_drop/";
-
-    private final BaseQuickstepLauncher mLauncher;
-    private final ItemInfo mDraggedItem;
-    // Randomly generated id used to verify the drag event.
-    private final String mId;
-
-    // Initialized in init().
-    DragLayer mDragLayer;
-
-    /**
-     * @param draggedItem The info of the item that was long clicked, which we will use to find
-     *                    the equivalent match on Hotseat to drag internally.
-     */
-    public TaskbarDragListener(BaseQuickstepLauncher launcher, ItemInfo draggedItem) {
-        mLauncher = launcher;
-        mDraggedItem = draggedItem;
-        mId = UUID.randomUUID().toString();
-    }
-
-    protected void init(DragLayer dragLayer) {
-        mDragLayer = dragLayer;
-        mDragLayer.setOnDragListener(this);
-        // Temporarily disable haptics, as system will already play one when drag and drop starts.
-        mDragLayer.setHapticFeedbackEnabled(false);
-    }
-
-    private void cleanup() {
-        mDragLayer.setOnDragListener(null);
-        mLauncher.setNextWorkspaceDragOptions(null);
-        mDragLayer.setHapticFeedbackEnabled(true);
-    }
-
-    /**
-     * Returns a randomly generated id used to verify the drag event.
-     */
-    protected String getMimeType() {
-        return MIME_TYPE_PREFIX + mId;
-    }
-
-    @Override
-    public boolean onDrag(View dragLayer, DragEvent dragEvent) {
-        ClipDescription clipDescription = dragEvent.getClipDescription();
-        if (dragEvent.getAction() == DragEvent.ACTION_DRAG_STARTED) {
-            if (clipDescription == null || !clipDescription.hasMimeType(getMimeType())) {
-                // We didn't initiate this drag, ignore.
-                cleanup();
-                return false;
-            }
-            View hotseatView = mLauncher.getHotseat().getFirstItemMatch(
-                    (info, view) -> info == mDraggedItem);
-            if (hotseatView == null) {
-                cleanup();
-                return false;
-            }
-            DragOptions dragOptions = new DragOptions();
-            dragOptions.simulatedDndStartPoint = new Point((int) dragEvent.getX(),
-                    (int) dragEvent.getY());
-            mLauncher.setNextWorkspaceDragOptions(dragOptions);
-            hotseatView.performLongClick();
-        } else if (dragEvent.getAction() == DragEvent.ACTION_DRAG_ENDED) {
-            cleanup();
-        }
-        return mLauncher.getDragController().onDragEvent(dragEvent);
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
index b4b5d8b..0a3819d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStateHandler.java
@@ -16,14 +16,12 @@
 package com.android.launcher3.taskbar;
 
 import static com.android.launcher3.LauncherState.TASKBAR;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_TASKBAR_FADE;
-import static com.android.launcher3.states.StateAnimationConfig.SKIP_TASKBAR;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
 
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.LauncherState;
-import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.states.StateAnimationConfig;
@@ -65,13 +63,9 @@
         if (mTaskbarCallbacks == null) {
             return;
         }
-        if (config.hasAnimationFlag(SKIP_TASKBAR)) {
-            return;
-        }
 
         AnimatedFloat alphaTarget = mTaskbarCallbacks.getAlphaTarget();
         boolean isTaskbarVisible = (toState.getVisibleElements(mLauncher) & TASKBAR) != 0;
-        animation.setFloat(alphaTarget, AnimatedFloat.VALUE, isTaskbarVisible ? 1f : 0f,
-                config.getInterpolator(ANIM_TASKBAR_FADE, Interpolators.LINEAR));
+        animation.setFloat(alphaTarget, AnimatedFloat.VALUE, isTaskbarVisible ? 1f : 0f, LINEAR);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java
index 2228eba..8745a7c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarVisibilityController.java
@@ -31,21 +31,18 @@
 public class TaskbarVisibilityController {
 
     private static final long IME_VISIBILITY_ALPHA_DURATION = 120;
-    private static final long FLOATING_VIEW_VISIBILITY_ALPHA_DURATION = 120;
 
     private final BaseQuickstepLauncher mLauncher;
     private final TaskbarController.TaskbarVisibilityControllerCallbacks mTaskbarCallbacks;
 
     // Background alpha.
-    private AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat(
+    private final AnimatedFloat mTaskbarBackgroundAlpha = new AnimatedFloat(
             this::onTaskbarBackgroundAlphaChanged);
 
     // Overall visibility.
-    private AnimatedFloat mTaskbarVisibilityAlphaForLauncherState = new AnimatedFloat(
+    private final AnimatedFloat mTaskbarVisibilityAlphaForLauncherState = new AnimatedFloat(
             this::updateVisibilityAlpha);
-    private AnimatedFloat mTaskbarVisibilityAlphaForIme = new AnimatedFloat(
-            this::updateVisibilityAlpha);
-    private AnimatedFloat mTaskbarVisibilityAlphaForFloatingView = new AnimatedFloat(
+    private final AnimatedFloat mTaskbarVisibilityAlphaForIme = new AnimatedFloat(
             this::updateVisibilityAlpha);
 
     public TaskbarVisibilityController(BaseQuickstepLauncher launcher,
@@ -62,7 +59,6 @@
         boolean isImeVisible = (SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags()
                 & QuickStepContract.SYSUI_STATE_IME_SHOWING) != 0;
         mTaskbarVisibilityAlphaForIme.updateValue(isImeVisible ? 0f : 1f);
-        mTaskbarVisibilityAlphaForFloatingView.updateValue(1f);
 
         onTaskbarBackgroundAlphaChanged();
         updateVisibilityAlpha();
@@ -86,11 +82,6 @@
                 .setDuration(IME_VISIBILITY_ALPHA_DURATION).start();
     }
 
-    protected void animateToVisibilityForFloatingView(float toAlpha) {
-        mTaskbarVisibilityAlphaForIme.animateToValue(mTaskbarVisibilityAlphaForFloatingView.value,
-                toAlpha).setDuration(FLOATING_VIEW_VISIBILITY_ALPHA_DURATION).start();
-    }
-
     private void onTaskbarBackgroundAlphaChanged() {
         mTaskbarCallbacks.updateTaskbarBackgroundAlpha(mTaskbarBackgroundAlpha.value);
         updateVisibilityAlpha();
@@ -102,8 +93,7 @@
         // LauncherState if Launcher is paused.
         float alphaDueToLauncher = Math.max(mTaskbarBackgroundAlpha.value,
                 mTaskbarVisibilityAlphaForLauncherState.value);
-        float alphaDueToOther = mTaskbarVisibilityAlphaForIme.value
-                * mTaskbarVisibilityAlphaForFloatingView.value;
+        float alphaDueToOther = mTaskbarVisibilityAlphaForIme.value;
         float taskbarAlpha = alphaDueToLauncher * alphaDueToOther;
         mTaskbarCallbacks.updateTaskbarVisibilityAlpha(taskbarAlpha);
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 473fe2d..de7be5d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -18,7 +18,6 @@
 import static android.view.View.VISIBLE;
 
 import static com.android.launcher3.LauncherState.HINT_STATE;
-import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.WorkspaceStateTransitionAnimation.getSpringScaleAnimator;
@@ -33,12 +32,10 @@
 import static com.android.launcher3.anim.Interpolators.clampToProgress;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_TASKBAR_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
@@ -82,7 +79,6 @@
         if (toState == NORMAL && fromState == OVERVIEW) {
             config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
             config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
-            config.setInterpolator(ANIM_TASKBAR_FADE, ACCEL);
             config.setInterpolator(ANIM_ALL_APPS_FADE, ACCEL);
             config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
             config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL_DEACCEL);
@@ -141,7 +137,6 @@
             config.setInterpolator(ANIM_DEPTH, OVERSHOOT_1_2);
             config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_2);
             config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, OVERSHOOT_1_2);
-            config.setInterpolator(ANIM_TASKBAR_FADE, OVERSHOOT_1_2);
         } else if (fromState == HINT_STATE && toState == NORMAL) {
             config.setInterpolator(ANIM_DEPTH, DEACCEL_3);
             if (mHintToNormalDuration == -1) {
@@ -150,17 +145,6 @@
                 mHintToNormalDuration = (int) va.getDuration();
             }
             config.duration = Math.max(config.duration, mHintToNormalDuration);
-        } else if (mActivity.getTaskbarController() != null)  {
-            boolean wasHotseatVisible = fromState.areElementsVisible(mActivity, HOTSEAT_ICONS);
-            boolean isHotseatVisible = toState.areElementsVisible(mActivity, HOTSEAT_ICONS);
-            if (wasHotseatVisible || isHotseatVisible) {
-                config.setInterpolator(ANIM_TASKBAR_FADE, INSTANT);
-                config.setInterpolator(ANIM_HOTSEAT_FADE, INSTANT);
-
-                if (isHotseatVisible) {
-                    mActivity.getTaskbarController().alignRealHotseatWithTaskbar();
-                }
-            }
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index b492825..f4ef1f7 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -923,6 +923,9 @@
         float currentShift = mCurrentShift.value;
         final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity,
                 isFling, isCancel);
+        // Set the state, but don't notify until the animation completes
+        mGestureState.setEndTarget(endTarget, false /* isAtomic */);
+
         float endShift = endTarget.isLauncher ? 1 : 0;
         final float startShift;
         if (!isFling) {
@@ -945,7 +948,7 @@
         }
         Interpolator interpolator;
         S state = mActivityInterface.stateFromGestureEndTarget(endTarget);
-        if (state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())) {
+        if (state.displayOverviewTasksAsGrid(mDp)) {
             interpolator = ACCEL_DEACCEL;
         } else if (endTarget == RECENTS) {
             interpolator = OVERSHOOT_1_2;
@@ -1055,8 +1058,6 @@
     @UiThread
     private void animateToProgressInternal(float start, float end, long duration,
             Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
-        // Set the state, but don't notify until the animation completes
-        mGestureState.setEndTarget(target, false /* isAtomic */);
         maybeUpdateRecentsAttachedState();
 
         // If we are transitioning to launcher, then listen for the activity to be restarted while
@@ -1147,10 +1148,8 @@
             });
             animatorSet.play(windowAnim);
             S state = mActivityInterface.stateFromGestureEndTarget(mGestureState.getEndTarget());
-            if (mRecentsView != null && state.displayOverviewTasksAsGrid(
-                    mActivity.getDeviceProfile())) {
+            if (mRecentsView != null && state.displayOverviewTasksAsGrid(mDp)) {
                 animatorSet.play(ObjectAnimator.ofFloat(mRecentsView, RECENTS_GRID_PROGRESS, 1));
-                animatorSet.play(mTaskViewSimulator.gridProgress.animateToValue(0, 1));
             }
             animatorSet.setDuration(duration).setInterpolator(interpolator);
             animatorSet.start();
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 5942b3a..0415009 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -31,6 +31,7 @@
 import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Build;
 import android.view.Gravity;
@@ -43,6 +44,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.statehandlers.DepthController;
 import com.android.launcher3.statemanager.BaseState;
 import com.android.launcher3.statemanager.StatefulActivity;
@@ -195,41 +197,53 @@
     }
 
     /**
-     * Calculates the taskView size for the provided device configuration
+     * Calculates the taskView size for the provided device configuration.
      */
     public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
             PagedOrientationHandler orientedState) {
         Resources res = context.getResources();
+        if (dp.isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
+            Rect gridRect = new Rect();
+            calculateGridSize(context, dp, gridRect);
 
-        int taskMargin = res.getDimensionPixelSize(R.dimen.overview_task_margin);
-        int taskIconAndMargin = res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_size)
-                + res.getDimensionPixelSize(R.dimen.task_icon_top_margin);
-        int proactiveRowAndMargin = res.getDimensionPixelSize(R.dimen.overview_proactive_row_height)
-                + res.getDimensionPixelSize(R.dimen.overview_proactive_row_bottom_margin);
+            int rowSpacing = res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
+            float rowHeight = (gridRect.height() - rowSpacing) / 2f;
 
-        calculateTaskSizeInternal(context, dp,
-                taskIconAndMargin + taskMargin,
-                proactiveRowAndMargin + getOverviewActionsHeight(context) + taskMargin,
-                res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
-                outRect);
+            PointF taskDimension = getTaskDimension(context, dp);
+            float scale = (rowHeight - dp.overviewTaskThumbnailTopMarginPx) / Math.max(
+                    taskDimension.x, taskDimension.y);
+            int outWidth = Math.round(scale * taskDimension.x);
+            int outHeight = Math.round(scale * taskDimension.y);
+
+            int gravity = Gravity.TOP;
+            gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
+            gridRect.inset(0, dp.overviewTaskThumbnailTopMarginPx, 0, 0);
+            Gravity.apply(gravity, outWidth, outHeight, gridRect, outRect);
+        } else {
+            int taskMargin = dp.overviewTaskMarginPx;
+            int proactiveRowAndMargin;
+            if (dp.isVerticalBarLayout()) {
+                // In Vertical Bar Layout the proactive row doesn't have its own space, it's inside
+                // the actions row.
+                proactiveRowAndMargin = 0;
+            } else {
+                proactiveRowAndMargin = res.getDimensionPixelSize(
+                        R.dimen.overview_proactive_row_height)
+                        + res.getDimensionPixelSize(R.dimen.overview_proactive_row_bottom_margin);
+            }
+            calculateTaskSizeInternal(context, dp,
+                    dp.overviewTaskThumbnailTopMarginPx,
+                    proactiveRowAndMargin + getOverviewActionsHeight(context) + taskMargin,
+                    res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
+                    outRect);
+        }
     }
 
     private void calculateTaskSizeInternal(Context context, DeviceProfile dp,
             int claimedSpaceAbove, int claimedSpaceBelow, int minimumHorizontalPadding,
             Rect outRect) {
-        float taskWidth, taskHeight;
+        PointF taskDimension = getTaskDimension(context, dp);
         Rect insets = dp.getInsets();
-        if (dp.isMultiWindowMode) {
-            WindowBounds bounds = SplitScreenBounds.INSTANCE.getSecondaryWindowBounds(context);
-            taskWidth = bounds.availableSize.x;
-            taskHeight = bounds.availableSize.y;
-        } else if (TaskView.CLIP_STATUS_AND_NAV_BARS) {
-            taskWidth = dp.availableWidthPx;
-            taskHeight = dp.availableHeightPx;
-        } else {
-            taskWidth = dp.widthPx;
-            taskHeight = dp.heightPx;
-        }
 
         Rect potentialTaskRect = new Rect(0, 0, dp.widthPx, dp.heightPx);
         potentialTaskRect.inset(insets.left, insets.top, insets.right, insets.bottom);
@@ -240,14 +254,30 @@
                 claimedSpaceBelow);
 
         float scale = Math.min(
-                potentialTaskRect.width() / taskWidth,
-                potentialTaskRect.height() / taskHeight);
-        int outWidth = Math.round(scale * taskWidth);
-        int outHeight = Math.round(scale * taskHeight);
+                potentialTaskRect.width() / taskDimension.x,
+                potentialTaskRect.height() / taskDimension.y);
+        int outWidth = Math.round(scale * taskDimension.x);
+        int outHeight = Math.round(scale * taskDimension.y);
 
         Gravity.apply(Gravity.CENTER, outWidth, outHeight, potentialTaskRect, outRect);
     }
 
+    private PointF getTaskDimension(Context context, DeviceProfile dp) {
+        PointF dimension = new PointF();
+        if (dp.isMultiWindowMode) {
+            WindowBounds bounds = SplitScreenBounds.INSTANCE.getSecondaryWindowBounds(context);
+            dimension.x = bounds.availableSize.x;
+            dimension.y = bounds.availableSize.y;
+        } else if (TaskView.CLIP_STATUS_AND_NAV_BARS) {
+            dimension.x = dp.availableWidthPx;
+            dimension.y = dp.availableHeightPx;
+        } else {
+            dimension.x = dp.widthPx;
+            dimension.y = dp.heightPx;
+        }
+        return dimension;
+    }
+
     /**
      * Calculates the overview grid size for the provided device configuration.
      */
@@ -267,13 +297,11 @@
      * Calculates the modal taskView size for the provided device configuration
      */
     public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
-        Resources res = context.getResources();
         calculateTaskSizeInternal(
                 context, dp,
-                res.getDimensionPixelSize(R.dimen.overview_task_margin),
-                getOverviewActionsHeight(context)
-                        + res.getDimensionPixelSize(R.dimen.overview_task_margin),
-                res.getDimensionPixelSize(R.dimen.overview_task_margin),
+                dp.overviewTaskMarginPx,
+                getOverviewActionsHeight(context) + dp.overviewTaskMarginPx,
+                dp.overviewTaskMarginPx,
                 outRect);
     }
 
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 7a428ce..79db842 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -22,6 +22,7 @@
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL;
 import static com.android.launcher3.anim.Interpolators.clampToProgress;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
 import static com.android.launcher3.statehandlers.DepthController.DEPTH;
@@ -200,8 +201,7 @@
             tsv.setPreview(targets.apps[targets.apps.length - 1]);
             tsv.fullScreenProgress.value = 0;
             tsv.recentsViewScale.value = 1;
-            tsv.gridProgress.value = gridProgress;
-            tsv.gridTranslationSecondary.value = gridTranslationSecondary;
+            tsv.taskSecondaryTranslation.value = gridTranslationSecondary;
             tsv.setScroll(startScroll);
 
             // Fade in the task during the initial 20% of the animation
@@ -214,7 +214,8 @@
                     AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
             out.setFloat(tsv.recentsViewScale,
                     AnimatedFloat.VALUE, tsv.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
-            out.setFloat(tsv.gridProgress, AnimatedFloat.VALUE, 0, TOUCH_RESPONSE_INTERPOLATOR);
+            out.setFloat(tsv.taskSecondaryTranslation, AnimatedFloat.VALUE, 0,
+                    TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL);
             out.setInt(tsv, TaskViewSimulator.SCROLL, 0, TOUCH_RESPONSE_INTERPOLATOR);
 
             TaskViewSimulator finalTsv = tsv;
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 3faf72a..d4ca31f 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -24,7 +24,6 @@
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_COMPONENTS;
 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_TASKBAR;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -83,34 +82,25 @@
 
         DeviceProfile grid = launcher.getDeviceProfile();
         Workspace workspace = launcher.getWorkspace();
-        CellLayout cellLayout = (CellLayout) workspace.getChildAt(workspace.getCurrentPage());
-        ShortcutAndWidgetContainer currentPage = cellLayout.getShortcutsAndWidgets();
         Hotseat hotseat = launcher.getHotseat();
 
+        // Hotseat and QSB takes up two additional rows.
+        int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
+
+        // Add animation for all the visible workspace pages
+        workspace.getVisiblePages()
+                .forEach(page -> addAnimationForPage((CellLayout) page, totalRows));
+
         boolean workspaceClipChildren = workspace.getClipChildren();
         boolean workspaceClipToPadding = workspace.getClipToPadding();
-        boolean cellLayoutClipChildren = cellLayout.getClipChildren();
-        boolean cellLayoutClipToPadding = cellLayout.getClipToPadding();
         boolean hotseatClipChildren = hotseat.getClipChildren();
         boolean hotseatClipToPadding = hotseat.getClipToPadding();
 
         workspace.setClipChildren(false);
         workspace.setClipToPadding(false);
-        cellLayout.setClipChildren(false);
-        cellLayout.setClipToPadding(false);
         hotseat.setClipChildren(false);
         hotseat.setClipToPadding(false);
 
-        // Hotseat and QSB takes up two additional rows.
-        int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
-
-        // Set up springs on workspace items.
-        for (int i = currentPage.getChildCount() - 1; i >= 0; i--) {
-            View child = currentPage.getChildAt(i);
-            CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
-            addStaggeredAnimationForView(child, lp.cellY + lp.cellVSpan, totalRows);
-        }
-
         // Set up springs for the hotseat and qsb.
         ViewGroup hotseatIcons = hotseat.getShortcutsAndWidgets();
         if (grid.isVerticalBarLayout()) {
@@ -155,21 +145,43 @@
             public void onAnimationEnd(Animator animation) {
                 workspace.setClipChildren(workspaceClipChildren);
                 workspace.setClipToPadding(workspaceClipToPadding);
-                cellLayout.setClipChildren(cellLayoutClipChildren);
-                cellLayout.setClipToPadding(cellLayoutClipToPadding);
                 hotseat.setClipChildren(hotseatClipChildren);
                 hotseat.setClipToPadding(hotseatClipToPadding);
             }
         });
     }
 
+    private void addAnimationForPage(CellLayout page, int totalRows) {
+        ShortcutAndWidgetContainer itemsContainer = page.getShortcutsAndWidgets();
+
+        boolean pageClipChildren = page.getClipChildren();
+        boolean pageClipToPadding = page.getClipToPadding();
+
+        page.setClipChildren(false);
+        page.setClipToPadding(false);
+
+        // Set up springs on workspace items.
+        for (int i = itemsContainer.getChildCount() - 1; i >= 0; i--) {
+            View child = itemsContainer.getChildAt(i);
+            CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams());
+            addStaggeredAnimationForView(child, lp.cellY + lp.cellVSpan, totalRows);
+        }
+
+        mAnimators.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                page.setClipChildren(pageClipChildren);
+                page.setClipToPadding(pageClipToPadding);
+            }
+        });
+    }
+
     /**
      * Setup workspace with 0 duration to prepare for our staggered animation.
      */
     private void prepareToAnimate(Launcher launcher, boolean animateOverviewScrim) {
         StateAnimationConfig config = new StateAnimationConfig();
-        config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER
-                | SKIP_TASKBAR;
+        config.animFlags = ANIM_ALL_COMPONENTS | SKIP_OVERVIEW | SKIP_DEPTH_CONTROLLER;
         config.duration = 0;
         // setRecentsAttachedToAppWindow() will animate recents out.
         launcher.getStateManager().createAtomicAnimation(BACKGROUND_APP, NORMAL, config).start();
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 8b5d498..6cfe302 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -15,7 +15,6 @@
  */
 package com.android.quickstep.util;
 
-import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
 import static com.android.launcher3.states.RotationHelper.deltaRotation;
 import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
 import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
@@ -36,7 +35,6 @@
 import androidx.annotation.NonNull;
 
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.touch.PagedOrientationHandler;
@@ -79,7 +77,6 @@
     private final boolean mIsRecentsRtl;
 
     private final Rect mTaskRect = new Rect();
-    private final Rect mGridRect = new Rect();
     private boolean mDrawsBelowRecents;
     private final PointF mPivot = new PointF();
     private DeviceProfile mDp;
@@ -98,22 +95,18 @@
     private final FullscreenDrawParams mCurrentFullscreenParams;
     public final AnimatedFloat taskPrimaryTranslation = new AnimatedFloat();
     public final AnimatedFloat taskSecondaryTranslation = new AnimatedFloat();
-    public final AnimatedFloat gridTranslationSecondary = new AnimatedFloat();
 
     // RecentsView properties
     public final AnimatedFloat recentsViewScale = new AnimatedFloat();
     public final AnimatedFloat fullScreenProgress = new AnimatedFloat();
     public final AnimatedFloat recentsViewSecondaryTranslation = new AnimatedFloat();
     public final AnimatedFloat recentsViewPrimaryTranslation = new AnimatedFloat();
-    public final AnimatedFloat gridProgress = new AnimatedFloat();
     private final ScrollState mScrollState = new ScrollState();
 
     // Cached calculations
     private boolean mLayoutValid = false;
     private boolean mScrollValid = false;
     private int mOrientationStateId;
-    private final int mTaskThumbnailPadding;
-    private final int mRowSpacing;
 
     public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
         mContext = context;
@@ -125,8 +118,6 @@
         mOrientationStateId = mOrientationState.getStateId();
         Resources resources = context.getResources();
         mIsRecentsRtl = mOrientationState.getOrientationHandler().getRecentsRtlSetting(resources);
-        mTaskThumbnailPadding = (int) resources.getDimension(R.dimen.task_thumbnail_top_margin);
-        mRowSpacing = (int) resources.getDimension(R.dimen.overview_grid_row_spacing);
     }
 
     /**
@@ -268,7 +259,6 @@
             mOrientationStateId = mOrientationState.getStateId();
 
             getFullScreenScale();
-            mSizeStrategy.calculateGridSize(mContext, mDp, mGridRect);
             mThumbnailData.rotation = mOrientationState.getDisplayRotation();
 
             // mIsRecentsRtl is the inverse of TaskView RTL.
@@ -309,34 +299,6 @@
         mMatrix.postTranslate(insets.left, insets.top);
         mMatrix.postScale(scale, scale);
 
-        // Apply TaskView matrix: gridProgress related properties
-        float interpolatedGridProgress = ACCEL_DEACCEL.getInterpolation(gridProgress.value);
-        final int boxLength = (int) Math.max(taskWidth, taskHeight);
-        float availableHeight = mGridRect.height();
-        float rowHeight = (availableHeight - mRowSpacing) / 2;
-        float gridScale = rowHeight / (boxLength + mTaskThumbnailPadding);
-        scale = Utilities.mapRange(interpolatedGridProgress, 1f, gridScale);
-        mMatrix.postScale(scale, scale, mIsRecentsRtl ? 0 : taskWidth, 0);
-        mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
-                Utilities.mapRange(interpolatedGridProgress, 0, gridTranslationSecondary.value));
-
-        // Apply TaskView matrix: task rect and grid rect difference
-        float scaledWidth = taskWidth * gridScale;
-        float taskGridHorizontalDiff;
-        if (mIsRecentsRtl) {
-            float taskRight = mTaskRect.left + scaledWidth;
-            taskGridHorizontalDiff = mGridRect.right - taskRight;
-        } else {
-            float taskLeft = mTaskRect.right - scaledWidth;
-            taskGridHorizontalDiff = mGridRect.left - taskLeft;
-        }
-        float taskGridVerticalDiff =
-                mGridRect.top + mTaskThumbnailPadding * gridScale - mTaskRect.top;
-        mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE,
-                Utilities.mapRange(interpolatedGridProgress, 0, taskGridHorizontalDiff));
-        mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
-                Utilities.mapRange(interpolatedGridProgress, 0, taskGridVerticalDiff));
-
         // Apply TaskView matrix: translate, scroll
         mMatrix.postTranslate(mTaskRect.left, mTaskRect.top);
         mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE,
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index e7101cc..12b59d0 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -21,6 +21,7 @@
 import android.util.FloatProperty;
 import android.widget.Button;
 
+import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.quickstep.views.RecentsView.PageCallbacks;
 import com.android.quickstep.views.RecentsView.ScrollState;
@@ -40,30 +41,32 @@
                 }
             };
 
+    private final StatefulActivity mActivity;
     private float mScrollAlpha = 1;
     private float mContentAlpha = 1;
     private float mVisibilityAlpha = 1;
     private float mGridProgress = 1;
 
     private boolean mIsRtl;
-    private final float mOriginalTranslationX, mOriginalTranslationY;
     private float mNormalTranslationPrimary;
     private float mGridTranslationPrimary;
+    private float mGridTranslationSecondary;
+    private float mGridScrollOffset;
+    private float mOffsetTranslationPrimary;
 
-    private int mScrollOffset;
+    private int mSidePadding;
 
     public ClearAllButton(Context context, AttributeSet attrs) {
         super(context, attrs);
         mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-        mOriginalTranslationX = getTranslationX();
-        mOriginalTranslationY = getTranslationY();
+        mActivity = StatefulActivity.fromContext(context);
     }
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
-        mScrollOffset = orientationHandler.getClearAllScrollOffset(getRecentsView(), mIsRtl);
+        mSidePadding = orientationHandler.getClearAllSidePadding(getRecentsView(), mIsRtl);
     }
 
     private RecentsView getRecentsView() {
@@ -96,25 +99,27 @@
     }
 
     @Override
-    public void onPageScroll(ScrollState scrollState) {
-        PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
+    public void onPageScroll(ScrollState scrollState, boolean gridEnabled) {
+        RecentsView recentsView = getRecentsView();
+        if (recentsView == null) {
+            return;
+        }
+
+        PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
         float orientationSize = orientationHandler.getPrimaryValue(getWidth(), getHeight());
         if (orientationSize == 0) {
             return;
         }
 
-        float shift;
-        if (mIsRtl) {
-            shift = Math.min(scrollState.scrollFromEdge, orientationSize);
-        } else {
-            shift = Math.min(scrollState.scrollFromEdge,
-                    orientationSize + getGridTrans(mGridTranslationPrimary))
-                    - getGridTrans(mGridTranslationPrimary);
+        int leftEdgeScroll = recentsView.getLeftMostChildScroll();
+        float adjustedScrollFromEdge = scrollState.scrollFromEdge - leftEdgeScroll;
+        float shift = Math.min(adjustedScrollFromEdge, orientationSize);
+        mNormalTranslationPrimary = mIsRtl ? -shift : shift;
+        if (!gridEnabled) {
+            mNormalTranslationPrimary += mSidePadding;
         }
-        mNormalTranslationPrimary = mIsRtl ? (mScrollOffset - shift) : (mScrollOffset + shift);
         applyPrimaryTranslation();
-        orientationHandler.getSecondaryViewTranslate().set(this,
-                orientationHandler.getSecondaryValue(mOriginalTranslationX, mOriginalTranslationY));
+        applySecondaryTranslation();
         mScrollAlpha = 1 - shift / orientationSize;
         updateAlpha();
     }
@@ -130,11 +135,26 @@
         applyPrimaryTranslation();
     }
 
+    public void setGridTranslationSecondary(float gridTranslationSecondary) {
+        mGridTranslationSecondary = gridTranslationSecondary;
+        applyPrimaryTranslation();
+    }
+
+    public void setGridScrollOffset(float gridScrollOffset) {
+        mGridScrollOffset = gridScrollOffset;
+    }
+
+    public void setOffsetTranslationPrimary(float offsetTranslationPrimary) {
+        mOffsetTranslationPrimary = offsetTranslationPrimary;
+        applyPrimaryTranslation();
+    }
+
     public float getScrollAdjustment(boolean gridEnabled) {
         float scrollAdjustment = 0;
         if (gridEnabled) {
-            scrollAdjustment += mGridTranslationPrimary;
+            scrollAdjustment += mGridTranslationPrimary + mGridScrollOffset;
         }
+        scrollAdjustment += mOffsetTranslationPrimary;
         return scrollAdjustment;
     }
 
@@ -160,10 +180,31 @@
 
         PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
         orientationHandler.getPrimaryViewTranslate().set(this,
-                mNormalTranslationPrimary + getGridTrans(mGridTranslationPrimary));
+                orientationHandler.getPrimaryValue(0f, getOriginalTranslationY())
+                        + mNormalTranslationPrimary + mOffsetTranslationPrimary + getGridTrans(
+                        mGridTranslationPrimary));
+    }
+
+    private void applySecondaryTranslation() {
+        RecentsView recentsView = getRecentsView();
+        if (recentsView == null) {
+            return;
+        }
+
+        PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
+        orientationHandler.getSecondaryViewTranslate().set(this,
+                orientationHandler.getSecondaryValue(0f, getOriginalTranslationY())
+                        + getGridTrans(mGridTranslationSecondary));
     }
 
     private float getGridTrans(float endTranslation) {
         return mGridProgress > 0 ? endTranslation : 0;
     }
+
+    /**
+     * Get the Y translation that is set in the original layout position, before scrolling.
+     */
+    private float getOriginalTranslationY() {
+        return mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx / 2.0f;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 1241982..6fcd54c 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -29,6 +29,7 @@
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
 import com.android.launcher3.util.MultiValueAlpha;
@@ -144,6 +145,7 @@
     public void setInsets(Rect insets) {
         mInsets.set(insets);
         updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
+        updateHorizontalPadding();
     }
 
     public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) {
@@ -187,6 +189,10 @@
         return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
     }
 
+    private void updateHorizontalPadding() {
+        setPadding(mInsets.left, 0, mInsets.right, 0);
+    }
+
     /** Updates vertical margins for different navigation mode or configuration changes. */
     public void updateVerticalMargin(Mode mode) {
         LayoutParams actionParams = (LayoutParams) findViewById(
@@ -196,6 +202,13 @@
                 getBottomVerticalMargin(mode));
     }
 
+    /**
+     * Set the device profile for this view to draw with.
+     */
+    public void setDp(DeviceProfile dp) {
+        requestLayout();
+    }
+
     protected int getBottomVerticalMargin(Mode mode) {
         int bottomMargin;
         int orientation = getResources().getConfiguration().orientation;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 3cdb1dc..d357ebe 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -301,6 +301,7 @@
     protected final Rect mTempRect = new Rect();
     protected final RectF mTempRectF = new RectF();
     private final PointF mTempPointF = new PointF();
+    private float mFullscreenScale;
 
     private static final int DISMISS_TASK_DURATION = 300;
     private static final int ADDITION_TASK_DURATION = 200;
@@ -310,7 +311,6 @@
     protected final T mActivity;
     private final float mFastFlingVelocity;
     private final RecentsModel mModel;
-    private final int mTaskTopMargin;
     private final int mRowSpacing;
     private final ClearAllButton mClearAllButton;
     private final Rect mClearAllButtonDeadZoneRect = new Rect();
@@ -529,8 +529,6 @@
 
         mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
         setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
-        mTaskTopMargin = getResources()
-                .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
         mRowSpacing = getResources().getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
         mSquaredTouchSlop = squaredTouchSlop(context);
 
@@ -744,7 +742,7 @@
         int taskStart = mOrientationHandler.getChildStart(tv) + (int) tv.getOffsetAdjustment(
                 mOverviewFullscreenEnabled, showAsGrid());
         int taskSize = (int) (mOrientationHandler.getMeasuredSize(tv) * tv.getSizeAdjustment(
-                mOverviewFullscreenEnabled, showAsGrid()));
+                mOverviewFullscreenEnabled));
         int taskEnd = taskStart + taskSize;
         return (taskStart >= start && taskStart <= end) || (taskEnd >= start
                 && taskEnd <= end);
@@ -1022,7 +1020,6 @@
             mLiveTileTaskViewSimulator.taskSecondaryTranslation.value = 0;
             mLiveTileTaskViewSimulator.fullScreenProgress.value = 0;
             mLiveTileTaskViewSimulator.recentsViewScale.value = 1;
-            mLiveTileTaskViewSimulator.gridProgress.value = 0;
         }
         if (mRunningTaskTileHidden) {
             setRunningTaskHidden(mRunningTaskTileHidden);
@@ -1066,7 +1063,9 @@
     public void setInsets(Rect insets) {
         mInsets.set(insets);
         resetPaddingFromTaskSize();
-        mLiveTileTaskViewSimulator.setDp(mActivity.getDeviceProfile());
+        DeviceProfile dp = mActivity.getDeviceProfile();
+        mLiveTileTaskViewSimulator.setDp(dp);
+        mActionsView.setDp(dp);
     }
 
     private void resetPaddingFromTaskSize() {
@@ -1075,7 +1074,7 @@
         mTaskWidth = mTempRect.width();
         mTaskHeight = mTempRect.height();
 
-        mTempRect.top -= mTaskTopMargin;
+        mTempRect.top -= dp.overviewTaskThumbnailTopMarginPx;
         setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top,
                 dp.widthPx - mInsets.right - mTempRect.right,
                 dp.heightPx - mInsets.bottom - mTempRect.bottom);
@@ -1092,6 +1091,10 @@
      */
     private void updateTaskSize() {
         final int taskCount = getTaskViewCount();
+        if (taskCount == 0) {
+            return;
+        }
+
         float accumulatedTranslationX = 0;
         float[] fullscreenTranslations = new float[taskCount];
         int firstNonHomeTaskIndex = 0;
@@ -1106,8 +1109,11 @@
 
             taskView.updateTaskSize();
             fullscreenTranslations[i] += accumulatedTranslationX;
+            // Compensate space caused by TaskView scaling.
             float widthDiff =
                     taskView.getLayoutParams().width * (1 - taskView.getFullscreenScale());
+            // Compensate page spacing widening caused by RecentsView scaling.
+            widthDiff += mPageSpacing * (1 - 1 / mFullscreenScale);
             float fullscreenTranslationX = mIsRtl ? widthDiff : -widthDiff;
             fullscreenTranslations[i] += fullscreenTranslationX;
             accumulatedTranslationX += fullscreenTranslationX;
@@ -1181,13 +1187,13 @@
             View page = getPageAt(i);
             mScrollState.updateInterpolation(mActivity.getDeviceProfile(),
                     mOrientationHandler.getChildStartWithTranslation(page));
-            ((PageCallbacks) page).onPageScroll(mScrollState);
+            ((PageCallbacks) page).onPageScroll(mScrollState, mOverviewGridEnabled);
         }
     }
 
     @Override
     protected int getDestinationPage(int scaledScroll) {
-        if (mGridProgress == 0) {
+        if (!showAsGrid()) {
             return super.getDestinationPage(scaledScroll);
         }
 
@@ -1600,10 +1606,7 @@
         }
 
         final int boxLength = Math.max(mTaskWidth, mTaskHeight);
-        float availableHeight = mLastComputedGridSize.height();
-        float rowHeight = (availableHeight - mRowSpacing) / 2;
-        float gridScale = rowHeight / (boxLength + mTaskTopMargin);
-
+        int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
         int topRowWidth = 0;
         int bottomRowWidth = 0;
         float topAccumulatedTranslationX = 0;
@@ -1621,43 +1624,17 @@
                 continue;
             }
 
-            taskView.setGridScale(gridScale);
-
-            float scaledWidth = taskView.getLayoutParams().width * gridScale;
-            float taskGridHorizontalDiff;
-            if (mIsRtl) {
-                float taskRight = mLastComputedTaskSize.left + scaledWidth;
-                taskGridHorizontalDiff = mLastComputedGridSize.right - taskRight;
-            } else {
-                float taskLeft = mLastComputedTaskSize.right - scaledWidth;
-                taskGridHorizontalDiff = mLastComputedGridSize.left - taskLeft;
-            }
-            gridTranslations[i] -= taskGridHorizontalDiff;
-            taskView.setGridOffsetTranslationX(taskGridHorizontalDiff);
-
-            float taskGridVerticalDiff = mLastComputedGridSize.top + mTaskTopMargin * gridScale
-                    - mLastComputedTaskSize.top;
-
-            // Off-set gap due to task scaling.
-            float widthDiff = taskView.getLayoutParams().width * (1 - gridScale);
-            float gridScaleTranslationX = mIsRtl ? widthDiff : -widthDiff;
-            gridTranslations[i] += gridScaleTranslationX;
-
-            // Visible offset caused by having scaling pivot on top-right.
-            taskView.setNonRtlVisibleOffset(mIsRtl ? 0 : widthDiff);
-
             if (topRowWidth <= bottomRowWidth) {
                 gridTranslations[i] += topAccumulatedTranslationX;
-                topRowWidth += taskView.getLayoutParams().width * gridScale + mPageSpacing;
+                topRowWidth += taskView.getLayoutParams().width + mPageSpacing;
                 topSet.add(i);
 
-                taskView.setGridTranslationY(taskGridVerticalDiff);
+                taskView.setGridTranslationY(0);
 
                 // Move horizontally into empty space.
                 float widthOffset = 0;
                 for (int j = i - 1; bottomSet.contains(j); j--) {
-                    widthOffset += getTaskViewAt(j).getLayoutParams().width * gridScale
-                            + mPageSpacing;
+                    widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
                 }
 
                 float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
@@ -1665,26 +1642,39 @@
                 topAccumulatedTranslationX += gridTranslationX;
             } else {
                 gridTranslations[i] += bottomAccumulatedTranslationX;
-                bottomRowWidth += taskView.getLayoutParams().width * gridScale + mPageSpacing;
+                bottomRowWidth += taskView.getLayoutParams().width + mPageSpacing;
                 bottomSet.add(i);
 
                 // Move into bottom row.
-                float heightOffset = (boxLength + mTaskTopMargin) * gridScale + mRowSpacing;
-                taskView.setGridTranslationY(heightOffset + taskGridVerticalDiff);
+                float heightOffset = (boxLength + taskTopMargin) + mRowSpacing;
+                taskView.setGridTranslationY(heightOffset);
 
                 // Move horizontally into empty space.
                 float widthOffset = 0;
                 for (int j = i - 1; topSet.contains(j); j--) {
-                    widthOffset += getTaskViewAt(j).getLayoutParams().width * gridScale
-                            + mPageSpacing;
+                    widthOffset += getTaskViewAt(j).getLayoutParams().width + mPageSpacing;
                 }
 
                 float gridTranslationX = mIsRtl ? widthOffset : -widthOffset;
                 gridTranslations[i] += gridTranslationX;
                 bottomAccumulatedTranslationX += gridTranslationX;
             }
-            topAccumulatedTranslationX += gridScaleTranslationX;
-            bottomAccumulatedTranslationX += gridScaleTranslationX;
+        }
+
+        // If the first non-home task does not take full width of task Rect, shift all tasks
+        // accordingly without affecting scrolls.
+        int firstTaskWidth = getTaskViewAt(firstNonHomeTaskIndex).getLayoutParams().width;
+        float firstNonHomeTaskOffset = firstTaskWidth == ViewGroup.LayoutParams.MATCH_PARENT ? 0
+                : mTaskWidth - firstTaskWidth;
+        float offsetTranslation = mIsRtl ? firstNonHomeTaskOffset : -firstNonHomeTaskOffset;
+
+        // We need to maintain first non-home task's grid translation at 0, now shift translation
+        // of all the TaskViews to achieve that.
+        for (int i = firstNonHomeTaskIndex; i < taskCount; i++) {
+            TaskView taskView = getTaskViewAt(i);
+            taskView.setGridTranslationX(
+                    gridTranslations[i] - gridTranslations[firstNonHomeTaskIndex]);
+            taskView.setGridOffsetTranslationX(offsetTranslation);
         }
 
         // Use the accumulated translation of the longer row.
@@ -1700,7 +1690,7 @@
                 shorterRowCompensation = bottomRowWidth - topRowWidth;
             }
         } else {
-            if (!topSet.contains(taskCount - 1)) {
+            if (bottomSet.contains(taskCount - 1)) {
                 shorterRowCompensation = topRowWidth - bottomRowWidth;
             }
         }
@@ -1721,14 +1711,14 @@
                 clearAllAccumulatedTranslation + clearAllShorterRowCompensation
                         + clearAllShortTotalCompensation;
 
-        // We need to maintain first non-home task's grid translation at 0, now shift translation
-        // of all the TaskViews to achieve that.
-        for (int i = firstNonHomeTaskIndex; i < taskCount; i++) {
-            getTaskViewAt(i).setGridTranslationX(
-                    gridTranslations[i] - gridTranslations[firstNonHomeTaskIndex]);
-        }
         mClearAllButton.setGridTranslationPrimary(
                 clearAllTotalTranslationX - gridTranslations[firstNonHomeTaskIndex]);
+        mClearAllButton.setGridTranslationSecondary(
+                boxLength - mTaskHeight / 2f + mRowSpacing / 2f);
+        mClearAllButton.setGridScrollOffset(
+                mIsRtl ? mLastComputedTaskSize.left - mLastComputedGridSize.left
+                        : mLastComputedTaskSize.right - mLastComputedGridSize.right);
+        mClearAllButton.setOffsetTranslationPrimary(offsetTranslation);
 
         setGridProgress(mGridProgress);
     }
@@ -1753,7 +1743,6 @@
         for (int i = 0; i < taskCount; i++) {
             getTaskViewAt(i).setGridProgress(gridProgress);
         }
-        mLiveTileTaskViewSimulator.gridProgress.value = gridProgress;
         mClearAllButton.setGridProgress(gridProgress);
     }
 
@@ -1801,8 +1790,10 @@
 
         /**
          * Updates the page UI based on scroll params.
+         *
+         * @param gridEnabled whether Overveiw is currently showing as 2 rows grid
          */
-        default void onPageScroll(ScrollState scrollState) {}
+        default void onPageScroll(ScrollState scrollState, boolean gridEnabled) {}
     }
 
     public static class ScrollState extends CurveProperties {
@@ -2297,7 +2288,7 @@
 
         // Update the pivots such that when the task is scaled, it fills the full page
         getTaskSize(mTempRect);
-        getPagedViewOrientedState().getFullScreenScaleAndPivot(
+        mFullscreenScale = getPagedViewOrientedState().getFullScreenScaleAndPivot(
                 mTempRect, mActivity.getDeviceProfile(), mTempPointF);
         setPivotX(mTempPointF.x);
         setPivotY(mTempPointF.y);
@@ -2485,7 +2476,7 @@
             if (child == mSplitHiddenTaskView) {
 
                 int left = newScroll[i] + getPaddingStart();
-                int topMargin = mSplitHiddenTaskView.getThumbnailTopMargin();
+                int topMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
                 int top = -mSplitHiddenTaskView.getHeight() - locationOnScreen[1];
                 mSplitHiddenTaskView.layout(left, top,
                         left + mSplitHiddenTaskView.getWidth(),
@@ -2858,22 +2849,42 @@
     @Override
     protected int computeMinScroll() {
         if (getTaskViewCount() > 0) {
-            if (mDisallowScrollToClearAll) {
+            if (mIsRtl && mDisallowScrollToClearAll) {
                 // We aren't showing the clear all button,
                 // so use the leftmost task as the min scroll.
-                if (mIsRtl) {
-                    return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
-                }
-                return getScrollForPage(mTaskViewStartIndex);
+                return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
             }
-            if (mIsRtl) {
-                return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
-            }
-            return getScrollForPage(mTaskViewStartIndex);
+            return getLeftMostChildScroll();
         }
         return super.computeMinScroll();
     }
 
+    /**
+     * Returns page scroll of the left most child.
+     */
+    public int getLeftMostChildScroll() {
+        if (mIsRtl) {
+            return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
+        }
+        return getScrollForPage(mTaskViewStartIndex);
+    }
+
+    @Override
+    protected int computeMaxScroll() {
+        if (getTaskViewCount() > 0) {
+            if (!mIsRtl && mDisallowScrollToClearAll) {
+                // We aren't showing the clear all button,
+                // so use the rightmost task as the min scroll.
+                return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
+            }
+            if (mIsRtl) {
+                return getScrollForPage(mTaskViewStartIndex);
+            }
+            return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
+        }
+        return super.computeMaxScroll();
+    }
+
     @Override
     protected boolean getPageScrolls(int[] outPageScrolls, boolean layoutChildren,
             ComputePageScrollsLogic scrollLogic) {
@@ -2919,26 +2930,7 @@
             return super.getChildVisibleSize(index);
         }
         return (int) (super.getChildVisibleSize(index) * taskView.getSizeAdjustment(
-                mOverviewFullscreenEnabled, showAsGrid()));
-    }
-
-    @Override
-    protected int computeMaxScroll() {
-        if (getTaskViewCount() > 0) {
-            if (mDisallowScrollToClearAll) {
-                // We aren't showing the clear all button,
-                // so use the rightmost task as the min scroll.
-                if (mIsRtl) {
-                    return getScrollForPage(mTaskViewStartIndex);
-                }
-                return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)));
-            }
-            if (mIsRtl) {
-                return getScrollForPage(mTaskViewStartIndex);
-            }
-            return getScrollForPage(indexOfChild(getTaskViewAt(getTaskViewCount() - 1)) + 1);
-        }
-        return super.computeMaxScroll();
+                mOverviewFullscreenEnabled));
     }
 
     public ClearAllButton getClearAllButton() {
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index a5b7a5b..a46daf3 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -58,7 +58,6 @@
     private static final int REVEAL_OPEN_DURATION = 150;
     private static final int REVEAL_CLOSE_DURATION = 100;
 
-    private final float mThumbnailTopMargin;
     private BaseDraggingActivity mActivity;
     private TextView mTaskName;
     private AnimatorSet mOpenCloseAnimator;
@@ -73,7 +72,6 @@
         super(context, attrs, defStyleAttr);
 
         mActivity = BaseDraggingActivity.fromContext(context);
-        mThumbnailTopMargin = getResources().getDimension(R.dimen.task_thumbnail_top_margin);
         setClipToOutline(true);
     }
 
@@ -123,14 +121,15 @@
     }
 
     public void setPosition(float x, float y, PagedOrientationHandler pagedOrientationHandler) {
-        float adjustedY = y + mThumbnailTopMargin;
+        int taskTopMargin = mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
+        float adjustedY = y + taskTopMargin;
         // Changing pivot to make computations easier
         // NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set,
         // which would render the X and Y position set here incorrect
         setPivotX(0);
         if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
             // In tablet, set pivotY to original position without mThumbnailTopMargin adjustment.
-            setPivotY(-mThumbnailTopMargin);
+            setPivotY(-taskTopMargin);
         } else {
             setPivotY(0);
         }
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index a2acab8..d497a96 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -279,7 +279,6 @@
     private float mFullscreenProgress;
     private float mGridProgress;
     private float mFullscreenScale = 1;
-    private float mGridScale = 1;
     private final FullscreenDrawParams mCurrentFullscreenParams;
     private final StatefulActivity mActivity;
 
@@ -298,7 +297,6 @@
     private float mGridTranslationY;
     // Offset translation does not affect scroll calculation.
     private float mGridOffsetTranslationX;
-    private float mNonRtlVisibleOffset;
 
     private ObjectAnimator mIconAndDimAnimator;
     private float mIconScaleAnimStartProgress = 0;
@@ -376,7 +374,8 @@
         mCurrentFullscreenParams = new FullscreenDrawParams(context);
         mDigitalWellBeingToast = new DigitalWellBeingToast(mActivity, this);
 
-        mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams);
+        mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams,
+                mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx);
         setOutlineProvider(mOutlineProvider);
     }
 
@@ -673,17 +672,14 @@
         }
     }
 
-    public int getThumbnailTopMargin() {
-        return (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
-    }
-
     public void setOrientationState(RecentsOrientedState orientationState) {
         PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
         boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
         LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
-        int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
-        int taskIconMargin = (int) getResources().getDimension(R.dimen.task_icon_top_margin);
-        int taskIconHeight = (int) getResources().getDimension(R.dimen.task_thumbnail_icon_size);
+        DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+        snapshotParams.topMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
+        int taskIconMargin = deviceProfile.overviewTaskMarginPx;
+        int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
         LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
         switch (orientationHandler.getRotation()) {
             case ROTATION_90:
@@ -694,7 +690,7 @@
                 break;
             case ROTATION_180:
                 iconParams.gravity = BOTTOM | CENTER_HORIZONTAL;
-                iconParams.bottomMargin = -thumbnailPadding;
+                iconParams.bottomMargin = -snapshotParams.topMargin;
                 iconParams.leftMargin = iconParams.rightMargin = 0;
                 iconParams.topMargin = taskIconMargin;
                 break;
@@ -711,8 +707,12 @@
                 iconParams.topMargin = taskIconMargin;
                 break;
         }
+        mSnapshotView.setLayoutParams(snapshotParams);
+        iconParams.width = iconParams.height = taskIconHeight;
         mIconView.setLayoutParams(iconParams);
         mIconView.setRotation(orientationHandler.getDegreesRotated());
+        snapshotParams.topMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
+        mSnapshotView.setLayoutParams(snapshotParams);
 
         if (mMenuView != null) {
             mMenuView.onRotationChanged();
@@ -792,8 +792,8 @@
 
     @Override
     public void onRecycle() {
-        mFullscreenTranslationX = mGridTranslationX = mGridTranslationY =
-                mGridOffsetTranslationX = mBoxTranslationY = mNonRtlVisibleOffset = 0f;
+        mFullscreenTranslationX = mGridTranslationX =
+                mGridTranslationY = mGridOffsetTranslationX = mBoxTranslationY = 0f;
         resetViewTransforms();
         // Clear any references to the thumbnail (it will be re-read either from the cache or the
         // system on next bind)
@@ -803,7 +803,7 @@
     }
 
     @Override
-    public void onPageScroll(ScrollState scrollState) {
+    public void onPageScroll(ScrollState scrollState, boolean gridEnabled) {
         // Don't do anything if it's modal.
         if (mModalness > 0) {
             return;
@@ -906,11 +906,6 @@
         return mFullscreenScale;
     }
 
-    public void setGridScale(float gridScale) {
-        mGridScale = gridScale;
-        applyScale();
-    }
-
     /**
      * Moves TaskView between carousel and 2 row grid.
      *
@@ -927,8 +922,6 @@
         float scale = 1;
         float fullScreenProgress = EXAGGERATED_EASE.getInterpolation(mFullscreenProgress);
         scale *= Utilities.mapRange(fullScreenProgress, 1f, mFullscreenScale);
-        float gridProgress = ACCEL_DEACCEL.getInterpolation(mGridProgress);
-        scale *= Utilities.mapRange(gridProgress, 1f, mGridScale);
         setScaleX(scale);
         setScaleY(scale);
     }
@@ -991,10 +984,6 @@
         applyTranslationX();
     }
 
-    public void setNonRtlVisibleOffset(float nonRtlVisibleOffset) {
-        mNonRtlVisibleOffset = nonRtlVisibleOffset;
-    }
-
     public float getScrollAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
         float scrollAdjustment = 0;
         if (fullscreenEnabled) {
@@ -1006,22 +995,19 @@
         return scrollAdjustment;
     }
 
-    public float getOffsetAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
+    public float getOffsetAdjustment(boolean fullscreenEnabled,boolean gridEnabled) {
         float offsetAdjustment = getScrollAdjustment(fullscreenEnabled, gridEnabled);
         if (gridEnabled) {
-            offsetAdjustment += mGridOffsetTranslationX + mNonRtlVisibleOffset;
+            offsetAdjustment += mGridOffsetTranslationX;
         }
         return offsetAdjustment;
     }
 
-    public float getSizeAdjustment(boolean fullscreenEnabled, boolean gridEnabled) {
+    public float getSizeAdjustment(boolean fullscreenEnabled) {
         float sizeAdjustment = 1;
         if (fullscreenEnabled) {
             sizeAdjustment *= mFullscreenScale;
         }
-        if (gridEnabled) {
-            sizeAdjustment *= mGridScale;
-        }
         return sizeAdjustment;
     }
 
@@ -1083,17 +1069,17 @@
 
     private static final class TaskOutlineProvider extends ViewOutlineProvider {
 
-        private final int mMarginTop;
+        private int mMarginTop;
         private FullscreenDrawParams mFullscreenParams;
 
-        TaskOutlineProvider(Context context, FullscreenDrawParams fullscreenParams) {
-            mMarginTop = context.getResources().getDimensionPixelSize(
-                    R.dimen.task_thumbnail_top_margin);
+        TaskOutlineProvider(Context context, FullscreenDrawParams fullscreenParams, int topMargin) {
+            mMarginTop = topMargin;
             mFullscreenParams = fullscreenParams;
         }
 
-        public void setFullscreenParams(FullscreenDrawParams params) {
+        public void updateParams(FullscreenDrawParams params, int topMargin) {
             mFullscreenParams = params;
+            mMarginTop = topMargin;
         }
 
         @Override
@@ -1216,7 +1202,9 @@
         }
 
         thumbnail.setFullscreenParams(mCurrentFullscreenParams);
-        mOutlineProvider.setFullscreenParams(mCurrentFullscreenParams);
+        mOutlineProvider.updateParams(
+                mCurrentFullscreenParams,
+                mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx);
         invalidateOutline();
     }
 
@@ -1238,8 +1226,8 @@
     void updateTaskSize() {
         ViewGroup.LayoutParams params = getLayoutParams();
         if (mActivity.getDeviceProfile().isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get()) {
-            final int thumbnailPadding = (int) getResources().getDimension(
-                    R.dimen.task_thumbnail_top_margin);
+            final int thumbnailPadding =
+                    mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
 
             Rect lastComputedTaskSize = getRecentsView().getLastComputedTaskSize();
             int taskWidth = lastComputedTaskSize.width();
diff --git a/res/drawable/gm_edit_24.xml b/res/drawable/gm_edit_24.xml
new file mode 100644
index 0000000..59a0dc2
--- /dev/null
+++ b/res/drawable/gm_edit_24.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M20.41,4.94l-1.35,-1.35c-0.78,-0.78 -2.05,-0.78 -2.83,0L3,16.82L3,21h4.18L20.41,7.77c0.79,-0.78 0.79,-2.05 0,-2.83zM6.41,19.06L5,19v-1.36l9.82,-9.82 1.41,1.41 -9.82,9.83z"/>
+</vector>
diff --git a/res/drawable/widget_reconfigure_button_frame.xml b/res/drawable/widget_reconfigure_button_frame.xml
new file mode 100644
index 0000000..37d93ad
--- /dev/null
+++ b/res/drawable/widget_reconfigure_button_frame.xml
@@ -0,0 +1,32 @@
+<?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
+        android:width="@dimen/widget_reconfigure_button_size"
+        android:height="@dimen/widget_reconfigure_button_size">
+        <shape
+            android:shape="rectangle">
+            <solid android:color="?android:attr/colorAccent" />
+            <corners android:radius="@dimen/widget_reconfigure_button_corner_radius" />
+        </shape>
+    </item>
+    <item
+        android:gravity="center"
+        android:padding="@dimen/widget_reconfigure_button_padding"
+        android:drawable="@drawable/gm_edit_24"
+        android:color="?android:attr/colorPrimary" />
+</layer-list>
diff --git a/res/layout/app_widget_resize_frame.xml b/res/layout/app_widget_resize_frame.xml
index 671dbc6..53db5ed 100644
--- a/res/layout/app_widget_resize_frame.xml
+++ b/res/layout/app_widget_resize_frame.xml
@@ -73,5 +73,17 @@
             android:src="@drawable/ic_widget_resize_handle"
             android:tint="?android:attr/colorAccent" />
 
+        <ImageButton
+            android:id="@+id/widget_reconfigure_button"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:padding="@dimen/widget_reconfigure_button_padding"
+            android:layout_gravity="bottom|end"
+            android:layout_marginBottom="@dimen/widget_reconfigure_button_margin"
+            android:layout_marginEnd="@dimen/widget_reconfigure_button_margin"
+            android:src="@drawable/widget_reconfigure_button_frame"
+            android:background="?android:attr/selectableItemBackground"
+            android:visibility="gone" />
+
     </FrameLayout>
 </com.android.launcher3.AppWidgetResizeFrame>
\ No newline at end of file
diff --git a/res/layout/widgets_search_bar.xml b/res/layout/widgets_search_bar.xml
index 1db7462..e3836df 100644
--- a/res/layout/widgets_search_bar.xml
+++ b/res/layout/widgets_search_bar.xml
@@ -32,5 +32,6 @@
         android:src="@drawable/ic_gm_close_24"
         android:background="?android:selectableItemBackground"
         android:layout_gravity="center"
+        android:contentDescription="@string/widgets_full_sheet_cancel_button_description"
         android:visibility="gone"/>
 </com.android.launcher3.widget.picker.search.LauncherWidgetsSearchBar>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index cf830c7..1fccdf3 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -56,6 +56,12 @@
     <dimen name="resize_frame_background_padding">24dp</dimen>
     <dimen name="resize_frame_margin">22dp</dimen>
 
+    <!-- App widget reconfigure button -->
+    <dimen name="widget_reconfigure_button_corner_radius">14dp</dimen>
+    <dimen name="widget_reconfigure_button_padding">6dp</dimen>
+    <dimen name="widget_reconfigure_button_margin">32dp</dimen>
+    <dimen name="widget_reconfigure_button_size">36dp</dimen>
+
 <!-- Fast scroll -->
     <dimen name="fastscroll_track_min_width">6dp</dimen>
     <dimen name="fastscroll_track_max_width">8dp</dimen>
@@ -286,4 +292,9 @@
     <!-- Size of the maximum radius for the enforced rounded rectangles. -->
     <dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
 
+<!-- Overview placeholder to compile in Launcer3 without Quickstep -->
+    <dimen name="task_thumbnail_icon_size">0dp</dimen>
+    <dimen name="task_thumbnail_icon_size_grid">0dp</dimen>
+    <dimen name="overview_task_margin">0dp</dimen>
+
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7c372830..e5e5db3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -81,6 +81,9 @@
     <!-- Search bar text shown in the popup view showing all available widgets installed on the
          device. [CHAR_LIMIT=50] -->
     <string name="widgets_full_sheet_search_bar_hint">Search</string>
+    <!-- Spoken text for screen readers. This text lets a user know that the button is used to clear
+         the text that the user entered in the search box. [CHAR_LIMIT=none] -->
+    <string name="widgets_full_sheet_cancel_button_description">Clear text from search box</string>
     <!-- Text shown when there is no widgets shown in the popup view showing all available widgets
          installed on the device. [CHAR_LIMIT=none] -->
     <string name="no_widgets_available">No widgets available</string>
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
index e1214ff..6b5678c 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
@@ -82,7 +82,7 @@
         mTestProfile.numColumns = 5;
         mUserHandle = Process.myUserHandle();
         mAdapter = new WidgetsListAdapter(mContext, mMockLayoutInflater, mMockWidgetCache,
-                mIconCache, null, null);
+                mIconCache, null, null, null);
         mAdapter.registerAdapterDataObserver(mListener);
 
         doAnswer(invocation -> ((ComponentWithLabel) invocation.getArgument(0))
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
index 84a03d5..12a092d 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
@@ -105,7 +105,8 @@
                 mWidgetPreviewLoader,
                 mIconCache,
                 /* iconClickListener= */ view -> {},
-                /* iconLongClickListener= */ view -> false);
+                /* iconLongClickListener= */ view -> false,
+                /* searchBarUIHelper= */ null);
         mViewHolderBinder = new WidgetsListHeaderViewHolderBinder(
                 LayoutInflater.from(mTestActivity), mOnHeaderClickListener, widgetsListAdapter);
     }
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
index 075c58d..e090341 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
@@ -105,7 +105,8 @@
                 mWidgetPreviewLoader,
                 mIconCache,
                 /* iconClickListener= */ view -> {},
-                /* iconLongClickListener= */ view -> false);
+                /* iconLongClickListener= */ view -> false,
+                /* searchBarUIHelper= */ null);
         mViewHolderBinder = new WidgetsListSearchHeaderViewHolderBinder(
                 LayoutInflater.from(mTestActivity), mOnHeaderClickListener, widgetsListAdapter);
     }
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index 0c6e717..0935d1c 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -111,7 +111,8 @@
                 mWidgetPreviewLoader,
                 mIconCache,
                 /* iconClickListener= */ view -> {},
-                /* iconLongClickListener= */ view -> false);
+                /* iconLongClickListener= */ view -> false,
+                /* searchBarUIHelper= */ null);
         mViewHolderBinder = new WidgetsListTableViewHolderBinder(
                 mContext,
                 LayoutInflater.from(mTestActivity),
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index d894bb4..95cdbdd 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -98,13 +98,6 @@
     public static final int TYPE_HIDE_BACK_BUTTON = TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
             | TYPE_SNACKBAR | TYPE_WIDGET_RESIZE_FRAME | TYPE_LISTENER;
 
-    // When these types of floating views are open, hide the taskbar hotseat and show the real one.
-    public static final int TYPE_REPLACE_TASKBAR_WITH_HOTSEAT = TYPE_FOLDER | TYPE_ACTION_POPUP;
-
-    // Hide the taskbar when these types of floating views are open.
-    public static final int TYPE_HIDE_TASKBAR = TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGETS_FULL_SHEET
-            | TYPE_ON_BOARD_POPUP;
-
     public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_LISTENER
             & ~TYPE_ALL_APPS_EDU;
 
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index ab91785..5d41bb5 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -22,6 +22,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 
 import androidx.annotation.Nullable;
@@ -74,6 +75,7 @@
     private LauncherAppWidgetHostView mWidgetView;
     private CellLayout mCellLayout;
     private DragLayer mDragLayer;
+    private ImageButton mReconfigureButton;
 
     private Rect mWidgetPadding;
 
@@ -211,6 +213,17 @@
             mDragHandles[INDEX_RIGHT].setVisibility(GONE);
         }
 
+        mReconfigureButton = (ImageButton) findViewById(R.id.widget_reconfigure_button);
+        if (info.isReconfigurable()) {
+            mReconfigureButton.setVisibility(VISIBLE);
+            mReconfigureButton.setOnClickListener(view -> mLauncher
+                    .getAppWidgetHost()
+                    .startConfigActivity(
+                            mLauncher,
+                            mWidgetView.getAppWidgetId(),
+                            Launcher.REQUEST_RECONFIGURE_APPWIDGET));
+        }
+
         // When we create the resize frame, we first mark all cells as unoccupied. The appropriate
         // cells (same if not resized, or different) will be marked as occupied when the resize
         // frame is dismissed.
@@ -582,6 +595,13 @@
         return false;
     }
 
+    private boolean isTouchOnReconfigureButton(MotionEvent ev) {
+        int xFrame = (int) ev.getX() - getLeft();
+        int yFrame = (int) ev.getY() - getTop();
+        mReconfigureButton.getHitRect(sTmpRect);
+        return sTmpRect.contains(xFrame, yFrame);
+    }
+
     @Override
     public boolean onControllerTouchEvent(MotionEvent ev) {
         int action = ev.getAction();
@@ -609,6 +629,11 @@
         if (ev.getAction() == MotionEvent.ACTION_DOWN && handleTouchDown(ev)) {
             return true;
         }
+        // Keep the resize frame open but let a click on the reconfigure button fall through to the
+        // button's OnClickListener.
+        if (isTouchOnReconfigureButton(ev)) {
+            return false;
+        }
         close(false);
         return false;
     }
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index fa19ee6..58d612d 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -151,6 +151,11 @@
     public int allAppsIconDrawablePaddingPx;
     public float allAppsIconTextSizePx;
 
+    // Overview
+    public int overviewTaskMarginPx;
+    public int overviewTaskIconSizePx;
+    public int overviewTaskThumbnailTopMarginPx;
+
     // Widgets
     public final PointF appWidgetScale = new PointF(1.0f, 1.0f);
 
@@ -297,6 +302,13 @@
                 : (hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx
                         + (isScalableGrid ? 0 : hotseatExtraVerticalSize)));
 
+        overviewTaskMarginPx = res.getDimensionPixelSize(R.dimen.overview_task_margin);
+        overviewTaskIconSizePx =
+                isTablet && FeatureFlags.ENABLE_OVERVIEW_GRID.get() ? res.getDimensionPixelSize(
+                        R.dimen.task_thumbnail_icon_size_grid) : res.getDimensionPixelSize(
+                        R.dimen.task_thumbnail_icon_size);
+        overviewTaskThumbnailTopMarginPx = overviewTaskIconSizePx + overviewTaskMarginPx * 2;
+
         // Calculate all of the remaining variables.
         extraSpace = updateAvailableDimensions(res);
         // Now that we have all of the variables calculated, we can tune certain sizes.
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 72eff62..76885cc 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -307,7 +307,7 @@
     /**
      * Returns the currently visible pages.
      */
-    protected Iterable<View> getVisiblePages() {
+    public Iterable<View> getVisiblePages() {
         int panelCount = getPanelCount();
         List<View> visiblePages = new ArrayList<>(panelCount);
         for (int i = mCurrentPage; i < mCurrentPage + panelCount; i++) {
@@ -1512,17 +1512,16 @@
         return getDestinationPage(mOrientationHandler.getPrimaryScroll(this));
     }
 
-    protected int getDestinationPage(int scaledScroll) {
-        return getPageNearestToCenterOfScreen(scaledScroll);
+    protected int getDestinationPage(int primaryScroll) {
+        return getPageNearestToCenterOfScreen(primaryScroll);
     }
 
     public int getPageNearestToCenterOfScreen() {
         return getPageNearestToCenterOfScreen(mOrientationHandler.getPrimaryScroll(this));
     }
 
-    private int getPageNearestToCenterOfScreen(int scaledScroll) {
-        int pageOrientationSize = mOrientationHandler.getMeasuredSize(this);
-        int screenCenter = scaledScroll + (pageOrientationSize / 2);
+    private int getPageNearestToCenterOfScreen(int primaryScroll) {
+        int screenCenter = getScreenCenter(primaryScroll);
         int minDistanceFromScreenCenter = Integer.MAX_VALUE;
         int minDistanceFromScreenCenterIndex = -1;
         final int childCount = getChildCount();
@@ -1538,18 +1537,26 @@
     }
 
     private int getDisplacementFromScreenCenter(int childIndex, int screenCenter) {
-        int childSize = getChildVisibleSize(childIndex);
+        int childSize = Math.round(getChildVisibleSize(childIndex));
         int halfChildSize = (childSize / 2);
         int childCenter = getChildOffset(childIndex) + halfChildSize;
         return childCenter - screenCenter;
     }
 
     protected int getDisplacementFromScreenCenter(int childIndex) {
-        int pageOrientationSize = mOrientationHandler.getMeasuredSize(this);
-        int screenCenter = mOrientationHandler.getPrimaryScroll(this) + (pageOrientationSize / 2);
+        int primaryScroll = mOrientationHandler.getPrimaryScroll(this);
+        int screenCenter = getScreenCenter(primaryScroll);
         return getDisplacementFromScreenCenter(childIndex, screenCenter);
     }
 
+    private int getScreenCenter(int primaryScroll) {
+        float primaryScale = mOrientationHandler.getPrimaryScale(this);
+        float primaryPivot =  mOrientationHandler.getPrimaryValue(getPivotX(), getPivotY());
+        int pageOrientationSize = mOrientationHandler.getMeasuredSize(this);
+        return Math.round(primaryScroll + (pageOrientationSize / 2f - primaryPivot) / primaryScale
+                + primaryPivot);
+    }
+
     protected void snapToDestination() {
         snapToPage(getDestinationPage(), getPageSnapDuration());
     }
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 6db7a75..16e022c 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -34,7 +34,6 @@
 import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
 import static com.android.launcher3.graphics.Scrim.SCRIM_PROGRESS;
 import static com.android.launcher3.graphics.SysUiScrim.SYSUI_PROGRESS;
-import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
 import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
@@ -133,8 +132,7 @@
             }
 
             float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
-            propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha,
-                    config.getInterpolator(ANIM_HOTSEAT_FADE, fadeInterpolator));
+            propertySetter.setViewAlpha(hotseat, hotseatIconsAlpha, fadeInterpolator);
             float workspacePageIndicatorAlpha = (elements & WORKSPACE_PAGE_INDICATOR) != 0 ? 1 : 0;
             propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
                     workspacePageIndicatorAlpha, fadeInterpolator);
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 6b9ed09..7980138 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -77,6 +77,9 @@
 
     public static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
             new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+    public static final Interpolator TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL =
+            v -> ACCEL_DEACCEL.getInterpolation(TOUCH_RESPONSE_INTERPOLATOR.getInterpolation(v));
+
 
     /**
      * Inversion of ZOOM_OUT, compounded with an ease-out.
diff --git a/src/com/android/launcher3/states/StateAnimationConfig.java b/src/com/android/launcher3/states/StateAnimationConfig.java
index e4c67ee..cd74390 100644
--- a/src/com/android/launcher3/states/StateAnimationConfig.java
+++ b/src/com/android/launcher3/states/StateAnimationConfig.java
@@ -38,7 +38,6 @@
             PLAY_ATOMIC_OVERVIEW_PEEK,
             SKIP_OVERVIEW,
             SKIP_DEPTH_CONTROLLER,
-            SKIP_TASKBAR,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AnimationFlags {}
@@ -47,7 +46,6 @@
     public static final int PLAY_ATOMIC_OVERVIEW_PEEK = 1 << 2;
     public static final int SKIP_OVERVIEW = 1 << 3;
     public static final int SKIP_DEPTH_CONTROLLER = 1 << 4;
-    public static final int SKIP_TASKBAR = 1 << 5;
 
     public long duration;
     public boolean userControlled;
@@ -74,8 +72,6 @@
             ANIM_OVERVIEW_MODAL,
             ANIM_DEPTH,
             ANIM_OVERVIEW_ACTIONS_FADE,
-            ANIM_TASKBAR_FADE,
-            ANIM_HOTSEAT_FADE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface AnimType {}
@@ -95,10 +91,8 @@
     public static final int ANIM_OVERVIEW_MODAL = 13;
     public static final int ANIM_DEPTH = 14;
     public static final int ANIM_OVERVIEW_ACTIONS_FADE = 15;
-    public static final int ANIM_TASKBAR_FADE = 16;
-    public static final int ANIM_HOTSEAT_FADE = 17; // if not set, falls back to ANIM_WORKSPACE_FADE
 
-    private static final int ANIM_TYPES_COUNT = 18;
+    private static final int ANIM_TYPES_COUNT = 16;
 
     protected final Interpolator[] mInterpolators = new Interpolator[ANIM_TYPES_COUNT];
 
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index c1cf0c8..19dfe15 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -136,7 +136,7 @@
     }
 
     @Override
-    public int getClearAllScrollOffset(View view, boolean isRtl) {
+    public int getClearAllSidePadding(View view, boolean isRtl) {
         return (isRtl ? view.getPaddingBottom() : - view.getPaddingTop()) / 2;
     }
 
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index fcfa205..9140a04 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -66,7 +66,7 @@
     float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId);
     int getMeasuredSize(View view);
     float getPrimarySize(RectF rect);
-    int getClearAllScrollOffset(View view, boolean isRtl);
+    int getClearAllSidePadding(View view, boolean isRtl);
     int getSecondaryDimension(View view);
     FloatProperty<View> getPrimaryViewTranslate();
     FloatProperty<View> getSecondaryViewTranslate();
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 2bc2dc7..29be627 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -132,7 +132,7 @@
     }
 
     @Override
-    public int getClearAllScrollOffset(View view, boolean isRtl) {
+    public int getClearAllSidePadding(View view, boolean isRtl) {
         return (isRtl ? view.getPaddingRight() : - view.getPaddingLeft()) / 2;
     }
 
diff --git a/src/com/android/launcher3/util/MultiValueAlpha.java b/src/com/android/launcher3/util/MultiValueAlpha.java
index 0ea0290..5be9529 100644
--- a/src/com/android/launcher3/util/MultiValueAlpha.java
+++ b/src/com/android/launcher3/util/MultiValueAlpha.java
@@ -42,43 +42,16 @@
                 }
             };
 
-    /**
-     * Determines how each alpha should factor into the final alpha.
-     */
-    public enum Mode {
-        BLEND() {
-            @Override
-            public float calculateNewAlpha(float currentAlpha, float otherAlpha) {
-                return currentAlpha * otherAlpha;
-            }
-        },
-
-        MAX() {
-            @Override
-            public float calculateNewAlpha(float currentAlpha, float otherAlpha) {
-                return Math.max(currentAlpha, otherAlpha);
-            }
-        };
-
-        protected abstract float calculateNewAlpha(float currentAlpha, float otherAlpha);
-    }
-
     private final View mView;
     private final AlphaProperty[] mMyProperties;
-    private final Mode mMode;
 
     private int mValidMask;
     // Whether we should change from INVISIBLE to VISIBLE and vice versa at low alpha values.
     private boolean mUpdateVisibility;
 
     public MultiValueAlpha(View view, int size) {
-        this(view, size, Mode.BLEND);
-    }
-
-    public MultiValueAlpha(View view, int size, Mode mode) {
         mView = view;
         mMyProperties = new AlphaProperty[size];
-        mMode = mode;
 
         mValidMask = 0;
         for (int i = 0; i < size; i++) {
@@ -124,7 +97,7 @@
                 mOthers = 1;
                 for (AlphaProperty prop : mMyProperties) {
                     if (prop != this) {
-                        mOthers = mMode.calculateNewAlpha(mOthers, prop.mValue);
+                        mOthers *= prop.mValue;
                     }
                 }
             }
@@ -134,7 +107,7 @@
             mValidMask = mMyMask;
             mValue = value;
 
-            mView.setAlpha(mMode.calculateNewAlpha(mOthers, mValue));
+            mView.setAlpha(mOthers * mValue);
             if (mUpdateVisibility) {
                 AlphaUpdateListener.updateVisibility(mView);
             }
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
index 8689fbf..ad61495 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
@@ -139,6 +139,10 @@
         }
     }
 
+    public boolean isReconfigurable() {
+        return configure != null && (getWidgetFeatures() & WIDGET_FEATURE_RECONFIGURABLE) != 0;
+    }
+
     @Override
     public final ComponentName getComponent() {
         return provider;
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 2fda86c..bbb0d92 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -26,6 +26,7 @@
 import android.util.Pair;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
@@ -152,6 +153,19 @@
         });
     }
 
+    @Override
+    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mNoIntercept = false;
+            ScrollView scrollView = findViewById(R.id.widgets_table_scroll_view);
+            if (getPopupContainer().isEventOverView(scrollView, ev)
+                    && scrollView.getScrollY() > 0) {
+                mNoIntercept = true;
+            }
+        }
+        return super.onControllerInterceptTouchEvent(ev);
+    }
+
     protected WidgetCell addItemCell(ViewGroup parent) {
         WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext())
                 .inflate(R.layout.widget_cell, parent, false);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index f43f712..29c00b2 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -34,6 +34,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowInsets;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.TextView;
@@ -57,6 +58,7 @@
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.picker.search.SearchModeListener;
 import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
+import com.android.launcher3.widget.picker.search.WidgetsSearchBarUIHelper;
 import com.android.launcher3.widget.util.WidgetsTableUtils;
 import com.android.launcher3.workprofile.PersonalWorkPagedView;
 import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
@@ -70,7 +72,8 @@
  */
 public class WidgetsFullSheet extends BaseWidgetSheet
         implements Insettable, ProviderChangedListener, OnActivePageChangedListener,
-        WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener {
+        WidgetsRecyclerView.HeaderViewDimensionsProvider, SearchModeListener,
+        WidgetsSearchBarUIHelper {
     private static final String TAG = WidgetsFullSheet.class.getSimpleName();
 
     private static final long DEFAULT_OPEN_DURATION = 267;
@@ -554,6 +557,17 @@
         return super.onBackPressed();
     }
 
+    @Override
+    public void onDragStart(boolean start, float startDisplacement) {
+        super.onDragStart(start, startDisplacement);
+        getWindowInsetsController().hide(WindowInsets.Type.ime());
+    }
+
+    @Override
+    public void clearSearchBarFocus() {
+        mSearchAndRecommendationViewHolder.mSearchBar.clearSearchBarFocus();
+    }
+
     /** A holder class for holding adapters & their corresponding recycler view. */
     private final class AdapterHolder {
         static final int PRIMARY = 0;
@@ -576,7 +590,9 @@
                     apps.getWidgetCache(),
                     apps.getIconCache(),
                     /* iconClickListener= */ WidgetsFullSheet.this,
-                    /* iconLongClickListener= */ WidgetsFullSheet.this);
+                    /* iconLongClickListener= */ WidgetsFullSheet.this,
+                    /* WidgetsSearchBarUIHelper= */
+                    mAdapterType == SEARCH ? WidgetsFullSheet.this : null);
             mWidgetsListAdapter.setHasStableIds(true);
             switch (mAdapterType) {
                 case PRIMARY:
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index d841c64..d9c9d4d 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -41,6 +41,7 @@
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
 import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
+import com.android.launcher3.widget.picker.search.WidgetsSearchBarUIHelper;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -69,6 +70,7 @@
     private static final int VIEW_TYPE_WIDGETS_HEADER = R.id.view_type_widgets_header;
     private static final int VIEW_TYPE_WIDGETS_SEARCH_HEADER = R.id.view_type_widgets_search_header;
 
+    @Nullable private final WidgetsSearchBarUIHelper mSearchBarUIHelper;
     private final WidgetsDiffReporter mDiffReporter;
     private final SparseArray<ViewHolderBinder> mViewHolderBinders = new SparseArray<>();
     private final WidgetsListTableViewHolderBinder mWidgetsListTableViewHolderBinder;
@@ -88,7 +90,9 @@
 
     public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
             WidgetPreviewLoader widgetPreviewLoader, IconCache iconCache,
-            OnClickListener iconClickListener, OnLongClickListener iconLongClickListener) {
+            OnClickListener iconClickListener, OnLongClickListener iconLongClickListener,
+            @Nullable WidgetsSearchBarUIHelper searchBarUIHelper) {
+        mSearchBarUIHelper = searchBarUIHelper;
         mDiffReporter = new WidgetsDiffReporter(iconCache, this);
         mWidgetsListTableViewHolderBinder = new WidgetsListTableViewHolderBinder(context,
                 layoutInflater, iconClickListener, iconLongClickListener,
@@ -237,6 +241,9 @@
 
     @Override
     public void onHeaderClicked(boolean showWidgets, PackageUserKey packageUserKey) {
+        if (mSearchBarUIHelper != null) {
+            mSearchBarUIHelper.clearSearchBarFocus();
+        }
         if (showWidgets) {
             mWidgetsContentVisiblePackageUserKey = packageUserKey;
             updateVisibleEntries();
diff --git a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
index cc33619..56a08b1 100644
--- a/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
+++ b/src/com/android/launcher3/widget/picker/search/LauncherWidgetsSearchBar.java
@@ -79,4 +79,9 @@
         super.onDetachedFromWindow();
         mController.onDestroy();
     }
+
+    @Override
+    public void clearSearchBarFocus() {
+        mController.clearFocus();
+    }
 }
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
index ef7bf23..3ac82c0 100644
--- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
+++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBar.java
@@ -35,6 +35,11 @@
     void reset();
 
     /**
+     * Clears focus from search bar.
+     */
+    void clearSearchBarFocus();
+
+    /**
      * Sets the vertical location, in pixels, of this search bar relative to its top position.
      */
     void setTranslationY(float translationY);
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
index 6011097..d35a75b 100644
--- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
+++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
@@ -103,8 +103,7 @@
     public void clearSearchResult() {
         mSearchAlgorithm.cancel(/* interruptActiveRequests= */ true);
         mInput.getText().clear();
-        mInput.clearFocus();
-        mInput.hideKeyboard();
+        clearFocus();
         mSearchModeListener.exitSearchMode();
     }
 
@@ -117,18 +116,24 @@
 
     @Override
     public boolean onBackKey() {
-        mInput.clearFocus();
-        mInput.hideKeyboard();
+        clearFocus();
         return true;
     }
 
     @Override
     public boolean onKey(View view, int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) {
-            mInput.clearFocus();
-            mInput.hideKeyboard();
+            clearFocus();
             return true;
         }
         return false;
     }
+
+    /**
+     * Clears focus from edit text.
+     */
+    public void clearFocus() {
+        mInput.clearFocus();
+        mInput.hideKeyboard();
+    }
 }
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarUIHelper.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarUIHelper.java
new file mode 100644
index 0000000..edfdc65
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarUIHelper.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker.search;
+
+/**
+ * UI helper for {@link WidgetsSearchBar}.
+ */
+public interface WidgetsSearchBarUIHelper {
+    /**
+     * Clears focus from the search bar.
+     */
+    void clearSearchBarFocus();
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java
index fe4c712..f084913 100644
--- a/tests/tapl/com/android/launcher3/tapl/Widgets.java
+++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java
@@ -18,7 +18,6 @@
 
 import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
 
-import android.graphics.Point;
 import android.graphics.Rect;
 
 import androidx.test.uiautomator.By;
@@ -30,6 +29,7 @@
 import com.android.launcher3.testing.TestProtocol;
 
 import java.util.Collection;
+import java.util.List;
 
 /**
  * All widgets container.
@@ -100,17 +100,18 @@
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                      "getting widget " + labelText + " in widgets list")) {
+            final UiObject2 searchBar = findSearchBar();
             final UiObject2 fullWidgetsPicker = verifyActiveContainer();
             mLauncher.assertTrue("Widgets container didn't become scrollable",
                     fullWidgetsPicker.wait(Until.scrollable(true), WAIT_TIME_MS));
-            final Point displaySize = mLauncher.getRealDisplaySize();
 
-            Rect headerRect = new Rect();
-            final UiObject2 widgetsContainer = findTestAppWidgetsTableContainer(headerRect);
+            final UiObject2 widgetsContainer = findTestAppWidgetsTableContainer(searchBar);
             mLauncher.assertTrue("Can't locate widgets list for the test app: "
                             + mLauncher.getLauncherPackageName(),
                     widgetsContainer != null);
             final BySelector labelSelector = By.clazz("android.widget.TextView").text(labelText);
+            final BySelector previewSelector = By.res(mLauncher.getLauncherPackageName(),
+                    "widget_preview");
             int i = 0;
             for (; ; ) {
                 final Collection<UiObject2> tableRows = widgetsContainer.getChildren();
@@ -125,19 +126,28 @@
                                 "View is not WidgetCell",
                                 "com.android.launcher3.widget.WidgetCell",
                                 widget.getClassName());
-
-                        return new Widget(mLauncher, widget);
+                        UiObject2 preview = widget.findObject(previewSelector);
+                        mLauncher.assertTrue("Can't find widget preview", preview != null);
+                        Rect previewRect = new Rect(preview.getVisibleBounds());
+                        boolean intersected = searchBar.getVisibleBounds().intersect(previewRect);
+                        if (intersected) {
+                            Rect scrollUp = new Rect(/* left= */ 0, /* top= */0, /* right*/ 0,
+                                    /* bottom= */ searchBar.getVisibleBounds().height());
+                            mLauncher.scroll(
+                                    fullWidgetsPicker,
+                                    Direction.UP,
+                                    scrollUp,
+                                    /* steps= */ 2,
+                                    /* slowDown= */ true);
+                        }
+                        preview = widget.findObject(previewSelector);
+                        return new Widget(mLauncher, preview);
                     }
                 }
 
                 mLauncher.assertTrue("Too many attempts", ++i <= 40);
                 final int scroll = getWidgetsScroll();
-                mLauncher.scroll(
-                        fullWidgetsPicker,
-                        Direction.DOWN,
-                        headerRect,
-                        10,
-                        true);
+                mLauncher.scrollToLastVisibleRow(fullWidgetsPicker, tableRows, 0);
                 final int newScroll = getWidgetsScroll();
                 mLauncher.assertTrue(
                         "Scrolled in a wrong direction in Widgets: from " + scroll + " to "
@@ -147,8 +157,21 @@
         }
     }
 
+    private UiObject2 findSearchBar() {
+        final BySelector searchBarContainerSelector = By.res(mLauncher.getLauncherPackageName(),
+                "search_and_recommendations_container");
+        final BySelector searchBarSelector = By.res(mLauncher.getLauncherPackageName(),
+                "widgets_search_bar");
+        final UiObject2 searchBarContainer = mLauncher.waitForLauncherObject(
+                searchBarContainerSelector);
+        mLauncher.assertTrue("Can't find a search bar container", searchBarContainer != null);
+        UiObject2 searchBar = searchBarContainer.findObject(searchBarSelector);
+        mLauncher.assertTrue("Can't find a search bar", searchBar != null);
+        return searchBar;
+    }
+
     /** Finds the widgets list of this test app from the collapsed full widgets picker. */
-    private UiObject2 findTestAppWidgetsTableContainer(Rect outHeaderRect) {
+    private UiObject2 findTestAppWidgetsTableContainer(final UiObject2 searchBar) {
         final BySelector headerSelector = By.res(mLauncher.getLauncherPackageName(),
                 "widgets_list_header");
         final BySelector targetAppSelector = By.clazz("android.widget.TextView").text(
@@ -161,12 +184,23 @@
             UiObject2 fullWidgetsPicker = verifyActiveContainer();
 
             UiObject2 header = fullWidgetsPicker.findObject(headerSelector);
-            outHeaderRect.set(0, 0, 0, header.getVisibleBounds().height());
             mLauncher.assertTrue("Can't find a widget header", header != null);
 
             // Look for a header that has the test app name.
             UiObject2 headerTitle = fullWidgetsPicker.findObject(targetAppSelector);
             if (headerTitle != null) {
+                Rect headerTitleRect = new Rect(headerTitle.getVisibleBounds());
+                boolean intersected = searchBar.getVisibleBounds().intersect(headerTitleRect);
+                if (intersected) {
+                    Rect scrollUp = new Rect(/* left= */ 0, /* top= */0, /* right*/ 0,
+                            /* bottom= */ searchBar.getVisibleBounds().height());
+                    mLauncher.scroll(
+                            fullWidgetsPicker,
+                            Direction.UP,
+                            scrollUp,
+                            /* steps= */ 2,
+                            /* slowDown= */ true);
+                }
                 // If we find the header and it has not been expanded, let's click it to see the
                 // widgets list.
                 if (!hasHeaderExpanded) {
@@ -185,14 +219,11 @@
                 if (widgetsContainer != null) {
                     return widgetsContainer;
                 }
-
+                mLauncher.scrollToLastVisibleRow(fullWidgetsPicker, List.of(headerTitle), 0);
+            } else {
+                mLauncher.scrollToLastVisibleRow(fullWidgetsPicker, fullWidgetsPicker.getChildren(),
+                        0);
             }
-            mLauncher.scroll(
-                    fullWidgetsPicker,
-                    Direction.DOWN,
-                    outHeaderRect,
-                    /* steps= */ 10,
-                    /* slowDown= */ true);
         }
 
         return null;