diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java index a4c6ae03a4..891397fe84 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduDialog.java @@ -88,11 +88,11 @@ public class HotseatEduDialog extends AbstractSlideInView implements I mSampleHotseat = findViewById(R.id.sample_prediction); Context context = getContext(); - DeviceProfile grid = mActivityContext.getDeviceProfile(); - Rect padding = grid.getHotseatLayoutPadding(context); + DeviceProfile dp = mActivityContext.getDeviceProfile(); + Rect padding = dp.getHotseatLayoutPadding(context); - mSampleHotseat.getLayoutParams().height = grid.cellHeightPx; - mSampleHotseat.setGridSize(grid.numShownHotseatIcons, 1); + mSampleHotseat.getLayoutParams().height = dp.cellHeightPx; + mSampleHotseat.setGridSize(dp.numShownHotseatIcons, 1); mSampleHotseat.setPadding(padding.left, 0, padding.right, 0); Button turnOnBtn = findViewById(R.id.turn_predictions_on); @@ -102,7 +102,8 @@ public class HotseatEduDialog extends AbstractSlideInView implements I mDismissBtn.setOnClickListener(this::onDismiss); LinearLayout buttonContainer = findViewById(R.id.button_container); - int adjustedMarginEnd = grid.hotseatBarEndOffset - buttonContainer.getPaddingEnd(); + int adjustedMarginEnd = + dp.getHotseatProfile().getBarEndOffset() - buttonContainer.getPaddingEnd(); if (InvariantDeviceProfile.INSTANCE.get(context) .getDeviceProfile(context).isTaskbarPresent && adjustedMarginEnd > 0) { ((LinearLayout.LayoutParams) buttonContainer.getLayoutParams()).setMarginEnd( diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java index 2b3705e9d3..4120a90020 100644 --- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java @@ -1433,7 +1433,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT // Skip additional translations on the nav bar container while in SUW layout return 0; } else if (mContext.shouldStartAlignTaskbar()) { - int navBarSpacing = dp.inlineNavButtonsEndSpacingPx; + int navBarSpacing = dp.getHotseatProfile().getInlineNavButtonsEndSpacingPx(); // If the taskbar is start aligned the navigation bar is aligned to the start or end of // the container, depending on the bubble bar location if (isNavbarOnRight) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index c6ae854ccf..d59002c5cf 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -217,11 +217,12 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar // Reserve space required for edge margins, or for navbar if shown. If task bar needs to be // center aligned with nav bar shown, reserve space on both sides. - availableWidth -= - Math.max(defaultEdgeMargin + spaceForBubbleBar, deviceProfile.hotseatBarEndOffset); + availableWidth -= Math.max( + defaultEdgeMargin + spaceForBubbleBar, + deviceProfile.getHotseatProfile().getBarEndOffset()); availableWidth -= Math.max( defaultEdgeMargin + (mShouldTryStartAlign ? 0 : spaceForBubbleBar), - mShouldTryStartAlign ? 0 : deviceProfile.hotseatBarEndOffset); + mShouldTryStartAlign ? 0 : deviceProfile.getHotseatProfile().getBarEndOffset()); // The space taken by an item icon used during layout. int iconSize = 2 * mItemMarginLeftRight + mIconTouchSize; @@ -823,11 +824,12 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar int spaceNeeded = getIconLayoutWidth(); boolean layoutRtl = isLayoutRtl(); DeviceProfile deviceProfile = mActivityContext.getDeviceProfile(); - int navSpaceNeeded = deviceProfile.hotseatBarEndOffset; + int navSpaceNeeded = deviceProfile.getHotseatProfile().getBarEndOffset(); int centerAlignIconEnd = (right + left + spaceNeeded) / 2; int iconEnd = centerAlignIconEnd; if (mShouldTryStartAlign) { - int startSpacingPx = deviceProfile.inlineNavButtonsEndSpacingPx; + int startSpacingPx = + deviceProfile.getHotseatProfile().getInlineNavButtonsEndSpacingPx(); if (mControllerCallbacks.isBubbleBarEnabled() && mBubbleBarLocation != null && mActivityContext.shouldStartAlignTaskbar()) { @@ -904,8 +906,8 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar qsbEnd = iconEnd - mItemMarginLeftRight; qsbStart = qsbEnd - deviceProfile.hotseatQsbWidth; } - int qsbTop = (bottom - top - deviceProfile.hotseatQsbHeight) / 2; - int qsbBottom = qsbTop + deviceProfile.hotseatQsbHeight; + int qsbTop = (bottom - top - deviceProfile.getHotseatProfile().getQsbHeight()) / 2; + int qsbBottom = qsbTop + deviceProfile.getHotseatProfile().getQsbHeight(); child.layout(qsbStart, qsbTop, qsbEnd, qsbBottom); } else if (child == mTaskbarDividerContainer) { iconEnd += mItemMarginLeftRight; @@ -1144,7 +1146,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar private float getTaskBarIconsEndForBubbleBarLocation(BubbleBarLocation location) { DeviceProfile deviceProfile = mActivityContext.getDeviceProfile(); boolean navbarOnRight = location.isOnLeft(isLayoutRtl()); - int navSpaceNeeded = deviceProfile.hotseatBarEndOffset; + int navSpaceNeeded = deviceProfile.getHotseatProfile().getBarEndOffset(); if (navbarOnRight) { return getWidth() - navSpaceNeeded; } else { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 12f5e925ae..e42c11ad5a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -1080,7 +1080,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar float halfQsbIconWidthDiff = (launcherDp.hotseatQsbWidth - taskbarDp.taskbarIconSize) / 2f; float scale = ((float) taskbarDp.taskbarIconSize) - / launcherDp.hotseatQsbVisualHeight; + / launcherDp.getHotseatProfile().getQsbVisualHeight(); setter.addFloat(child, SCALE_PROPERTY, scale, 1f, interpolator); float fromX = isRtl ? -halfQsbIconWidthDiff : halfQsbIconWidthDiff; diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/HotseatWidthCalculationTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/HotseatWidthCalculationTest.kt index a38851098e..a2435188a1 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/HotseatWidthCalculationTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/HotseatWidthCalculationTest.kt @@ -39,7 +39,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(510) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(510) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(70) assertThat(dp.hotseatColumnSpan).isEqualTo(6) @@ -63,7 +63,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(510) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(510) assertThat(dp.numShownHotseatIcons).isEqualTo(4) assertThat(dp.hotseatBorderSpace).isEqualTo(40) assertThat(dp.hotseatColumnSpan).isEqualTo(6) @@ -86,7 +86,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(705) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(705) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(54) assertThat(dp.hotseatColumnSpan).isEqualTo(6) @@ -110,7 +110,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(660) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(660) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(100) assertThat(dp.hotseatColumnSpan).isEqualTo(6) @@ -131,7 +131,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(660) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(660) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(34) assertThat(dp.hotseatColumnSpan).isEqualTo(4) @@ -155,7 +155,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(660) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(660) assertThat(dp.numShownHotseatIcons).isEqualTo(5) assertThat(dp.hotseatBorderSpace).isEqualTo(36) assertThat(dp.hotseatColumnSpan).isEqualTo(4) @@ -174,7 +174,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(600) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(600) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(48) assertThat(dp.hotseatColumnSpan).isEqualTo(8) diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index eddbce41b7..704fa6b7ca 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -57,6 +57,7 @@ import com.android.launcher3.DevicePaddings.DevicePadding; import com.android.launcher3.InvariantDeviceProfile.DisplayOptionSpec; import com.android.launcher3.deviceprofile.DeviceProperties; import com.android.launcher3.deviceprofile.DropTargetProfile; +import com.android.launcher3.deviceprofile.HotseatProfile; import com.android.launcher3.deviceprofile.OverviewProfile; import com.android.launcher3.graphics.ThemeManager; import com.android.launcher3.icons.DotRenderer; @@ -203,32 +204,17 @@ public class DeviceProfile { public int maxFolderChildTextLineCount; // Hotseat + private final HotseatProfile hotseatProfile; public int numShownHotseatIcons; public int hotseatCellHeightPx; private int mHotseatColumnSpan; private int mHotseatWidthPx; // not used in vertical bar layout - public final boolean areNavButtonsInline; // In portrait: size = height, in landscape: size = width public int hotseatBarSizePx; public int hotseatBarBottomSpacePx; - public int hotseatBarEndOffset; public int hotseatQsbSpace; - public int inlineNavButtonsEndSpacingPx; - public int navButtonsLayoutWidthPx; - public int springLoadedHotseatBarTopMarginPx; - // These 2 values are only used for isVerticalBar - // Padding between edge of screen and hotseat - public final int mHotseatBarEdgePaddingPx; - // Space between hotseat and workspace (not used in responsive) - public final int mHotseatBarWorkspaceSpacePx; public int hotseatQsbWidth; // only used when isQsbInline - public final int hotseatQsbHeight; - public final int hotseatQsbVisualHeight; - public final int hotseatQsbShadowHeight; public int hotseatBorderSpace; - private final int mMinHotseatIconSpacePx; - private final int mMinHotseatQsbWidthPx; - private final int mMaxHotseatIconSpacePx; // Space required for the bubble bar between the hotseat and the edge of the screen. If there's // not enough space, the hotseat will adjust itself for the bubble bar. private final int mBubbleBarSpaceThresholdPx; @@ -321,6 +307,7 @@ public class DeviceProfile { 0, 0 ); + hotseatProfile = new HotseatProfile(false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); inv = null; mDisplayOptionSpec = null; mInfo = null; @@ -343,18 +330,8 @@ public class DeviceProfile { numFolderColumns = 0; mDropTargetProfile = new DropTargetProfile(0, 0, 0, 0, 0, 0, 0, 0, 0); folderLabelTextScale = 0; - areNavButtonsInline = false; - mHotseatBarEdgePaddingPx = 0; - mHotseatBarWorkspaceSpacePx = 0; hotseatQsbWidth = 0; - hotseatQsbHeight = 0; - hotseatQsbVisualHeight = 0; - hotseatQsbShadowHeight = 0; hotseatBorderSpace = 0; - mMinHotseatIconSpacePx = 0; - mMinHotseatQsbWidthPx = 0; - mMaxHotseatIconSpacePx = 0; - inlineNavButtonsEndSpacingPx = 0; mBubbleBarSpaceThresholdPx = 0; numShownAllAppsColumns = 0; mViewScaleProvider = null; @@ -417,6 +394,11 @@ public class DeviceProfile { windowBounds); final Resources res = context.getResources(); + workspacePageIndicatorHeight = res.getDimensionPixelSize( + R.dimen.workspace_page_indicator_height); + mWorkspacePageIndicatorOverlapWorkspace = + res.getDimensionPixelSize(R.dimen.workspace_page_indicator_overlap_workspace); + overviewProfile = OverviewProfile.Factory.createOverviewProfile(res); mMetrics = res.getDisplayMetrics(); @@ -532,11 +514,6 @@ public class DeviceProfile { pxFromDp(inv.allAppsBorderSpaces[mTypeIndex].y, mMetrics)); setupAllAppsStyle(context); - workspacePageIndicatorHeight = res.getDimensionPixelSize( - R.dimen.workspace_page_indicator_height); - mWorkspacePageIndicatorOverlapWorkspace = - res.getDimensionPixelSize(R.dimen.workspace_page_indicator_overlap_workspace); - if (!mIsResponsiveGrid) { TypedArray cellStyle; if (inv.cellStyle != INVALID_RESOURCE_HANDLE) { @@ -565,14 +542,8 @@ public class DeviceProfile { workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x); - hotseatQsbHeight = res.getDimensionPixelSize(R.dimen.qsb_widget_height); - hotseatQsbShadowHeight = res.getDimensionPixelSize(R.dimen.qsb_shadow_height); - hotseatQsbVisualHeight = hotseatQsbHeight - 2 * hotseatQsbShadowHeight; - // Whether QSB might be inline in appropriate orientation (e.g. landscape). - isQsbInline = isQsbInline(inv); - areNavButtonsInline = isTaskbarPresent && !isGestureMode; numShownHotseatIcons = displayOptionSpec.numShownHotseatIcons; mHotseatColumnSpan = inv.numColumns; @@ -594,9 +565,6 @@ public class DeviceProfile { hotseatQsbSpace = mResponsiveHotseatSpec.getHotseatQsbSpace(); hotseatBarBottomSpace = isVerticalBarLayout() ? 0 : mResponsiveHotseatSpec.getEdgePadding(); - mHotseatBarEdgePaddingPx = - isVerticalBarLayout() ? mResponsiveHotseatSpec.getEdgePadding() : 0; - mHotseatBarWorkspaceSpacePx = 0; ResponsiveCellSpecsProvider workspaceCellSpecs = ResponsiveCellSpecsProvider.create( new ResourceHelper(context, displayOptionSpec.workspaceCellSpecsId)); @@ -605,12 +573,27 @@ public class DeviceProfile { } else { hotseatQsbSpace = pxFromDp(inv.hotseatQsbSpace[mTypeIndex], mMetrics); hotseatBarBottomSpace = pxFromDp(inv.hotseatBarBottomSpace[mTypeIndex], mMetrics); - mHotseatBarEdgePaddingPx = - isVerticalBarLayout() ? workspacePageIndicatorHeight : 0; - mHotseatBarWorkspaceSpacePx = - res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding); } + hotseatProfile = HotseatProfile.Factory.createHotseatProfile( + getDeviceProperties(), + res, + inv, + isTaskbarPresent, + shouldApplyWidePortraitDimens, + isVerticalBarLayout(), + mResponsiveHotseatSpec, + workspacePageIndicatorHeight + ); + + // Whether QSB might be inline in appropriate orientation (e.g. landscape). + isQsbInline = isQsbInline( + inv, + hotseatProfile, + mDeviceProperties, + mIsScalableGrid + ); + if (!isVerticalBarLayout()) { // Have a little space between the inset and the QSB if (mInsets.bottom + minQsbMargin > hotseatBarBottomSpace) { @@ -633,27 +616,12 @@ public class DeviceProfile { } } - springLoadedHotseatBarTopMarginPx = shouldApplyWidePortraitDimens - ? res.getDimensionPixelSize(R.dimen.spring_loaded_hotseat_top_margin_wide_portrait) - : res.getDimensionPixelSize(R.dimen.spring_loaded_hotseat_top_margin); - if (mIsResponsiveGrid) { updateHotseatSizes(mResponsiveWorkspaceCellSpec.getIconSize()); } else { updateHotseatSizes(pxFromDp(inv.iconSize[mTypeIndex], mMetrics)); } - if (areNavButtonsInline && !mDeviceProperties.isPhone()) { - inlineNavButtonsEndSpacingPx = - res.getDimensionPixelSize(inv.inlineNavButtonsEndSpacing); - /* 3 nav buttons + Spacing between nav buttons */ - navButtonsLayoutWidthPx = 3 * res.getDimensionPixelSize( - R.dimen.taskbar_nav_buttons_size) - + 2 * res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween); - /* nav buttons layout width + Space at the end for contextual buttons */ - hotseatBarEndOffset = navButtonsLayoutWidthPx + inlineNavButtonsEndSpacingPx; - } - mBubbleBarSpaceThresholdPx = res.getDimensionPixelSize(R.dimen.bubblebar_hotseat_adjustment_threshold); @@ -747,10 +715,6 @@ public class DeviceProfile { // Folder scaling requires correct workspace paddings updateAvailableFolderCellDimensions(res); - mMinHotseatIconSpacePx = res.getDimensionPixelSize(R.dimen.min_hotseat_icon_space); - mMinHotseatQsbWidthPx = res.getDimensionPixelSize(R.dimen.min_hotseat_qsb_width); - mMaxHotseatIconSpacePx = areNavButtonsInline - ? res.getDimensionPixelSize(R.dimen.max_hotseat_icon_space) : Integer.MAX_VALUE; // Hotseat and QSB width depends on updated cellSize and workspace padding recalculateHotseatWidthAndBorderSpace(); @@ -790,10 +754,19 @@ public class DeviceProfile { return overviewProfile; } + public HotseatProfile getHotseatProfile() { + return hotseatProfile; + } + /** * Takes care of the logic that determines if we show a the QSB inline or not. */ - private boolean isQsbInline(InvariantDeviceProfile inv) { + private boolean isQsbInline( + InvariantDeviceProfile inv, + HotseatProfile hotseatProfile, + DeviceProperties deviceProperties, + boolean isScalableGrid + ) { // For foldable (two panel), we inline the qsb if we have the screen open and we are in // either Landscape or Portrait. This cal also be disabled in the device_profile.xml boolean twoPanelCanInline = inv.inlineQsb[INDEX_TWO_PANEL_PORTRAIT] @@ -801,10 +774,10 @@ public class DeviceProfile { // In tablets we inline in both orientations but only if we have enough space in the QSB boolean tabletInlineQsb = inv.inlineQsb[INDEX_DEFAULT] || inv.inlineQsb[INDEX_LANDSCAPE]; - boolean canQsbInline = mDeviceProperties.isTwoPanels() ? twoPanelCanInline : tabletInlineQsb; - canQsbInline = canQsbInline && hotseatQsbHeight > 0; + boolean canQsbInline = deviceProperties.isTwoPanels() ? twoPanelCanInline : tabletInlineQsb; + canQsbInline = canQsbInline && hotseatProfile.getQsbHeight() > 0; - return (mIsScalableGrid && inv.inlineQsb[mTypeIndex] && canQsbInline) + return (isScalableGrid && inv.inlineQsb[mTypeIndex] && canQsbInline) || inv.isFixedLandscape; } @@ -896,15 +869,15 @@ public class DeviceProfile { hotseatCellHeightPx = getIconSizeWithOverlap(hotseatIconSizePx); if (isVerticalBarLayout()) { - hotseatBarSizePx = hotseatIconSizePx + mHotseatBarEdgePaddingPx - + mHotseatBarWorkspaceSpacePx; + hotseatBarSizePx = hotseatIconSizePx + getHotseatProfile().getBarEdgePaddingPx() + + getHotseatProfile().getBarWorkspaceSpacePx(); } else if (isQsbInline) { - hotseatBarSizePx = Math.max(hotseatIconSizePx, hotseatQsbVisualHeight) + hotseatBarSizePx = Math.max(hotseatIconSizePx, getHotseatProfile().getQsbVisualHeight()) + hotseatBarBottomSpacePx; } else { hotseatBarSizePx = hotseatIconSizePx + hotseatQsbSpace - + hotseatQsbVisualHeight + + getHotseatProfile().getQsbVisualHeight() + hotseatBarBottomSpacePx; } } @@ -922,7 +895,7 @@ public class DeviceProfile { updateHotseatWidthAndBorderSpace(inv.numDatabaseHotseatIcons); // If hotseat doesn't fit with current width, increase column span to fit by multiple // of 2. - while (hotseatBorderSpace < mMinHotseatIconSpacePx + while (hotseatBorderSpace < getHotseatProfile().getMinIconSpacePx() && mHotseatColumnSpan < numWorkspaceColumns) { updateHotseatWidthAndBorderSpace(mHotseatColumnSpan + 2); } @@ -931,45 +904,46 @@ public class DeviceProfile { // If QSB is inline, reduce column span until it fits. int maxHotseatWidthAllowedPx = getIconToIconWidthForColumns(numWorkspaceColumns); int minHotseatWidthRequiredPx = - mMinHotseatQsbWidthPx + hotseatBorderSpace + mHotseatWidthPx; + getHotseatProfile().getMinQsbWidthPx() + hotseatBorderSpace + mHotseatWidthPx; while (minHotseatWidthRequiredPx > maxHotseatWidthAllowedPx && mHotseatColumnSpan > 1) { updateHotseatWidthAndBorderSpace(mHotseatColumnSpan - 1); - minHotseatWidthRequiredPx = - mMinHotseatQsbWidthPx + hotseatBorderSpace + mHotseatWidthPx; + minHotseatWidthRequiredPx = getHotseatProfile().getMinQsbWidthPx() + + hotseatBorderSpace + mHotseatWidthPx; } } hotseatQsbWidth = calculateQsbWidth(hotseatBorderSpace); // Spaces should be correct when the nav buttons are not inline - if (!areNavButtonsInline) { + if (!getHotseatProfile().getAreNavButtonsInline()) { return; } // The side space with inline buttons should be what is defined in InvariantDeviceProfile - int sideSpacePx = inlineNavButtonsEndSpacingPx; - int maxHotseatWidthPx = mDeviceProperties.getAvailableWidthPx() - sideSpacePx - hotseatBarEndOffset; + int sideSpacePx = getHotseatProfile().getInlineNavButtonsEndSpacingPx(); + int maxHotseatWidthPx = mDeviceProperties.getAvailableWidthPx() - sideSpacePx + - getHotseatProfile().getBarEndOffset(); int maxHotseatIconsWidthPx = maxHotseatWidthPx - (isQsbInline ? hotseatQsbWidth : 0); hotseatBorderSpace = calculateHotseatBorderSpace(maxHotseatIconsWidthPx, (isQsbInline ? 1 : 0) + /* border between nav buttons and first icon */ 1); - if (hotseatBorderSpace >= mMinHotseatIconSpacePx) { + if (hotseatBorderSpace >= getHotseatProfile().getMinIconSpacePx()) { return; } // Border space can't be less than the minimum - hotseatBorderSpace = mMinHotseatIconSpacePx; + hotseatBorderSpace = getHotseatProfile().getMinIconSpacePx(); int requiredWidth = getHotseatRequiredWidth(); // If there is an inline qsb, change its size if (isQsbInline) { hotseatQsbWidth -= requiredWidth - maxHotseatWidthPx; - if (hotseatQsbWidth >= mMinHotseatQsbWidthPx) { + if (hotseatQsbWidth >= getHotseatProfile().getMinQsbWidthPx()) { return; } // QSB can't be less than the minimum - hotseatQsbWidth = mMinHotseatQsbWidthPx; + hotseatQsbWidth = getHotseatProfile().getMinQsbWidthPx(); } maxHotseatIconsWidthPx = maxHotseatWidthPx - (isQsbInline ? hotseatQsbWidth : 0); @@ -979,7 +953,9 @@ public class DeviceProfile { numShownHotseatIcons--; hotseatBorderSpace = calculateHotseatBorderSpace(maxHotseatIconsWidthPx, (isQsbInline ? 1 : 0) + /* border between nav buttons and first icon */ 1); - } while (hotseatBorderSpace < mMinHotseatIconSpacePx && numShownHotseatIcons > 1); + } while ( + hotseatBorderSpace < getHotseatProfile().getMinIconSpacePx() + && numShownHotseatIcons > 1); } private void updateHotseatWidthAndBorderSpace(int columns) { @@ -1350,7 +1326,7 @@ public class DeviceProfile { float hotseatIconsTotalPx = iconSizePx * numShownHotseatIcons; int hotseatBorderSpacePx = (int) (hotseatWidthPx - hotseatIconsTotalPx) / numBorders; - return Math.min(hotseatBorderSpacePx, mMaxHotseatIconSpacePx); + return Math.min(hotseatBorderSpacePx, getHotseatProfile().getMaxIconSpacePx()); } /** @@ -1705,7 +1681,7 @@ public class DeviceProfile { * Gets the scaled bottom of the workspace in px for the spring-loaded edit state. */ public float getCellLayoutSpringLoadShrunkBottom(Context context) { - int topOfHotseat = hotseatBarSizePx + springLoadedHotseatBarTopMarginPx; + int topOfHotseat = hotseatBarSizePx + getHotseatProfile().getSpringLoadedBarTopMarginPx(); return mDeviceProperties.getHeightPx() - (isVerticalBarLayout() ? getVerticalHotseatLastItemBottomOffset(context) : topOfHotseat); } @@ -1778,9 +1754,9 @@ public class DeviceProfile { padding.bottom = edgeMarginPx; if (isSeascape()) { padding.left = hotseatBarSizePx; - padding.right = mHotseatBarEdgePaddingPx; + padding.right = getHotseatProfile().getBarEdgePaddingPx(); } else { - padding.left = mHotseatBarEdgePaddingPx; + padding.left = getHotseatProfile().getBarEdgePaddingPx(); padding.right = hotseatBarSizePx; } } @@ -1895,11 +1871,11 @@ public class DeviceProfile { int paddingBottom = Math.max((int) (mInsets.bottom + cellLayoutPaddingPx.bottom), 0); if (isSeascape()) { - hotseatBarPadding.set(mInsets.left + mHotseatBarEdgePaddingPx, paddingTop, - mHotseatBarWorkspaceSpacePx, paddingBottom); + hotseatBarPadding.set(mInsets.left + getHotseatProfile().getBarEdgePaddingPx(), + paddingTop, getHotseatProfile().getBarWorkspaceSpacePx(), paddingBottom); } else { - hotseatBarPadding.set(mHotseatBarWorkspaceSpacePx, paddingTop, - mInsets.right + mHotseatBarEdgePaddingPx, paddingBottom); + hotseatBarPadding.set(getHotseatProfile().getBarWorkspaceSpacePx(), paddingTop, + mInsets.right + getHotseatProfile().getBarEdgePaddingPx(), paddingBottom); } } else if (inv.isFixedLandscape) { // Center the QSB vertically with hotseat @@ -1937,8 +1913,8 @@ public class DeviceProfile { int startSpacing; int endSpacing; // Hotseat aligns to the left with nav buttons - if (hotseatBarEndOffset > 0) { - startSpacing = inlineNavButtonsEndSpacingPx; + if (getHotseatProfile().getBarEndOffset() > 0) { + startSpacing = getHotseatProfile().getInlineNavButtonsEndSpacingPx(); endSpacing = mDeviceProperties.getAvailableWidthPx() - hotseatWidth - startSpacing + hotseatBorderSpace; } else { startSpacing = (mDeviceProperties.getAvailableWidthPx() - hotseatWidth) / 2; @@ -2026,7 +2002,8 @@ public class DeviceProfile { private int getHotseatRequiredWidth() { int additionalQsbSpace = getAdditionalQsbSpace(); return iconSizePx * numShownHotseatIcons - + hotseatBorderSpace * (numShownHotseatIcons - (areNavButtonsInline ? 0 : 1)) + + hotseatBorderSpace * (numShownHotseatIcons + - (getHotseatProfile().getAreNavButtonsInline() ? 0 : 1)) + additionalQsbSpace; } @@ -2035,11 +2012,13 @@ public class DeviceProfile { */ public int getQsbOffsetY() { if (isQsbInline) { - return getHotseatBarBottomPadding() - ((hotseatQsbHeight - hotseatCellHeightPx) / 2); + return getHotseatBarBottomPadding() + - ((getHotseatProfile().getQsbHeight() - hotseatCellHeightPx) / 2); } else if (isTaskbarPresent) { // QSB on top - return hotseatBarSizePx - hotseatQsbHeight + hotseatQsbShadowHeight; + return hotseatBarSizePx - getHotseatProfile().getQsbHeight() + + getHotseatProfile().getQsbShadowHeight(); } else { - return hotseatBarBottomSpacePx - hotseatQsbShadowHeight; + return hotseatBarBottomSpacePx - getHotseatProfile().getQsbShadowHeight(); } } @@ -2061,12 +2040,12 @@ public class DeviceProfile { public int getBubbleBarVerticalCenterForHome() { if (shouldAlignBubbleBarWithHotseat()) { return hotseatBarSizePx - - (isQsbInline ? 0 : hotseatQsbVisualHeight) + - (isQsbInline ? 0 : getHotseatProfile().getQsbVisualHeight()) - hotseatQsbSpace - (hotseatCellHeightPx / 2) + ((hotseatCellHeightPx - iconSizePx) / 2); } else { - return hotseatBarSizePx - (hotseatQsbVisualHeight / 2); + return hotseatBarSizePx - (getHotseatProfile().getQsbVisualHeight() / 2); } } @@ -2296,18 +2275,19 @@ public class DeviceProfile { writer.println(prefix + pxToDpStr("hotseatCellHeightPx", hotseatCellHeightPx)); writer.println(prefix + pxToDpStr("hotseatBarBottomSpacePx", hotseatBarBottomSpacePx)); writer.println(prefix + pxToDpStr("mHotseatBarEdgePaddingPx", - mHotseatBarEdgePaddingPx)); + getHotseatProfile().getBarEdgePaddingPx())); writer.println(prefix + pxToDpStr("mHotseatBarWorkspaceSpacePx", - mHotseatBarWorkspaceSpacePx)); - writer.println(prefix - + pxToDpStr("inlineNavButtonsEndSpacingPx", inlineNavButtonsEndSpacingPx)); - writer.println(prefix - + pxToDpStr("navButtonsLayoutWidthPx", navButtonsLayoutWidthPx)); - writer.println(prefix + pxToDpStr("hotseatBarEndOffset", hotseatBarEndOffset)); + getHotseatProfile().getBarWorkspaceSpacePx())); + writer.println(prefix + pxToDpStr("inlineNavButtonsEndSpacingPx", + getHotseatProfile().getInlineNavButtonsEndSpacingPx())); + writer.println(prefix + pxToDpStr("navButtonsLayoutWidthPx", + getHotseatProfile().getNavButtonsLayoutWidthPx())); + writer.println(prefix + pxToDpStr("hotseatBarEndOffset", + getHotseatProfile().getBarEndOffset())); writer.println(prefix + pxToDpStr("hotseatQsbSpace", hotseatQsbSpace)); - writer.println(prefix + pxToDpStr("hotseatQsbHeight", hotseatQsbHeight)); + writer.println(prefix + pxToDpStr("hotseatQsbHeight", getHotseatProfile().getQsbHeight())); writer.println(prefix + pxToDpStr("springLoadedHotseatBarTopMarginPx", - springLoadedHotseatBarTopMarginPx)); + getHotseatProfile().getSpringLoadedBarTopMarginPx())); Rect hotseatLayoutPadding = getHotseatLayoutPadding(context); writer.println(prefix + pxToDpStr("getHotseatLayoutPadding(context).top", hotseatLayoutPadding.top)); @@ -2435,9 +2415,9 @@ public class DeviceProfile { if (shouldAdjustHotseatOnNavBarLocationUpdate(context)) { boolean isRtl = Utilities.isRtl(context.getResources()); if (isBubblesOnLeft) { - return isRtl ? -navButtonsLayoutWidthPx : 0; + return isRtl ? -getHotseatProfile().getNavButtonsLayoutWidthPx() : 0; } else { - return isRtl ? 0 : navButtonsLayoutWidthPx; + return isRtl ? 0 : getHotseatProfile().getNavButtonsLayoutWidthPx(); } } else { return 0; diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index ef0f44f1fd..63e9685155 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -16,6 +16,8 @@ package com.android.launcher3; +import static android.view.View.MeasureSpec.makeMeasureSpec; + import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_BUBBLE_ADJUSTMENT_ANIM; @@ -315,8 +317,8 @@ public class Hotseat extends CellLayout implements Insettable { super.onMeasure(widthMeasureSpec, heightMeasureSpec); DeviceProfile dp = mActivity.getDeviceProfile(); - mQsb.measure(MeasureSpec.makeMeasureSpec(dp.hotseatQsbWidth, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(dp.hotseatQsbHeight, MeasureSpec.EXACTLY)); + mQsb.measure(makeMeasureSpec(dp.hotseatQsbWidth, MeasureSpec.EXACTLY), + makeMeasureSpec(dp.getHotseatProfile().getQsbHeight(), MeasureSpec.EXACTLY)); } @Override @@ -336,7 +338,7 @@ public class Hotseat extends CellLayout implements Insettable { int right = left + qsbMeasuredWidth; int bottom = b - t - dp.getQsbOffsetY(); - int top = bottom - dp.hotseatQsbHeight; + int top = bottom - dp.getHotseatProfile().getQsbHeight(); mQsb.layout(left, top, right, bottom); } diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index fd91b59aa7..72b203a759 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -219,7 +219,7 @@ public abstract class LauncherState implements BaseState { public int getFloatingSearchBarRestingMarginBottom(Launcher launcher) { DeviceProfile dp = launcher.getDeviceProfile(); return areElementsVisible(launcher, FLOATING_SEARCH_BAR) ? dp.getQsbOffsetY() - : -dp.hotseatQsbHeight; + : -dp.getHotseatProfile().getQsbHeight(); } /** diff --git a/src/com/android/launcher3/allapps/WorkUtilityView.java b/src/com/android/launcher3/allapps/WorkUtilityView.java index 80cdaeb025..9fcf3721a7 100644 --- a/src/com/android/launcher3/allapps/WorkUtilityView.java +++ b/src/com/android/launcher3/allapps/WorkUtilityView.java @@ -162,7 +162,7 @@ public class WorkUtilityView extends LinearLayout implements Insettable, int bottomMargin = getResources().getDimensionPixelSize(R.dimen.work_fab_margin_bottom); DeviceProfile dp = ActivityContext.lookupContext(getContext()).getDeviceProfile(); if (mActivityContext.getAppsView().isSearchBarFloating()) { - bottomMargin += dp.hotseatQsbHeight; + bottomMargin += dp.getHotseatProfile().getQsbHeight(); } if (!dp.getDeviceProperties().isGestureMode() && dp.isTaskbarPresent) { diff --git a/src/com/android/launcher3/deviceprofile/HotseatProfile.kt b/src/com/android/launcher3/deviceprofile/HotseatProfile.kt new file mode 100644 index 0000000000..0aa574c017 --- /dev/null +++ b/src/com/android/launcher3/deviceprofile/HotseatProfile.kt @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2025 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.deviceprofile + +import android.content.res.Resources +import com.android.launcher3.InvariantDeviceProfile +import com.android.launcher3.R +import com.android.launcher3.responsive.CalculatedHotseatSpec + +// Remaining hotseat properties +// int numShownHotseatIcons - updates multiple times +// int hotseatCellHeightPx - updates multiple times +// int mHotseatColumnSpan - updates multiple times +// int mHotseatWidthPx - updates multiple times +// int hotseatBarSizePx - updates multiple times +// int hotseatBarBottomSpacePx - relies on var +// int hotseatQsbSpace - relies on var +// int hotseatQsbWidth - updates multiple times +// int hotseatBorderSpace - updates multiple times + +data class HotseatProfile( + val areNavButtonsInline: Boolean, + val navButtonsLayoutWidthPx: Int, + val inlineNavButtonsEndSpacingPx: Int, + val barEndOffset: Int, + val springLoadedBarTopMarginPx: Int, + val barEdgePaddingPx: Int, + val barWorkspaceSpacePx: Int, + val qsbHeight: Int, + val qsbShadowHeight: Int, + val qsbVisualHeight: Int, + val minIconSpacePx: Int, + val minQsbWidthPx: Int, + val maxIconSpacePx: Int, +) { + + companion object Factory { + fun createHotseatProfile( + deviceProperties: DeviceProperties, + res: Resources, + inv: InvariantDeviceProfile, + isTaskbarPresent: Boolean, + shouldApplyWidePortraitDimens: Boolean, + isVerticalBarLayout: Boolean, + responsiveHotseatSpec: CalculatedHotseatSpec?, + workspacePageIndicatorHeight: Int, + ): HotseatProfile { + val areNavButtonsInline = isTaskbarPresent && !deviceProperties.isGestureMode + var inlineNavButtonsEndSpacingPx = 0 + var navButtonsLayoutWidthPx = 0 + var barEndOffset = 0 + // 3 nav buttons + Spacing between nav buttons + if (areNavButtonsInline && !deviceProperties.isPhone) { + inlineNavButtonsEndSpacingPx = + res.getDimensionPixelSize(inv.inlineNavButtonsEndSpacing) + /* 3 nav buttons + Spacing between nav buttons */ + navButtonsLayoutWidthPx = + 3 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) + + 2 * res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween) + barEndOffset = navButtonsLayoutWidthPx + inlineNavButtonsEndSpacingPx + } + val springLoadedHotseatBarTopMarginPx = + if (shouldApplyWidePortraitDimens) + res.getDimensionPixelSize( + R.dimen.spring_loaded_hotseat_top_margin_wide_portrait + ) + else res.getDimensionPixelSize(R.dimen.spring_loaded_hotseat_top_margin) + val hotseatBarEdgePaddingPx = + when { + !isVerticalBarLayout -> 0 + responsiveHotseatSpec != null -> responsiveHotseatSpec.edgePadding + else -> workspacePageIndicatorHeight + } + val hotseatBarWorkspaceSpacePx = + if (responsiveHotseatSpec != null) 0 + else res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_side_padding) + val hotseatQsbHeight = res.getDimensionPixelSize(R.dimen.qsb_widget_height) + val hotseatQsbShadowHeight = res.getDimensionPixelSize(R.dimen.qsb_shadow_height) + + return HotseatProfile( + areNavButtonsInline = areNavButtonsInline, + navButtonsLayoutWidthPx = navButtonsLayoutWidthPx, + inlineNavButtonsEndSpacingPx = inlineNavButtonsEndSpacingPx, + barEndOffset = barEndOffset, + springLoadedBarTopMarginPx = springLoadedHotseatBarTopMarginPx, + barEdgePaddingPx = hotseatBarEdgePaddingPx, + barWorkspaceSpacePx = hotseatBarWorkspaceSpacePx, + qsbHeight = hotseatQsbHeight, + qsbShadowHeight = hotseatQsbShadowHeight, + qsbVisualHeight = hotseatQsbHeight - 2 * hotseatQsbShadowHeight, + minIconSpacePx = res.getDimensionPixelSize(R.dimen.min_hotseat_icon_space), + minQsbWidthPx = res.getDimensionPixelSize(R.dimen.min_hotseat_qsb_width), + maxIconSpacePx = + if (areNavButtonsInline) + res.getDimensionPixelSize(R.dimen.max_hotseat_icon_space) + else Int.MAX_VALUE, + ) + } + } +} diff --git a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt index 408691cb79..7258284011 100644 --- a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt +++ b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt @@ -39,7 +39,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(0) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(145) assertThat(dp.hotseatColumnSpan).isEqualTo(6) @@ -63,7 +63,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(0) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(72) assertThat(dp.hotseatColumnSpan).isEqualTo(6) @@ -86,7 +86,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(0) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(104) assertThat(dp.hotseatColumnSpan).isEqualTo(6) @@ -110,7 +110,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(0) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(248) assertThat(dp.hotseatColumnSpan).isEqualTo(6) @@ -131,7 +131,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(0) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(233) assertThat(dp.hotseatColumnSpan).isEqualTo(6) @@ -155,7 +155,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(0) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(205) assertThat(dp.hotseatColumnSpan).isEqualTo(6) @@ -195,7 +195,7 @@ class HotseatWidthCalculationTest : FakeInvariantDeviceProfileTest() { val dp = newDP() dp.isTaskbarPresentInApps = true - assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.hotseatProfile.barEndOffset).isEqualTo(0) assertThat(dp.numShownHotseatIcons).isEqualTo(6) assertThat(dp.hotseatBorderSpace).isEqualTo(112) assertThat(dp.hotseatColumnSpan).isEqualTo(8)