Adjust edit state drop targets and workspace scaling per device type and orientation.

This is a partial revert of ag/17540098

Bug: 202971709
Test: manual
Change-Id: I0a642f932afd75e47ce11a2c1ee94643d1a67e0c
diff --git a/res/drawable/drop_target_frame.xml b/res/drawable/drop_target_frame.xml
index 666a96e..9f04103 100644
--- a/res/drawable/drop_target_frame.xml
+++ b/res/drawable/drop_target_frame.xml
@@ -17,6 +17,6 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
     <solid android:color="@android:color/transparent" />
-    <corners android:radius="28dp" />
+    <corners android:radius="80dp" />
     <stroke android:width="2dp" android:color="?attr/workspaceAccentColor" />
 </shape>
\ No newline at end of file
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 662b86e..58aeda4 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -23,7 +23,16 @@
 
     <!-- Dynamic grid -->
     <dimen name="dynamic_grid_icon_drawable_padding">4dp</dimen>
+    <dimen name="dynamic_grid_drop_target_size">36dp</dimen>
 
     <!-- Hotseat -->
     <dimen name="dynamic_grid_hotseat_side_padding">16dp</dimen>
+    <dimen name="spring_loaded_hotseat_top_margin">45dp</dimen>
+
+    <!-- Dragging -->
+    <dimen name="drop_target_button_gap">28dp</dimen>
+    <dimen name="drop_target_button_drawable_horizontal_padding">16dp</dimen>
+    <dimen name="drop_target_button_drawable_vertical_padding">2dp</dimen>
+    <dimen name="drop_target_top_margin">6dp</dimen>
+    <dimen name="drop_target_bottom_margin">6dp</dimen>
 </resources>
diff --git a/res/values-sw600dp-land/dimens.xml b/res/values-sw600dp-land/dimens.xml
new file mode 100644
index 0000000..e052d61
--- /dev/null
+++ b/res/values-sw600dp-land/dimens.xml
@@ -0,0 +1,25 @@
+<?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.
+  -->
+
+<resources>
+    <!-- Hotseat -->
+    <dimen name="spring_loaded_hotseat_top_margin">44dp</dimen>
+
+    <!-- Dragging -->
+    <dimen name="drop_target_top_margin">0dp</dimen>
+    <dimen name="drop_target_bottom_margin">16dp</dimen>
+</resources>
diff --git a/res/values-sw600dp/dimens.xml b/res/values-sw600dp/dimens.xml
index 4a10e56..823fc62 100644
--- a/res/values-sw600dp/dimens.xml
+++ b/res/values-sw600dp/dimens.xml
@@ -36,4 +36,12 @@
 
 <!-- Hotseat -->
     <dimen name="dynamic_grid_hotseat_side_padding">0dp</dimen>
+    <dimen name="spring_loaded_hotseat_top_margin">97dp</dimen>
+
+<!-- Dragging -->
+    <dimen name="drop_target_top_margin">34dp</dimen>
+    <dimen name="drop_target_bottom_margin">16dp</dimen>
+    <dimen name="drop_target_button_drawable_horizontal_padding">16dp</dimen>
+    <dimen name="drop_target_button_drawable_vertical_padding">16dp</dimen>
+    <dimen name="dynamic_grid_drop_target_size">56dp</dimen>
 </resources>
diff --git a/res/values-sw720dp-land/dimens.xml b/res/values-sw720dp-land/dimens.xml
index 9821526..77d15c7 100644
--- a/res/values-sw720dp-land/dimens.xml
+++ b/res/values-sw720dp-land/dimens.xml
@@ -15,9 +15,16 @@
 -->
 
 <resources>
-    <!-- Widget picker-->
+<!-- Dragging-->
+    <dimen name="drop_target_top_margin">0dp</dimen>
+    <dimen name="drop_target_bottom_margin">32dp</dimen>
+
+<!-- Hotseat -->
+    <dimen name="spring_loaded_hotseat_top_margin">64dp</dimen>
+
+<!-- Widget picker-->
     <dimen name="widget_list_horizontal_margin">49dp</dimen>
 
-    <!-- Bottom sheet-->
+<!-- Bottom sheet-->
     <dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
 </resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 7ebc3f8..e273b09 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -18,6 +18,18 @@
 <!-- AllApps -->
     <dimen name="all_apps_bottom_sheet_horizontal_padding">65dp</dimen>
 
