Update the computation of the widget span from size

The new computation takes into account the new cell layout border
spacing.

Change-Id: Ic20e0906bbbaaf1e53475585e2a6ca31c277e09b
Bug: 187461595
Test: Manual testing, varying the sizes in a widget
diff --git a/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java b/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
index d977011..d18138f 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
+++ b/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
@@ -20,8 +20,10 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 
+import android.appwidget.AppWidgetHostView;
 import android.content.Context;
 import android.graphics.Point;
+import android.graphics.Rect;
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InvariantDeviceProfile;
@@ -110,6 +112,47 @@
         assertThat(info.minSpanY).isEqualTo(2);
     }
 
+    @Test
+    public void initSpans_minResizeWidthWithCellSpacingAndWidgetInset_shouldInitializeMinSpans() {
+        InvariantDeviceProfile idp = createIDP();
+        DeviceProfile dp = idp.supportedProfiles.get(0);
+        Rect padding = new Rect();
+        AppWidgetHostView.getDefaultPaddingForWidget(mContext, null, padding);
+        int maxPadding = Math.max(Math.max(padding.left, padding.right),
+                Math.max(padding.top, padding.bottom));
+        dp.cellLayoutBorderSpacingPx = maxPadding + 1;
+        Mockito.when(dp.shouldInsetWidgets()).thenReturn(true);
+
+        LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
+        info.minResizeWidth = CELL_SIZE * 2 + maxPadding;
+        info.minResizeHeight = CELL_SIZE * 2 + maxPadding;
+
+        info.initSpans(mContext, idp);
+
+        assertThat(info.minSpanX).isEqualTo(2);
+        assertThat(info.minSpanY).isEqualTo(2);
+    }
+
+    @Test
+    public void initSpans_minResizeWidthWithCellSpacingAndNoWidgetInset_shouldInitializeMinSpans() {
+        InvariantDeviceProfile idp = createIDP();
+        DeviceProfile dp = idp.supportedProfiles.get(0);
+        Rect padding = new Rect();
+        AppWidgetHostView.getDefaultPaddingForWidget(mContext, null, padding);
+        int maxPadding = Math.max(Math.max(padding.left, padding.right),
+                Math.max(padding.top, padding.bottom));
+        dp.cellLayoutBorderSpacingPx = maxPadding - 1;
+        Mockito.when(dp.shouldInsetWidgets()).thenReturn(false);
+        LauncherAppWidgetProviderInfo info = new LauncherAppWidgetProviderInfo();
+        info.minResizeWidth = CELL_SIZE * 2 + maxPadding;
+        info.minResizeHeight = CELL_SIZE * 2 + maxPadding;
+
+        info.initSpans(mContext, idp);
+
+        assertThat(info.minSpanX).isEqualTo(3);
+        assertThat(info.minSpanY).isEqualTo(3);
+    }
+
     private InvariantDeviceProfile createIDP() {
         DeviceProfile profile = Mockito.mock(DeviceProfile.class);
         doAnswer(i -> {
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
index 53b5fec..14108f6 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
@@ -67,61 +67,86 @@
     }
 
     public void initSpans(Context context, InvariantDeviceProfile idp) {
-        // Always assume we're working with the smallest span to make sure we
-        // reserve enough space in both orientations.
-        float smallestCellWidth = Float.MAX_VALUE;
-        float smallestCellHeight = Float.MAX_VALUE;
+        int minSpanX = 0;
+        int minSpanY = 0;
+        int maxSpanX = idp.numColumns;
+        int maxSpanY = idp.numRows;
+        int spanX = 0;
+        int spanY = 0;
+
+        Rect widgetPadding = new Rect();
+        Rect localPadding = new Rect();
+        AppWidgetHostView.getDefaultPaddingForWidget(context, provider, widgetPadding);
 
         Point cellSize = new Point();
-        boolean isWidgetPadded = false;
         for (DeviceProfile dp : idp.supportedProfiles) {
             dp.getCellSize(cellSize);
-            smallestCellWidth = Math.min(smallestCellWidth, cellSize.x);
-            smallestCellHeight = Math.min(smallestCellHeight, cellSize.y);
-            isWidgetPadded = isWidgetPadded || !dp.shouldInsetWidgets();
+            // We want to account for the extra amount of padding that we are adding to the widget
+            // to ensure that it gets the full amount of space that it has requested.
+            // If grids supports insetting widgets, we do not account for widget padding.
+            if (dp.shouldInsetWidgets()) {
+                localPadding.setEmpty();
+            } else {
+                localPadding.set(widgetPadding);
+            }
+            minSpanX = Math.max(minSpanX,
+                    getSpanX(localPadding, minResizeWidth, dp.cellLayoutBorderSpacingPx,
+                            cellSize.x));
+            minSpanY = Math.max(minSpanY,
+                    getSpanY(localPadding, minResizeHeight, dp.cellLayoutBorderSpacingPx,
+                            cellSize.y));
+
+            if (ATLEAST_S) {
+                if (maxResizeWidth > 0) {
+                    maxSpanX = Math.min(maxSpanX,
+                            getSpanX(localPadding, maxResizeWidth, dp.cellLayoutBorderSpacingPx,
+                                    cellSize.x));
+                }
+                if (maxResizeHeight > 0) {
+                    maxSpanY = Math.min(maxSpanY,
+                            getSpanY(localPadding, maxResizeHeight, dp.cellLayoutBorderSpacingPx,
+                                    cellSize.y));
+                }
+            }
+
+            spanX = Math.max(spanX,
+                    getSpanX(localPadding, minWidth, dp.cellLayoutBorderSpacingPx, cellSize.x));
+            spanY = Math.max(spanY,
+                    getSpanY(localPadding, minHeight, dp.cellLayoutBorderSpacingPx, cellSize.y));
         }
 
-        // We want to account for the extra amount of padding that we are adding to the widget
-        // to ensure that it gets the full amount of space that it has requested.
-        // If grids supports insetting widgets, we do not account for widget padding.
-        Rect widgetPadding = new Rect();
-        if (isWidgetPadded) {
-            AppWidgetHostView.getDefaultPaddingForWidget(context, provider, widgetPadding);
+        if (ATLEAST_S) {
+            // Ensures maxSpan >= minSpan
+            maxSpanX = Math.max(maxSpanX, minSpanX);
+            maxSpanY = Math.max(maxSpanY, minSpanY);
+
+            // Use targetCellWidth/Height if it is within the min/max ranges.
+            // Otherwise, use the span of minWidth/Height.
+            if (targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX
+                    && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {
+                spanX = targetCellWidth;
+                spanY = targetCellHeight;
+            }
         }
 
-        minSpanX = getSpanX(widgetPadding, minResizeWidth, smallestCellWidth);
-        minSpanY = getSpanY(widgetPadding, minResizeHeight, smallestCellHeight);
-
-        // Use maxResizeWidth/Height if they are defined and we're on S or above.
-        maxSpanX =
-                (ATLEAST_S && maxResizeWidth > 0)
-                        ? getSpanX(widgetPadding, maxResizeWidth, smallestCellWidth)
-                        : idp.numColumns;
-        maxSpanY =
-                (ATLEAST_S && maxResizeHeight > 0)
-                        ? getSpanY(widgetPadding, maxResizeHeight, smallestCellHeight)
-                        : idp.numRows;
-
-        // Use targetCellWidth/Height if it is within the min/max ranges and we're on S or above.
-        // Otherwise, fall back to minWidth/Height.
-        if (ATLEAST_S && targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX
-                && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {
-            spanX = targetCellWidth;
-            spanY = targetCellHeight;
-        } else {
-            spanX = getSpanX(widgetPadding, minWidth, smallestCellWidth);
-            spanY = getSpanY(widgetPadding, minHeight, smallestCellHeight);
-        }
+        this.minSpanX = minSpanX;
+        this.minSpanY = minSpanY;
+        this.maxSpanX = maxSpanX;
+        this.maxSpanY = maxSpanY;
+        this.spanX = spanX;
+        this.spanY = spanY;
     }
 
-    private int getSpanX(Rect widgetPadding, int widgetWidth, float cellWidth) {
+    private int getSpanX(Rect widgetPadding, int widgetWidth, int cellSpacing, float cellWidth) {
         return Math.max(1, (int) Math.ceil(
-                (widgetWidth + widgetPadding.left + widgetPadding.right) / cellWidth));
+                (widgetWidth + widgetPadding.left + widgetPadding.right + cellSpacing) / (cellWidth
+                        + cellSpacing)));
     }
 
-    private int getSpanY(Rect widgetPadding, int widgetHeight, float cellHeight) {
+    private int getSpanY(Rect widgetPadding, int widgetHeight, int cellSpacing, float cellHeight) {
         return Math.max(1, (int) Math.ceil(
-                (widgetHeight + widgetPadding.top + widgetPadding.bottom) / cellHeight));
+                (widgetHeight + widgetPadding.top + widgetPadding.bottom + cellSpacing) / (
+                        cellHeight + cellSpacing)));
     }
 
     public String getLabel(PackageManager packageManager) {