Merge "Cleanup overview threshold which was only needed for 2-button mode" into tm-qpr-dev
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index cd60879..c0b6657 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -289,6 +289,8 @@
     <dimen name="transient_taskbar_key_shadow_distance">10dp</dimen>
     <dimen name="transient_taskbar_stashed_size">32dp</dimen>
     <dimen name="transient_taskbar_icon_spacing">10dp</dimen>
+    <!-- An additional touch slop to prevent x-axis movement during the swipe up to show taskbar -->
+    <dimen name="transient_taskbar_clamped_offset_bound">16dp</dimen>
     <!-- Taskbar swipe up thresholds -->
     <dimen name="taskbar_app_window_threshold">150dp</dimen>
     <dimen name="taskbar_home_overview_threshold">225dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index dcad873..59dbd4b 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1678,9 +1678,10 @@
                 mLauncher.getStateManager().moveToRestState();
             }
 
+            RectF windowTargetBounds =
+                    new RectF(getWindowTargetBounds(appTargets, getRotationChange(appTargets)));
             Pair<RectFSpringAnim, AnimatorSet> pair = createWallpaperOpenAnimations(
-                    appTargets, wallpaperTargets, mFromUnlock,
-                    new RectF(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx),
+                    appTargets, wallpaperTargets, mFromUnlock, windowTargetBounds,
                     QuickStepContract.getWindowCornerRadius(mLauncher));
 
             mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index f51bc55..13ca58d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -762,9 +762,7 @@
             });
         } else if (tag instanceof WorkspaceItemInfo) {
             WorkspaceItemInfo info = (WorkspaceItemInfo) tag;
-            if (info.isDisabled()) {
-                ItemClickHandler.handleDisabledItemClicked(info, this);
-            } else {
+            if (!info.isDisabled() || !ItemClickHandler.handleDisabledItemClicked(info, this)) {
                 TaskbarUIController taskbarUIController = mControllers.uiController;
                 RecentsView recents = taskbarUIController.getRecentsView();
                 if (recents != null
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 3045eca..a26f5e5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -207,8 +207,13 @@
 
                     if (FeatureFlags.ENABLE_TASKBAR_POPUP_MENU.get()
                             && !shouldStartDrag(0)) {
-                        // Immediately close the popup menu.
-                        mDragView.setOnAnimationEndCallback(() -> callOnDragStart());
+                        mDragView.setOnAnimationEndCallback(() -> {
+                            // Drag might be cancelled during the DragView animation, so check
+                            // mIsPreDrag again.
+                            if (mIsInPreDrag) {
+                                callOnDragStart();
+                            }
+                        });
                     }
                 }
 
@@ -305,6 +310,9 @@
         if (mDisallowGlobalDrag) {
             AbstractFloatingView.closeAllOpenViewsExcept(mActivity, TYPE_TASKBAR_ALL_APPS);
         } else {
+            // stash the transient taskbar
+            mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
+
             AbstractFloatingView.closeAllOpenViews(mActivity);
         }
 
@@ -413,6 +421,9 @@
                     if (dragEvent.getResult()) {
                         maybeOnDragEnd();
                     } else {
+                        // un-stash the transient taskbar in case drag and drop was canceled
+                        mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
+
                         // This will take care of calling maybeOnDragEnd() after the animation
                         animateGlobalDragViewToOriginalPosition(btv, dragEvent);
                     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
index 6c7bdbf..019e5a6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
@@ -61,6 +61,11 @@
         public void onTaskStackChanged() {
             mProxyView.close(false);
         }
+
+        @Override
+        public void onTaskMovedToFront(int taskId) {
+            mProxyView.close(false);
+        }
     };
 
     private DeviceProfile mLauncherDeviceProfile;
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index b65d408..305fa93 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -288,7 +288,7 @@
     private AnimatorControllerWithResistance mLauncherTransitionController;
     private boolean mHasEndedLauncherTransition;
 
-    private AnimationFactory mAnimationFactory = (t, s) -> { };
+    private AnimationFactory mAnimationFactory = (t) -> { };
 
     private boolean mWasLauncherAlreadyVisible;
 
@@ -535,9 +535,7 @@
             Runnable initAnimFactory = () -> {
                 mAnimationFactory = mActivityInterface.prepareRecentsUI(mDeviceState,
                         mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated);
-                maybeUpdateRecentsAttachedState(
-                        false /* animate */,
-                        new ActiveGestureLog.CompoundString("on Launcher start (animate=false)"));
+                maybeUpdateRecentsAttachedState(false /* animate */);
                 if (mGestureState.getEndTarget() != null) {
                     // Update the end target in case the gesture ended before we init.
                     mAnimationFactory.setEndTarget(mGestureState.getEndTarget());
@@ -642,8 +640,7 @@
     }
 
     private void initializeLauncherAnimationController() {
-        buildAnimationController(new ActiveGestureLog.CompoundString(
-                "initializing launcher animation controller"));
+        buildAnimationController();
 
         Object traceToken = TraceHelper.INSTANCE.beginSection("logToggleRecents",
                 TraceHelper.FLAG_IGNORE_BINDERS);
@@ -662,11 +659,7 @@
             @Override
             public void onMotionPauseDetected() {
                 mHasMotionEverBeenPaused = true;
-                maybeUpdateRecentsAttachedState(
-                        true/* animate */,
-                        true/* moveFocusedTask */,
-                        new ActiveGestureLog.CompoundString(
-                                "motion pause detected (animate=true)"));
+                maybeUpdateRecentsAttachedState(true/* animate */, true/* moveFocusedTask */);
                 Optional.ofNullable(mActivityInterface.getTaskbarController())
                         .ifPresent(TaskbarUIController::startTranslationSpring);
                 performHapticFeedback();
@@ -679,13 +672,12 @@
         };
     }
 
-    private void maybeUpdateRecentsAttachedState(ActiveGestureLog.CompoundString reason) {
-        maybeUpdateRecentsAttachedState(true /* animate */, reason.append(" (animate=true)"));
+    private void maybeUpdateRecentsAttachedState() {
+        maybeUpdateRecentsAttachedState(true /* animate */);
     }
 
-    private void maybeUpdateRecentsAttachedState(
-            boolean animate, ActiveGestureLog.CompoundString reason) {
-        maybeUpdateRecentsAttachedState(animate, false /* moveFocusedTask */, reason);
+    private void maybeUpdateRecentsAttachedState(boolean animate) {
+        maybeUpdateRecentsAttachedState(animate, false /* moveFocusedTask */);
     }
 
     /**
@@ -697,8 +689,7 @@
      * @param animate whether to animate when attaching RecentsView
      * @param moveFocusedTask whether to move focused task to front when attaching
      */
-    private void maybeUpdateRecentsAttachedState(
-            boolean animate, boolean moveFocusedTask, ActiveGestureLog.CompoundString reason) {
+    private void maybeUpdateRecentsAttachedState(boolean animate, boolean moveFocusedTask) {
         if (!mDeviceState.isFullyGesturalNavMode() || mRecentsView == null) {
             return;
         }
@@ -708,25 +699,14 @@
         final boolean recentsAttachedToAppWindow;
         if (mGestureState.getEndTarget() != null) {
             recentsAttachedToAppWindow = mGestureState.getEndTarget().recentsAttachedToAppWindow;
-            reason.append("; gesture state end target != null (attached=")
-                    .append(Boolean.toString(recentsAttachedToAppWindow))
-                    .append(")");
         } else if (mContinuingLastGesture
                 && mRecentsView.getRunningTaskIndex() != mRecentsView.getNextPage()) {
             recentsAttachedToAppWindow = true;
-            reason.append("; continuing last gesture (attached=true)");
         } else if (runningTaskTarget != null && isNotInRecents(runningTaskTarget)) {
             // The window is going away so make sure recents is always visible in this case.
             recentsAttachedToAppWindow = true;
-            reason.append("; make sure recents is always visible (attached=true)");
         } else {
             recentsAttachedToAppWindow = mHasMotionEverBeenPaused || mIsLikelyToStartNewTask;
-            reason.append(mHasMotionEverBeenPaused
-                            ? "; motion has been paused"
-                            : "; gesture is likely to start a new task")
-                    .append(" (attached=")
-                    .append(Boolean.toString(recentsAttachedToAppWindow))
-                    .append(")");
         }
         if (moveFocusedTask && !mAnimationFactory.hasRecentsEverAttachedToAppWindow()
                 && recentsAttachedToAppWindow) {
@@ -734,8 +714,7 @@
             // TaskView jumping to new position as we move the tasks.
             mRecentsView.moveFocusedTaskToFront();
         }
-        mAnimationFactory.setRecentsAttachedToAppWindow(
-                recentsAttachedToAppWindow, animate, reason);
+        mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
 
         // Reapply window transform throughout the attach animation, as the animation affects how
         // much the window is bound by overscroll (vs moving freely).
@@ -754,30 +733,38 @@
         }
     }
 
-    public void setIsLikelyToStartNewTask(boolean isLikelyToStartNewTask) {
-        setIsLikelyToStartNewTask(
-                isLikelyToStartNewTask,
-                true /* animate */,
-                new ActiveGestureLog.CompoundString(
-                        "setting gesture likely to start (animate=true)"));
+    /**
+     * Sets whether or not we should clamp the scroll offset.
+     * This is used to avoid x-axis movement when swiping up transient taskbar.
+     * @param clampScrollOffset When true, we clamp the scroll to 0 before the clamp threshold is
+     *                          met.
+     */
+    public void setClampScrollOffset(boolean clampScrollOffset) {
+        if (mRecentsView == null) {
+            mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT,
+                    () -> mRecentsView.setClampScrollOffset(clampScrollOffset));
+            return;
+        }
+        mRecentsView.setClampScrollOffset(clampScrollOffset);
     }
 
-    private void setIsLikelyToStartNewTask(
-            boolean isLikelyToStartNewTask,
-            boolean animate,
-            ActiveGestureLog.CompoundString reason) {
+    public void setIsLikelyToStartNewTask(boolean isLikelyToStartNewTask) {
+        setIsLikelyToStartNewTask(isLikelyToStartNewTask, true /* animate */);
+    }
+
+    private void setIsLikelyToStartNewTask(boolean isLikelyToStartNewTask, boolean animate) {
         if (mIsLikelyToStartNewTask != isLikelyToStartNewTask) {
             mIsLikelyToStartNewTask = isLikelyToStartNewTask;
-            maybeUpdateRecentsAttachedState(animate, reason);
+            maybeUpdateRecentsAttachedState(animate);
         }
     }
 
-    private void buildAnimationController(ActiveGestureLog.CompoundString reason) {
+    private void buildAnimationController() {
         if (!canCreateNewOrUpdateExistingLauncherTransitionController()) {
             return;
         }
         initTransitionEndpoints(mActivity.getDeviceProfile());
-        mAnimationFactory.createActivityInterface(mTransitionDragLength, reason);
+        mAnimationFactory.createActivityInterface(mTransitionDragLength);
     }
 
     /**
@@ -792,7 +779,7 @@
     @Override
     public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
         WindowInsets result = view.onApplyWindowInsets(windowInsets);
-        buildAnimationController(new ActiveGestureLog.CompoundString("applying window insets"));
+        buildAnimationController();
         // Reapply the current shift to ensure it takes new insets into account, e.g. when long
         // pressing to stash taskbar without moving the finger.
         updateFinalShift();
@@ -956,10 +943,7 @@
             });
         }
         notifyGestureStartedAsync();
-        setIsLikelyToStartNewTask(
-                isLikelyToStartNewTask,
-                false /* animate */,
-                new ActiveGestureLog.CompoundString("on gesture started (animate=false)"));
+        setIsLikelyToStartNewTask(isLikelyToStartNewTask, false /* animate */);
         mStateCallback.setStateOnUiThread(STATE_GESTURE_STARTED);
         mGestureStarted = true;
     }
@@ -1040,8 +1024,7 @@
 
     private void onSettledOnEndTarget() {
         // Fast-finish the attaching animation if it's still running.
-        maybeUpdateRecentsAttachedState(false, new ActiveGestureLog.CompoundString(
-                "on settled on end target (animate=false)"));
+        maybeUpdateRecentsAttachedState(false);
         final GestureEndTarget endTarget = mGestureState.getEndTarget();
         // Wait until the given View (if supplied) draws before resuming the last task.
         View postResumeLastTask = mActivityInterface.onSettledOnEndTarget(endTarget);
@@ -1348,8 +1331,7 @@
     @UiThread
     private void animateToProgressInternal(float start, float end, long duration,
             Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
-        maybeUpdateRecentsAttachedState(new ActiveGestureLog.CompoundString(
-                "animate to progress internal"));
+        maybeUpdateRecentsAttachedState();
 
         // If we are transitioning to launcher, then listen for the activity to be restarted while
         // the transition is in progress
@@ -1672,9 +1654,7 @@
                     mRecentsView.post(mRecentsView::resetTaskVisuals);
                 }
                 // Make sure recents is in its final state
-                maybeUpdateRecentsAttachedState(
-                        false, new ActiveGestureLog.CompoundString(
-                                "setting up window animation (animate=false)"));
+                maybeUpdateRecentsAttachedState(false);
                 mActivityInterface.onSwipeUpToHomeComplete(mDeviceState);
             }
         });
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 2c3ba85..274b686 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -60,7 +60,6 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.NavigationMode;
 import com.android.launcher3.views.ScrimView;
-import com.android.quickstep.util.ActiveGestureLog;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.views.RecentsView;
@@ -399,16 +398,14 @@
 
     public interface AnimationFactory {
 
-        void createActivityInterface(long transitionLength, ActiveGestureLog.CompoundString reason);
+        void createActivityInterface(long transitionLength);
 
         /**
          * @param attached Whether to show RecentsView alongside the app window. If false, recents
          *                 will be hidden by some property we can animate, e.g. alpha.
          * @param animate Whether to animate recents to/from its new attached state.
-         * @param reason Explanation for why this method is being called with the given param values
          */
-        default void setRecentsAttachedToAppWindow(
-                boolean attached, boolean animate, ActiveGestureLog.CompoundString reason) { }
+        default void setRecentsAttachedToAppWindow(boolean attached, boolean animate) { }
 
         default boolean isRecentsAttachedToAppWindow() {
             return false;
@@ -450,8 +447,7 @@
         }
 
         @Override
-        public void createActivityInterface(
-                long transitionLength, ActiveGestureLog.CompoundString reason) {
+        public void createActivityInterface(long transitionLength) {
             PendingAnimation pa = new PendingAnimation(transitionLength * 2);
             createBackgroundToOverviewAnim(mActivity, pa);
             AnimatorPlaybackController controller = pa.createPlaybackController();
@@ -474,29 +470,13 @@
             // (because we set the animation as the current state animation), so we reapply the
             // attached state here as well to ensure recents is shown/hidden appropriately.
             if (DisplayController.getNavigationMode(mActivity) == NavigationMode.NO_BUTTON) {
-                setRecentsAttachedToAppWindow(
-                        mIsAttachedToWindow,
-                        false,
-                        reason.append("; reapplying the attached state (attached=")
-                                .append(Boolean.toString(mIsAttachedToWindow))
-                                .append(", animate=false)"));
+                setRecentsAttachedToAppWindow(mIsAttachedToWindow, false);
             }
         }
 
         @Override
-        public void setRecentsAttachedToAppWindow(
-                boolean attached, boolean animate, ActiveGestureLog.CompoundString reason) {
-            // TODO(b/244593270): remove these logs; too verbose
-            ActiveGestureLog.INSTANCE.addLog(
-                    new ActiveGestureLog.CompoundString("setRecentsAttachedToAppWindow: attached=")
-                            .append(Boolean.toString(attached))
-                            .append(", animate=")
-                            .append(Boolean.toString(animate))
-                            .append(", reason=")
-                            .append(reason));
+        public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
             if (mIsAttachedToWindow == attached && animate) {
-                ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
-                        "setRecentsAttachedToAppWindow: exiting early"));
                 return;
             }
             mActivity.getStateManager()
@@ -525,11 +505,6 @@
             float fromTranslation = ADJACENT_PAGE_HORIZONTAL_OFFSET.get(
                     mActivity.getOverviewPanel());
             float toTranslation = attached ? 0 : 1;
-            ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
-                    "setRecentsAttachedToAppWindow: fromTranslation=")
-                    .append(Float.toString(fromTranslation))
-                    .append(", toTranslation=")
-                    .append(Float.toString(toTranslation)));
 
             Animator translationAnimator = mActivity.getStateManager().createStateElementAnimation(
                     INDEX_RECENTS_TRANSLATE_X_ANIM, fromTranslation, toTranslation);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index 8410149..db7e087 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -53,6 +53,7 @@
 import com.android.quickstep.RecentsAnimationController;
 import com.android.quickstep.RecentsAnimationDeviceState;
 import com.android.quickstep.RecentsAnimationTargets;
+import com.android.quickstep.RemoteAnimationTargets;
 import com.android.quickstep.TaskAnimationManager;
 import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
 import com.android.quickstep.util.TransformParams;
@@ -226,6 +227,10 @@
                     mStateCallback.setState(STATE_HANDLER_INVALIDATED);
                 }
             });
