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;