Extract cell size information to responsive grid structure
Bug: 287975993
Flag: ACONFIG com.android.launcher3.enable_responsive_workspace TEAMFOOD
Test: ResponsiveCellSpecsProviderTest
Test: DeviceProfileDumpTest
Test: DeviceProfileResponsiveDumpTest
Change-Id: I26a87d9b690fdfcff1599d862c09e97fe9f9f930
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 8a63477..7ca8b82 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -54,9 +54,11 @@
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconNormalizer;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.responsive.CalculatedCellSpec;
import com.android.launcher3.responsive.CalculatedHotseatSpec;
import com.android.launcher3.responsive.CalculatedResponsiveSpec;
import com.android.launcher3.responsive.HotseatSpecsProvider;
+import com.android.launcher3.responsive.ResponsiveCellSpecsProvider;
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType;
import com.android.launcher3.responsive.ResponsiveSpec.DimensionType;
import com.android.launcher3.responsive.ResponsiveSpecsProvider;
@@ -125,6 +127,8 @@
private CalculatedResponsiveSpec mResponsiveFolderWidthSpec;
private CalculatedResponsiveSpec mResponsiveFolderHeightSpec;
private CalculatedHotseatSpec mResponsiveHotseatSpec;
+ private CalculatedCellSpec mResponsiveWorkspaceCellSpec;
+ private CalculatedCellSpec mResponsiveAllAppsCellSpec;
/**
* The maximum amount of left/right workspace padding as a percentage of the screen width.
@@ -165,7 +169,7 @@
public int iconSizePx;
public int iconTextSizePx;
public int iconDrawablePaddingPx;
- private final int mIconDrawablePaddingOriginalPx;
+ private int mIconDrawablePaddingOriginalPx;
public boolean iconCenterVertically;
public float cellScaleToFit;
@@ -178,7 +182,7 @@
// Folder
public final int numFolderRows;
public final int numFolderColumns;
- public float folderLabelTextScale;
+ public final float folderLabelTextScale;
public int folderLabelTextSizePx;
public int folderFooterHeightPx;
public int folderIconSizePx;
@@ -330,7 +334,9 @@
mIsResponsiveGrid = inv.workspaceSpecsId != INVALID_RESOURCE_HANDLE
&& inv.allAppsSpecsId != INVALID_RESOURCE_HANDLE
&& inv.folderSpecsId != INVALID_RESOURCE_HANDLE
- && inv.hotseatSpecsId != INVALID_RESOURCE_HANDLE;
+ && inv.hotseatSpecsId != INVALID_RESOURCE_HANDLE
+ && inv.workspaceCellSpecsId != INVALID_RESOURCE_HANDLE
+ && inv.allAppsCellSpecsId != INVALID_RESOURCE_HANDLE;
mIsScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
// Determine device posture.
@@ -470,17 +476,19 @@
mWorkspacePageIndicatorOverlapWorkspace =
res.getDimensionPixelSize(R.dimen.workspace_page_indicator_overlap_workspace);
- TypedArray cellStyle;
- if (inv.cellStyle != INVALID_RESOURCE_HANDLE) {
- cellStyle = context.obtainStyledAttributes(inv.cellStyle,
- R.styleable.CellStyle);
- } else {
- cellStyle = context.obtainStyledAttributes(R.style.CellStyleDefault,
- R.styleable.CellStyle);
+ if (!mIsResponsiveGrid) {
+ TypedArray cellStyle;
+ if (inv.cellStyle != INVALID_RESOURCE_HANDLE) {
+ cellStyle = context.obtainStyledAttributes(inv.cellStyle,
+ R.styleable.CellStyle);
+ } else {
+ cellStyle = context.obtainStyledAttributes(R.style.CellStyleDefault,
+ R.styleable.CellStyle);
+ }
+ mIconDrawablePaddingOriginalPx = cellStyle.getDimensionPixelSize(
+ R.styleable.CellStyle_iconDrawablePadding, 0);
+ cellStyle.recycle();
}
- mIconDrawablePaddingOriginalPx = cellStyle.getDimensionPixelSize(
- R.styleable.CellStyle_iconDrawablePadding, 0);
- cellStyle.recycle();
dropTargetBarSizePx = res.getDimensionPixelSize(R.dimen.dynamic_grid_drop_target_size);
dropTargetBarTopMarginPx = res.getDimensionPixelSize(R.dimen.drop_target_top_margin);
@@ -537,6 +545,13 @@
mHotseatBarEdgePaddingPx =
isVerticalBarLayout() ? mResponsiveHotseatSpec.getEdgePadding() : 0;
mHotseatBarWorkspaceSpacePx = 0;
+
+ ResponsiveCellSpecsProvider workspaceCellSpecs = ResponsiveCellSpecsProvider.create(
+ new ResourceHelper(context,
+ isTwoPanels ? inv.workspaceCellSpecsTwoPanelId
+ : inv.workspaceCellSpecsId));
+ mResponsiveWorkspaceCellSpec = workspaceCellSpecs.getCalculatedSpec(
+ responsiveAspectRatio, heightPx);
} else {
hotseatQsbSpace = pxFromDp(inv.hotseatQsbSpace[mTypeIndex], mMetrics);
hotseatBarBottomSpace = pxFromDp(inv.hotseatBarBottomSpace[mTypeIndex], mMetrics);
@@ -570,7 +585,13 @@
springLoadedHotseatBarTopMarginPx = res.getDimensionPixelSize(
R.dimen.spring_loaded_hotseat_top_margin);
- updateHotseatSizes(pxFromDp(inv.iconSize[mTypeIndex], mMetrics));
+
+ if (mIsResponsiveGrid) {
+ updateHotseatSizes(mResponsiveWorkspaceCellSpec.getIconSize());
+ } else {
+ updateHotseatSizes(pxFromDp(inv.iconSize[mTypeIndex], mMetrics));
+ }
+
if (areNavButtonsInline && !isPhone) {
inlineNavButtonsEndSpacingPx =
res.getDimensionPixelSize(inv.inlineNavButtonsEndSpacing);
@@ -633,6 +654,15 @@
DimensionType.HEIGHT, numFolderRows,
mResponsiveWorkspaceHeightSpec.getAvailableSpace(),
mResponsiveWorkspaceHeightSpec);
+
+ ResponsiveCellSpecsProvider allAppsCellSpecs = ResponsiveCellSpecsProvider.create(
+ new ResourceHelper(context,
+ isTwoPanels ? inv.allAppsCellSpecsTwoPanelId
+ : inv.allAppsCellSpecsId));
+ mResponsiveAllAppsCellSpec = allAppsCellSpecs.getCalculatedSpec(
+ responsiveAspectRatio,
+ mResponsiveAllAppsHeightSpec.getAvailableSpace(),
+ mResponsiveWorkspaceCellSpec);
}
desiredWorkspaceHorizontalMarginPx = getHorizontalMarginPx(inv, res);
@@ -969,19 +999,22 @@
* Returns the amount of extra (or unused) vertical space.
*/
private int updateAvailableDimensions(Resources res) {
+ iconCenterVertically = mIsScalableGrid || mIsResponsiveGrid;
+
+ if (mIsResponsiveGrid) {
+ updateIconSize(1f, res);
+ updateWorkspacePadding();
+ return 0;
+ }
+
float invIconSizeDp = inv.iconSize[mTypeIndex];
float invIconTextSizeSp = inv.iconTextSize[mTypeIndex];
iconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics));
iconTextSizePx = pxFromSp(invIconTextSizeSp, mMetrics);
- iconCenterVertically = mIsScalableGrid || mIsResponsiveGrid;
updateIconSize(1f, res);
updateWorkspacePadding();
- if (mIsResponsiveGrid) {
- return 0;
- }
-
// Check to see if the icons fit within the available height.
float usedHeight = getCellLayoutHeightSpecification();
final int maxHeight = getCellLayoutHeight();
@@ -1025,7 +1058,7 @@
// TODO(b/235886078): workaround needed because of this bug
// Icons are 10% larger on XML than their visual size,
// so remove that extra space to get labels closer to the correct padding
- int iconVisibleSizePx = (int) Math.round(ICON_VISIBLE_AREA_FACTOR * iconSizePx);
+ int iconVisibleSizePx = Math.round(ICON_VISIBLE_AREA_FACTOR * iconSizePx);
return Math.max(0, iconDrawablePadding - ((iconSizePx - iconVisibleSizePx) / 2));
}
@@ -1063,6 +1096,10 @@
cellLayoutBorderSpacePx = getCellLayoutBorderSpace(inv, scale);
if (mIsResponsiveGrid) {
+ iconSizePx = mResponsiveWorkspaceCellSpec.getIconSize();
+ iconTextSizePx = mResponsiveWorkspaceCellSpec.getIconTextSize();
+ mIconDrawablePaddingOriginalPx = mResponsiveWorkspaceCellSpec.getIconDrawablePadding();
+
cellWidthPx = mResponsiveWorkspaceWidthSpec.getCellSizePx();
cellHeightPx = mResponsiveWorkspaceHeightSpec.getCellSizePx();
@@ -1168,7 +1205,7 @@
// All apps
if (mIsResponsiveGrid) {
- updateAllAppsWithResponsiveMeasures(res);
+ updateAllAppsWithResponsiveMeasures();
} else {
updateAllAppsIconSize(scale, res);
}
@@ -1267,13 +1304,16 @@
}
}
- private void updateAllAppsWithResponsiveMeasures(Resources res) {
+ private void updateAllAppsWithResponsiveMeasures() {
+ allAppsIconSizePx = mResponsiveAllAppsCellSpec.getIconSize();
+ allAppsIconTextSizePx = mResponsiveAllAppsCellSpec.getIconTextSize();
+ allAppsIconDrawablePaddingPx = getNormalizedIconDrawablePadding(allAppsIconSizePx,
+ mResponsiveAllAppsCellSpec.getIconDrawablePadding());
allAppsBorderSpacePx = new Point(
mResponsiveAllAppsWidthSpec.getGutterPx(),
mResponsiveAllAppsHeightSpec.getGutterPx()
);
- allAppsCellHeightPx = mResponsiveAllAppsHeightSpec.getCellSizePx()
- + mResponsiveAllAppsHeightSpec.getGutterPx();
+ allAppsCellHeightPx = mResponsiveAllAppsHeightSpec.getCellSizePx();
allAppsCellWidthPx = mResponsiveAllAppsWidthSpec.getCellSizePx();
// This workaround is needed to align AllApps icons with Workspace icons
@@ -1282,22 +1322,6 @@
allAppsPadding.left = mResponsiveAllAppsWidthSpec.getStartPaddingPx() - halfBorder;
allAppsPadding.right = mResponsiveAllAppsWidthSpec.getEndPaddingPx() - halfBorder;
- // TODO(b/287975993): Remove this after icon size is extracted to responsive grid
- // Copy icon size from the workspace when spec is matchWorkspace or
- // use the default all apps icon size
- if (mResponsiveAllAppsHeightSpec.isCellSizeMatchWorkspace()
- || mResponsiveAllAppsWidthSpec.isCellSizeMatchWorkspace()) {
- allAppsIconSizePx = iconSizePx;
- allAppsIconTextSizePx = iconTextSizePx;
- allAppsIconDrawablePaddingPx = iconDrawablePaddingPx;
- } else {
- allAppsIconSizePx = pxFromDp(inv.allAppsIconSize[mTypeIndex], mMetrics);
- allAppsIconTextSizePx = pxFromSp(inv.allAppsIconTextSize[mTypeIndex], mMetrics);
- allAppsIconDrawablePaddingPx = res.getDimensionPixelSize(
- R.dimen.all_apps_icon_drawable_padding);
- allAppsIconDrawablePaddingPx = getNormalizedIconDrawablePadding(allAppsIconSizePx,
- allAppsIconDrawablePaddingPx);
- }
// Reduce the size of the app icon if it doesn't fit
if (allAppsCellWidthPx < allAppsIconSizePx) {
@@ -1322,6 +1346,8 @@
allAppsIconDrawablePaddingPx = cellContentDimensions.getIconDrawablePaddingPx();
allAppsIconTextSizePx = cellContentDimensions.getIconTextSizePx();
}
+
+ allAppsCellHeightPx += mResponsiveAllAppsHeightSpec.getGutterPx();
}
/**
@@ -1390,15 +1416,14 @@
}
private void updateFolderCellSize(float scale, Resources res) {
- float invIconSizeDp = inv.iconSize[mTypeIndex];
- folderChildIconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics, scale));
- folderChildTextSizePx = pxFromSp(inv.iconTextSize[mTypeIndex], mMetrics, scale);
- folderLabelTextSizePx = Math.max(pxFromSp(MIN_FOLDER_TEXT_SIZE_SP, mMetrics, scale),
- (int) (folderChildTextSizePx * folderLabelTextScale));
-
- int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx);
-
+ int minLabelTextSize = pxFromSp(MIN_FOLDER_TEXT_SIZE_SP, mMetrics, scale);
if (mIsResponsiveGrid) {
+ folderChildIconSizePx = mResponsiveWorkspaceCellSpec.getIconSize();
+ folderChildTextSizePx = mResponsiveWorkspaceCellSpec.getIconTextSize();
+ folderLabelTextSizePx = Math.max(minLabelTextSize,
+ (int) (folderChildTextSizePx * folderLabelTextScale));
+ int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx);
+
folderCellWidthPx = mResponsiveFolderWidthSpec.getCellSizePx();
folderCellHeightPx = mResponsiveFolderHeightSpec.getCellSizePx();
folderContentPaddingTop = mResponsiveFolderHeightSpec.getStartPaddingPx();
@@ -1425,9 +1450,20 @@
folderChildIconSizePx = cellContentDimensions.getIconSizePx();
folderChildDrawablePaddingPx = cellContentDimensions.getIconDrawablePaddingPx();
folderChildTextSizePx = cellContentDimensions.getIconTextSizePx();
- folderLabelTextSizePx = Math.max(pxFromSp(MIN_FOLDER_TEXT_SIZE_SP, mMetrics, scale),
+ folderLabelTextSizePx = Math.max(minLabelTextSize,
(int) (folderChildTextSizePx * folderLabelTextScale));
- } else if (mIsScalableGrid) {
+ return;
+ }
+
+ float invIconSizeDp = inv.iconSize[mTypeIndex];
+ float invIconTextSizeDp = inv.iconTextSize[mTypeIndex];
+ folderChildIconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics, scale));
+ folderChildTextSizePx = pxFromSp(invIconTextSizeDp, mMetrics, scale);
+ folderLabelTextSizePx = Math.max(minLabelTextSize,
+ (int) (folderChildTextSizePx * folderLabelTextScale));
+ int textHeight = Utilities.calculateTextHeight(folderChildTextSizePx);
+
+ if (mIsScalableGrid) {
if (inv.folderStyle == INVALID_RESOURCE_HANDLE) {
folderCellWidthPx = roundPxValueFromFloat(getCellSize().x * scale);
folderCellHeightPx = roundPxValueFromFloat(getCellSize().y * scale);
@@ -2136,6 +2172,9 @@
writer.println(prefix + "\tmResponsiveFolderHeightSpec:" + mResponsiveFolderHeightSpec);
writer.println(prefix + "\tmResponsiveFolderWidthSpec:" + mResponsiveFolderWidthSpec);
writer.println(prefix + "\tmResponsiveHotseatSpec:" + mResponsiveHotseatSpec);
+ writer.println(prefix + "\tmResponsiveWorkspaceCellSpec:"
+ + mResponsiveWorkspaceCellSpec);
+ writer.println(prefix + "\tmResponsiveAllAppsCellSpec:" + mResponsiveAllAppsCellSpec);
}
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index e5a6b2b..567d0c5 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -191,8 +191,18 @@
public int folderSpecsId = INVALID_RESOURCE_HANDLE;
@XmlRes
public int folderSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
+ @XmlRes
public int hotseatSpecsId = INVALID_RESOURCE_HANDLE;
+ @XmlRes
public int hotseatSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
+ @XmlRes
+ public int workspaceCellSpecsId = INVALID_RESOURCE_HANDLE;
+ @XmlRes
+ public int workspaceCellSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
+ @XmlRes
+ public int allAppsCellSpecsId = INVALID_RESOURCE_HANDLE;
+ @XmlRes
+ public int allAppsCellSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
public String dbFile;
public int defaultLayoutId;
@@ -375,6 +385,10 @@
folderSpecsTwoPanelId = closestProfile.mFolderSpecsTwoPanelId;
hotseatSpecsId = closestProfile.mHotseatSpecsId;
hotseatSpecsTwoPanelId = closestProfile.mHotseatSpecsTwoPanelId;
+ workspaceCellSpecsId = closestProfile.mWorkspaceCellSpecsId;
+ workspaceCellSpecsTwoPanelId = closestProfile.mWorkspaceCellSpecsTwoPanelId;
+ allAppsCellSpecsId = closestProfile.mAllAppsCellSpecsId;
+ allAppsCellSpecsTwoPanelId = closestProfile.mAllAppsCellSpecsTwoPanelId;
this.deviceType = deviceType;
inlineNavButtonsEndSpacing = closestProfile.inlineNavButtonsEndSpacing;
@@ -827,6 +841,10 @@
private final int mFolderSpecsTwoPanelId;
private final int mHotseatSpecsId;
private final int mHotseatSpecsTwoPanelId;
+ private final int mWorkspaceCellSpecsId;
+ private final int mWorkspaceCellSpecsTwoPanelId;
+ private final int mAllAppsCellSpecsId;
+ private final int mAllAppsCellSpecsTwoPanelId;
public GridOption(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(
@@ -909,6 +927,18 @@
mHotseatSpecsTwoPanelId = a.getResourceId(
R.styleable.GridDisplayOption_hotseatSpecsTwoPanelId,
INVALID_RESOURCE_HANDLE);
+ mWorkspaceCellSpecsId = a.getResourceId(
+ R.styleable.GridDisplayOption_workspaceCellSpecsId,
+ INVALID_RESOURCE_HANDLE);
+ mWorkspaceCellSpecsTwoPanelId = a.getResourceId(
+ R.styleable.GridDisplayOption_workspaceCellSpecsTwoPanelId,
+ INVALID_RESOURCE_HANDLE);
+ mAllAppsCellSpecsId = a.getResourceId(
+ R.styleable.GridDisplayOption_allAppsCellSpecsId,
+ INVALID_RESOURCE_HANDLE);
+ mAllAppsCellSpecsTwoPanelId = a.getResourceId(
+ R.styleable.GridDisplayOption_allAppsCellSpecsTwoPanelId,
+ INVALID_RESOURCE_HANDLE);
} else {
mWorkspaceSpecsId = INVALID_RESOURCE_HANDLE;
mWorkspaceSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
@@ -918,6 +948,10 @@
mFolderSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
mHotseatSpecsId = INVALID_RESOURCE_HANDLE;
mHotseatSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
+ mWorkspaceCellSpecsId = INVALID_RESOURCE_HANDLE;
+ mWorkspaceCellSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
+ mAllAppsCellSpecsId = INVALID_RESOURCE_HANDLE;
+ mAllAppsCellSpecsTwoPanelId = INVALID_RESOURCE_HANDLE;
}
int inlineForRotation = a.getInt(R.styleable.GridDisplayOption_inlineQsb,
diff --git a/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
index 8710303..8e3a5b4 100644
--- a/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
+++ b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
@@ -23,7 +23,13 @@
import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
import com.android.launcher3.util.ResourceHelper
-class HotseatSpecsProvider(private val groupOfSpecs: List<ResponsiveSpecGroup<HotseatSpec>>) {
+class HotseatSpecsProvider(groupOfSpecs: List<ResponsiveSpecGroup<HotseatSpec>>) {
+
+ private val groupOfSpecs: List<ResponsiveSpecGroup<HotseatSpec>>
+ init {
+ this.groupOfSpecs = groupOfSpecs.sortedBy { it.aspectRatio }
+ }
+
fun getSpecsByAspectRatio(aspectRatio: Float): ResponsiveSpecGroup<HotseatSpec> {
check(aspectRatio > 0f) { "Invalid aspect ratio! The value should be bigger than 0." }
diff --git a/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt b/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt
new file mode 100644
index 0000000..affca60
--- /dev/null
+++ b/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.responsive
+
+import android.content.res.TypedArray
+import android.util.Log
+import com.android.launcher3.R
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
+import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
+import com.android.launcher3.util.ResourceHelper
+
+class ResponsiveCellSpecsProvider(groupOfSpecs: List<ResponsiveSpecGroup<CellSpec>>) {
+ private val groupOfSpecs: List<ResponsiveSpecGroup<CellSpec>>
+
+ init {
+ this.groupOfSpecs =
+ groupOfSpecs
+ .onEach { group ->
+ check(group.widthSpecs.isEmpty() && group.heightSpecs.isNotEmpty()) {
+ "${this::class.simpleName} is invalid, only heightSpecs are allowed - " +
+ "width list size = ${group.widthSpecs.size}; " +
+ "height list size = ${group.heightSpecs.size}."
+ }
+ }
+ .sortedBy { it.aspectRatio }
+ }
+
+ fun getSpecsByAspectRatio(aspectRatio: Float): ResponsiveSpecGroup<CellSpec> {
+ check(aspectRatio > 0f) { "Invalid aspect ratio! The value should be bigger than 0." }
+
+ val specsGroup = groupOfSpecs.firstOrNull { aspectRatio <= it.aspectRatio }
+ check(specsGroup != null) { "No available spec with aspectRatio within $aspectRatio." }
+
+ return specsGroup
+ }
+
+ fun getCalculatedSpec(aspectRatio: Float, availableHeightSpace: Int): CalculatedCellSpec {
+ val specsGroup = getSpecsByAspectRatio(aspectRatio)
+ val spec = specsGroup.getSpec(DimensionType.HEIGHT, availableHeightSpace)
+ return CalculatedCellSpec(availableHeightSpace, spec)
+ }
+
+ fun getCalculatedSpec(
+ aspectRatio: Float,
+ availableHeightSpace: Int,
+ workspaceCellSpec: CalculatedCellSpec
+ ): CalculatedCellSpec {
+ val specsGroup = getSpecsByAspectRatio(aspectRatio)
+ val spec = specsGroup.getSpec(DimensionType.HEIGHT, availableHeightSpace)
+ return CalculatedCellSpec(availableHeightSpace, spec, workspaceCellSpec)
+ }
+
+ companion object {
+ @JvmStatic
+ fun create(resourceHelper: ResourceHelper): ResponsiveCellSpecsProvider {
+ val parser = ResponsiveSpecsParser(resourceHelper)
+ val specs = parser.parseXML(ResponsiveSpecType.Cell, ::CellSpec)
+ return ResponsiveCellSpecsProvider(specs)
+ }
+ }
+}
+
+data class CellSpec(
+ override val maxAvailableSize: Int,
+ override val dimensionType: DimensionType,
+ override val specType: ResponsiveSpecType,
+ val iconSize: SizeSpec,
+ val iconTextSize: SizeSpec,
+ val iconDrawablePadding: SizeSpec
+) : IResponsiveSpec {
+ init {
+ check(isValid()) { "Invalid CellSpec found." }
+ }
+
+ constructor(
+ responsiveSpecType: ResponsiveSpecType,
+ attrs: TypedArray,
+ specs: Map<String, SizeSpec>
+ ) : this(
+ maxAvailableSize =
+ attrs.getDimensionPixelSize(R.styleable.ResponsiveSpec_maxAvailableSize, 0),
+ dimensionType =
+ DimensionType.entries[
+ attrs.getInt(
+ R.styleable.ResponsiveSpec_dimensionType,
+ DimensionType.HEIGHT.ordinal
+ )],
+ specType = responsiveSpecType,
+ iconSize = specs.getOrError(SizeSpec.XmlTags.ICON_SIZE),
+ iconTextSize = specs.getOrError(SizeSpec.XmlTags.ICON_TEXT_SIZE),
+ iconDrawablePadding = specs.getOrError(SizeSpec.XmlTags.ICON_DRAWABLE_PADDING)
+ )
+
+ fun isValid(): Boolean {
+ if (maxAvailableSize <= 0) {
+ Log.e(LOG_TAG, "${this::class.simpleName}#isValid - maxAvailableSize <= 0")
+ return false
+ }
+
+ // All specs need to be individually valid
+ if (!allSpecsAreValid()) {
+ Log.e(LOG_TAG, "${this::class.simpleName}#isValid - !allSpecsAreValid()")
+ return false
+ }
+
+ return true
+ }
+
+ private fun allSpecsAreValid(): Boolean {
+ return (iconSize.fixedSize > 0f || iconSize.matchWorkspace) &&
+ (iconTextSize.fixedSize >= 0f || iconTextSize.matchWorkspace) &&
+ (iconDrawablePadding.fixedSize >= 0f || iconDrawablePadding.matchWorkspace)
+ }
+
+ companion object {
+ private const val LOG_TAG = "CellSpec"
+ }
+}
+
+data class CalculatedCellSpec(
+ val availableSpace: Int,
+ val spec: CellSpec,
+ val iconSize: Int,
+ val iconTextSize: Int,
+ val iconDrawablePadding: Int
+) {
+ constructor(
+ availableSpace: Int,
+ spec: CellSpec
+ ) : this(
+ availableSpace = availableSpace,
+ spec = spec,
+ iconSize = spec.iconSize.getCalculatedValue(availableSpace),
+ iconTextSize = spec.iconTextSize.getCalculatedValue(availableSpace),
+ iconDrawablePadding = spec.iconDrawablePadding.getCalculatedValue(availableSpace)
+ )
+
+ constructor(
+ availableSpace: Int,
+ spec: CellSpec,
+ workspaceCellSpec: CalculatedCellSpec
+ ) : this(
+ availableSpace = availableSpace,
+ spec = spec,
+ iconSize = getCalculatedValue(availableSpace, spec.iconSize, workspaceCellSpec.iconSize),
+ iconTextSize =
+ getCalculatedValue(availableSpace, spec.iconTextSize, workspaceCellSpec.iconTextSize),
+ iconDrawablePadding =
+ getCalculatedValue(
+ availableSpace,
+ spec.iconDrawablePadding,
+ workspaceCellSpec.iconDrawablePadding
+ )
+ )
+
+ companion object {
+ private fun getCalculatedValue(
+ availableSpace: Int,
+ spec: SizeSpec,
+ workspaceValue: Int
+ ): Int =
+ if (spec.matchWorkspace) workspaceValue else spec.getCalculatedValue(availableSpace)
+ }
+
+ override fun toString(): String {
+ return "${this::class.simpleName}(" +
+ "availableSpace=$availableSpace, iconSize=$iconSize, " +
+ "iconTextSize=$iconTextSize, iconDrawablePadding=$iconDrawablePadding, " +
+ "${spec::class.simpleName}.maxAvailableSize=${spec.maxAvailableSize}" +
+ ")"
+ }
+}
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpec.kt b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
index 413e2dc..32dedfb 100644
--- a/src/com/android/launcher3/responsive/ResponsiveSpec.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveSpec.kt
@@ -127,7 +127,8 @@
AllApps("allAppsSpec"),
Folder("folderSpec"),
Workspace("workspaceSpec"),
- Hotseat("hotseatSpec")
+ Hotseat("hotseatSpec"),
+ Cell("cellSpec")
}
}
}
@@ -205,9 +206,6 @@
fun isResponsiveSpecType(type: ResponsiveSpecType) = spec.specType == type
- // TODO(b/287975993): Remove this after icon size is extracted to responsive grid
- fun isCellSizeMatchWorkspace(): Boolean = spec.cellSize.matchWorkspace
-
private fun updateRemainderSpaces(availableSpace: Int, cells: Int, spec: ResponsiveSpec) {
val gutters = cells - 1
val usedSpace = startPaddingPx + endPaddingPx + (gutterPx * gutters) + (cellSizePx * cells)
diff --git a/src/com/android/launcher3/responsive/SizeSpec.kt b/src/com/android/launcher3/responsive/SizeSpec.kt
index 2db843b..d146898 100644
--- a/src/com/android/launcher3/responsive/SizeSpec.kt
+++ b/src/com/android/launcher3/responsive/SizeSpec.kt
@@ -122,6 +122,9 @@
const val CELL_SIZE = "cellSize"
const val HOTSEAT_QSB_SPACE = "hotseatQsbSpace"
const val EDGE_PADDING = "edgePadding"
+ const val ICON_SIZE = "iconSize"
+ const val ICON_TEXT_SIZE = "iconTextSize"
+ const val ICON_DRAWABLE_PADDING = "iconDrawablePadding"
}
companion object {