+            RemoteAnimationTargets targets = mTransformParams.getTargetSet();
+            if (targets != null) {
+                targets.addReleaseCheck(new DeviceLockedReleaseCheck(animator));
+            }
             animator.start();
         } else {
             mStateCallback.setState(STATE_HANDLER_INVALIDATED);
@@ -304,4 +309,27 @@
     public boolean allowInterceptByParent() {
         return !mThresholdCrossed;
     }
+
+    private static final class DeviceLockedReleaseCheck extends
+            RemoteAnimationTargets.ReleaseCheck {
+
+        private DeviceLockedReleaseCheck(Animator animator) {
+            setCanRelease(true);
+
+            animator.addListener(new AnimatorListenerAdapter() {
+
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    super.onAnimationStart(animation);
+                    setCanRelease(false);
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
+                    setCanRelease(true);
+                }
+            });
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 4d005b2..b39d13c 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -378,6 +378,9 @@
         mInteractionHandler.onGestureStarted(isLikelyToStartNewTask);
 
         mInteractionHandler.setTaskbarAlreadyOpen(mTaskbarAlreadyOpen);
+        if (mIsTransientTaskbar && !mTaskbarAlreadyOpen && !isLikelyToStartNewTask) {
+            mInteractionHandler.setClampScrollOffset(true);
+        }
     }
 
     private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
@@ -473,6 +476,9 @@
     @UiThread
     private void onInteractionGestureFinished() {
         Preconditions.assertUIThread();
+        if (mInteractionHandler != null) {
+            mInteractionHandler.setClampScrollOffset(false);
+        }
         removeListener();
         mInteractionHandler = null;
         cleanupAfterGesture();
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 80b41a7..5a26f32 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -498,6 +498,9 @@
     private boolean mOverviewFullscreenEnabled;
     private boolean mOverviewSelectEnabled;
 
+    private boolean mShouldClampScrollOffset;
+    private int mClampedScrollOffsetBound;
+
     private float mAdjacentPageHorizontalOffset = 0;
     protected float mTaskViewsSecondaryTranslation = 0;
     protected float mTaskViewsPrimarySplitTranslation = 0;
@@ -752,6 +755,8 @@
         mSplitPlaceholderInset = getResources().getDimensionPixelSize(
                 R.dimen.split_placeholder_inset);
         mSquaredTouchSlop = squaredTouchSlop(context);
+        mClampedScrollOffsetBound = getResources().getDimensionPixelSize(
+                R.dimen.transient_taskbar_clamped_offset_bound);
 
         mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents);
         mEmptyIcon.setCallback(this);
@@ -5055,9 +5060,35 @@
     }
 
     /**
+     * Sets whether or not we should clamp the scroll offset.
+     * This is used to avoid x-axis movement when swiping up transient taskbar.
+     * Should only be set at the beginning and end of the gesture, otherwise a jump may occur.
+     * @param clampScrollOffset When true, we clamp the scroll to 0 before the clamp threshold is
+     *                          met.
+     */
+    public void setClampScrollOffset(boolean clampScrollOffset) {
+        mShouldClampScrollOffset = clampScrollOffset;
+    }
+
+    /**
      * Returns how many pixels the page is offset on the currently laid out dominant axis.
      */
     public int getScrollOffset(int pageIndex) {
+        int unboundedOffset = getUnclampedScrollOffset(pageIndex);
+        if (!mShouldClampScrollOffset) {
+            return unboundedOffset;
+        }
+        if (Math.abs(unboundedOffset) < mClampedScrollOffsetBound) {
+            return 0;
+        }
+        return unboundedOffset
+                - Math.round(Math.signum(unboundedOffset) * mClampedScrollOffsetBound);
+    }
+
+    /**
+     * Returns how many pixels the page is offset on the currently laid out dominant axis.
+     */
+    private int getUnclampedScrollOffset(int pageIndex) {
         if (pageIndex == -1) {
             return 0;
         }
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 3b92ac4..50b7563 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -368,6 +368,7 @@
     <dimen name="transient_taskbar_shadow_blur">0dp</dimen>
     <dimen name="transient_taskbar_key_shadow_distance">0dp</dimen>
     <dimen name="transient_taskbar_stashed_size">0dp</dimen>
+    <dimen name="transient_taskbar_clamped_offset_bound">0dp</dimen>
     <!-- Note that this applies to both sides of all icons, so visible space is double this. -->
     <dimen name="transient_taskbar_icon_spacing">0dp</dimen>
     <!-- Note that this applies to both sides of all icons, so visible space is double this. -->
diff --git a/res/xml/paddings_handhelds.xml b/res/xml/paddings_handhelds.xml
new file mode 100644
index 0000000..b9549a6
--- /dev/null
+++ b/res/xml/paddings_handhelds.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+
+<!-- Putting in the test/xml folder gives an error that maxEmptySpace doesn't exist -->
+<device-paddings xmlns:launcher="http://schemas.android.com/apk/res-auto" >
+
+    <device-padding
+        launcher:maxEmptySpace="9999dp">
+        <workspaceTopPadding
+            launcher:a="0.48"
+            launcher:b="0"/>
+        <workspaceBottomPadding
+            launcher:a="0.52"
+            launcher:b="0"/>
+        <hotseatBottomPadding
+            launcher:a="0"
+            launcher:b="0"/>
+    </device-padding>
+</device-paddings>
\ No newline at end of file
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 3cb3461..92530ea 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -498,10 +498,11 @@
         extraSpace = updateAvailableDimensions(res);
 
         // Now that we have all of the variables calculated, we can tune certain sizes.
-        if (isScalableGrid && inv.devicePaddings != null) {
+        if (isScalableGrid && inv.devicePaddingId != INVALID_RESOURCE_HANDLE) {
             // Paddings were created assuming no scaling, so we first unscale the extra space.
             int unscaledExtraSpace = (int) (extraSpace / cellScaleToFit);
-            DevicePadding padding = inv.devicePaddings.getDevicePadding(unscaledExtraSpace);
+            DevicePaddings devicePaddings = new DevicePaddings(context, inv.devicePaddingId);
+            DevicePadding padding = devicePaddings.getDevicePadding(unscaledExtraSpace);
 
             int paddingWorkspaceTop = padding.getWorkspaceTopPadding(unscaledExtraSpace);
             int paddingWorkspaceBottom = padding.getWorkspaceBottomPadding(unscaledExtraSpace);
@@ -1565,10 +1566,11 @@
         writer.println(prefix + pxToDpStr("extraSpace", extraSpace));
         writer.println(prefix + pxToDpStr("unscaled extraSpace", extraSpace / iconScale));
 
-        if (inv.devicePaddings != null) {
+        if (inv.devicePaddingId != INVALID_RESOURCE_HANDLE) {
             int unscaledExtraSpace = (int) (extraSpace / iconScale);
+            DevicePaddings devicePaddings = new DevicePaddings(context, inv.devicePaddingId);
             writer.println(prefix + pxToDpStr("maxEmptySpace",
-                    inv.devicePaddings.getDevicePadding(unscaledExtraSpace).getMaxEmptySpacePx()));
+                    devicePaddings.getDevicePadding(unscaledExtraSpace).getMaxEmptySpacePx()));
         }
         writer.println(prefix + pxToDpStr("workspaceTopPadding", workspaceTopPadding));
         writer.println(prefix + pxToDpStr("workspaceBottomPadding", workspaceBottomPadding));
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 87f5210..1f97535 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -47,9 +47,9 @@
 
 import androidx.annotation.DimenRes;
 import androidx.annotation.IntDef;
-import androidx.annotation.Nullable;
 import androidx.annotation.StyleRes;
 import androidx.annotation.VisibleForTesting;
+import androidx.annotation.XmlRes;
 import androidx.core.content.res.ResourcesCompat;
 
 import com.android.launcher3.icons.DotRenderer;
@@ -172,7 +172,8 @@
      * Do not query directly. see {@link DeviceProfile#isScalableGrid}.
      */
     protected boolean isScalable;
-    public int devicePaddingId;
+    @XmlRes
+    public int devicePaddingId = INVALID_RESOURCE_HANDLE;
 
     public String dbFile;
     public int defaultLayoutId;
@@ -184,9 +185,6 @@
      */
     public List<DeviceProfile> supportedProfiles = Collections.EMPTY_LIST;
 
-    @Nullable
-    public DevicePaddings devicePaddings;
-
     public Point defaultWallpaperSize;
     public Rect defaultWidgetPadding;
 
@@ -385,10 +383,6 @@
         allAppsIconSize = displayOption.allAppsIconSizes;
         allAppsIconTextSize = displayOption.allAppsIconTextSizes;
 
-        if (devicePaddingId != 0) {
-            devicePaddings = new DevicePaddings(context, devicePaddingId);
-        }
-
         inlineQsb = closestProfile.inlineQsb;
 
         // If the partner customization apk contains any grid overrides, apply them
@@ -826,7 +820,7 @@
             isScalable = a.getBoolean(
                     R.styleable.GridDisplayOption_isScalable, false);
             devicePaddingId = a.getResourceId(
-                    R.styleable.GridDisplayOption_devicePaddingId, 0);
+                    R.styleable.GridDisplayOption_devicePaddingId, INVALID_RESOURCE_HANDLE);
 
             int deviceCategory = a.getInt(R.styleable.GridDisplayOption_deviceCategory,
                     DEVICE_CATEGORY_ALL);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 9607da8..982f6a9 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -79,10 +79,6 @@
     public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(
             "PROMISE_APPS_IN_ALL_APPS", false, "Add promise icon in all-apps");
 
-    // TODO: b/206508141: Long pressing on some icons on home screen cause launcher to crash.
-    public static final BooleanFlag ENABLE_LOCAL_COLOR_POPUPS = getDebugFlag(
-            "ENABLE_LOCAL_COLOR_POPUPS", false, "Enable local color extraction for popups.");
-
     public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag(
             "KEYGUARD_ANIMATION", false, "Enable animation for keyguard going away on wallpaper");
 
@@ -273,6 +269,10 @@
             "ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES", false,
             "Enable option to replace decorator-based search result backgrounds with drawables");
 
+    public static final BooleanFlag TWO_PREDICTED_ROWS_ALL_APPS_SEARCH = new DeviceFlag(
+            "TWO_PREDICTED_ROWS_ALL_APPS_SEARCH", false,
+            "Use 2 rows of app predictions in All Apps search zero-state");
+
     public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = new DeviceFlag(
             "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", true,
             "Enable option to show keyboard when going to all-apps");
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 196cc56..9a745ab 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -21,14 +21,12 @@
 import static com.android.launcher3.anim.Interpolators.ACCELERATED_EASE;
 import static com.android.launcher3.anim.Interpolators.DECELERATED_EASE;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_LOCAL_COLOR_POPUPS;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Color;
@@ -36,15 +34,12 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.util.Pair;
-import android.util.SparseIntArray;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 
@@ -52,21 +47,17 @@
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.InsettableFrameLayout;
-import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
-import com.android.launcher3.widget.LocalColorExtractor;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.List;
 
 /**
  * A container for shortcuts to deep links and notifications associated with an app.
@@ -89,10 +80,6 @@
     protected int CLOSE_CHILD_FADE_START_DELAY = 0;
     protected int CLOSE_CHILD_FADE_DURATION = 140;
 
-    // Index used to get background color when using local wallpaper color extraction,
-    private static final int DARK_COLOR_EXTRACTION_INDEX = android.R.color.system_neutral2_800;
-    private static final int LIGHT_COLOR_EXTRACTION_INDEX = android.R.color.system_accent2_50;
-
     protected final Rect mTempRect = new Rect();
 
     protected final LayoutInflater mInflater;
@@ -124,10 +111,8 @@
 
     // The rect string of the view that the arrow is attached to, in screen reference frame.
     protected int mArrowColor;
-    protected final List<LocalColorExtractor> mColorExtractors;
 
     protected final float mElevation;
-    private final int mBackgroundColor;
 
     private final String mIterateChildrenTag;
 
@@ -140,8 +125,8 @@
         mActivityContext = ActivityContext.lookupContext(context);
         mIsRtl = Utilities.isRtl(getResources());
 
-        mBackgroundColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
-        mArrowColor = mBackgroundColor;
+        int backgroundColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
+        mArrowColor = backgroundColor;
         mElevation = getResources().getDimension(R.dimen.deep_shortcuts_elevation);
 
         // Initialize arrow view
@@ -158,25 +143,18 @@
 
         int smallerRadius = resources.getDimensionPixelSize(R.dimen.popup_smaller_radius);
         mRoundedTop = new GradientDrawable();
-        mRoundedTop.setColor(mBackgroundColor);
+        mRoundedTop.setColor(backgroundColor);
         mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius,
                 mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius});
 
         mRoundedBottom = new GradientDrawable();
-        mRoundedBottom.setColor(mBackgroundColor);
+        mRoundedBottom.setColor(backgroundColor);
         mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius,
                 smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius});
 
         mIterateChildrenTag = getContext().getString(R.string.popup_container_iterate_children);
 
-        boolean shouldUseColorExtraction = mActivityContext.shouldUseColorExtractionForPopup();
-        if (shouldUseColorExtraction && Utilities.ATLEAST_S && ENABLE_LOCAL_COLOR_POPUPS.get()) {
-            mColorExtractors = new ArrayList<>();
-        } else {
-            mColorExtractors = null;
-        }
-
-        if (shouldUseColorExtraction) {
+        if (mActivityContext.shouldUseColorExtractionForPopup()) {
             mColorIds = new int[]{R.color.popup_shade_first, R.color.popup_shade_second,
                     R.color.popup_shade_third};
         } else {
@@ -220,11 +198,6 @@
     }
 
     /**
-     * Called when all view inflation and reordering in complete.
-     */
-    protected void onInflationComplete(boolean isReversed) { }
-
-    /**
      * Set the margins and radius of backgrounds after views are properly ordered.
      */
     public void assignMarginsAndBackgrounds(ViewGroup viewGroup) {
@@ -271,13 +244,9 @@
                     backgroundColor = colors[numVisibleChild % colors.length];
                 }
 
-                if (!ENABLE_LOCAL_COLOR_POPUPS.get()) {
-                    // Arrow color matches the first child or the last child.
-                    if (!mIsAboveIcon && numVisibleChild == 0 && viewGroup == this) {
-                        mArrowColor = backgroundColor;
-                    } else if (mIsAboveIcon) {
-                        mArrowColor = backgroundColor;
-                    }
+                // Arrow color matches the first child or the last child.
+                if (mIsAboveIcon || (numVisibleChild == 0 && viewGroup == this)) {
+                    mArrowColor = backgroundColor;
                 }
 
                 if (view instanceof ViewGroup && mIterateChildrenTag.equals(view.getTag())) {
@@ -301,10 +270,7 @@
                     }
                 }
 
-                if (!ENABLE_LOCAL_COLOR_POPUPS.get()) {
-                    setChildColor(view, backgroundColor, colorAnimator);
-                }
-
+                setChildColor(view, backgroundColor, colorAnimator);
                 numVisibleChild++;
             }
         }