+<!-- Dragging -->
+    <dimen name="drop_target_text_size">20sp</dimen>
+    <dimen name="dynamic_grid_drop_target_size">72dp</dimen>
+    <dimen name="drop_target_button_drawable_horizontal_padding">24dp</dimen>
+    <dimen name="drop_target_button_drawable_vertical_padding">20dp</dimen>
+    <dimen name="drop_target_button_gap">32dp</dimen>
+    <dimen name="drop_target_top_margin">32dp</dimen>
+    <dimen name="drop_target_bottom_margin">32dp</dimen>
+
+<!-- Hotseat -->
+    <dimen name="spring_loaded_hotseat_top_margin">164dp</dimen>
+
 <!-- Widget picker-->
     <dimen name="widget_list_horizontal_margin">30dp</dimen>
 
diff --git a/res/values/config.xml b/res/values/config.xml
index 76d1161..0ed2d85 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -22,9 +22,6 @@
     <item type="id" name="drag_event_parity" />
 
     <!-- AllApps & Launcher transitions -->
-    <!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
-    <integer name="config_workspaceSpringLoadShrinkPercentage">85</integer>
-
     <!-- The duration of the animation from search hint to text entry -->
     <integer name="config_searchHintAnimationDuration">50</integer>
 
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index ce54565..83d40d5 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -34,6 +34,7 @@
     <dimen name="dynamic_grid_hotseat_bottom_padding">2dp</dimen>
     <dimen name="dynamic_grid_hotseat_bottom_tall_padding">0dp</dimen>
     <dimen name="inline_qsb_bottom_margin">0dp</dimen>
+    <dimen name="spring_loaded_hotseat_top_margin">76dp</dimen>
 
     <!-- Qsb -->
     <!-- Used for adjusting the position of QSB when placed in hotseat. This is a ratio and a higher
@@ -55,8 +56,10 @@
     <dimen name="workspace_page_indicator_overlap_workspace">0dp</dimen>
 
 <!-- Drop target bar -->
-    <dimen name="dynamic_grid_drop_target_size">52dp</dimen>
+    <dimen name="dynamic_grid_drop_target_size">56dp</dimen>
     <dimen name="drop_target_vertical_gap">20dp</dimen>
+    <dimen name="drop_target_top_margin">36dp</dimen>
+    <dimen name="drop_target_bottom_margin">16dp</dimen>
 
 <!-- App Widget resize frame -->
     <dimen name="widget_handle_margin">13dp</dimen>
@@ -207,6 +210,9 @@
     <dimen name="drop_target_shadow_elevation">2dp</dimen>
     <dimen name="drop_target_bar_margin_horizontal">4dp</dimen>
     <dimen name="drop_target_button_drawable_padding">8dp</dimen>
+    <dimen name="drop_target_button_drawable_horizontal_padding">16dp</dimen>
+    <dimen name="drop_target_button_drawable_vertical_padding">8dp</dimen>
+    <dimen name="drop_target_button_gap">22dp</dimen>
 
     <!-- the distance an icon must be dragged before button drop targets accept it -->
     <dimen name="drag_distanceThreshold">30dp</dimen>
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 3489c31..67d6f40 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -108,7 +108,8 @@
     public final int cellLayoutPaddingLeftRightPx;
     public final int cellLayoutBottomPaddingPx;
     public final int edgeMarginPx;
-    public float workspaceSpringLoadShrinkFactor;
+    public float workspaceSpringLoadShrunkTop;
+    public float workspaceSpringLoadShrunkBottom;
     public final int workspaceSpringLoadedBottomSpace;
 
     private final int extraSpace;
@@ -164,6 +165,7 @@
     public int hotseatBarSizePx;
     public int hotseatBarTopPaddingPx;
     public final int hotseatBarBottomPaddingPx;
+    public int springLoadedHotseatBarTopMarginPx;
     // Start is the side next to the nav bar, end is the side next to the workspace
     public final int hotseatBarSidePaddingStartPx;
     public final int hotseatBarSidePaddingEndPx;
@@ -209,8 +211,13 @@
 
     // Drop Target
     public int dropTargetBarSizePx;
+    public int dropTargetBarTopMarginPx;
+    public int dropTargetBarBottomMarginPx;
     public int dropTargetDragPaddingPx;
     public int dropTargetTextSizePx;
+    public int dropTargetHorizontalPaddingPx;
+    public int dropTargetVerticalPaddingPx;
+    public int dropTargetGapPx;
 
     // Insets
     private final Rect mInsets = new Rect();
@@ -347,8 +354,15 @@
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding);
 
         dropTargetBarSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_drop_target_size);
