Update DeviceProfile to calculate responsive grid for folders

It uses the new responsive folder calculations and specs when responsive grid is enabled. The grid has to have folderSpecsId defined to use the new specifications, otherwise it will use the current scalable grid implementation.

Fix: 284155638
Test: DeviceProfileDumpTest
Test: ResponsiveHomeScreenFolderImageTest
Test: HomeScreenFolderImageTest
Flag: ENABLE_RESPONSIVE_WORKSPACE
Change-Id: I535cff4bb00e969f782447a898230fe2b2c05cc9
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 32421a4..64ac841 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -382,8 +382,7 @@
     private void resetCellSizeInternal(DeviceProfile deviceProfile) {
         switch (mContainerType) {
             case FOLDER:
-                mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx,
-                        deviceProfile.folderCellLayoutBorderSpacePx);
+                mBorderSpace = new Point(deviceProfile.folderCellLayoutBorderSpacePx);
                 break;
             case HOTSEAT:
                 mBorderSpace = new Point(deviceProfile.hotseatBorderSpace,
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index a166271..bd47fca 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -55,6 +55,8 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.responsive.AllAppsSpecs;
 import com.android.launcher3.responsive.CalculatedAllAppsSpec;
+import com.android.launcher3.responsive.CalculatedFolderSpec;
+import com.android.launcher3.responsive.FolderSpecs;
 import com.android.launcher3.uioverrides.ApiWrapper;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.Info;
@@ -78,8 +80,7 @@
 
     public static final PointF DEFAULT_SCALE = new PointF(1.0f, 1.0f);
     public static final ViewScaleProvider DEFAULT_PROVIDER = itemInfo -> DEFAULT_SCALE;
-    public static final Consumer<DeviceProfile> DEFAULT_DIMENSION_PROVIDER = dp -> {
-    };
+    public static final Consumer<DeviceProfile> DEFAULT_DIMENSION_PROVIDER = dp -> {};
 
     public final InvariantDeviceProfile inv;
     private final Info mInfo;
@@ -120,6 +121,9 @@
     private AllAppsSpecs mAllAppsSpecs;
     private CalculatedAllAppsSpec mAllAppsResponsiveWidthSpec;
     private CalculatedAllAppsSpec mAllAppsResponsiveHeightSpec;
+    private FolderSpecs mFolderSpecs;
+    private CalculatedFolderSpec mResponsiveFolderWidthSpec;
+    private CalculatedFolderSpec mResponsiveFolderHeightSpec;
 
     /**
      * The maximum amount of left/right workspace padding as a percentage of the screen width.
@@ -178,7 +182,7 @@
     public int folderIconOffsetYPx;
 
     // Folder content
-    public int folderCellLayoutBorderSpacePx;
+    public Point folderCellLayoutBorderSpacePx;
     public int folderContentPaddingLeftRight;
     public int folderContentPaddingTop;
 
@@ -314,7 +318,8 @@
 
         // TODO(b/241386436): shouldn't change any launcher behaviour
         mIsResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE
-                && inv.allAppsSpecsId != INVALID_RESOURCE_HANDLE;
+                && inv.allAppsSpecsId != INVALID_RESOURCE_HANDLE
+                && inv.folderSpecsId != INVALID_RESOURCE_HANDLE;
 
         mIsScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
         // Determine device posture.
@@ -420,13 +425,15 @@
 
             folderContentPaddingTop = folderStyle.getDimensionPixelSize(
                     R.styleable.FolderStyle_folderTopPadding, 0);
-            folderCellLayoutBorderSpacePx = folderStyle.getDimensionPixelSize(
+
+            int gutter = folderStyle.getDimensionPixelSize(
                     R.styleable.FolderStyle_folderBorderSpace, 0);
+            folderCellLayoutBorderSpacePx = new Point(gutter, gutter);
             folderFooterHeightPx = folderStyle.getDimensionPixelSize(
                     R.styleable.FolderStyle_folderFooterHeight, 0);
             folderStyle.recycle();
-        } else {
-            folderCellLayoutBorderSpacePx = 0;
+        } else if (!mIsResponsiveGrid) {
+            folderCellLayoutBorderSpacePx = new Point(0, 0);
             folderFooterHeightPx = res.getDimensionPixelSize(R.dimen.folder_footer_height_default);
             folderContentPaddingTop = res.getDimensionPixelSize(R.dimen.folder_top_padding_default);
         }
@@ -556,6 +563,12 @@
             mAllAppsResponsiveHeightSpec = mAllAppsSpecs.getCalculatedHeightSpec(inv.numRows,
                     mResponsiveHeightSpec.getAvailableSpace(),
                     mResponsiveHeightSpec);
+
+            mFolderSpecs = new FolderSpecs(new ResourceHelper(context, inv.folderSpecsId));
+            mResponsiveFolderWidthSpec = mFolderSpecs.getWidthSpec(inv.numFolderColumns,
+                    mResponsiveWidthSpec.getAvailableSpace(), mResponsiveWidthSpec);
+            mResponsiveFolderHeightSpec = mFolderSpecs.getHeightSpec(inv.numFolderRows,
+                    mResponsiveHeightSpec.getAvailableSpace(), mResponsiveHeightSpec);
         }
 
         desiredWorkspaceHorizontalMarginPx = getHorizontalMarginPx(inv, res);
@@ -1179,15 +1192,19 @@
         allAppsStyle.recycle();
     }
 
+    // TODO(b/288075868): Resize the icon size to make sure it will fit inside the cell size
     private void updateAvailableFolderCellDimensions(Resources res) {
         updateFolderCellSize(1f, res);
 
+        // Responsive grid doesn't need to scale the folder
+        if (mIsResponsiveGrid) return;
+
         // For usability we can't have the folder use the whole width of the screen
         Point totalWorkspacePadding = getTotalWorkspacePadding();
 
         // Check if the folder fit within the available height.
         float contentUsedHeight = folderCellHeightPx * inv.numFolderRows
-                + ((inv.numFolderRows - 1) * folderCellLayoutBorderSpacePx)
+                + ((inv.numFolderRows - 1) * folderCellLayoutBorderSpacePx.y)
                 + folderFooterHeightPx
                 + folderContentPaddingTop;
         int contentMaxHeight = availableHeightPx - totalWorkspacePadding.y;
@@ -1195,7 +1212,7 @@
 
         // Check if the folder fit within the available width.
         float contentUsedWidth = folderCellWidthPx * inv.numFolderColumns
-                + ((inv.numFolderColumns - 1) * folderCellLayoutBorderSpacePx)
+                + ((inv.numFolderColumns - 1) * folderCellLayoutBorderSpacePx.x)
                 + folderContentPaddingLeftRight * 2;
         int contentMaxWidth = availableWidthPx - totalWorkspacePadding.x;
         float scaleX = contentMaxWidth / contentUsedWidth;
@@ -1215,7 +1232,19 @@
 
         int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx);
 
-        if (mIsScalableGrid) {
+        if (mIsResponsiveGrid) {
+            folderCellWidthPx = mResponsiveFolderWidthSpec.getCellSizePx();
+
+            // Height
+            folderCellHeightPx = mResponsiveFolderHeightSpec.getCellSizePx();
+            folderContentPaddingTop = mResponsiveFolderHeightSpec.getStartPaddingPx();
+            folderFooterHeightPx = mResponsiveFolderHeightSpec.getEndPaddingPx();
+
+            folderCellLayoutBorderSpacePx = new Point(mResponsiveFolderWidthSpec.getGutterPx(),
+                    mResponsiveHeightSpec.getGutterPx());
+
+            folderContentPaddingLeftRight = mResponsiveFolderWidthSpec.getStartPaddingPx();
+        } else if (mIsScalableGrid) {
             if (inv.folderStyle == INVALID_RESOURCE_HANDLE) {
                 folderCellWidthPx = roundPxValueFromFloat(getCellSize().x * scale);
                 folderCellHeightPx = roundPxValueFromFloat(getCellSize().y * scale);
@@ -1225,11 +1254,13 @@
             }
 
             folderContentPaddingTop = roundPxValueFromFloat(folderContentPaddingTop * scale);
-            folderCellLayoutBorderSpacePx = roundPxValueFromFloat(
-                    folderCellLayoutBorderSpacePx * scale);
+            folderCellLayoutBorderSpacePx = new Point(
+                    roundPxValueFromFloat(folderCellLayoutBorderSpacePx.x * scale),
+                    roundPxValueFromFloat(folderCellLayoutBorderSpacePx.y * scale)
+            );
             folderFooterHeightPx = roundPxValueFromFloat(folderFooterHeightPx * scale);
 
-            folderContentPaddingLeftRight = folderCellLayoutBorderSpacePx;
+            folderContentPaddingLeftRight = folderCellLayoutBorderSpacePx.x;
         } else {
             int cellPaddingX = (int) (res.getDimensionPixelSize(R.dimen.folder_cell_x_padding)
                     * scale);
@@ -1750,8 +1781,10 @@
         writer.println(prefix + pxToDpStr("folderChildTextSizePx", folderChildTextSizePx));
         writer.println(prefix + pxToDpStr("folderChildDrawablePaddingPx",
                 folderChildDrawablePaddingPx));
-        writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx",
-                folderCellLayoutBorderSpacePx));
+        writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx.x",
+                folderCellLayoutBorderSpacePx.x));
+        writer.println(prefix + pxToDpStr("folderCellLayoutBorderSpacePx.y",
+                folderCellLayoutBorderSpacePx.y));
         writer.println(prefix + pxToDpStr("folderContentPaddingLeftRight",
                 folderContentPaddingLeftRight));
         writer.println(prefix + pxToDpStr("folderTopPadding", folderContentPaddingTop));
@@ -1871,6 +1904,8 @@
                     + mAllAppsResponsiveHeightSpec.toString());
             writer.println(prefix + "\tmAllAppsResponsiveWidthSpec:"
                     + mAllAppsResponsiveWidthSpec.toString());
+            writer.println(prefix + "\tmResponsiveFolderHeightSpec:" + mResponsiveFolderHeightSpec);
+            writer.println(prefix + "\tmResponsiveFolderWidthSpec:" + mResponsiveFolderWidthSpec);
         }
     }
 
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 81aa2b2..4eaacdc 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -181,6 +181,8 @@
     public int workspaceSpecsId = INVALID_RESOURCE_HANDLE;
     @XmlRes
     public int allAppsSpecsId = INVALID_RESOURCE_HANDLE;
+    @XmlRes
+    public int folderSpecsId = INVALID_RESOURCE_HANDLE;
 
     public String dbFile;
     public int defaultLayoutId;
@@ -356,6 +358,7 @@
         devicePaddingId = closestProfile.devicePaddingId;
         workspaceSpecsId = closestProfile.mWorkspaceSpecsId;
         allAppsSpecsId = closestProfile.mAllAppsSpecsId;
+        folderSpecsId = closestProfile.mFolderSpecsId;
         this.deviceType = deviceType;
 
         inlineNavButtonsEndSpacing = closestProfile.inlineNavButtonsEndSpacing;
@@ -803,6 +806,7 @@
         private final int devicePaddingId;
         private final int mWorkspaceSpecsId;
         private final int mAllAppsSpecsId;
+        private final int mFolderSpecsId;
 
         public GridOption(Context context, AttributeSet attrs) {
             TypedArray a = context.obtainStyledAttributes(
@@ -869,9 +873,12 @@
                         R.styleable.GridDisplayOption_workspaceSpecsId, INVALID_RESOURCE_HANDLE);
                 mAllAppsSpecsId = a.getResourceId(
                         R.styleable.GridDisplayOption_allAppsSpecsId, INVALID_RESOURCE_HANDLE);
+                mFolderSpecsId = a.getResourceId(
+                        R.styleable.GridDisplayOption_folderSpecsId, INVALID_RESOURCE_HANDLE);
             } else {
                 mWorkspaceSpecsId = INVALID_RESOURCE_HANDLE;
                 mAllAppsSpecsId = INVALID_RESOURCE_HANDLE;
+                mFolderSpecsId = INVALID_RESOURCE_HANDLE;
             }
 
             int inlineForRotation = a.getInt(R.styleable.GridDisplayOption_inlineQsb,
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index ba6dc26..f921d1d 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -162,7 +162,7 @@
             // No need to add padding when cell layout border spacing is present.
             boolean noPaddingX =
                     (dp.cellLayoutBorderSpacePx.x > 0 && mContainerType == WORKSPACE)
-                            || (dp.folderCellLayoutBorderSpacePx > 0 && mContainerType == FOLDER)
+                            || (dp.folderCellLayoutBorderSpacePx.x > 0 && mContainerType == FOLDER)
                             || (dp.hotseatBorderSpace > 0 && mContainerType == HOTSEAT);
             int cellPaddingX = noPaddingX
                     ? 0
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index dd82ecf..b09985c 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -236,9 +236,9 @@
                 mFolder, startRect, endRect, finalRadius, !mIsOpening));
 
         // Create reveal animator for the folder content (capture the top 4 icons 2x2)
-        int width = mDeviceProfile.folderCellLayoutBorderSpacePx
+        int width = mDeviceProfile.folderCellLayoutBorderSpacePx.x
                 + mDeviceProfile.folderCellWidthPx * 2;
-        int height = mDeviceProfile.folderCellLayoutBorderSpacePx
+        int height = mDeviceProfile.folderCellLayoutBorderSpacePx.y
                 + mDeviceProfile.folderCellHeightPx * 2;
         int page = mIsOpening ? mContent.getCurrentPage() : mContent.getDestinationPage();
         int left = mContent.getPaddingLeft() + page * lp.width;
diff --git a/src/com/android/launcher3/responsive/FolderSpecs.kt b/src/com/android/launcher3/responsive/FolderSpecs.kt
index be97cf8..f4446bc 100644
--- a/src/com/android/launcher3/responsive/FolderSpecs.kt
+++ b/src/com/android/launcher3/responsive/FolderSpecs.kt
@@ -188,12 +188,12 @@
 }
 
 data class CalculatedFolderSpec(
+    val availableSpace: Int,
+    val cells: Int,
     val startPaddingPx: Int,
     val endPaddingPx: Int,
     val gutterPx: Int,
-    val cellSizePx: Int,
-    val availableSpace: Int,
-    val cells: Int
+    val cellSizePx: Int
 )
 
 /**
@@ -270,11 +270,11 @@
     cellSizePx = folderSpec.cellSize.getRemainderSpaceValue(remainderSpace, cellSizePx)
 
     return CalculatedFolderSpec(
+        availableSpace = availableSpace,
+        cells = cells,
         startPaddingPx = startPaddingPx,
         endPaddingPx = endPaddingPx,
         gutterPx = gutterPx,
-        cellSizePx = cellSizePx,
-        availableSpace = availableSpace,
-        cells = cells
+        cellSizePx = cellSizePx
     )
 }