Make hotseat column span responsive

Flag: NONE
Test: DeviceProfileDumpTest, DeviceProfileAlternativeDumpTest, HomeScreenImageTest
Bug: 325084912
Change-Id: Ifa9e8066662a1ab053f66b8800b739d813d2dab8
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 3ddc7aa..65e2120 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -47,6 +47,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 import androidx.core.content.res.ResourcesCompat;
 
 import com.android.launcher3.CellLayout.ContainerType;
@@ -212,6 +213,8 @@
     // Hotseat
     public int numShownHotseatIcons;
     public int hotseatCellHeightPx;
+    private int mHotseatColumnSpan;
+    private int mHotseatWidthPx; // not used in vertical bar layout
     public final boolean areNavButtonsInline;
     // In portrait: size = height, in landscape: size = width
     public int hotseatBarSizePx;
@@ -550,6 +553,7 @@
         areNavButtonsInline = isTaskbarPresent && !isGestureMode;
         numShownHotseatIcons =
                 isTwoPanels ? inv.numDatabaseHotseatIcons : inv.numShownHotseatIcons;
+        mHotseatColumnSpan = inv.numColumns;
 
         numShownAllAppsColumns =
                 isTwoPanels ? inv.numDatabaseAllAppsColumns : inv.numAllAppsColumns;
@@ -817,8 +821,7 @@
                     - hotseatBorderSpace * numShownHotseatIcons
                     - iconExtraSpacePx;
         } else {
-            int columns = inv.hotseatColumnSpan[mTypeIndex];
-            return getIconToIconWidthForColumns(columns) - iconExtraSpacePx;
+            return getIconToIconWidthForColumns(mHotseatColumnSpan) - iconExtraSpacePx;
         }
     }
 
@@ -889,10 +892,31 @@
     public void recalculateHotseatWidthAndBorderSpace() {
         if (!mIsScalableGrid) return;
 
-        int columns = inv.hotseatColumnSpan[mTypeIndex];
-        float hotseatWidthPx = getIconToIconWidthForColumns(columns);
-        hotseatBorderSpace = calculateHotseatBorderSpace(hotseatWidthPx, /* numExtraBorder= */ 0);
+        updateHotseatWidthAndBorderSpace(inv.numColumns);
+        int numWorkspaceColumns = getPanelCount() * inv.numColumns;
+        if (isTwoPanels) {
+            updateHotseatWidthAndBorderSpace(inv.numDatabaseHotseatIcons);
+            // If hotseat doesn't fit with current width, increase column span to fit by multiple
+            // of 2.
+            while (hotseatBorderSpace < mMinHotseatIconSpacePx
+                    && mHotseatColumnSpan < numWorkspaceColumns) {
+                updateHotseatWidthAndBorderSpace(mHotseatColumnSpan + 2);
+            }
+        }
+        if (isQsbInline) {
+            // If QSB is inline, reduce column span until it fits.
+            int maxHotseatWidthAllowedPx = getIconToIconWidthForColumns(numWorkspaceColumns);
+            int minHotseatWidthRequiredPx =
+                    mMinHotseatQsbWidthPx + hotseatBorderSpace + mHotseatWidthPx;
+            while (minHotseatWidthRequiredPx > maxHotseatWidthAllowedPx
+                    && mHotseatColumnSpan > 1) {
+                updateHotseatWidthAndBorderSpace(mHotseatColumnSpan - 1);
+                minHotseatWidthRequiredPx =
+                        mMinHotseatQsbWidthPx + hotseatBorderSpace + mHotseatWidthPx;
+            }
+        }
         hotseatQsbWidth = calculateQsbWidth(hotseatBorderSpace);
+
         // Spaces should be correct when the nav buttons are not inline
         if (!areNavButtonsInline) {
             return;
@@ -934,6 +958,12 @@
         } while (hotseatBorderSpace < mMinHotseatIconSpacePx && numShownHotseatIcons > 1);
     }
 
