diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java index 300f085b2a..3803f0350b 100644 --- a/quickstep/src/com/android/quickstep/TaskIconCache.java +++ b/quickstep/src/com/android/quickstep/TaskIconCache.java @@ -256,7 +256,7 @@ public class TaskIconCache implements DisplayInfoChangeListener { private BaseIconFactory getIconFactory() { if (mIconFactory == null) { mIconFactory = new BaseIconFactory(mContext, - DisplayController.INSTANCE.get(mContext).getInfo().densityDpi, + DisplayController.INSTANCE.get(mContext).getInfo().getDensityDpi(), mContext.getResources().getDimensionPixelSize(R.dimen.taskbar_icon_size)); } return mIconFactory; diff --git a/res/values/attrs.xml b/res/values/attrs.xml index dd3e08b19b..e85969bfc0 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -306,6 +306,17 @@ if not specified --> + + + + + + + + + + diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml index 07ce59862b..258da80c40 100644 --- a/res/xml/device_profiles.xml +++ b/res/xml/device_profiles.xml @@ -176,6 +176,7 @@ launcher:allAppsBorderSpaceHorizontal="8" launcher:allAppsBorderSpaceVertical="16" launcher:allAppsBorderSpaceLandscape="16" + launcher:hotseatColumnSpanLandscape="4" launcher:hotseatBorderSpace="58" launcher:hotseatBorderSpaceLandscape="50.4" launcher:canBeDefault="true" /> diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 31f1da85c4..88030ae61f 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -158,6 +158,7 @@ public class DeviceProfile { public final int numShownHotseatIcons; public int hotseatCellHeightPx; private final int hotseatExtraVerticalSize; + private final boolean areNavButtonsInline; // In portrait: size = height, in landscape: size = width public int hotseatBarSizePx; public int hotseatBarTopPaddingPx; @@ -358,7 +359,7 @@ public class DeviceProfile { // We shrink hotseat sizes regardless of orientation, if nav buttons are inline and QSB // might be inline in either orientations, to keep hotseat size consistent across rotation. - boolean areNavButtonsInline = isTaskbarPresent && !isGestureMode; + areNavButtonsInline = isTaskbarPresent && !isGestureMode; if (areNavButtonsInline && canQsbInline) { numShownHotseatIcons = inv.numShrunkenHotseatIcons; } else { @@ -373,15 +374,14 @@ public class DeviceProfile { res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_top_padding); if (isQsbInline) { hotseatBarBottomPaddingPx = res.getDimensionPixelSize(R.dimen.inline_qsb_bottom_margin); - qsbWidth = calculateQsbWidth(); } else { hotseatBarBottomPaddingPx = (isTallDevice ? res.getDimensionPixelSize( R.dimen.dynamic_grid_hotseat_bottom_tall_padding) : res.getDimensionPixelSize( R.dimen.dynamic_grid_hotseat_bottom_non_tall_padding)) + res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_bottom_padding); - qsbWidth = 0; } + springLoadedHotseatBarTopMarginPx = res.getDimensionPixelSize( R.dimen.spring_loaded_hotseat_top_margin); hotseatBarSidePaddingEndPx = @@ -390,9 +390,7 @@ public class DeviceProfile { hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0; hotseatExtraVerticalSize = res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_extra_vertical_size); - hotseatBorderSpace = pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics); - updateHotseatIconSize( - pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics)); + updateHotseatIconSize(pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics)); qsbBottomMarginOriginalPx = isScalableGrid ? res.getDimensionPixelSize(R.dimen.scalable_grid_qsb_bottom_margin) @@ -483,6 +481,10 @@ public class DeviceProfile { cellLayoutPadding); updateWorkspacePadding(); + // Hotseat and QSB width depends on updated cellSize and workspace padding + hotseatBorderSpace = calculateHotseatBorderSpace(); + qsbWidth = calculateQsbWidth(); + flingToDeleteThresholdVelocity = res.getDimensionPixelSize( R.dimen.drag_flingToDeleteMinVelocity); @@ -493,14 +495,26 @@ public class DeviceProfile { new DotRenderer(allAppsIconSizePx, dotPath, DEFAULT_DOT_SIZE); } + /** + * QSB width is always calculated because when in 3 button nav the width doesn't follow the + * width of the hotseat. + */ private int calculateQsbWidth() { - int columns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns; + if (isQsbInline) { + int columns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns; + return getIconToIconWidthForColumns(columns) + - iconSizePx * numShownHotseatIcons + - hotseatBorderSpace * numShownHotseatIcons; + } else { + int columns = inv.hotseatColumnSpan[mTypeIndex]; + return getIconToIconWidthForColumns(columns); + } + } - return cellWidthPx * columns - + cellLayoutBorderSpacePx.x * (columns - 1) - - (cellWidthPx - iconSizePx) // left and right cell space - - iconSizePx * numShownHotseatIcons - - hotseatBorderSpace * numShownHotseatIcons; + private int getIconToIconWidthForColumns(int columns) { + return columns * getCellSize().x + + (columns - 1) * cellLayoutBorderSpacePx.x + - (getCellSize().x - iconSizePx); // left and right cell space } private int getHorizontalMarginPx(InvariantDeviceProfile idp, Resources res) { @@ -741,13 +755,6 @@ public class DeviceProfile { // All apps updateAllAppsIconSize(scale, res); - // Hotseat - hotseatBorderSpace = pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics, scale); - if (isQsbInline) { - qsbWidth = calculateQsbWidth(); - } else { - qsbWidth = 0; - } updateHotseatIconSize(iconSizePx); // Folder icon @@ -755,6 +762,23 @@ public class DeviceProfile { folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2; } + /** + * Hotseat width spans a certain number of columns on scalable grids. + * This method calculates the space between the icons to achieve that width. + */ + private int calculateHotseatBorderSpace() { + if (!isScalableGrid) return 0; + //TODO(http://b/228998082) remove this when 3 button spaces are fixed + if (areNavButtonsInline) { + return pxFromDp(inv.hotseatBorderSpaces[mTypeIndex], mMetrics); + } else { + int columns = inv.hotseatColumnSpan[mTypeIndex]; + float hotseatWidthPx = getIconToIconWidthForColumns(columns); + float hotseatIconsTotalPx = iconSizePx * numShownHotseatIcons; + return (int) (hotseatWidthPx - hotseatIconsTotalPx) / (numShownHotseatIcons - 1); + } + } + /** * Updates the iconSize for allApps* variants. @@ -1070,6 +1094,13 @@ public class DeviceProfile { mHotseatPadding.left -= diff; mHotseatPadding.right += diff; } + } else if (isScalableGrid) { + int sideSpacing = (availableWidthPx - qsbWidth) / 2; + mHotseatPadding.set(sideSpacing, + hotseatBarTopPaddingPx, + sideSpacing, + hotseatBarSizePx - hotseatCellHeightPx - hotseatBarTopPaddingPx + + mInsets.bottom); } else { // We want the edges of the hotseat to line up with the edges of the workspace, but the // icons in the hotseat are a different size, and so don't line up perfectly. To account @@ -1306,6 +1337,7 @@ public class DeviceProfile { writer.println(prefix + pxToDpStr("allAppsLeftRightMargin", allAppsLeftRightMargin)); writer.println(prefix + pxToDpStr("hotseatBarSizePx", hotseatBarSizePx)); + writer.println(prefix + "\tinv.hotseatColumnSpan: " + inv.hotseatColumnSpan[mTypeIndex]); writer.println(prefix + pxToDpStr("hotseatCellHeightPx", hotseatCellHeightPx)); writer.println(prefix + pxToDpStr("hotseatBarTopPaddingPx", hotseatBarTopPaddingPx)); writer.println(prefix + pxToDpStr("hotseatBarBottomPaddingPx", hotseatBarBottomPaddingPx)); @@ -1384,7 +1416,7 @@ public class DeviceProfile { private static Context getContext(Context c, Info info, int orientation, WindowBounds bounds) { Configuration config = new Configuration(c.getResources().getConfiguration()); config.orientation = orientation; - config.densityDpi = info.densityDpi; + config.densityDpi = info.getDensityDpi(); config.smallestScreenWidthDp = (int) info.smallestSizeDp(bounds); return c.createConfigurationContext(config); } diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index a9db5ce089..76106fc58d 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -173,17 +173,9 @@ public class Hotseat extends CellLayout implements Insettable { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - int width; - if (mActivity.getDeviceProfile().isQsbInline) { - width = mActivity.getDeviceProfile().qsbWidth; - } else { - MarginLayoutParams qsbParams = (MarginLayoutParams) mQsb.getLayoutParams(); - width = getShortcutsAndWidgets().getMeasuredWidth() - - qsbParams.getMarginStart() - - qsbParams.getMarginEnd(); - } + int qsbWidth = mActivity.getDeviceProfile().qsbWidth; - mQsb.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + mQsb.measure(MeasureSpec.makeMeasureSpec(qsbWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mQsbHeight, MeasureSpec.EXACTLY)); } diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 36c179798f..89b177165f 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -125,6 +125,7 @@ public class InvariantDeviceProfile { public PointF[] borderSpaces; public float folderBorderSpace; public float[] hotseatBorderSpaces; + public int[] hotseatColumnSpan; public float[] horizontalMargin; @@ -356,6 +357,7 @@ public class InvariantDeviceProfile { numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY ? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons; hotseatBorderSpaces = displayOption.hotseatBorderSpaces; + hotseatColumnSpan = displayOption.hotseatColumnSpan; numAllAppsColumns = closestProfile.numAllAppsColumns; numDatabaseAllAppsColumns = deviceType == TYPE_MULTI_DISPLAY @@ -396,7 +398,8 @@ public class InvariantDeviceProfile { // We need to ensure that there is enough extra space in the wallpaper // for the intended parallax effects float parallaxFactor = - dpiFromPx(Math.min(displayWidth, displayHeight), displayInfo.densityDpi) < 720 + dpiFromPx(Math.min(displayWidth, displayHeight), displayInfo.getDensityDpi()) + < 720 ? 2 : wallpaperTravelToScreenWidthRatio(displayWidth, displayHeight); defaultWallpaperSize.x = @@ -585,8 +588,8 @@ public class InvariantDeviceProfile { } } - float width = dpiFromPx(minWidthPx, displayInfo.densityDpi); - float height = dpiFromPx(minHeightPx, displayInfo.densityDpi); + float width = dpiFromPx(minWidthPx, displayInfo.getDensityDpi()); + float height = dpiFromPx(minHeightPx, displayInfo.getDensityDpi()); // Sort the profiles based on the closeness to the device size Collections.sort(points, (a, b) -> @@ -806,7 +809,9 @@ public class InvariantDeviceProfile { private float folderBorderSpace; private final PointF[] borderSpaces = new PointF[COUNT_SIZES]; private final float[] horizontalMargin = new float[COUNT_SIZES]; + //TODO(http://b/228998082) remove this when 3 button spaces are fixed private final float[] hotseatBorderSpaces = new float[COUNT_SIZES]; + private final int[] hotseatColumnSpan = new int[COUNT_SIZES]; private final float[] iconSizes = new float[COUNT_SIZES]; private final float[] textSizes = new float[COUNT_SIZES]; @@ -1032,6 +1037,17 @@ public class InvariantDeviceProfile { R.styleable.ProfileDisplayOption_hotseatBorderSpaceTwoPanelPortrait, hotseatBorderSpaces[INDEX_DEFAULT]); + hotseatColumnSpan[INDEX_DEFAULT] = a.getInt( + R.styleable.ProfileDisplayOption_hotseatColumnSpan, grid.numColumns); + hotseatColumnSpan[INDEX_LANDSCAPE] = a.getInt( + R.styleable.ProfileDisplayOption_hotseatColumnSpanLandscape, grid.numColumns); + hotseatColumnSpan[INDEX_TWO_PANEL_LANDSCAPE] = a.getInt( + R.styleable.ProfileDisplayOption_hotseatColumnSpanTwoPanelLandscape, + grid.numColumns); + hotseatColumnSpan[INDEX_TWO_PANEL_PORTRAIT] = a.getInt( + R.styleable.ProfileDisplayOption_hotseatColumnSpanTwoPanelPortrait, + grid.numColumns); + a.recycle(); } @@ -1090,6 +1106,7 @@ public class InvariantDeviceProfile { minCellSize[i].y += p.minCellSize[i].y; horizontalMargin[i] += p.horizontalMargin[i]; hotseatBorderSpaces[i] += p.hotseatBorderSpaces[i]; + hotseatColumnSpan[i] = p.hotseatColumnSpan[i]; allAppsCellSize[i].x += p.allAppsCellSize[i].x; allAppsCellSize[i].y += p.allAppsCellSize[i].y; allAppsIconSizes[i] += p.allAppsIconSizes[i]; diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java index 777da23e86..7c73be51c6 100644 --- a/src/com/android/launcher3/util/DisplayController.java +++ b/src/com/android/launcher3/util/DisplayController.java @@ -290,7 +290,7 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { // Configuration property public final float fontScale; - public final int densityDpi; + private final int densityDpi; public final NavigationMode navigationMode; private final PortraitSize mScreenSizeDp; @@ -357,6 +357,10 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { public float smallestSizeDp(WindowBounds bounds) { return dpiFromPx(Math.min(bounds.bounds.width(), bounds.bounds.height()), densityDpi); } + + public int getDensityDpi() { + return densityDpi; + } } /** diff --git a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt index f91f1c4288..6d0fcb6faa 100644 --- a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt +++ b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt @@ -64,6 +64,7 @@ abstract class DeviceProfileBaseTest { windowBounds = WindowBounds(x, y, x, y - 100, 0) whenever(info.isTablet(any())).thenReturn(false) + whenever(info.getDensityDpi()).thenReturn(560) inv = newScalableInvariantDeviceProfile() } @@ -77,6 +78,7 @@ abstract class DeviceProfileBaseTest { windowBounds = WindowBounds(x, y, x, y - 100, 0) whenever(info.isTablet(any())).thenReturn(true) + whenever(info.getDensityDpi()).thenReturn(320) inv = newScalableInvariantDeviceProfile() } @@ -107,6 +109,7 @@ abstract class DeviceProfileBaseTest { PointF(16f, 16f) ).toTypedArray() hotseatBorderSpaces = FloatArray(4) { 16f } + hotseatColumnSpan = IntArray(4) { 4 } iconSize = FloatArray(4) { 56f } allAppsIconSize = FloatArray(4) { 56f } iconTextSize = FloatArray(4) { 14f } diff --git a/tests/src/com/android/launcher3/HotseatSizeTest.kt b/tests/src/com/android/launcher3/HotseatShownIconsTest.kt similarity index 98% rename from tests/src/com/android/launcher3/HotseatSizeTest.kt rename to tests/src/com/android/launcher3/HotseatShownIconsTest.kt index a44939f4cf..593239d6f7 100644 --- a/tests/src/com/android/launcher3/HotseatSizeTest.kt +++ b/tests/src/com/android/launcher3/HotseatShownIconsTest.kt @@ -23,15 +23,13 @@ import com.android.launcher3.InvariantDeviceProfile.TYPE_TABLET import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers -import org.mockito.Mockito.`when` as whenever /** * Test for [DeviceProfile] */ @SmallTest @RunWith(AndroidJUnit4::class) -class HotseatSizeTest : DeviceProfileBaseTest() { +class HotseatShownIconsTest : DeviceProfileBaseTest() { @Test fun hotseat_size_is_normal_for_handhelds() { diff --git a/tests/src/com/android/launcher3/InlineQsbTest.kt b/tests/src/com/android/launcher3/InlineQsbTest.kt index e00dca86e2..905c1e1a0f 100644 --- a/tests/src/com/android/launcher3/InlineQsbTest.kt +++ b/tests/src/com/android/launcher3/InlineQsbTest.kt @@ -29,17 +29,16 @@ import org.junit.runner.RunWith class InlineQsbTest : DeviceProfileBaseTest() { @Test - fun qsbWidth_is_match_parent_for_phones() { + fun qsb_is_not_inline_for_phones() { initializeVarsForPhone() val dp = newDP() assertThat(dp.isQsbInline).isFalse() - assertThat(dp.qsbWidth).isEqualTo(0) } @Test - fun qsbWidth_is_match_parent_for_tablet_portrait() { + fun qsb_is_inline_for_tablet_portrait() { initializeVarsForTablet() inv = newScalableInvariantDeviceProfile().apply { inlineQsb = booleanArrayOf( @@ -62,11 +61,10 @@ class InlineQsbTest : DeviceProfileBaseTest() { ) assertThat(dp.isQsbInline).isFalse() - assertThat(dp.qsbWidth).isEqualTo(0) } @Test - fun qsbWidth_has_size_for_tablet_landscape() { + fun qsb_is_inline_for_tablet_landscape() { initializeVarsForTablet(isLandscape = true) inv = newScalableInvariantDeviceProfile().apply { inlineQsb = booleanArrayOf( @@ -75,16 +73,17 @@ class InlineQsbTest : DeviceProfileBaseTest() { false, false ) + numColumns = 6 + numRows = 5 + numShownHotseatIcons = 6 } val dp = newDP() if (dp.hotseatQsbHeight > 0) { assertThat(dp.isQsbInline).isTrue() - assertThat(dp.qsbWidth).isGreaterThan(0) } else { // Launcher3 doesn't have QSB height assertThat(dp.isQsbInline).isFalse() - assertThat(dp.qsbWidth).isEqualTo(0) } } @@ -92,14 +91,13 @@ class InlineQsbTest : DeviceProfileBaseTest() { * This test is to make sure that a tablet doesn't inline the QSB if the layout doesn't support */ @Test - fun qsbWidth_is_match_parent_for_tablet_landscape_without_inline() { + fun qsb_is_not_inline_for_tablet_landscape_without_inline() { initializeVarsForTablet(isLandscape = true) useTwoPanels = true val dp = newDP() assertThat(dp.isQsbInline).isFalse() - assertThat(dp.qsbWidth).isEqualTo(0) } } \ No newline at end of file diff --git a/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java b/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java index 36235134f5..8d275cc04b 100644 --- a/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java +++ b/tests/src/com/android/launcher3/deviceemulator/models/DeviceEmulationData.java @@ -135,7 +135,7 @@ public class DeviceEmulationData { resourceOverrides.put(s, getDimenByName(s, context.getResources(), 0)); } return new DeviceEmulationData(info.currentSize.x, info.currentSize.y, - info.densityDpi, info.cutout, code, grids, resourceOverrides); + info.getDensityDpi(), info.cutout, code, grids, resourceOverrides); } public static DeviceEmulationData getDevice(String deviceCode) throws Exception {