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",