@@ -320,85 +286,6 @@
         return view instanceof DeepShortcutView;
     }
 
-    @TargetApi(Build.VERSION_CODES.S)
-    private int getExtractedColor(SparseIntArray colors) {
-        int index = Utilities.isDarkTheme(getContext())
-                ? DARK_COLOR_EXTRACTION_INDEX
-                : LIGHT_COLOR_EXTRACTION_INDEX;
-        return colors.get(index, mBackgroundColor);
-    }
-
-    protected void addPreDrawForColorExtraction(Launcher launcher) {
-        getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
-            @Override
-            public boolean onPreDraw() {
-                getViewTreeObserver().removeOnPreDrawListener(this);
-                initColorExtractionLocations(launcher);
-                return true;
-            }
-        });
-    }
-
-    /**
-     * Returns list of child views that will receive local color extraction treatment.
-     * Note: Order should match the view hierarchy.
-     */
-    protected List<View> getChildrenForColorExtraction() {
-        return Collections.emptyList();
-    }
-
-    private void initColorExtractionLocations(Launcher launcher) {
-        if (mColorExtractors == null) {
-            return;
-        }
-        Workspace<?> workspace = launcher.getWorkspace();
-        if (workspace == null) {
-            return;
-        }
-
-        boolean firstVisibleChild = true;
-        int screenId = workspace.getScreenIdForPageIndex(workspace.getCurrentPage());
-        DragLayer dragLayer = launcher.getDragLayer();
-
-        final View[] viewAlignedWithArrow = new View[1];
-
-        // Order matters here, since we need the arrow to match the color of its adjacent view.
-        for (final View view : getChildrenForColorExtraction()) {
-            if (view != null && view.getVisibility() == VISIBLE) {
-                Rect pos = new Rect();
-                dragLayer.getDescendantRectRelativeToSelf(view, pos);
-                if (!pos.isEmpty()) {
-                    LocalColorExtractor extractor = LocalColorExtractor.newInstance(launcher);
-                    extractor.setWorkspaceLocation(pos, dragLayer, screenId);
-                    extractor.setListener(extractedColors -> {
-                        AnimatorSet colors = new AnimatorSet();
-                        int newColor = getExtractedColor(extractedColors);
-                        setChildColor(view, newColor, colors);
-                        int numChildren = view instanceof ViewGroup
-                                ? ((ViewGroup) view).getChildCount() : 0;
-                        for (int i = 0; i < numChildren; ++i) {
-                            View childView = ((ViewGroup) view).getChildAt(i);
-                            setChildColor(childView, newColor, colors);
-                        }
-                        if (viewAlignedWithArrow[0] == view) {
-                            mArrowColor = newColor;
-                            updateArrowColor();
-                        }
-                        colors.setDuration(150);
-                        view.post(colors::start);
-                    });
-                    mColorExtractors.add(extractor);
-
-                    if (mIsAboveIcon || firstVisibleChild) {
-                        viewAlignedWithArrow[0] = view;
-                    }
-                    firstVisibleChild = false;
-                }
-            }
-        }
-
-    }
-
     /**
      * Sets the background color of the child.
      */
