diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index f920d7507c..05d434e479 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -210,7 +210,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx); setCompoundDrawablePadding(grid.iconDrawablePaddingPx); defaultIconSize = grid.iconSizePx; - setCenterVertically(grid.isScalableGrid); + setCenterVertically(grid.iconCenterVertically); } else if (mDisplay == DISPLAY_ALL_APPS) { setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.allAppsIconTextSizePx); setCompoundDrawablePadding(grid.allAppsIconDrawablePaddingPx); diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index fb41044875..1085e4c550 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -103,7 +103,7 @@ public class DeviceProfile { public final float aspectRatio; - public final boolean isScalableGrid; + private final boolean mIsScalableGrid; private final int mTypeIndex; // Responsive grid @@ -152,13 +152,14 @@ public class DeviceProfile { public int iconTextSizePx; public int iconDrawablePaddingPx; public int iconDrawablePaddingOriginalPx; + public boolean iconCenterVertically; public float cellScaleToFit; public int cellWidthPx; public int cellHeightPx; public int workspaceCellPaddingXPx; - public int cellYPaddingPx; + public int cellYPaddingPx = -1; // Folder public float folderLabelTextScale; @@ -305,7 +306,7 @@ public class DeviceProfile { // TODO(b/241386436): shouldn't change any launcher behaviour mIsResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE; - isScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode; + mIsScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode; // Determine device posture. mInfo = info; isTablet = info.isTablet(windowBounds); @@ -342,14 +343,6 @@ public class DeviceProfile { } } - if (mIsResponsiveGrid) { - mWorkspaceSpecs = new WorkspaceSpecs(new ResourceHelper(context, inv.workspaceSpecsId)); - mResponsiveWidthSpec = mWorkspaceSpecs.getCalculatedWidthSpec(inv.numColumns, - availableWidthPx); - mResponsiveHeightSpec = mWorkspaceSpecs.getCalculatedHeightSpec(inv.numRows, - availableHeightPx); - } - if (DisplayController.isTransientTaskbar(context)) { float invTransientIconSizeDp = inv.transientTaskbarIconSize[mTypeIndex]; taskbarIconSize = pxFromDp(invTransientIconSizeDp, mMetrics); @@ -372,8 +365,6 @@ public class DeviceProfile { edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin); workspaceContentScale = res.getFloat(R.dimen.workspace_content_scale); - desiredWorkspaceHorizontalMarginPx = getHorizontalMarginPx(inv, res); - desiredWorkspaceHorizontalMarginOriginalPx = desiredWorkspaceHorizontalMarginPx; gridVisualizationPaddingX = res.getDimensionPixelSize( R.dimen.grid_visualization_horizontal_cell_spacing); gridVisualizationPaddingY = res.getDimensionPixelSize( @@ -406,7 +397,7 @@ public class DeviceProfile { folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale); - if (isScalableGrid && inv.folderStyle != INVALID_RESOURCE_HANDLE) { + if (mIsScalableGrid && inv.folderStyle != INVALID_RESOURCE_HANDLE) { TypedArray folderStyle = context.obtainStyledAttributes(inv.folderStyle, R.styleable.FolderStyle); // These are re-set in #updateFolderCellSize if the grid is not scalable @@ -428,8 +419,6 @@ public class DeviceProfile { folderContentPaddingTop = res.getDimensionPixelSize(R.dimen.folder_top_padding_default); } - cellLayoutBorderSpacePx = getCellLayoutBorderSpace(inv); - cellLayoutBorderSpaceOriginalPx = new Point(cellLayoutBorderSpacePx); allAppsBorderSpacePx = new Point( pxFromDp(inv.allAppsBorderSpaces[mTypeIndex].x, mMetrics), pxFromDp(inv.allAppsBorderSpaces[mTypeIndex].y, mMetrics)); @@ -479,7 +468,7 @@ public class DeviceProfile { || inv.inlineQsb[INDEX_TWO_PANEL_LANDSCAPE] : inv.inlineQsb[INDEX_DEFAULT] || inv.inlineQsb[INDEX_LANDSCAPE]) && hotseatQsbHeight > 0; - isQsbInline = isScalableGrid && inv.inlineQsb[mTypeIndex] && canQsbInline; + isQsbInline = mIsScalableGrid && inv.inlineQsb[mTypeIndex] && canQsbInline; areNavButtonsInline = isTaskbarPresent && !isGestureMode; numShownHotseatIcons = @@ -534,6 +523,21 @@ public class DeviceProfile { hotseatBarEndOffset = 0; } + // Needs to be calculated after hotseatBarSizePx is correct, + // for the available height to be correct + if (mIsResponsiveGrid) { + mWorkspaceSpecs = new WorkspaceSpecs(new ResourceHelper(context, inv.workspaceSpecsId)); + mResponsiveWidthSpec = mWorkspaceSpecs.getCalculatedWidthSpec(inv.numColumns, + availableWidthPx); + mResponsiveHeightSpec = mWorkspaceSpecs.getCalculatedHeightSpec(inv.numRows, + // don't use availableHeightPx because it subtracts bottom padding, + // but the hotseat go behind it + heightPx - mInsets.top - hotseatBarSizePx); + } + + desiredWorkspaceHorizontalMarginPx = getHorizontalMarginPx(inv, res); + desiredWorkspaceHorizontalMarginOriginalPx = desiredWorkspaceHorizontalMarginPx; + overviewTaskMarginPx = res.getDimensionPixelSize(R.dimen.overview_task_margin); overviewTaskIconSizePx = res.getDimensionPixelSize(R.dimen.task_thumbnail_icon_size); overviewTaskIconDrawableSizePx = @@ -554,21 +558,7 @@ 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 && inv.devicePaddingId != INVALID_RESOURCE_HANDLE) { - // Paddings were created assuming no scaling, so we first unscale the extra space. - int unscaledExtraSpace = (int) (extraSpace / cellScaleToFit); - DevicePaddings devicePaddings = new DevicePaddings(context, inv.devicePaddingId); - DevicePadding padding = devicePaddings.getDevicePadding(unscaledExtraSpace); - maxEmptySpace = padding.getMaxEmptySpacePx(); - - int paddingWorkspaceTop = padding.getWorkspaceTopPadding(unscaledExtraSpace); - int paddingWorkspaceBottom = padding.getWorkspaceBottomPadding(unscaledExtraSpace); - int paddingHotseatBottom = padding.getHotseatBottomPadding(unscaledExtraSpace); - - workspaceTopPadding = Math.round(paddingWorkspaceTop * cellScaleToFit); - workspaceBottomPadding = Math.round(paddingWorkspaceBottom * cellScaleToFit); - } + calculateAndSetWorkspaceVerticalPadding(context, inv, extraSpace); int cellLayoutPadding = isTwoPanels ? cellLayoutBorderSpacePx.x / 2 : res.getDimensionPixelSize( @@ -649,15 +639,40 @@ public class DeviceProfile { } private int getHorizontalMarginPx(InvariantDeviceProfile idp, Resources res) { + if (mIsResponsiveGrid) { + return mResponsiveWidthSpec.getStartPaddingPx(); + } + if (isVerticalBarLayout()) { return 0; } - return isScalableGrid + return mIsScalableGrid ? pxFromDp(idp.horizontalMargin[mTypeIndex], mMetrics) : res.getDimensionPixelSize(R.dimen.dynamic_grid_left_right_margin); } + private void calculateAndSetWorkspaceVerticalPadding(Context context, + InvariantDeviceProfile inv, + int extraSpace) { + if (mIsResponsiveGrid) { + workspaceTopPadding = mResponsiveHeightSpec.getStartPaddingPx(); + workspaceBottomPadding = mResponsiveHeightSpec.getEndPaddingPx(); + } else if (mIsScalableGrid && inv.devicePaddingId != INVALID_RESOURCE_HANDLE) { + // Paddings were created assuming no scaling, so we first unscale the extra space. + int unscaledExtraSpace = (int) (extraSpace / cellScaleToFit); + DevicePaddings devicePaddings = new DevicePaddings(context, inv.devicePaddingId); + DevicePadding padding = devicePaddings.getDevicePadding(unscaledExtraSpace); + maxEmptySpace = padding.getMaxEmptySpacePx(); + + int paddingWorkspaceTop = padding.getWorkspaceTopPadding(unscaledExtraSpace); + int paddingWorkspaceBottom = padding.getWorkspaceBottomPadding(unscaledExtraSpace); + + workspaceTopPadding = Math.round(paddingWorkspaceTop * cellScaleToFit); + workspaceBottomPadding = Math.round(paddingWorkspaceBottom * cellScaleToFit); + } + } + /** Updates hotseatCellHeightPx and hotseatBarSizePx */ private void updateHotseatSizes(int hotseatIconSizePx) { // Ensure there is enough space for folder icons, which have a slightly larger radius. @@ -682,7 +697,7 @@ public class DeviceProfile { * necessary. */ public void recalculateHotseatWidthAndBorderSpace() { - if (!isScalableGrid) return; + if (!mIsScalableGrid) return; int columns = inv.hotseatColumnSpan[mTypeIndex]; float hotseatWidthPx = getIconToIconWidthForColumns(columns); @@ -735,12 +750,16 @@ public class DeviceProfile { } private Point getCellLayoutBorderSpace(InvariantDeviceProfile idp, float scale) { - if (!isScalableGrid) { - return new Point(0, 0); - } + int horizontalSpacePx = 0; + int verticalSpacePx = 0; - int horizontalSpacePx = pxFromDp(idp.borderSpaces[mTypeIndex].x, mMetrics, scale); - int verticalSpacePx = pxFromDp(idp.borderSpaces[mTypeIndex].y, mMetrics, scale); + if (mIsResponsiveGrid) { + horizontalSpacePx = mResponsiveWidthSpec.getGutterPx(); + verticalSpacePx = mResponsiveHeightSpec.getGutterPx(); + } else if (mIsScalableGrid) { + horizontalSpacePx = pxFromDp(idp.borderSpaces[mTypeIndex].x, mMetrics, scale); + verticalSpacePx = pxFromDp(idp.borderSpaces[mTypeIndex].y, mMetrics, scale); + } return new Point(horizontalSpacePx, verticalSpacePx); } @@ -861,6 +880,7 @@ public class DeviceProfile { float invIconTextSizeSp = inv.iconTextSize[mTypeIndex]; iconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics)); iconTextSizePx = pxFromSp(invIconTextSizeSp, mMetrics); + iconCenterVertically = mIsScalableGrid || mIsResponsiveGrid; updateIconSize(1f, res); @@ -874,7 +894,7 @@ public class DeviceProfile { boolean shouldScale = scaleY < 1f; float scaleX = 1f; - if (isScalableGrid) { + if (mIsScalableGrid) { // We scale to fit the cellWidth and cellHeight in the available space. // The benefit of scalable grids is that we can get consistent aspect ratios between // devices. @@ -919,8 +939,18 @@ public class DeviceProfile { final boolean isVerticalLayout = isVerticalBarLayout(); iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * iconScale); cellLayoutBorderSpacePx = getCellLayoutBorderSpace(inv, scale); + int cellTextAndPaddingHeight = + iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx); - if (isScalableGrid) { + if (mIsResponsiveGrid) { + int cellContentHeight = iconSizePx + cellTextAndPaddingHeight; + + cellWidthPx = mResponsiveWidthSpec.getCellSizePx(); + cellHeightPx = mResponsiveHeightSpec.getCellSizePx(); + cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2; + + // TODO(b/283929701): decrease icon size if content doesn't fit on cell + } else if (mIsScalableGrid) { cellWidthPx = pxFromDp(inv.minCellSize[mTypeIndex].x, mMetrics, scale); cellHeightPx = pxFromDp(inv.minCellSize[mTypeIndex].y, mMetrics, scale); @@ -942,8 +972,6 @@ public class DeviceProfile { } } - int cellTextAndPaddingHeight = - iconDrawablePaddingPx + Utilities.calculateTextHeight(iconTextSizePx); int cellContentHeight = iconSizePx + cellTextAndPaddingHeight; if (cellHeightPx < cellContentHeight) { // If cellHeight no longer fit iconSize, reduce borderSpace to make cellHeight @@ -1041,7 +1069,7 @@ public class DeviceProfile { + allAppsBorderSpacePx.y; // but width is just the cell, // the border is added in #updateAllAppsContainerWidth - if (isScalableGrid) { + if (mIsScalableGrid) { allAppsIconSizePx = pxFromDp(inv.allAppsIconSize[mTypeIndex], mMetrics); allAppsIconTextSizePx = pxFromSp(inv.allAppsIconTextSize[mTypeIndex], mMetrics); allAppsIconDrawablePaddingPx = iconDrawablePaddingOriginalPx; @@ -1124,7 +1152,7 @@ public class DeviceProfile { int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx); - if (isScalableGrid) { + if (mIsScalableGrid) { if (inv.folderStyle == INVALID_RESOURCE_HANDLE) { folderCellWidthPx = roundPxValueFromFloat(getCellSize().x * scale); folderCellHeightPx = roundPxValueFromFloat(getCellSize().y * scale); @@ -1299,10 +1327,12 @@ public class DeviceProfile { } else { // Pad the bottom of the workspace with hotseat bar // and leave a bit of space in case a widget go all the way down - int paddingBottom = hotseatBarSizePx + workspaceBottomPadding - + workspacePageIndicatorHeight - mWorkspacePageIndicatorOverlapWorkspace - - mInsets.bottom; - int paddingTop = workspaceTopPadding + (isScalableGrid ? 0 : edgeMarginPx); + int paddingBottom = hotseatBarSizePx + workspaceBottomPadding - mInsets.bottom; + if (!mIsResponsiveGrid) { + paddingBottom += + workspacePageIndicatorHeight - mWorkspacePageIndicatorOverlapWorkspace; + } + int paddingTop = workspaceTopPadding + (mIsScalableGrid ? 0 : edgeMarginPx); int paddingSide = desiredWorkspaceHorizontalMarginPx; padding.set(paddingSide, paddingTop, paddingSide, paddingBottom); @@ -1378,7 +1408,7 @@ public class DeviceProfile { hotseatBarPadding.right = endSpacing; } - } else if (isScalableGrid) { + } else if (mIsScalableGrid) { int sideSpacing = (availableWidthPx - hotseatQsbWidth) / 2; hotseatBarPadding.set(sideSpacing, 0, @@ -1598,7 +1628,7 @@ public class DeviceProfile { writer.println(prefix + "\taspectRatio:" + aspectRatio); writer.println(prefix + "\tisResponsiveGrid:" + mIsResponsiveGrid); - writer.println(prefix + "\tisScalableGrid:" + isScalableGrid); + writer.println(prefix + "\tisScalableGrid:" + mIsScalableGrid); writer.println(prefix + "\tinv.numRows: " + inv.numRows); writer.println(prefix + "\tinv.numColumns: " + inv.numColumns); @@ -1752,6 +1782,10 @@ public class DeviceProfile { getWorkspaceSpringLoadScale(context))); writer.println(prefix + pxToDpStr("getCellLayoutHeight()", getCellLayoutHeight())); writer.println(prefix + pxToDpStr("getCellLayoutWidth()", getCellLayoutWidth())); + if (mIsResponsiveGrid) { + writer.println(prefix + "\tmResponsiveHeightSpec:" + mResponsiveHeightSpec.toString()); + writer.println(prefix + "\tmResponsiveWidthSpec:" + mResponsiveWidthSpec.toString()); + } } /** Returns a reduced representation of this DeviceProfile. */ diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java index a0ceefb733..ba6dc26b39 100644 --- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java +++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java @@ -154,9 +154,10 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon. mBorderSpace); // Center the icon/folder int cHeight = getCellContentHeight(); - int cellPaddingY = dp.isScalableGrid && mContainerType == WORKSPACE - ? dp.cellYPaddingPx - : (int) Math.max(0, ((lp.height - cHeight) / 2f)); + int cellPaddingY = + dp.cellYPaddingPx >= 0 && mContainerType == WORKSPACE + ? dp.cellYPaddingPx + : (int) Math.max(0, ((lp.height - cHeight) / 2f)); // No need to add padding when cell layout border spacing is present. boolean noPaddingX = diff --git a/src/com/android/launcher3/workspace/WorkspaceSpecs.kt b/src/com/android/launcher3/workspace/WorkspaceSpecs.kt index ac0a166b18..dc5ae47b16 100644 --- a/src/com/android/launcher3/workspace/WorkspaceSpecs.kt +++ b/src/com/android/launcher3/workspace/WorkspaceSpecs.kt @@ -231,6 +231,13 @@ class CalculatedWorkspaceSpec( if (workspaceSpec.cellSize.ofRemainderSpace > 0) cellSizePx = (workspaceSpec.cellSize.ofRemainderSpace * remainderSpace).roundToInt() } + + override fun toString(): String { + return "CalculatedWorkspaceSpec(availableSpace=$availableSpace, " + + "cells=$cells, startPaddingPx=$startPaddingPx, endPaddingPx=$endPaddingPx, " + + "gutterPx=$gutterPx, cellSizePx=$cellSizePx, " + + "workspaceSpec.maxAvailableSize=${workspaceSpec.maxAvailableSize})" + } } data class WorkspaceSpec(