From bb3571806e1a88fe45570ea38f7e913a74f4b2a4 Mon Sep 17 00:00:00 2001 From: Ajinkya Chalke Date: Tue, 29 Apr 2025 20:25:01 +0000 Subject: [PATCH] Reparse all grids for secondary displays for DP - This is required to show a half width all apps sheet on external monitor connected to the phone. Without this the apps sheet covers the full width of the external monitor in projected mode. - Create a new class to hold all the properties that need to be overridden. Set this class as part of DP buider. - Override all props that are overridden for isTwoPanels. - Update isTwoPanels to override using the new class in DP constructor. Flag: com.android.window.flags.enable_taskbar_connected_displays Bug: 414342881 Test: m Change-Id: Ia035620c96c5a8912b99314014d4b19a125c7c5c --- src/com/android/launcher3/DeviceProfile.java | 73 ++++++++++--------- .../launcher3/InvariantDeviceProfile.java | 65 +++++++++++++++++ .../FakeInvariantDeviceProfileTest.kt | 7 ++ 3 files changed, 109 insertions(+), 36 deletions(-) diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 507cc5aef2..30c3c46518 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -22,6 +22,7 @@ import static com.android.launcher3.InvariantDeviceProfile.INDEX_DEFAULT; import static com.android.launcher3.InvariantDeviceProfile.INDEX_LANDSCAPE; import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_LANDSCAPE; import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_PORTRAIT; +import static com.android.launcher3.InvariantDeviceProfile.createDisplayOptionSpec; import static com.android.launcher3.Utilities.dpiFromPx; import static com.android.launcher3.Utilities.pxFromSp; import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR; @@ -54,6 +55,7 @@ import androidx.core.content.res.ResourcesCompat; import com.android.launcher3.CellLayout.ContainerType; import com.android.launcher3.DevicePaddings.DevicePadding; +import com.android.launcher3.InvariantDeviceProfile.DisplayOptionSpec; import com.android.launcher3.graphics.ThemeManager; import com.android.launcher3.icons.DotRenderer; import com.android.launcher3.model.data.ItemInfo; @@ -392,7 +394,7 @@ public class DeviceProfile { boolean transposeLayoutWithOrientation, boolean isMultiDisplay, boolean isGestureMode, @NonNull final ViewScaleProvider viewScaleProvider, @NonNull final Consumer dimensionOverrideProvider, - boolean isTransientTaskbar) { + boolean isTransientTaskbar, DisplayOptionSpec displayOptionSpec) { this.inv = inv; this.isLandscape = windowBounds.isLandscape(); @@ -443,19 +445,7 @@ public class DeviceProfile { availableHeightPx = windowBounds.availableSize.y; aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx); - if (isTwoPanels) { - if (isLandscape) { - mTypeIndex = INDEX_TWO_PANEL_LANDSCAPE; - } else { - mTypeIndex = INDEX_TWO_PANEL_PORTRAIT; - } - } else { - if (isLandscape) { - mTypeIndex = INDEX_LANDSCAPE; - } else { - mTypeIndex = INDEX_DEFAULT; - } - } + mTypeIndex = displayOptionSpec.typeIndex; this.isTransientTaskbar = isTransientTaskbar; int transientTaskbarIconSize = pxFromDp(inv.transientTaskbarIconSize[mTypeIndex], mMetrics); @@ -615,19 +605,13 @@ public class DeviceProfile { hotseatQsbVisualHeight = hotseatQsbHeight - 2 * hotseatQsbShadowHeight; // Whether QSB might be inline in appropriate orientation (e.g. landscape). - boolean canQsbInline = (isTwoPanels ? inv.inlineQsb[INDEX_TWO_PANEL_PORTRAIT] - || inv.inlineQsb[INDEX_TWO_PANEL_LANDSCAPE] - : inv.inlineQsb[INDEX_DEFAULT] || inv.inlineQsb[INDEX_LANDSCAPE]) - && hotseatQsbHeight > 0; isQsbInline = isQsbInline(inv); areNavButtonsInline = isTaskbarPresent && !isGestureMode; - numShownHotseatIcons = - isTwoPanels ? inv.numDatabaseHotseatIcons : inv.numShownHotseatIcons; + numShownHotseatIcons = displayOptionSpec.numShownHotseatIcons; mHotseatColumnSpan = inv.numColumns; - numShownAllAppsColumns = - isTwoPanels ? inv.numDatabaseAllAppsColumns : inv.numAllAppsColumns; + numShownAllAppsColumns = displayOptionSpec.numAllAppsColumns; int hotseatBarBottomSpace; int minQsbMargin = res.getDimensionPixelSize(R.dimen.min_qsb_margin); @@ -636,7 +620,7 @@ public class DeviceProfile { float responsiveAspectRatio = (float) widthPx / heightPx; HotseatSpecsProvider hotseatSpecsProvider = HotseatSpecsProvider.create(new ResourceHelper(context, - isTwoPanels ? inv.hotseatSpecsTwoPanelId : inv.hotseatSpecsId)); + displayOptionSpec.hotseatSpecsId)); mResponsiveHotseatSpec = isVerticalBarLayout() ? hotseatSpecsProvider.getCalculatedSpec( responsiveAspectRatio, DimensionType.WIDTH, widthPx) @@ -650,9 +634,7 @@ public class DeviceProfile { mHotseatBarWorkspaceSpacePx = 0; ResponsiveCellSpecsProvider workspaceCellSpecs = ResponsiveCellSpecsProvider.create( - new ResourceHelper(context, - isTwoPanels ? inv.workspaceCellSpecsTwoPanelId - : inv.workspaceCellSpecsId)); + new ResourceHelper(context, displayOptionSpec.workspaceCellSpecsId)); mResponsiveWorkspaceCellSpec = workspaceCellSpecs.getCalculatedSpec( responsiveAspectRatio, heightPx); } else { @@ -722,8 +704,7 @@ public class DeviceProfile { float responsiveAspectRatio = (float) widthPx / heightPx; ResponsiveSpecsProvider workspaceSpecs = ResponsiveSpecsProvider.create( - new ResourceHelper(context, - isTwoPanels ? inv.workspaceSpecsTwoPanelId : inv.workspaceSpecsId), + new ResourceHelper(context, displayOptionSpec.workspaceSpecsId), ResponsiveSpecType.Workspace); mResponsiveWorkspaceWidthSpec = workspaceSpecs.getCalculatedSpec(responsiveAspectRatio, DimensionType.WIDTH, numWorkspaceColumns, availableResponsiveWidth); @@ -731,8 +712,7 @@ public class DeviceProfile { DimensionType.HEIGHT, inv.numRows, availableResponsiveHeight); ResponsiveSpecsProvider allAppsSpecs = ResponsiveSpecsProvider.create( - new ResourceHelper(context, - isTwoPanels ? inv.allAppsSpecsTwoPanelId : inv.allAppsSpecsId), + new ResourceHelper(context, displayOptionSpec.allAppsSpecsId), ResponsiveSpecType.AllApps); mResponsiveAllAppsWidthSpec = allAppsSpecs.getCalculatedSpec(responsiveAspectRatio, DimensionType.WIDTH, numShownAllAppsColumns, availableWidthPx, @@ -742,8 +722,7 @@ public class DeviceProfile { heightPx - mInsets.top, mResponsiveWorkspaceHeightSpec); ResponsiveSpecsProvider folderSpecs = ResponsiveSpecsProvider.create( - new ResourceHelper(context, - isTwoPanels ? inv.folderSpecsTwoPanelId : inv.folderSpecsId), + new ResourceHelper(context, displayOptionSpec.folderSpecsId), ResponsiveSpecType.Folder); mResponsiveFolderWidthSpec = folderSpecs.getCalculatedSpec(responsiveAspectRatio, DimensionType.WIDTH, numFolderColumns, @@ -755,9 +734,7 @@ public class DeviceProfile { mResponsiveWorkspaceHeightSpec); ResponsiveCellSpecsProvider allAppsCellSpecs = ResponsiveCellSpecsProvider.create( - new ResourceHelper(context, - isTwoPanels ? inv.allAppsCellSpecsTwoPanelId - : inv.allAppsCellSpecsId)); + new ResourceHelper(context, displayOptionSpec.allAppsCellSpecsId)); mResponsiveAllAppsCellSpec = allAppsCellSpecs.getCalculatedSpec( responsiveAspectRatio, mResponsiveAllAppsHeightSpec.getAvailableSpace(), @@ -2519,6 +2496,7 @@ public class DeviceProfile { private Consumer mOverrideProvider; private boolean mIsTransientTaskbar; + private DisplayOptionSpec mDisplayOptionSpec; public Builder(Context context, InvariantDeviceProfile inv, Info info, WindowManagerProxy wmProxy, ThemeManager themeManager) { @@ -2587,6 +2565,16 @@ public class DeviceProfile { return this; } + /** + * Set the displayOptionSpec for the builder for secondary displays + * @return This Builder + */ + public Builder setSecondaryDisplayOptionSpec() { + mDisplayOptionSpec = createDisplayOptionSpec(mContext, mInfo, + mWindowBounds.isLandscape()); + return this; + } + public DeviceProfile build() { if (mWindowBounds == null) { throw new IllegalArgumentException("Window bounds not set"); @@ -2607,10 +2595,23 @@ public class DeviceProfile { if (mOverrideProvider == null) { mOverrideProvider = DEFAULT_DIMENSION_PROVIDER; } + if (mDisplayOptionSpec == null) { + mDisplayOptionSpec = createDefaultDisplayOptionSpec(mInfo, mWindowBounds, + mIsMultiDisplay, mInv); + } return new DeviceProfile(mContext, mInv, mInfo, mWMProxy, mThemeManager, mWindowBounds, mDotRendererCache, mIsMultiWindowMode, mTransposeLayoutWithOrientation, mIsMultiDisplay, - mIsGestureMode, mViewScaleProvider, mOverrideProvider, mIsTransientTaskbar); + mIsGestureMode, mViewScaleProvider, mOverrideProvider, mIsTransientTaskbar, + mDisplayOptionSpec); + } + + @VisibleForTesting + static DisplayOptionSpec createDefaultDisplayOptionSpec(DisplayController.Info info, + WindowBounds windowBounds, boolean isMultiDisplay, InvariantDeviceProfile inv) { + boolean isTwoPanels = info.isTablet(windowBounds) && isMultiDisplay; + boolean isLandscape = windowBounds.isLandscape(); + return new DisplayOptionSpec(inv, isTwoPanels, isLandscape); } } } diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index f963913db1..ff8f1989ff 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -857,6 +857,7 @@ public class InvariantDeviceProfile { .setWindowBounds(mWMProxy.getRealBounds( displayContext, mWMProxy.getDisplayInfo(displayContext))) .setTransposeLayoutWithOrientation(false) + .setSecondaryDisplayOptionSpec() .build(); } @@ -932,6 +933,70 @@ public class InvariantDeviceProfile { void onIdpChanged(boolean modelPropertiesChanged); } + /** Returns {@link DisplayOptionSpec} for the provided displayInfo. */ + static DisplayOptionSpec createDisplayOptionSpec(Context context, Info displayInfo, + boolean isLandscape) { + // Get predefined profiles for provided displayInfo without using any main device's pref. + List allOptions = getPredefinedDeviceProfiles(context, + /* gridName= */ null, displayInfo, /* allowDisabledGrid= */ false, + /* isFixedLandscapeMode= */ false); + + return new DisplayOptionSpec( + invDistWeightedInterpolate(displayInfo, new ArrayList<>(allOptions), + displayInfo.getDeviceType()), isLandscape); + } + + /** Class to expose properties required for external displays to {@link DeviceProfile} */ + public static final class DisplayOptionSpec { + public final int typeIndex; + public final int numShownHotseatIcons; + public final int numAllAppsColumns; + @XmlRes public final int hotseatSpecsId; + @XmlRes public final int workspaceCellSpecsId; + @XmlRes public final int workspaceSpecsId; + @XmlRes public final int allAppsSpecsId; + @XmlRes public final int folderSpecsId; + @XmlRes public final int allAppsCellSpecsId; + + DisplayOptionSpec(DisplayOption displayOption, boolean isLandscape) { + typeIndex = isLandscape ? INDEX_LANDSCAPE : INDEX_DEFAULT; + numShownHotseatIcons = displayOption.grid.numHotseatIcons; + numAllAppsColumns = displayOption.grid.numAllAppsColumns; + hotseatSpecsId = displayOption.grid.mHotseatSpecsId; + workspaceCellSpecsId = displayOption.grid.mWorkspaceCellSpecsId; + workspaceSpecsId = displayOption.grid.mWorkspaceSpecsId; + allAppsSpecsId = displayOption.grid.mAllAppsSpecsId; + folderSpecsId = displayOption.grid.mFolderSpecsId; + allAppsCellSpecsId = displayOption.grid.mAllAppsCellSpecsId; + } + + DisplayOptionSpec(InvariantDeviceProfile inv, boolean isTwoPanels, boolean isLandscape) { + if (isTwoPanels) { + if (isLandscape) { + typeIndex = INDEX_TWO_PANEL_LANDSCAPE; + } else { + typeIndex = INDEX_TWO_PANEL_PORTRAIT; + } + } else { + if (isLandscape) { + typeIndex = INDEX_LANDSCAPE; + } else { + typeIndex = INDEX_DEFAULT; + } + } + numShownHotseatIcons = + isTwoPanels ? inv.numDatabaseHotseatIcons : inv.numShownHotseatIcons; + numAllAppsColumns = isTwoPanels ? inv.numDatabaseAllAppsColumns : inv.numAllAppsColumns; + hotseatSpecsId = isTwoPanels ? inv.hotseatSpecsTwoPanelId : inv.hotseatSpecsId; + workspaceCellSpecsId = isTwoPanels ? inv.workspaceCellSpecsTwoPanelId + : inv.workspaceCellSpecsId; + workspaceSpecsId = isTwoPanels ? inv.workspaceSpecsTwoPanelId : inv.workspaceSpecsId; + allAppsSpecsId = isTwoPanels ? inv.allAppsSpecsTwoPanelId : inv.allAppsSpecsId; + folderSpecsId = isTwoPanels ? inv.folderSpecsTwoPanelId : inv.folderSpecsId; + allAppsCellSpecsId = + isTwoPanels ? inv.allAppsCellSpecsTwoPanelId : inv.allAppsCellSpecsId; + } + } public static final class GridOption { diff --git a/tests/multivalentTests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt b/tests/multivalentTests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt index f855c51f8e..34a603d571 100644 --- a/tests/multivalentTests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt @@ -22,6 +22,7 @@ import android.platform.test.rule.DeviceProduct import android.platform.test.rule.IgnoreLimit import android.platform.test.rule.LimitDevicesRule import android.util.SparseArray +import com.android.launcher3.DeviceProfile.Builder.createDefaultDisplayOptionSpec import com.android.launcher3.DeviceProfile.DEFAULT_DIMENSION_PROVIDER import com.android.launcher3.DeviceProfile.DEFAULT_PROVIDER import com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE @@ -81,6 +82,12 @@ abstract class FakeInvariantDeviceProfileTest { DEFAULT_PROVIDER, DEFAULT_DIMENSION_PROVIDER, isTransientTaskbar, + createDefaultDisplayOptionSpec( + info, + windowBounds, + /* isMultiDisplay= */ useTwoPanels, + inv, + ), ) protected fun initializeVarsForPhone(