@@ -425,7 +312,6 @@
         if (reverseOrder) {
             reverseOrder(viewsToFlip);
         }
-        onInflationComplete(reverseOrder);
         assignMarginsAndBackgrounds(this);
         if (shouldAddArrow()) {
             addArrow();
@@ -438,7 +324,6 @@
      */
     public void show() {
         setupForDisplay();
-        onInflationComplete(false);
         assignMarginsAndBackgrounds(this);
         if (shouldAddArrow()) {
             addArrow();
@@ -819,9 +704,6 @@
         if (mOnCloseCallback != null) {
             mOnCloseCallback.run();
         }
-        if (mColorExtractors != null) {
-            mColorExtractors.forEach(e -> e.setListener(null));
-        }
     }
 
     /**
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 8e7a10c..4da588e 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -69,7 +69,6 @@
 import com.android.launcher3.views.BaseDragLayer;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -236,13 +235,6 @@
         mPopupItemDragHandler = new LauncherPopupItemDragHandler(launcher, this);
         mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(launcher);
         launcher.getDragController().addDragListener(this);
-        addPreDrawForColorExtraction(launcher);
-    }
-
-    @Override
-    protected List<View> getChildrenForColorExtraction() {
-        return Arrays.asList(mSystemShortcutContainer, mWidgetContainer, mDeepShortcutContainer,
-                mNotificationContainer);
     }
 
     private void initializeSystemShortcuts(List<SystemShortcut> shortcuts) {
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index b3c376f..622516f 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -139,14 +139,13 @@
         mTargetRect.roundOut(outPos);
     }
 
-    public static OptionsPopupView show(
-            Launcher launcher, RectF targetRect, List<OptionItem> items, boolean shouldAddArrow) {
+    public static OptionsPopupView show(AppLauncher launcher, RectF targetRect,
+            List<OptionItem> items, boolean shouldAddArrow) {
         return show(launcher, targetRect, items, shouldAddArrow, 0 /* width */);
     }
 