+    private void updateHotseatWidthAndBorderSpace(int columns) {
+        mHotseatColumnSpan = columns;
+        mHotseatWidthPx = getIconToIconWidthForColumns(mHotseatColumnSpan);
+        hotseatBorderSpace = calculateHotseatBorderSpace(mHotseatWidthPx, /* numExtraBorder= */ 0);
+    }
+
     private Point getCellLayoutBorderSpace(InvariantDeviceProfile idp) {
         return getCellLayoutBorderSpace(idp, 1f);
     }
@@ -957,6 +987,16 @@
         return mInfo;
     }
 
+    @VisibleForTesting
+    public int getHotseatColumnSpan() {
+        return mHotseatColumnSpan;
+    }
+
+    @VisibleForTesting
+    public int getHotseatWidthPx() {
+        return mHotseatWidthPx;
+    }
+
     public Builder toBuilder(Context context) {
         WindowBounds bounds = new WindowBounds(
                 widthPx, heightPx, availableWidthPx, availableHeightPx, rotationHint);
@@ -2119,7 +2159,8 @@
         writer.println(prefix + pxToDpStr("allAppsLeftRightMargin", allAppsLeftRightMargin));
 
         writer.println(prefix + pxToDpStr("hotseatBarSizePx", hotseatBarSizePx));
-        writer.println(prefix + "\tinv.hotseatColumnSpan: " + inv.hotseatColumnSpan[mTypeIndex]);
+        writer.println(prefix + "\tmHotseatColumnSpan: " + mHotseatColumnSpan);
+        writer.println(prefix + pxToDpStr("mHotseatWidthPx", mHotseatWidthPx));
         writer.println(prefix + pxToDpStr("hotseatCellHeightPx", hotseatCellHeightPx));
         writer.println(prefix + pxToDpStr("hotseatBarBottomSpacePx", hotseatBarBottomSpacePx));
         writer.println(prefix + pxToDpStr("mHotseatBarEdgePaddingPx",
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 2e0f676..ca10a57 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -163,7 +163,6 @@
      */
     public int numDatabaseHotseatIcons;
 
-    public int[] hotseatColumnSpan;
     public float[] hotseatBarBottomSpace;
     public float[] hotseatQsbSpace;
 
@@ -420,7 +419,6 @@
         numShownHotseatIcons = closestProfile.numHotseatIcons;
         numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY
                 ? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons;
-        hotseatColumnSpan = closestProfile.hotseatColumnSpan;
         hotseatBarBottomSpace = displayOption.hotseatBarBottomSpace;
         hotseatQsbSpace = displayOption.hotseatQsbSpace;
 
@@ -870,8 +868,6 @@
         private final int numHotseatIcons;
         private final int numDatabaseHotseatIcons;
 
-        private final int[] hotseatColumnSpan = new int[COUNT_SIZES];
-
         private final boolean[] inlineQsb = new boolean[COUNT_SIZES];
 
         private @DimenRes int inlineNavButtonsEndSpacing;
@@ -922,17 +918,6 @@
             numDatabaseHotseatIcons = a.getInt(
                     R.styleable.GridDisplayOption_numExtendedHotseatIcons, 2 * numHotseatIcons);
 
-            hotseatColumnSpan[INDEX_DEFAULT] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpan, numColumns);
-            hotseatColumnSpan[INDEX_LANDSCAPE] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpanLandscape, numColumns);
-            hotseatColumnSpan[INDEX_TWO_PANEL_LANDSCAPE] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpanTwoPanelLandscape,
-                    numColumns);
-            hotseatColumnSpan[INDEX_TWO_PANEL_PORTRAIT] = a.getInt(
-                    R.styleable.GridDisplayOption_hotseatColumnSpanTwoPanelPortrait,
-                    numColumns);
-
             inlineNavButtonsEndSpacing =
                     a.getResourceId(R.styleable.GridDisplayOption_inlineNavButtonsEndSpacing,
                             R.dimen.taskbar_button_margin_default);