+        dropTargetBarTopMarginPx = res.getDimensionPixelSize(R.dimen.drop_target_top_margin);
+        dropTargetBarBottomMarginPx = res.getDimensionPixelSize(R.dimen.drop_target_bottom_margin);
         dropTargetDragPaddingPx = res.getDimensionPixelSize(R.dimen.drop_target_drag_padding);
         dropTargetTextSizePx = res.getDimensionPixelSize(R.dimen.drop_target_text_size);
+        dropTargetHorizontalPaddingPx = res.getDimensionPixelSize(
+                R.dimen.drop_target_button_drawable_horizontal_padding);
+        dropTargetVerticalPaddingPx = res.getDimensionPixelSize(
+                R.dimen.drop_target_button_drawable_vertical_padding);
+        dropTargetGapPx = res.getDimensionPixelSize(R.dimen.drop_target_button_gap);
 
         workspaceSpringLoadedBottomSpace =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_min_spring_loaded_space);
@@ -389,6 +403,8 @@
                     + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
             qsbWidth = 0;
         }
+        springLoadedHotseatBarTopMarginPx = res.getDimensionPixelSize(
+                R.dimen.spring_loaded_hotseat_top_margin);
         hotseatBarSidePaddingEndPx =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding);
         // Add a bit of space between nav bar and hotseat in vertical bar layout.
@@ -744,18 +760,6 @@
         }
         updateHotseatIconSize(iconSizePx);
 
-        if (!isVerticalLayout) {
-            int expectedWorkspaceHeight = availableHeightPx - hotseatBarSizePx
-                    - workspacePageIndicatorHeight - edgeMarginPx;
-            float minRequiredHeight = dropTargetBarSizePx + workspaceSpringLoadedBottomSpace;
-            workspaceSpringLoadShrinkFactor = Math.min(
-                    res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f,
-                    1 - (minRequiredHeight / expectedWorkspaceHeight));
-        } else {
-            workspaceSpringLoadShrinkFactor =
-                    res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f;
-        }
-
         // Folder icon
         folderIconSizePx = IconNormalizer.getNormalizedCircleSize(iconSizePx);
         folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2;
@@ -897,6 +901,41 @@
         return result;
     }
 
+    /**
+     * Gets the space in px from the bottom of last item in the vertical-bar hotseat to the
+     * bottom of the screen.
+     */
+    public int getVerticalHotseatLastItemBottomOffset() {
+        int cellHeight = calculateCellHeight(
+                heightPx - mHotseatPadding.top - mHotseatPadding.bottom, hotseatBorderSpace,
+                numShownHotseatIcons);
+        int hotseatSize = (cellHeight * numShownHotseatIcons)
+                + (hotseatBorderSpace * (numShownHotseatIcons - 1));
+        int extraHotseatEndSpacing = (heightPx - hotseatSize) / 2;
+        int extraIconEndSpacing = (cellHeight - iconSizePx) / 2;
+        return extraHotseatEndSpacing + extraIconEndSpacing + mHotseatPadding.bottom;
+    }
+
+    /**
+     * Gets the scaled top of the workspace in px for the spring-loaded edit state.
+     */
+    public float getWorkspaceSpringLoadShrunkTop() {
+        workspaceSpringLoadShrunkTop = mInsets.top + dropTargetBarTopMarginPx + dropTargetBarSizePx
+                + dropTargetBarBottomMarginPx;
+        return workspaceSpringLoadShrunkTop;
+    }
+
+    /**
+     * Gets the scaled bottom of the workspace in px for the spring-loaded edit state.
+     */
+    public float getWorkspaceSpringLoadShrunkBottom() {
+        int topOfHotseat = hotseatBarSizePx + springLoadedHotseatBarTopMarginPx;
+        workspaceSpringLoadShrunkBottom =
+                heightPx - (isVerticalBarLayout() ? getVerticalHotseatLastItemBottomOffset()
+                        : topOfHotseat);
+        return workspaceSpringLoadShrunkBottom;
+    }
+
     public int getWorkspaceWidth() {
         return getWorkspaceWidth(getTotalWorkspacePadding());
     }
@@ -1206,6 +1245,12 @@
                 hotseatBarSidePaddingStartPx));
         writer.println(prefix + pxToDpStr("hotseatBarSidePaddingEndPx",
                 hotseatBarSidePaddingEndPx));