-    public static OptionsPopupView show(
-            Launcher launcher, RectF targetRect, List<OptionItem> items, boolean shouldAddArrow,
-            int width) {
+    public static OptionsPopupView show(AppLauncher launcher, RectF targetRect,
+            List<OptionItem> items, boolean shouldAddArrow, int width) {
         OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater()
                 .inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false);
         popup.mTargetRect = targetRect;
@@ -165,21 +164,10 @@
             popup.mItemMap.put(view, item);
         }
 
-        popup.addPreDrawForColorExtraction(launcher);
         popup.show();
         return popup;
     }
 
-    @Override
-    protected List<View> getChildrenForColorExtraction() {
-        int childCount = getChildCount();
-        ArrayList<View> children = new ArrayList<>(childCount);
-        for (int i = 0; i < childCount; ++i) {
-            children.add(getChildAt(i));
-        }
-        return children;
-    }
-
     /**
      * Returns the list of supported actions
      */
diff --git a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
index fe30fdc..4e166ce 100644
--- a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
+++ b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
@@ -16,7 +16,6 @@
 package com.android.launcher3
 
 import android.content.Context
-import android.graphics.Point
 import android.graphics.PointF
 import android.graphics.Rect
 import android.util.SparseArray
@@ -26,7 +25,6 @@
 import com.android.launcher3.util.WindowBounds
 import org.junit.Before
 import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mockito.mock
 import java.io.PrintWriter
 import java.io.StringWriter
