Fix hotseat width to span a number of columns

Fix: 227344807
Fix: 231283023
Test: manual
Change-Id: Iad0f38c2323be6d9752a8e509fc7e1164edbcf4e
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 31f1da8..88030ae 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -158,6 +158,7 @@
     public final int numShownHotseatIcons;
     public int hotseatCellHeightPx;
     private final int hotseatExtraVerticalSize;
+    private final boolean areNavButtonsInline;
     // In portrait: size = height, in landscape: size = width
     public int hotseatBarSizePx;
     public int hotseatBarTopPaddingPx;
@@ -358,7 +359,7 @@
 
         // We shrink hotseat sizes regardless of orientation, if nav buttons are inline and QSB
         // might be inline in either orientations, to keep hotseat size consistent across rotation.
-        boolean areNavButtonsInline = isTaskbarPresent && !isGestureMode;
+        areNavButtonsInline = isTaskbarPresent && !isGestureMode;
         if (areNavButtonsInline && canQsbInline) {
             numShownHotseatIcons = inv.numShrunkenHotseatIcons;
         } else {
@@ -373,15 +374,14 @@
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding);
         if (isQsbInline) {
             hotseatBarBottomPaddingPx = res.getDimensionPixelSize(R.dimen.inline_qsb_bottom_margin);
-            qsbWidth = calculateQsbWidth();
         } else {
             hotseatBarBottomPaddingPx = (isTallDevice ? res.getDimensionPixelSize(
                     R.dimen.dynamic_grid_hotseat_bottom_tall_padding)
                     : res.getDimensionPixelSize(
                             R.dimen.dynamic_grid_hotseat_bottom_non_tall_padding))
                     + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding);
-            qsbWidth = 0;
         }
+
         springLoadedHotseatBarTopMarginPx = res.getDimensionPixelSize(
                 R.dimen.spring_loaded_hotseat_top_margin);
         hotseatBarSidePaddingEndPx =
@@ -390,9 +390,7 @@
         hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0;
         hotseatExtraVerticalSize =
                 res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size);
-        hotseatBorderSpace = pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics);
-        updateHotseatIconSize(
-                pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics));
+        updateHotseatIconSize(pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics));
 
         qsbBottomMarginOriginalPx = isScalableGrid
                 ? res.getDimensionPixelSize(R.dimen.scalable_grid_qsb_bottom_margin)
@@ -483,6 +481,10 @@
                 cellLayoutPadding);
         updateWorkspacePadding();
 
+        // Hotseat and QSB width depends on updated cellSize and workspace padding
+        hotseatBorderSpace = calculateHotseatBorderSpace();
+        qsbWidth = calculateQsbWidth();
+
         flingToDeleteThresholdVelocity = res.getDimensionPixelSize(
                 R.dimen.drag_flingToDeleteMinVelocity);
 
@@ -493,14 +495,26 @@
                 new DotRenderer(allAppsIconSizePx, dotPath, DEFAULT_DOT_SIZE);
     }
 
+    /**
+     * QSB width is always calculated because when in 3 button nav the width doesn't follow the
+     * width of the hotseat.
+     */
     private int calculateQsbWidth() {
-        int columns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns;
+        if (isQsbInline) {
+            int columns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns;
+            return getIconToIconWidthForColumns(columns)
+                    - iconSizePx * numShownHotseatIcons
+                    - hotseatBorderSpace * numShownHotseatIcons;
+        } else {
+            int columns = inv.hotseatColumnSpan[mTypeIndex];
+            return getIconToIconWidthForColumns(columns);
+        }
+    }
 
-        return cellWidthPx * columns
-                + cellLayoutBorderSpacePx.x * (columns - 1)
-                - (cellWidthPx - iconSizePx) // left and right cell space
-                - iconSizePx * numShownHotseatIcons
-                - hotseatBorderSpace * numShownHotseatIcons;
+    private int getIconToIconWidthForColumns(int columns) {
+        return columns * getCellSize().x
+                + (columns - 1) * cellLayoutBorderSpacePx.x
+                - (getCellSize().x - iconSizePx);  // left and right cell space
     }
 
     private int getHorizontalMarginPx(InvariantDeviceProfile idp, Resources res) {
@@ -741,13 +755,6 @@
         // All apps
         updateAllAppsIconSize(scale, res);
 
-        // Hotseat
-        hotseatBorderSpace = pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics, scale);
-        if (isQsbInline) {
-            qsbWidth = calculateQsbWidth();
-        } else {
-            qsbWidth = 0;
-        }
         updateHotseatIconSize(iconSizePx);
 
         // Folder icon
@@ -755,6 +762,23 @@
         folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2;
     }
 
+    /**
+     * Hotseat width spans a certain number of columns on scalable grids.
+     * This method calculates the space between the icons to achieve that width.
+     */
+    private int calculateHotseatBorderSpace() {
+        if (!isScalableGrid) return 0;
+        //TODO(http://b/228998082) remove this when 3 button spaces are fixed
+        if (areNavButtonsInline) {
+            return pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics);
+        } else {
+            int columns = inv.hotseatColumnSpan[mTypeIndex];
+            float hotseatWidthPx = getIconToIconWidthForColumns(columns);
+            float hotseatIconsTotalPx = iconSizePx * numShownHotseatIcons;
+            return (int) (hotseatWidthPx - hotseatIconsTotalPx) / (numShownHotseatIcons - 1);
+        }
+    }
+
 
     /**
      * Updates the iconSize for allApps* variants.
@@ -1070,6 +1094,13 @@
                 mHotseatPadding.left -= diff;
                 mHotseatPadding.right += diff;
             }
+        } else if (isScalableGrid) {
+            int sideSpacing = (availableWidthPx - qsbWidth) / 2;
+            mHotseatPadding.set(sideSpacing,
+                    hotseatBarTopPaddingPx,
+                    sideSpacing,
+                    hotseatBarSizePx - hotseatCellHeightPx - hotseatBarTopPaddingPx
+                            + mInsets.bottom);
         } else {
             // We want the edges of the hotseat to line up with the edges of the workspace, but the
             // icons in the hotseat are a different size, and so don't line up perfectly. To account
@@ -1306,6 +1337,7 @@
         writer.println(prefix + pxToDpStr("allAppsLeftRightMargin", allAppsLeftRightMargin));
 
         writer.println(prefix + pxToDpStr("hotseatBarSizePx", hotseatBarSizePx));
+        writer.println(prefix + "\tinv.hotseatColumnSpan: " + inv.hotseatColumnSpan[mTypeIndex]);
         writer.println(prefix + pxToDpStr("hotseatCellHeightPx", hotseatCellHeightPx));
         writer.println(prefix + pxToDpStr("hotseatBarTopPaddingPx", hotseatBarTopPaddingPx));
         writer.println(prefix + pxToDpStr("hotseatBarBottomPaddingPx", hotseatBarBottomPaddingPx));
@@ -1384,7 +1416,7 @@
     private static Context getContext(Context c, Info info, int orientation, WindowBounds bounds) {
         Configuration config = new Configuration(c.getResources().getConfiguration());
         config.orientation = orientation;
-        config.densityDpi = info.densityDpi;
+        config.densityDpi = info.getDensityDpi();
         config.smallestScreenWidthDp = (int) info.smallestSizeDp(bounds);
         return c.createConfigurationContext(config);
     }