+        writer.println(prefix + pxToDpStr("springLoadedHotseatBarTopMarginPx",
+                springLoadedHotseatBarTopMarginPx));
+        writer.println(prefix + pxToDpStr("mHotseatPadding.top", mHotseatPadding.top));
+        writer.println(prefix + pxToDpStr("mHotseatPadding.bottom", mHotseatPadding.bottom));
+        writer.println(prefix + pxToDpStr("mHotseatPadding.left", mHotseatPadding.left));
+        writer.println(prefix + pxToDpStr("mHotseatPadding.right", mHotseatPadding.right));
         writer.println(prefix + "\tnumShownHotseatIcons: " + numShownHotseatIcons);
         writer.println(prefix + pxToDpStr("hotseatBorderSpace", hotseatBorderSpace));
         writer.println(prefix + "\tisQsbInline: " + isQsbInline);
@@ -1256,6 +1301,16 @@
         writer.println(prefix + pxToDpStr("overviewPageSpacing", overviewPageSpacing));
         writer.println(prefix + pxToDpStr("overviewRowSpacing", overviewRowSpacing));
         writer.println(prefix + pxToDpStr("overviewGridSideMargin", overviewGridSideMargin));
+
+        writer.println(prefix + pxToDpStr("dropTargetBarTopMarginPx", dropTargetBarTopMarginPx));
+        writer.println(prefix + pxToDpStr("dropTargetBarSizePx", dropTargetBarSizePx));
+        writer.println(
+                prefix + pxToDpStr("dropTargetBarBottomMarginPx", dropTargetBarBottomMarginPx));
+
+        writer.println(
+                prefix + pxToDpStr("workspaceSpringLoadShrunkTop", workspaceSpringLoadShrunkTop));
+        writer.println(prefix + pxToDpStr("workspaceSpringLoadShrunkBottom",
+                workspaceSpringLoadShrunkBottom));
     }
 
     private static Context getContext(Context c, Info info, int orientation, WindowBounds bounds) {
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index 9fb14f6..73289fb 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -17,8 +17,6 @@
 package com.android.launcher3;
 
 import static com.android.launcher3.ButtonDropTarget.TOOLTIP_DEFAULT;
-import static com.android.launcher3.ButtonDropTarget.TOOLTIP_LEFT;
-import static com.android.launcher3.ButtonDropTarget.TOOLTIP_RIGHT;
 import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility;
 
 import android.animation.TimeInterpolator;
@@ -41,6 +39,8 @@
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.testing.TestProtocol;
 
+import java.util.Arrays;
+
 /*
  * The top bar containing various drop targets: Delete/App Info/Uninstall.
  */
@@ -94,30 +94,28 @@
         lp.rightMargin = insets.right;
         int tooltipLocation = TOOLTIP_DEFAULT;
 
-        if (grid.isVerticalBarLayout()) {
-            lp.width = grid.dropTargetBarSizePx;
-            lp.height = grid.availableHeightPx - 2 * grid.edgeMarginPx;
-            lp.gravity = grid.isSeascape() ? Gravity.RIGHT : Gravity.LEFT;
-            tooltipLocation = grid.isSeascape() ? TOOLTIP_LEFT : TOOLTIP_RIGHT;
+        int horizontalMargin;
+        if (grid.isTablet) {
+            // XXX: If the icon size changes across orientations, we will have to take
+            //      that into account here too.
+            horizontalMargin = ((grid.widthPx - 2 * grid.edgeMarginPx
+                    - (grid.inv.numColumns * grid.cellWidthPx))
+                    / (2 * (grid.inv.numColumns + 1)))
+                    + grid.edgeMarginPx;
         } else {
-            int gap;
-            if (grid.isTablet) {
-                // XXX: If the icon size changes across orientations, we will have to take
-                //      that into account here too.
-                gap = ((grid.widthPx - 2 * grid.edgeMarginPx
-                        - (grid.inv.numColumns * grid.cellWidthPx))
-                        / (2 * (grid.inv.numColumns + 1)))
-                        + grid.edgeMarginPx;
-            } else {
-                gap = getContext().getResources()
-                        .getDimensionPixelSize(R.dimen.drop_target_bar_margin_horizontal);
-            }
-            lp.width = grid.availableWidthPx - 2 * gap;
-
-            lp.topMargin += grid.edgeMarginPx;
-            lp.height = grid.dropTargetBarSizePx;
-            lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+            horizontalMargin = getContext().getResources()
+                    .getDimensionPixelSize(R.dimen.drop_target_bar_margin_horizontal);
         }
+        lp.topMargin += grid.dropTargetBarTopMarginPx;
+        lp.bottomMargin += grid.dropTargetBarBottomMarginPx;
+        lp.width = grid.availableWidthPx - 2 * horizontalMargin;
+        if (mIsVertical) {
+            lp.leftMargin = (grid.widthPx - lp.width) / 2;
+            lp.rightMargin = (grid.widthPx - lp.width) / 2;
+        }
+        lp.height = grid.dropTargetBarSizePx;
+        lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
+
         setLayoutParams(lp);
         for (ButtonDropTarget button : mDropTargets) {
             button.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.dropTargetTextSizePx);
@@ -139,19 +137,7 @@
         int height = MeasureSpec.getSize(heightMeasureSpec);
 
         int visibleCount = getVisibleButtonsCount();
-        if (visibleCount == 0) {
-            // do nothing
-        } else if (mIsVertical) {
-            int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
-            int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
-
-            for (ButtonDropTarget button : mDropTargets) {
-                if (button.getVisibility() != GONE) {
-                    button.setTextVisible(false);
-                    button.measure(widthSpec, heightSpec);
-                }
-            }
-        } else {
+        if (visibleCount > 0) {
             int availableWidth = width / visibleCount;
             boolean textVisible = true;
             for (ButtonDropTarget buttons : mDropTargets) {
@@ -176,31 +162,91 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         int visibleCount = getVisibleButtonsCount();
         if (visibleCount == 0) {
-            // do nothing
-        } else if (mIsVertical) {
-            int gap = getResources().getDimensionPixelSize(R.dimen.drop_target_vertical_gap);
-            int start = gap;
-            int end;
+            return;
+        }
 
-            for (ButtonDropTarget button : mDropTargets) {
-                if (button.getVisibility() != GONE) {
-                    end = start + button.getMeasuredHeight();
-                    button.layout(0, start, button.getMeasuredWidth(), end);
-                    start = end + gap;
-                }
-            }
-        } else {
-            int frameSize = (right - left) / visibleCount;
+        Launcher launcher = Launcher.getLauncher(getContext());
+        Workspace workspace = launcher.getWorkspace();
+        DeviceProfile dp = launcher.getDeviceProfile();
+        int buttonHorizontalPadding = dp.dropTargetHorizontalPaddingPx;
+        int buttonVerticalPadding = dp.dropTargetVerticalPaddingPx;
+        int barCenter = (right - left) / 2;
 
-            int start = frameSize / 2;
-            int halfWidth;
-            for (ButtonDropTarget button : mDropTargets) {
-                if (button.getVisibility() != GONE) {
-                    halfWidth = button.getMeasuredWidth() / 2;
-                    button.layout(start - halfWidth, 0,
-                            start + halfWidth, button.getMeasuredHeight());
-                    start = start + frameSize;
+        ButtonDropTarget[] visibleButtons = Arrays.stream(mDropTargets)
+                .filter(b -> b.getVisibility() != GONE)
+                .toArray(ButtonDropTarget[]::new);
+        Arrays.stream(visibleButtons).forEach(
+                b -> b.setPadding(buttonHorizontalPadding, buttonVerticalPadding,
+                        buttonHorizontalPadding, buttonVerticalPadding));
+
+        if (visibleCount == 1) {
+            ButtonDropTarget button = visibleButtons[0];
+            button.layout(barCenter - (button.getMeasuredWidth() / 2), 0,
+                    barCenter + (button.getMeasuredWidth() / 2), button.getMeasuredHeight());
+        } else if (visibleCount == 2) {
+            int buttonGap = dp.dropTargetGapPx;
+
+            if (dp.isTwoPanels) {
+                ButtonDropTarget leftButton = visibleButtons[0];
+                leftButton.layout(barCenter - leftButton.getMeasuredWidth() - (buttonGap / 2), 0,
+                        barCenter - (buttonGap / 2), leftButton.getMeasuredHeight());
+
+                ButtonDropTarget rightButton = visibleButtons[1];
+                rightButton.layout(barCenter + (buttonGap / 2), 0,
+                        barCenter + rightButton.getMeasuredWidth() + (buttonGap / 2),
+                        rightButton.getMeasuredHeight());
+            } else if (dp.isTablet) {
+                int numberOfMargins = visibleCount - 1;
+                int buttonWidths = Arrays.stream(mDropTargets)
+                        .filter(b -> b.getVisibility() != GONE)
+                        .mapToInt(ButtonDropTarget::getMeasuredWidth)
+                        .sum();
+                int totalWidth = buttonWidths + (numberOfMargins * buttonGap);
+                int buttonsStartMargin = barCenter - (totalWidth / 2);
+
+                int start = buttonsStartMargin;
+                for (ButtonDropTarget button : visibleButtons) {
+                    int margin = (start != buttonsStartMargin) ? buttonGap : 0;
+                    button.layout(start + margin, 0, start + margin + button.getMeasuredWidth(),
+                            button.getMeasuredHeight());
+                    start += button.getMeasuredWidth() + margin;
                 }
+            } else if (mIsVertical) {
+                // Center buttons over workspace, not screen.
+                int verticalCenter = (workspace.getRight() - workspace.getLeft()) / 2;
+                ButtonDropTarget leftButton = visibleButtons[0];
+                leftButton.layout(verticalCenter - leftButton.getMeasuredWidth() - (buttonGap / 2),
+                        0, verticalCenter - (buttonGap / 2), leftButton.getMeasuredHeight());
+
+                ButtonDropTarget rightButton = visibleButtons[1];
+                rightButton.layout(verticalCenter + (buttonGap / 2), 0,
+                        verticalCenter + rightButton.getMeasuredWidth() + (buttonGap / 2),
+                        rightButton.getMeasuredHeight());
+            } else if (dp.isPhone) {
+                // Buttons aligned to outer edges of scaled workspace.
+                float shrunkTop = dp.getWorkspaceSpringLoadShrunkTop();
+                float shrunkBottom = dp.getWorkspaceSpringLoadShrunkBottom();
+                float scale =
+                        (shrunkBottom - shrunkTop) / launcher.getWorkspace().getNormalChildHeight();
+                int workspaceWidth = (int) (launcher.getWorkspace().getNormalChildWidth() * scale);
+                int start = barCenter - (workspaceWidth / 2);
+                int end = barCenter + (workspaceWidth / 2);
+
+                ButtonDropTarget leftButton = visibleButtons[0];
+                ButtonDropTarget rightButton = visibleButtons[1];
+
+                // If the text within the buttons is too long, the buttons can overlap
+                int overlap = start + leftButton.getMeasuredWidth() + rightButton.getMeasuredWidth()
+                        - end;
+                if (overlap > 0) {
+                    start -= overlap / 2;
+                    end += overlap / 2;
+                }
+
+                leftButton.layout(start, 0, start + leftButton.getMeasuredWidth(),
+                        leftButton.getMeasuredHeight());
+                rightButton.layout(end - rightButton.getMeasuredWidth(), 0, end,
+                        rightButton.getMeasuredHeight());
             }
         }
     }
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index d52594e..9be3cc5 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -18,7 +18,6 @@
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
 
 import android.content.Context;
-import android.graphics.Rect;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
@@ -52,28 +51,15 @@
             return super.getWorkspaceScaleAndTranslation(launcher);
         }
 
-        if (grid.isVerticalBarLayout()) {
-            float scale = grid.workspaceSpringLoadShrinkFactor;
-            return new ScaleAndTranslation(scale, 0, 0);
-        }
-
-        float scale = grid.workspaceSpringLoadShrinkFactor;
-        Rect insets = launcher.getDragLayer().getInsets();
-
-        float scaledHeight = scale * ws.getNormalChildHeight();
-        float shrunkTop = insets.top + grid.dropTargetBarSizePx;
-        float shrunkBottom = ws.getMeasuredHeight() - insets.bottom
-                - grid.workspacePadding.bottom
-                - grid.workspaceSpringLoadedBottomSpace;
-        float totalShrunkSpace = shrunkBottom - shrunkTop;
-
-        float desiredCellTop = shrunkTop + (totalShrunkSpace - scaledHeight) / 2;
+        float shrunkTop = grid.getWorkspaceSpringLoadShrunkTop();
+        float shrunkBottom = grid.getWorkspaceSpringLoadShrunkBottom();
+        float scale = (shrunkBottom - shrunkTop) / ws.getNormalChildHeight();
 
         float halfHeight = ws.getHeight() / 2;
         float myCenter = ws.getTop() + halfHeight;
         float cellTopFromCenter = halfHeight - ws.getChildAt(0).getTop();
         float actualCellTop = myCenter - cellTopFromCenter * scale;
-        return new ScaleAndTranslation(scale, 0, (desiredCellTop - actualCellTop) / scale);
+        return new ScaleAndTranslation(scale, 0, (shrunkTop - actualCellTop) / scale);
     }
 
     @Override