@@ -42,9 +40,6 @@
     protected var transposeLayoutWithOrientation: Boolean = false
     protected var useTwoPanels: Boolean = false
     protected var isGestureMode: Boolean = true
-    protected var devicePaddingsMock: DevicePaddings = mock(DevicePaddings::class.java)
-    protected var staticdevicePaddingsMock: DevicePaddings.DevicePadding =
-            mock(DevicePaddings.DevicePadding::class.java)
 
     @Before
     fun setUp() {
@@ -83,11 +78,6 @@
         whenever(info.isTablet(any())).thenReturn(false)
         whenever(info.getDensityDpi()).thenReturn(420)
         whenever(info.smallestSizeDp(any())).thenReturn(411f)
-        whenever(devicePaddingsMock.getDevicePadding(anyInt())).thenReturn(staticdevicePaddingsMock)
-        whenever(staticdevicePaddingsMock.getWorkspaceTopPadding(anyInt())).thenReturn(95)
-        whenever(staticdevicePaddingsMock.getWorkspaceBottomPadding(anyInt())).thenReturn(116)
-        whenever(staticdevicePaddingsMock.maxEmptySpacePx)
-                .thenReturn(if (isVerticalBar) if (isGestureMode) 131 else 184 else 315)
 
         this.isGestureMode = isGestureMode
         transposeLayoutWithOrientation = true
@@ -152,7 +142,7 @@
 
             inlineQsb = BooleanArray(4) { false }
 
-            devicePaddings = devicePaddingsMock
+            devicePaddingId = R.xml.paddings_handhelds
         }
     }
 
