diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 031f291185..631dfa9cfd 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -178,6 +178,11 @@ + + + + + @@ -278,6 +283,9 @@ Needs FeatureFlags.ENABLE_RESPONSIVE_WORKSPACE enabled --> + + diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index cc9c9f7588..51da925b98 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -698,6 +698,8 @@ public class DeviceProfile { mBubbleBarSpaceThresholdPx = res.getDimensionPixelSize(R.dimen.bubblebar_hotseat_adjustment_threshold); + int allAppsTopPadding = mInsets.top; + // Needs to be calculated after hotseatBarSizePx is correct, // for the available height to be correct if (mIsResponsiveGrid) { @@ -723,9 +725,15 @@ public class DeviceProfile { mResponsiveAllAppsWidthSpec = allAppsSpecs.getCalculatedSpec(responsiveAspectRatio, DimensionType.WIDTH, numShownAllAppsColumns, availableWidthPx, mResponsiveWorkspaceWidthSpec); + if (inv.appListAlignedWithWorkspaceRow >= 0) { + allAppsTopPadding += mResponsiveWorkspaceHeightSpec.getStartPaddingPx() + + inv.appListAlignedWithWorkspaceRow + * (mResponsiveWorkspaceHeightSpec.getCellSizePx() + + mResponsiveWorkspaceHeightSpec.getGutterPx()); + } mResponsiveAllAppsHeightSpec = allAppsSpecs.getCalculatedSpec(responsiveAspectRatio, DimensionType.HEIGHT, inv.numAllAppsRowsForCellHeightCalculation, - heightPx - mInsets.top, mResponsiveWorkspaceHeightSpec); + heightPx - allAppsTopPadding, mResponsiveWorkspaceHeightSpec); ResponsiveSpecsProvider folderSpecs = ResponsiveSpecsProvider.create( new ResourceHelper(context, displayOptionSpec.folderSpecsId), @@ -809,9 +817,10 @@ public class DeviceProfile { hotseatBorderSpace = cellLayoutBorderSpacePx.y; } + if (shouldShowAllAppsOnSheet()) { - allAppsPadding.top = mInsets.top; - allAppsShiftRange = heightPx; + allAppsPadding.top = allAppsTopPadding; + allAppsShiftRange = heightPx - allAppsTopPadding + mInsets.top; } else { allAppsPadding.top = 0; allAppsShiftRange = diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 18821c7cb9..f8bf01ddbb 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -16,6 +16,7 @@ package com.android.launcher3; +import static com.android.launcher3.Flags.enableScalabilityForDesktopExperience; import static com.android.launcher3.GridType.GRID_TYPE_ANY; import static com.android.launcher3.GridType.GRID_TYPE_NON_ONE_GRID; import static com.android.launcher3.GridType.GRID_TYPE_ONE_GRID; @@ -240,6 +241,11 @@ public class InvariantDeviceProfile { private String mLocale = ""; public boolean enableTwoLinesInAllApps = false; + + // If non-negative, the workspace row with which top of the all apps container is to be aligned + // with. + public int appListAlignedWithWorkspaceRow = -1; + /** * Fixed landscape mode is the landscape on the phones. */ @@ -400,6 +406,7 @@ public class InvariantDeviceProfile { allAppsCellSpecsTwoPanelId = closestProfile.mAllAppsCellSpecsTwoPanelId; numAllAppsRowsForCellHeightCalculation = closestProfile.mNumAllAppsRowsForCellHeightCalculation; + appListAlignedWithWorkspaceRow = closestProfile.mAllAppsAlignedWithWorkspaceRow; this.deviceType = displayInfo.getDeviceType(); this.displayInfo = displayInfo; @@ -633,12 +640,36 @@ public class InvariantDeviceProfile { throw new RuntimeException(e); } - // Finds the min width and height in dp for all displays. + // Finds the min width and height in px for all displays. int[] dimens = findMinWidthAndHeightPxForDevice(displayInfo); return findBestGridSize(gridSizes, dimens[0], dimens[1]); } + private static AllAppsSize getAllAppsSize(ResourceHelper resourceHelper, Context context, + Info displayInfo) { + ArrayList allAppsSizes = new ArrayList<>(); + + try (XmlResourceParser parser = resourceHelper.getXml()) { + final int depth = parser.getDepth(); + int type; + while (((type = parser.next()) != XmlPullParser.END_TAG + || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { + if ((type == XmlPullParser.START_TAG) + && "AllAppsSize".equals(parser.getName())) { + allAppsSizes.add(new AllAppsSize(context, Xml.asAttributeSet(parser))); + } + } + } catch (IOException | XmlPullParserException e) { + throw new RuntimeException(e); + } + + // Finds the min width and height in px for all displays. + int[] dimens = findMinWidthAndHeightPxForDevice(displayInfo); + + return findBestAllAppsSize(allAppsSizes, dimens[0]); + } + /** * @return the biggest grid size that fits the display dimensions. * If no best grid size is found, return null. @@ -658,6 +689,23 @@ public class InvariantDeviceProfile { return selectedGridSize; } + /** + * @return An `AllAppsSize` spec with min width at most `targetWidthPx`. + * If multiple specs are available, selects the one closest to the `targetWidthPx`. + */ + private static AllAppsSize findBestAllAppsSize(List list, int targetWidthPx) { + AllAppsSize selectedGridSize = null; + for (AllAppsSize item : list) { + if (targetWidthPx >= item.mMinDeviceWidthPx) { + if (selectedGridSize == null + || selectedGridSize.mMinDeviceWidthPx < item.mMinDeviceWidthPx) { + selectedGridSize = item; + } + } + } + return selectedGridSize; + } + private static int[] findMinWidthAndHeightPxForDevice(Info displayInfo) { int minDisplayWidthPx = Integer.MAX_VALUE; int minDisplayHeightPx = Integer.MAX_VALUE; @@ -1065,7 +1113,11 @@ public class InvariantDeviceProfile { private final int mAllAppsCellSpecsId; private final int mAllAppsCellSpecsTwoPanelId; private final int mGridSizeSpecsId; + private final int mAllAppsSizeSpecId; private final boolean mIsFixedLandscape; + // If non-negative, the index of workspace row with which the top of the all apps container + // should be aligned with. + private final int mAllAppsAlignedWithWorkspaceRow; public GridOption(Context context, AttributeSet attrs, Info displayInfo) { TypedArray a = context.obtainStyledAttributes( @@ -1078,6 +1130,10 @@ public class InvariantDeviceProfile { DEVICE_CATEGORY_ANY); mGridSizeSpecsId = a.getResourceId( R.styleable.GridDisplayOption_gridSizeSpecsId, INVALID_RESOURCE_HANDLE); + mAllAppsSizeSpecId = enableScalabilityForDesktopExperience() + ? a.getResourceId(R.styleable.GridDisplayOption_allAppsSizeSpecsId, + INVALID_RESOURCE_HANDLE) + : INVALID_RESOURCE_HANDLE; mIsDualGrid = a.getBoolean(R.styleable.GridDisplayOption_isDualGrid, false); if (mGridSizeSpecsId != INVALID_RESOURCE_HANDLE) { ResourceHelper resourceHelper = new ResourceHelper(context, mGridSizeSpecsId); @@ -1094,6 +1150,14 @@ public class InvariantDeviceProfile { R.styleable.GridDisplayOption_defaultLayoutId, 0); } + if (mAllAppsSizeSpecId != INVALID_RESOURCE_HANDLE) { + ResourceHelper resourceHelper = new ResourceHelper(context, mAllAppsSizeSpecId); + AllAppsSize allAppsSize = getAllAppsSize(resourceHelper, context, displayInfo); + mAllAppsAlignedWithWorkspaceRow = allAppsSize.mAlignWithWorkspaceRow; + } else { + mAllAppsAlignedWithWorkspaceRow = -1; + } + numSearchContainerColumns = a.getInt( R.styleable.GridDisplayOption_numSearchContainerColumns, numColumns); @@ -1293,6 +1357,31 @@ public class InvariantDeviceProfile { } } + /** + * Optional spec that configures the size of the all apps container. + * + * Allows the all apps height to be set so the top of the all apps container aligns with the + * top of a workspace row. + */ + private static final class AllAppsSize { + // The workspace row with which top of all apps container should be aligned with. + // Negative value will be ignored, and cause all apps container to fill up vertical space. + final int mAlignWithWorkspaceRow; + + // The minimum device pixel width to which the spec can be applied. + final float mMinDeviceWidthPx; + + AllAppsSize(Context context, AttributeSet attrs) { + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AllAppsSize); + + mAlignWithWorkspaceRow = a.getInt(R.styleable.AllAppsSize_alignWithWorkspaceRow, -1); + mMinDeviceWidthPx = a.getFloat(R.styleable.AllAppsSize_minDeviceWidthDp, 0) + * DisplayMetrics.DENSITY_DEVICE_STABLE / DisplayMetrics.DENSITY_DEFAULT; + + a.recycle(); + } + } + @VisibleForTesting static final class DisplayOption { public final GridOption grid;