From c9e69fa98da5bb166edf0978bf45d3c1bfd952ab Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Mon, 22 Mar 2021 17:13:34 -0400 Subject: [PATCH] Refactor device padding to be set per grid option - Fixes bug where devices with scaled grids were not getting the correct deivce padding. - Also fix bug where device padding was invalid. Added validation check when processing paddings to prevent this from happening again. Bug: 175329686 Test: manual, enable debug flag, run and verify no crash from validation check Change-Id: I35b019c40667c08de4fad95ac4b05b2d8f8a0e74 --- res/values/attrs.xml | 1 + ...size_limits.xml => size_limits_80x104.xml} | 2 +- src/com/android/launcher3/DevicePaddings.java | 44 ++++++++++++++++--- src/com/android/launcher3/DeviceProfile.java | 27 +++++++++--- .../launcher3/InvariantDeviceProfile.java | 14 ++++-- 5 files changed, 74 insertions(+), 14 deletions(-) rename res/xml/{size_limits.xml => size_limits_80x104.xml} (98%) diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 4078ef4092..f4a729f734 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -134,6 +134,7 @@ + diff --git a/res/xml/size_limits.xml b/res/xml/size_limits_80x104.xml similarity index 98% rename from res/xml/size_limits.xml rename to res/xml/size_limits_80x104.xml index ba570146de..e11bc5ecfa 100644 --- a/res/xml/size_limits.xml +++ b/res/xml/size_limits_80x104.xml @@ -38,7 +38,7 @@ + launcher:c="16dp"/> mDevicePaddings = new ArrayList<>(); - public DevicePaddings(Context context) { - try (XmlResourceParser parser = context.getResources().getXml(R.xml.size_limits)) { + public DevicePaddings(Context context, int devicePaddingId) { + try (XmlResourceParser parser = context.getResources().getXml(devicePaddingId)) { final int depth = parser.getDepth(); int type; while (((type = parser.next()) != XmlPullParser.END_TAG || @@ -94,16 +94,27 @@ public class DevicePaddings { if (workspaceTopPadding == null || workspaceBottomPadding == null || hotseatBottomPadding == null) { - throw new RuntimeException("DevicePadding missing padding."); + if (Utilities.IS_DEBUG_DEVICE) { + throw new RuntimeException("DevicePadding missing padding."); + } } - mDevicePaddings.add(new DevicePadding(maxWidthPx, workspaceTopPadding, - workspaceBottomPadding, hotseatBottomPadding)); + DevicePadding dp = new DevicePadding(maxWidthPx, workspaceTopPadding, + workspaceBottomPadding, hotseatBottomPadding); + if (dp.isValid()) { + mDevicePaddings.add(dp); + } else { + Log.e(TAG, "Invalid device padding found."); + if (Utilities.IS_DEBUG_DEVICE) { + throw new RuntimeException("DevicePadding is invalid"); + } + } } } } } } catch (IOException | XmlPullParserException e) { + Log.e(TAG, "Failure parsing device padding layout.", e); throw new RuntimeException(e); } @@ -128,6 +139,9 @@ public class DevicePaddings { */ public static final class DevicePadding { + // One for each padding since they can each be off by 1 due to rounding errors. + private static final int ROUNDING_THRESHOLD_PX = 3; + private final int maxEmptySpacePx; private final PaddingFormula workspaceTopPadding; private final PaddingFormula workspaceBottomPadding; @@ -143,6 +157,10 @@ public class DevicePaddings { this.hotseatBottomPadding = hotseatBottomPadding; } + public int getMaxEmptySpacePx() { + return maxEmptySpacePx; + } + public int getWorkspaceTopPadding(int extraSpacePx) { return workspaceTopPadding.calculate(extraSpacePx); } @@ -154,6 +172,22 @@ public class DevicePaddings { public int getHotseatBottomPadding(int extraSpacePx) { return hotseatBottomPadding.calculate(extraSpacePx); } + + public boolean isValid() { + int workspaceTopPadding = getWorkspaceTopPadding(maxEmptySpacePx); + int workspaceBottomPadding = getWorkspaceBottomPadding(maxEmptySpacePx); + int hotseatBottomPadding = getHotseatBottomPadding(maxEmptySpacePx); + int sum = workspaceTopPadding + workspaceBottomPadding + hotseatBottomPadding; + int diff = Math.abs(sum - maxEmptySpacePx); + if (DEBUG) { + Log.d(TAG, "isValid: workspaceTopPadding=" + workspaceTopPadding + + ", workspaceBottomPadding=" + workspaceBottomPadding + + ", hotseatBottomPadding=" + hotseatBottomPadding + + ", sum=" + sum + + ", diff=" + diff); + } + return diff <= ROUNDING_THRESHOLD_PX; + } } /** diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 58d612d014..1ce5f4dba6 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -104,6 +104,7 @@ public class DeviceProfile { private final int mWorkspacePageIndicatorOverlapWorkspace; // Workspace icons + public float iconScale; public int iconSizePx; public int iconTextSizePx; public int iconDrawablePaddingPx; @@ -312,12 +313,19 @@ public class DeviceProfile { // Calculate all of the remaining variables. extraSpace = updateAvailableDimensions(res); // Now that we have all of the variables calculated, we can tune certain sizes. - if (isScalableGrid) { - DevicePadding padding = inv.devicePaddings.getDevicePadding(extraSpace); - workspaceTopPadding = padding.getWorkspaceTopPadding(extraSpace); - workspaceBottomPadding = padding.getWorkspaceBottomPadding(extraSpace); + if (isScalableGrid && inv.devicePaddings != null) { + // Paddings were created assuming no scaling, so we first unscale the extra space. + int unscaledExtraSpace = (int) (extraSpace / iconScale); + DevicePadding padding = inv.devicePaddings.getDevicePadding(unscaledExtraSpace); + + int paddingWorkspaceTop = padding.getWorkspaceTopPadding(unscaledExtraSpace); + int paddingWorkspaceBottom = padding.getWorkspaceBottomPadding(unscaledExtraSpace); + int paddingHotseatBottom = padding.getHotseatBottomPadding(unscaledExtraSpace); + + workspaceTopPadding = Math.round(paddingWorkspaceTop * iconScale); + workspaceBottomPadding = Math.round(paddingWorkspaceBottom * iconScale); + extraHotseatBottomPadding = Math.round(paddingHotseatBottom * iconScale); - extraHotseatBottomPadding = padding.getHotseatBottomPadding(extraSpace); hotseatBarSizePx += extraHotseatBottomPadding; hotseatBarBottomPaddingPx += extraHotseatBottomPadding; } else if (!isVerticalBarLayout() && isPhone && isTallDevice) { @@ -490,6 +498,8 @@ public class DeviceProfile { * hotseat sizes, workspaceSpringLoadedShrinkFactor, folderIconSizePx, and folderIconOffsetYPx. */ public void updateIconSize(float scale, Resources res) { + iconScale = scale; + // Workspace final boolean isVerticalLayout = isVerticalBarLayout(); float invIconSizeDp = isVerticalLayout ? inv.landscapeIconSize : inv.iconSize; @@ -890,7 +900,14 @@ public class DeviceProfile { writer.println(prefix + pxToDpStr("workspacePadding.right", workspacePadding.right)); writer.println(prefix + pxToDpStr("workspacePadding.bottom", workspacePadding.bottom)); + writer.println(prefix + pxToDpStr("scaleToFit", iconScale)); writer.println(prefix + pxToDpStr("extraSpace", extraSpace)); + + if (inv.devicePaddings != null) { + int unscaledExtraSpace = (int) (extraSpace / iconScale); + writer.println(prefix + pxToDpStr("maxEmptySpace", + inv.devicePaddings.getDevicePadding(unscaledExtraSpace).getMaxEmptySpacePx())); + } writer.println(prefix + pxToDpStr("workspaceTopPadding", workspaceTopPadding)); writer.println(prefix + pxToDpStr("workspaceBottomPadding", workspaceBottomPadding)); writer.println(prefix + pxToDpStr("extraHotseatBottomPadding", extraHotseatBottomPadding)); diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 348d9eef2c..3dbd4794a2 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -132,6 +132,7 @@ public class InvariantDeviceProfile { * Do not query directly. see {@link DeviceProfile#isScalableGrid}. */ protected boolean isScalable; + public int devicePaddingId; public String dbFile; public int defaultLayoutId; @@ -140,7 +141,7 @@ public class InvariantDeviceProfile { public DeviceProfile landscapeProfile; public DeviceProfile portraitProfile; - public DevicePaddings devicePaddings; + @Nullable public DevicePaddings devicePaddings; public Point defaultWallpaperSize; public Rect defaultWidgetPadding; @@ -165,6 +166,7 @@ public class InvariantDeviceProfile { numHotseatIcons = p.numHotseatIcons; numAllAppsColumns = p.numAllAppsColumns; isScalable = p.isScalable; + devicePaddingId = p.devicePaddingId; minCellHeight = p.minCellHeight; minCellWidth = p.minCellWidth; borderSpacing = p.borderSpacing; @@ -231,7 +233,6 @@ public class InvariantDeviceProfile { result.minCellWidth = defaultDisplayOption.minCellWidth; result.borderSpacing = defaultDisplayOption.borderSpacing; - devicePaddings = new DevicePaddings(context); initGrid(context, myInfo, result); } @@ -262,7 +263,6 @@ public class InvariantDeviceProfile { ArrayList allOptions = getPredefinedDeviceProfiles(context, gridName); DisplayOption displayOption = invDistWeightedInterpolate(displayInfo, allOptions); - devicePaddings = new DevicePaddings(context); initGrid(context, displayInfo, displayOption); return displayOption.grid.name; } @@ -280,6 +280,7 @@ public class InvariantDeviceProfile { numFolderColumns = closestProfile.numFolderColumns; numAllAppsColumns = closestProfile.numAllAppsColumns; isScalable = closestProfile.isScalable; + devicePaddingId = closestProfile.devicePaddingId; mExtraAttrs = closestProfile.extraAttrs; @@ -302,6 +303,10 @@ public class InvariantDeviceProfile { allAppsIconTextSize = iconTextSize; } + if (devicePaddingId != 0) { + devicePaddings = new DevicePaddings(context, devicePaddingId); + } + // If the partner customization apk contains any grid overrides, apply them // Supported overrides: numRows, numColumns, iconSize applyPartnerDeviceProfileOverrides(context, displayInfo.metrics); @@ -615,6 +620,7 @@ public class InvariantDeviceProfile { private final int demoModeLayoutId; private final boolean isScalable; + private final int devicePaddingId; private final SparseArray extraAttrs; @@ -641,6 +647,8 @@ public class InvariantDeviceProfile { isScalable = a.getBoolean( R.styleable.GridDisplayOption_isScalable, false); + devicePaddingId = a.getResourceId( + R.styleable.GridDisplayOption_devicePaddingId, 0); a.recycle();