@@ -169,13 +159,6 @@
         whenever(info.isTablet(any())).thenReturn(true)
         whenever(info.getDensityDpi()).thenReturn(320)
         whenever(info.smallestSizeDp(any())).thenReturn(800f)
-        whenever(devicePaddingsMock.getDevicePadding(anyInt())).thenReturn(staticdevicePaddingsMock)
-        whenever(staticdevicePaddingsMock.getWorkspaceTopPadding(anyInt()))
-                .thenReturn(if (isLandscape) 32 else 159)
-        whenever(staticdevicePaddingsMock.getWorkspaceBottomPadding(anyInt()))
-                .thenReturn(if (isLandscape) 72 else 203)
-        whenever(staticdevicePaddingsMock.maxEmptySpacePx).thenReturn(if (isLandscape) 200 else 19998)
-
 
         this.isGestureMode = isGestureMode
         useTwoPanels = false
@@ -246,7 +229,7 @@
                     false
             )
 
-            devicePaddings = devicePaddingsMock
+            devicePaddingId = R.xml.paddings_handhelds
         }
     }
 
@@ -263,15 +246,6 @@
         whenever(info.isTablet(any())).thenReturn(true)
         whenever(info.getDensityDpi()).thenReturn(420)
         whenever(info.smallestSizeDp(any())).thenReturn(700f)
-        whenever(devicePaddingsMock.getDevicePadding(anyInt())).thenReturn(staticdevicePaddingsMock)
-
-        val topPadding = if (isLandscape) 18 else 89
-        val bottomPadding = if (isLandscape) 39 else 146
-        val maxEmptySpace = if (isLandscape) 131 else 236
-        whenever(staticdevicePaddingsMock.getWorkspaceTopPadding(anyInt())).thenReturn(topPadding)
-        whenever(staticdevicePaddingsMock.getWorkspaceBottomPadding(anyInt()))
-                .thenReturn(bottomPadding)
-        whenever(staticdevicePaddingsMock.maxEmptySpacePx).thenReturn(maxEmptySpace)
 
         this.isGestureMode = isGestureMode
         useTwoPanels = true
@@ -342,7 +316,7 @@
                     false
             )
 
-            devicePaddings = devicePaddingsMock
+            devicePaddingId = R.xml.paddings_handhelds
         }
     }