From 9938c2f7919709493dbe2c9e8444c67850d49187 Mon Sep 17 00:00:00 2001 From: Thales Lima Date: Mon, 25 Jul 2022 14:38:16 +0100 Subject: [PATCH] Calculate hotseat width based on available width Navigation buttons take space on the hotseat, so hotseat width (qsb width and border space between icons) should be calculated instead of having a coded value. Bug: 223724516 Bug: 228998463 Test: manual, changing display size Test: manual, changing hotseatBarEndOffset value Test: HotseatWidthCalculationTest Change-Id: Ibd4f5ff2e06afda8e7420fb744db049d2e418e14 --- quickstep/res/values-land/dimens.xml | 2 +- quickstep/res/values/dimens.xml | 2 +- .../android/quickstep/DeviceProfileTest.kt | 28 +-- .../quickstep/HotseatWidthCalculationTest.kt | 163 +++++++++++++++ res/values/attrs.xml | 12 -- res/values/dimens.xml | 2 + res/xml/device_profiles.xml | 2 - src/com/android/launcher3/DeviceProfile.java | 117 ++++++++--- .../launcher3/InvariantDeviceProfile.java | 29 +-- tests/Android.bp | 13 ++ .../launcher3/DeviceProfileBaseTest.kt | 9 - .../launcher3/HotseatShownIconsTest.kt | 185 ------------------ .../HotseatWidthCalculationTest.kt | 163 +++++++++++++++ 13 files changed, 448 insertions(+), 279 deletions(-) create mode 100644 quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt delete mode 100644 tests/src/com/android/launcher3/HotseatShownIconsTest.kt create mode 100644 tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml index 83680696ad..905fbda7a3 100644 --- a/quickstep/res/values-land/dimens.xml +++ b/quickstep/res/values-land/dimens.xml @@ -77,7 +77,7 @@ 94.5dp - 94.5dp + 219.6dp 84dp 79dp \ No newline at end of file diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index cfe602eb28..6bc3d38c8b 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -278,7 +278,7 @@ 24dp 26dp - 26dp + 75dp 47dp 47dp 47dp diff --git a/quickstep/tests/src/com/android/quickstep/DeviceProfileTest.kt b/quickstep/tests/src/com/android/quickstep/DeviceProfileTest.kt index b50d3eef5a..45a342ae32 100644 --- a/quickstep/tests/src/com/android/quickstep/DeviceProfileTest.kt +++ b/quickstep/tests/src/com/android/quickstep/DeviceProfileTest.kt @@ -338,18 +338,18 @@ class DeviceProfileTest : DeviceProfileBaseTest() { "\thotseatBarBottomSpacePx: 80.0px (40.0dp)\n" + "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" + "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" + - "\thotseatBarEndOffset: 597.0px (298.5dp)\n" + + "\thotseatBarEndOffset: 705.0px (352.5dp)\n" + "\thotseatQsbSpace: 64.0px (32.0dp)\n" + "\thotseatQsbHeight: 126.0px (63.0dp)\n" + "\tspringLoadedHotseatBarTopMarginPx: 128.0px (64.0dp)\n" + "\tgetHotseatLayoutPadding(context).top: -8.0px (-4.0dp)\n" + "\tgetHotseatLayoutPadding(context).bottom: 73.0px (36.5dp)\n" + - "\tgetHotseatLayoutPadding(context).left: 959.0px (479.5dp)\n" + - "\tgetHotseatLayoutPadding(context).right: 597.0px (298.5dp)\n" + - "\tnumShownHotseatIcons: 5\n" + - "\thotseatBorderSpace: 101.0px (50.5dp)\n" + + "\tgetHotseatLayoutPadding(context).left: 954.0px (477.0dp)\n" + + "\tgetHotseatLayoutPadding(context).right: 705.0px (352.5dp)\n" + + "\tnumShownHotseatIcons: 6\n" + + "\thotseatBorderSpace: 36.0px (18.0dp)\n" + "\tisQsbInline: true\n" + - "\thotseatQsbWidth: 855.0px (427.5dp)\n" + + "\thotseatQsbWidth: 619.0px (309.5dp)\n" + "\tisTaskbarPresent:true\n" + "\tisTaskbarPresentInApps:true\n" + "\ttaskbarSize: 120.0px (60.0dp)\n" + @@ -578,16 +578,16 @@ class DeviceProfileTest : DeviceProfileBaseTest() { "\thotseatBarBottomSpacePx: 72.0px (36.0dp)\n" + "\thotseatBarSidePaddingStartPx: 0.0px (0.0dp)\n" + "\thotseatBarSidePaddingEndPx: 0.0px (0.0dp)\n" + - "\thotseatBarEndOffset: 460.0px (230.0dp)\n" + + "\thotseatBarEndOffset: 558.0px (279.0dp)\n" + "\thotseatQsbSpace: 64.0px (32.0dp)\n" + "\thotseatQsbHeight: 126.0px (63.0dp)\n" + "\tspringLoadedHotseatBarTopMarginPx: 216.0px (108.0dp)\n" + "\tgetHotseatLayoutPadding(context).top: 158.0px (79.0dp)\n" + "\tgetHotseatLayoutPadding(context).bottom: 65.0px (32.5dp)\n" + - "\tgetHotseatLayoutPadding(context).left: 76.0px (38.0dp)\n" + - "\tgetHotseatLayoutPadding(context).right: 460.0px (230.0dp)\n" + + "\tgetHotseatLayoutPadding(context).left: 150.0px (75.0dp)\n" + + "\tgetHotseatLayoutPadding(context).right: 558.0px (279.0dp)\n" + "\tnumShownHotseatIcons: 5\n" + - "\thotseatBorderSpace: 116.0px (58.0dp)\n" + + "\thotseatBorderSpace: 73.0px (36.5dp)\n" + "\tisQsbInline: false\n" + "\thotseatQsbWidth: 1300.0px (650.0dp)\n" + "\tisTaskbarPresent:true\n" + @@ -824,10 +824,10 @@ class DeviceProfileTest : DeviceProfileBaseTest() { "\tspringLoadedHotseatBarTopMarginPx: 116.0px (44.190475dp)\n" + "\tgetHotseatLayoutPadding(context).top: 197.0px (75.04762dp)\n" + "\tgetHotseatLayoutPadding(context).bottom: 43.0px (16.380953dp)\n" + - "\tgetHotseatLayoutPadding(context).left: 216.0px (82.28571dp)\n" + + "\tgetHotseatLayoutPadding(context).left: 106.0px (40.38095dp)\n" + "\tgetHotseatLayoutPadding(context).right: 744.0px (283.42856dp)\n" + "\tnumShownHotseatIcons: 6\n" + - "\thotseatBorderSpace: 61.0px (23.238094dp)\n" + + "\thotseatBorderSpace: 83.0px (31.619047dp)\n" + "\tisQsbInline: false\n" + "\thotseatQsbWidth: 1467.0px (558.8571dp)\n" + "\tisTaskbarPresent:true\n" + @@ -1064,10 +1064,10 @@ class DeviceProfileTest : DeviceProfileBaseTest() { "\tspringLoadedHotseatBarTopMarginPx: 171.0px (65.14286dp)\n" + "\tgetHotseatLayoutPadding(context).top: 219.0px (83.42857dp)\n" + "\tgetHotseatLayoutPadding(context).bottom: 87.0px (33.142857dp)\n" + - "\tgetHotseatLayoutPadding(context).left: 128.0px (48.761906dp)\n" + + "\tgetHotseatLayoutPadding(context).left: 78.0px (29.714285dp)\n" + "\tgetHotseatLayoutPadding(context).right: 660.0px (251.42857dp)\n" + "\tnumShownHotseatIcons: 6\n" + - "\thotseatBorderSpace: 47.0px (17.904762dp)\n" + + "\thotseatBorderSpace: 57.0px (21.714285dp)\n" + "\tisQsbInline: false\n" + "\thotseatQsbWidth: 1236.0px (470.85715dp)\n" + "\tisTaskbarPresent:true\n" + diff --git a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt new file mode 100644 index 0000000000..3967f75fa6 --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2022 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.quickstep + +import android.graphics.Rect +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.launcher3.DeviceProfileBaseTest +import com.android.launcher3.util.WindowBounds +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class HotseatWidthCalculationTest : DeviceProfileBaseTest() { + + /** + * This is a case when after setting the hotseat, the space needs to be recalculated + * but it doesn't need to change QSB width or remove icons + */ + @Test + fun distribute_border_space_when_space_is_enough_portrait() { + initializeVarsForTablet(isGestureMode = false) + windowBounds = WindowBounds(Rect(0, 0, 1800, 2560), Rect(0, 104, 0, 0)) + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(558) + assertThat(dp.numShownHotseatIcons).isEqualTo(6) + assertThat(dp.hotseatBorderSpace).isEqualTo(69) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(176) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(558) + + assertThat(dp.isQsbInline).isFalse() + assertThat(dp.hotseatQsbWidth).isEqualTo(1445) + } + + /** + * This is a case when after setting the hotseat, and recalculating spaces + * it still needs to remove icons for everything to fit + */ + @Test + fun decrease_num_of_icons_when_not_enough_space_portrait() { + initializeVarsForTablet(isGestureMode = false) + windowBounds = WindowBounds(Rect(0, 0, 1300, 2560), Rect(0, 104, 0, 0)) + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(558) + assertThat(dp.numShownHotseatIcons).isEqualTo(4) + assertThat(dp.hotseatBorderSpace).isEqualTo(76) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(122) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(558) + + assertThat(dp.isQsbInline).isFalse() + assertThat(dp.hotseatQsbWidth).isEqualTo(1058) + } + + /** + * This is a case when after setting the hotseat, the space needs to be recalculated + * but it doesn't need to change QSB width or remove icons + */ + @Test + fun distribute_border_space_when_space_is_enough_landscape() { + initializeVarsForTwoPanel(isGestureMode = false, isLandscape = true) + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(744) + assertThat(dp.numShownHotseatIcons).isEqualTo(6) + assertThat(dp.hotseatBorderSpace).isEqualTo(83) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(106) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(744) + + assertThat(dp.isQsbInline).isFalse() + assertThat(dp.hotseatQsbWidth).isEqualTo(1467) + } + + /** + * This is a case when the hotseat spans a certain amount of columns + * and the nav buttons push the hotseat to the side, but not enough to change the border space. + */ + @Test + fun nav_buttons_dont_interfere_with_required_hotseat_width() { + initializeVarsForTablet(isGestureMode = false, isLandscape = true) + inv?.apply { + hotseatColumnSpan = IntArray(4) { 4 } + inlineQsb = BooleanArray(4) { false } + } + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(705) + assertThat(dp.numShownHotseatIcons).isEqualTo(6) + assertThat(dp.hotseatBorderSpace).isEqualTo(108) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(631) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(705) + + assertThat(dp.isQsbInline).isFalse() + assertThat(dp.hotseatQsbWidth).isEqualTo(1227) + } + + /** + * This is a case when after setting the hotseat, the QSB width needs to be changed to fit + */ + @Test + fun decrease_qsb_when_not_enough_space_landscape() { + initializeVarsForTablet(isGestureMode = false, isLandscape = true) + windowBounds = WindowBounds(Rect(0, 0, 2460, 1600), Rect(0, 104, 0, 0)) + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(705) + assertThat(dp.numShownHotseatIcons).isEqualTo(6) + assertThat(dp.hotseatBorderSpace).isEqualTo(36) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(884) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(705) + + assertThat(dp.isQsbInline).isTrue() + assertThat(dp.hotseatQsbWidth).isEqualTo(559) + } + + /** + * This is a case when after setting the hotseat, changing QSB width, and recalculating spaces + * it still needs to remove icons for everything to fit + */ + @Test + fun decrease_num_of_icons_when_not_enough_space_landscape() { + initializeVarsForTablet(isGestureMode = false, isLandscape = true) + windowBounds = WindowBounds(Rect(0, 0, 2260, 1600), Rect(0, 104, 0, 0)) + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(705) + assertThat(dp.numShownHotseatIcons).isEqualTo(5) + assertThat(dp.hotseatBorderSpace).isEqualTo(56) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(801) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(705) + + assertThat(dp.isQsbInline).isTrue() + assertThat(dp.hotseatQsbWidth).isEqualTo(480) + } +} diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 3b7158547c..28d094b138 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -158,9 +158,6 @@ - - @@ -328,15 +325,6 @@ if not specified --> - - - - - - - - - diff --git a/res/values/dimens.xml b/res/values/dimens.xml index c8554ecfb1..546ee35c17 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -354,6 +354,8 @@ 0dp 0dp 0dp + 18dp + 0dp 44dp 8dp diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml index 0238e7d972..407f2176b9 100644 --- a/res/xml/device_profiles.xml +++ b/res/xml/device_profiles.xml @@ -200,8 +200,6 @@ launcher:allAppsBorderSpaceHorizontal="8" launcher:allAppsBorderSpaceVertical="16" launcher:allAppsBorderSpaceLandscape="16" - launcher:hotseatBorderSpace="58" - launcher:hotseatBorderSpaceLandscape="50.4" launcher:hotseatBarBottomSpace="76" launcher:hotseatBarBottomSpaceLandscape="40" launcher:canBeDefault="true" /> diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 0d412300c5..f27eb7995b 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -158,7 +158,7 @@ public class DeviceProfile { public int folderChildDrawablePaddingPx; // Hotseat - public final int numShownHotseatIcons; + public int numShownHotseatIcons; public int hotseatCellHeightPx; public final boolean areNavButtonsInline; // In portrait: size = height, in landscape: size = width @@ -362,15 +362,9 @@ public class DeviceProfile { && hotseatQsbHeight > 0; isQsbInline = inv.inlineQsb[mTypeIndex] && canQsbInline; - // 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. areNavButtonsInline = isTaskbarPresent && !isGestureMode; - if (areNavButtonsInline && canQsbInline) { - numShownHotseatIcons = inv.numShrunkenHotseatIcons; - } else { - numShownHotseatIcons = - isTwoPanels ? inv.numDatabaseHotseatIcons : inv.numShownHotseatIcons; - } + numShownHotseatIcons = + isTwoPanels ? inv.numDatabaseHotseatIcons : inv.numShownHotseatIcons; numShownAllAppsColumns = isTwoPanels ? inv.numDatabaseAllAppsColumns : inv.numAllAppsColumns; @@ -460,8 +454,7 @@ public class DeviceProfile { updateWorkspacePadding(); // Hotseat and QSB width depends on updated cellSize and workspace padding - hotseatBorderSpace = calculateHotseatBorderSpace(); - hotseatQsbWidth = calculateQsbWidth(); + recalculateHotseatWidthAndBorderSpace(res); // AllApps height calculation depends on updated cellSize if (isTablet) { @@ -499,7 +492,7 @@ public class DeviceProfile { * QSB width is always calculated because when in 3 button nav the width doesn't follow the * width of the hotseat. */ - private int calculateQsbWidth() { + private int calculateQsbWidth(int hotseatBorderSpace) { if (isQsbInline) { int columns = getPanelCount() * inv.numColumns; return getIconToIconWidthForColumns(columns) @@ -546,6 +539,70 @@ public class DeviceProfile { } } + private void recalculateHotseatWidthAndBorderSpace(Resources res) { + hotseatBorderSpace = calculateHotseatBorderSpace(); + hotseatQsbWidth = calculateQsbWidth(hotseatBorderSpace); + // Spaces should be correct when there nav buttons are not inline + if (!areNavButtonsInline) { + return; + } + + // Get the maximum width that the hotseat can be + int columns = getPanelCount() * inv.numColumns; + int maxHotseatWidth = getIconToIconWidthForColumns(columns); + int sideSpace = (availableWidthPx - maxHotseatWidth) / 2; + int inlineButtonsOverlap = Math.max(0, hotseatBarEndOffset - sideSpace); + // decrease how much the nav buttons go "inside" the hotseat + maxHotseatWidth -= inlineButtonsOverlap; + + // Get how much space is required to show the hotseat with QSB + int requiredWidth = getHotseatRequiredWidth(); + + // If spaces are fine, use them + if (requiredWidth <= maxHotseatWidth) { + return; + } + + // Calculate the difference of widths and remove a little from each space between icons + // and QSB if it's inline + int spaceDiff = requiredWidth - maxHotseatWidth; + int numOfSpaces = numShownHotseatIcons - (isQsbInline ? 0 : 1); + hotseatBorderSpace -= (spaceDiff / numOfSpaces); + + int minHotseatIconSpaceDp = res.getDimensionPixelSize(R.dimen.min_hotseat_icon_space); + int minHotseatQsbWidthDp = res.getDimensionPixelSize(R.dimen.min_hotseat_qsb_width); + + if (hotseatBorderSpace >= minHotseatIconSpaceDp) { + return; + } + + // Border space can't be less than the minimum + hotseatBorderSpace = minHotseatIconSpaceDp; + requiredWidth = getHotseatRequiredWidth(); + + // If there is an inline qsb, change its size + if (isQsbInline) { + hotseatQsbWidth -= requiredWidth - maxHotseatWidth; + if (hotseatQsbWidth >= minHotseatQsbWidthDp) { + return; + } + + // QSB can't be less than the minimum + hotseatQsbWidth = minHotseatQsbWidthDp; + } + + // If it still doesn't fit, start removing icons + do { + numShownHotseatIcons--; + requiredWidth = getHotseatRequiredWidth(); + } while (requiredWidth > maxHotseatWidth && numShownHotseatIcons > 1); + + // Add back some space between the icons + spaceDiff = maxHotseatWidth - requiredWidth; + numOfSpaces = numShownHotseatIcons - (isQsbInline ? 0 : 1); + hotseatBorderSpace += (spaceDiff / numOfSpaces); + } + private Point getCellLayoutBorderSpace(InvariantDeviceProfile idp) { return getCellLayoutBorderSpace(idp, 1f); } @@ -778,15 +835,10 @@ public class DeviceProfile { */ 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); - } + int columns = inv.hotseatColumnSpan[mTypeIndex]; + float hotseatWidthPx = getIconToIconWidthForColumns(columns); + float hotseatIconsTotalPx = iconSizePx * numShownHotseatIcons; + return (int) (hotseatWidthPx - hotseatIconsTotalPx) / (numShownHotseatIcons - 1); } @@ -1078,10 +1130,7 @@ public class DeviceProfile { hotseatBarSizePx - hotseatBarBottomPadding - hotseatCellHeightPx; // Push icons to the side - int additionalQsbSpace = isQsbInline ? hotseatQsbWidth + hotseatBorderSpace : 0; - int requiredWidth = iconSizePx * numShownHotseatIcons - + hotseatBorderSpace * (numShownHotseatIcons - 1) - + additionalQsbSpace; + int requiredWidth = getHotseatRequiredWidth(); int hotseatWidth = Math.min(requiredWidth, availableWidthPx - hotseatBarEndOffset); int sideSpacing = (availableWidthPx - hotseatWidth) / 2; @@ -1090,9 +1139,9 @@ public class DeviceProfile { boolean isRtl = Utilities.isRtl(context.getResources()); if (isRtl) { - hotseatBarPadding.right += additionalQsbSpace; + hotseatBarPadding.right += getAdditionalQsbSpace(); } else { - hotseatBarPadding.left += additionalQsbSpace; + hotseatBarPadding.left += getAdditionalQsbSpace(); } if (hotseatBarEndOffset > sideSpacing) { @@ -1127,6 +1176,20 @@ public class DeviceProfile { return hotseatBarPadding; } + private int getAdditionalQsbSpace() { + return isQsbInline ? hotseatQsbWidth + hotseatBorderSpace : 0; + } + + /** + * Calculate how much space the hotseat needs to be shown completely + */ + private int getHotseatRequiredWidth() { + int additionalQsbSpace = getAdditionalQsbSpace(); + return iconSizePx * numShownHotseatIcons + + hotseatBorderSpace * (numShownHotseatIcons - 1) + + additionalQsbSpace; + } + /** * Returns the number of pixels the QSB is translated from the bottom of the screen. */ diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java index 67620e3ef9..21eba00ee2 100644 --- a/src/com/android/launcher3/InvariantDeviceProfile.java +++ b/src/com/android/launcher3/InvariantDeviceProfile.java @@ -128,7 +128,6 @@ public class InvariantDeviceProfile { public PointF[] borderSpaces; public float folderBorderSpace; - public float[] hotseatBorderSpaces; public int inlineNavButtonsEndSpacing; public float[] horizontalMargin; @@ -145,11 +144,6 @@ public class InvariantDeviceProfile { */ public int numShownHotseatIcons; - /** - * Number of icons inside the hotseat area when using 3 buttons navigation. - */ - public int numShrunkenHotseatIcons; - /** * Number of icons inside the hotseat area that is stored in the database. This is greater than * or equal to numnShownHotseatIcons, allowing for a seamless transition between two hotseat @@ -176,7 +170,7 @@ public class InvariantDeviceProfile { public String dbFile; public int defaultLayoutId; int demoModeLayoutId; - boolean[] inlineQsb = new boolean[COUNT_SIZES]; + public boolean[] inlineQsb = new boolean[COUNT_SIZES]; /** * An immutable list of supported profiles. @@ -364,11 +358,9 @@ public class InvariantDeviceProfile { horizontalMargin = displayOption.horizontalMargin; numShownHotseatIcons = closestProfile.numHotseatIcons; - numShrunkenHotseatIcons = closestProfile.numShrunkenHotseatIcons; numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY ? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons; hotseatColumnSpan = closestProfile.hotseatColumnSpan; - hotseatBorderSpaces = displayOption.hotseatBorderSpaces; hotseatBarBottomSpace = displayOption.hotseatBarBottomSpace; hotseatQsbSpace = displayOption.hotseatQsbSpace; @@ -737,7 +729,6 @@ public class InvariantDeviceProfile { private final int numAllAppsColumns; private final int numDatabaseAllAppsColumns; private final int numHotseatIcons; - private final int numShrunkenHotseatIcons; private final int numDatabaseHotseatIcons; private final int[] hotseatColumnSpan = new int[COUNT_SIZES]; @@ -777,8 +768,6 @@ public class InvariantDeviceProfile { numHotseatIcons = a.getInt( R.styleable.GridDisplayOption_numHotseatIcons, numColumns); - numShrunkenHotseatIcons = a.getInt( - R.styleable.GridDisplayOption_numShrunkenHotseatIcons, numHotseatIcons / 2); numDatabaseHotseatIcons = a.getInt( R.styleable.GridDisplayOption_numExtendedHotseatIcons, 2 * numHotseatIcons); @@ -842,8 +831,6 @@ 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 float[] hotseatBarBottomSpace = new float[COUNT_SIZES]; private final float[] hotseatQsbSpace = new float[COUNT_SIZES]; @@ -1059,18 +1046,6 @@ public class InvariantDeviceProfile { R.styleable.ProfileDisplayOption_horizontalMarginTwoPanelPortrait, horizontalMargin[INDEX_DEFAULT]); - hotseatBorderSpaces[INDEX_DEFAULT] = a.getFloat( - R.styleable.ProfileDisplayOption_hotseatBorderSpace, borderSpace); - hotseatBorderSpaces[INDEX_LANDSCAPE] = a.getFloat( - R.styleable.ProfileDisplayOption_hotseatBorderSpaceLandscape, - hotseatBorderSpaces[INDEX_DEFAULT]); - hotseatBorderSpaces[INDEX_TWO_PANEL_LANDSCAPE] = a.getFloat( - R.styleable.ProfileDisplayOption_hotseatBorderSpaceTwoPanelLandscape, - hotseatBorderSpaces[INDEX_DEFAULT]); - hotseatBorderSpaces[INDEX_TWO_PANEL_PORTRAIT] = a.getFloat( - R.styleable.ProfileDisplayOption_hotseatBorderSpaceTwoPanelPortrait, - hotseatBorderSpaces[INDEX_DEFAULT]); - hotseatBarBottomSpace[INDEX_DEFAULT] = a.getFloat( R.styleable.ProfileDisplayOption_hotseatBarBottomSpace, ResourcesCompat.getFloat(context.getResources(), @@ -1133,7 +1108,6 @@ public class InvariantDeviceProfile { minCellSize[i].x *= w; minCellSize[i].y *= w; horizontalMargin[i] *= w; - hotseatBorderSpaces[i] *= w; hotseatBarBottomSpace[i] *= w; hotseatQsbSpace[i] *= w; allAppsCellSize[i].x *= w; @@ -1158,7 +1132,6 @@ public class InvariantDeviceProfile { minCellSize[i].x += p.minCellSize[i].x; minCellSize[i].y += p.minCellSize[i].y; horizontalMargin[i] += p.horizontalMargin[i]; - hotseatBorderSpaces[i] += p.hotseatBorderSpaces[i]; hotseatBarBottomSpace[i] += p.hotseatBarBottomSpace[i]; hotseatQsbSpace[i] += p.hotseatQsbSpace[i]; allAppsCellSize[i].x += p.allAppsCellSize[i].x; diff --git a/tests/Android.bp b/tests/Android.bp index 54cded0fd3..1584308091 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -24,6 +24,18 @@ filegroup { "src/**/*.java", "src/**/*.kt" ], + exclude_srcs: [ + ":launcher-non-quickstep-tests-src" + ], +} + +// Source code used for non-quickstep tests +filegroup { + name: "launcher-non-quickstep-tests-src", + srcs: [ + "src/com/android/launcher3/nonquickstep/**/*.java", + "src/com/android/launcher3/nonquickstep/**/*.kt", + ], } // Source code used for oop test helpers @@ -84,6 +96,7 @@ android_test { name: "Launcher3Tests", srcs: [ ":launcher-tests-src", + ":launcher-non-quickstep-tests-src", ], static_libs: ["Launcher3TestLib"], libs: [ diff --git a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt index 7046782ecf..cf6be7fb58 100644 --- a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt +++ b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt @@ -114,7 +114,6 @@ abstract class DeviceProfileBaseTest { PointF(16f, 16f) ).toTypedArray() folderBorderSpace = 16f - hotseatBorderSpaces = FloatArray(4) { 16f } inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_4_5 horizontalMargin = FloatArray(4) { 22f } @@ -136,8 +135,6 @@ abstract class DeviceProfileBaseTest { numShownHotseatIcons = 4 - numShrunkenHotseatIcons = 4 - numDatabaseHotseatIcons = 4 hotseatColumnSpan = IntArray(4) { 4 } @@ -200,7 +197,6 @@ abstract class DeviceProfileBaseTest { PointF(16f, 64f), PointF(16f, 64f) ).toTypedArray() - hotseatBorderSpaces = floatArrayOf(58f, 50.4f, 58f, 58f) inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_6_5 horizontalMargin = floatArrayOf(54f, 120f, 54f, 54f) @@ -222,8 +218,6 @@ abstract class DeviceProfileBaseTest { numShownHotseatIcons = 6 - numShrunkenHotseatIcons = 5 - numDatabaseHotseatIcons = 6 hotseatColumnSpan = intArrayOf(6, 4, 6, 6) @@ -297,7 +291,6 @@ abstract class DeviceProfileBaseTest { PointF(20f, 20f) ).toTypedArray() folderBorderSpace = 16f - hotseatBorderSpaces = floatArrayOf(36f, 36f, 18f, 23.3f) inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_4_4 horizontalMargin = floatArrayOf(21.5f, 21.5f, 22.5f, 30.5f) @@ -319,8 +312,6 @@ abstract class DeviceProfileBaseTest { numShownHotseatIcons = 6 - numShrunkenHotseatIcons = 6 - numDatabaseHotseatIcons = 6 hotseatColumnSpan = IntArray(4) { 6 } diff --git a/tests/src/com/android/launcher3/HotseatShownIconsTest.kt b/tests/src/com/android/launcher3/HotseatShownIconsTest.kt deleted file mode 100644 index 95651ca9fe..0000000000 --- a/tests/src/com/android/launcher3/HotseatShownIconsTest.kt +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2022 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 - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.filters.SmallTest -import com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY -import com.android.launcher3.InvariantDeviceProfile.TYPE_PHONE -import com.android.launcher3.InvariantDeviceProfile.TYPE_TABLET -import com.google.common.truth.Truth.assertThat -import org.junit.Test -import org.junit.runner.RunWith - -/** - * Test for [DeviceProfile] - */ -@SmallTest -@RunWith(AndroidJUnit4::class) -class HotseatShownIconsTest : DeviceProfileBaseTest() { - - @Test - fun hotseat_size_is_shrunk_if_needed_when_large_screen() { - initializeVarsForTablet(isLandscape = true) - inv = inv!!.apply { - deviceType = TYPE_MULTI_DISPLAY - inlineQsb = booleanArrayOf( - false, - false, - false, - true // two panels landscape - ) - } - useTwoPanels = true - - isGestureMode = false - val dp = newDP() - - if (dp.hotseatQsbHeight > 0) { - assertThat(dp.isQsbInline).isTrue() - assertThat(dp.numShownHotseatIcons).isEqualTo(5) - } else { // Launcher3 doesn't have QSB height - assertThat(dp.isQsbInline).isFalse() - assertThat(dp.numShownHotseatIcons).isEqualTo(6) - } - } - - /** - * For consistency, the hotseat should shrink if any orientation on the device type has an - * inline qsb - */ - @Test - fun hotseat_size_is_shrunk_even_in_portrait_when_large_screen() { - initializeVarsForTablet() - inv = inv!!.apply { - deviceType = TYPE_MULTI_DISPLAY - inlineQsb = booleanArrayOf( - false, - false, - false, - true // two panels landscape - ) - } - useTwoPanels = true - - isGestureMode = false - val dp = newDP() - - if (dp.hotseatQsbHeight > 0) { - assertThat(dp.isQsbInline).isFalse() - assertThat(dp.numShownHotseatIcons).isEqualTo(5) - } else { // Launcher3 doesn't have QSB height - assertThat(dp.isQsbInline).isFalse() - assertThat(dp.numShownHotseatIcons).isEqualTo(6) - } - } - - @Test - fun hotseat_size_is_default_when_small_screen() { - initializeVarsForPhone() - inv = inv!!.apply { - deviceType = TYPE_MULTI_DISPLAY - } - useTwoPanels = true - - val dp = newDP() - - assertThat(dp.numShownHotseatIcons).isEqualTo(4) - } - - @Test - fun hotseat_size_is_not_shrunk_on_gesture_tablet() { - initializeVarsForTablet(isLandscape = true) - inv = inv!!.apply { - deviceType = TYPE_TABLET - inlineQsb = booleanArrayOf( - false, - true, // landscape - false, - false - ) - numShownHotseatIcons = 6 - } - - isGestureMode = true - val dp = newDP() - - if (dp.hotseatQsbHeight > 0) { - assertThat(dp.isQsbInline).isTrue() - assertThat(dp.numShownHotseatIcons).isEqualTo(6) - } else { // Launcher3 doesn't have QSB height - assertThat(dp.isQsbInline).isFalse() - assertThat(dp.numShownHotseatIcons).isEqualTo(6) - } - } - - @Test - fun hotseat_size_is_shrunk_if_needed_on_tablet() { - initializeVarsForTablet(isLandscape = true) - inv = inv!!.apply { - deviceType = TYPE_TABLET - inlineQsb = booleanArrayOf( - false, - true, // landscape - false, - false - ) - numShownHotseatIcons = 6 - } - - isGestureMode = false - val dp = newDP() - - if (dp.hotseatQsbHeight > 0) { - assertThat(dp.isQsbInline).isTrue() - assertThat(dp.numShownHotseatIcons).isEqualTo(5) - } else { // Launcher3 doesn't have QSB height - assertThat(dp.isQsbInline).isFalse() - assertThat(dp.numShownHotseatIcons).isEqualTo(6) - } - } - - /** - * For consistency, the hotseat should shrink if any orientation on the device type has an - * inline qsb - */ - @Test - fun hotseat_size_is_shrunk_even_in_portrait_on_tablet() { - initializeVarsForTablet() - inv = inv!!.apply { - deviceType = TYPE_TABLET - inlineQsb = booleanArrayOf( - false, - true, // landscape - false, - false - ) - numShownHotseatIcons = 6 - } - - isGestureMode = false - val dp = newDP() - - if (dp.hotseatQsbHeight > 0) { - assertThat(dp.isQsbInline).isFalse() - assertThat(dp.numShownHotseatIcons).isEqualTo(5) - } else { // Launcher3 doesn't have QSB height - assertThat(dp.isQsbInline).isFalse() - assertThat(dp.numShownHotseatIcons).isEqualTo(6) - } - } - -} \ No newline at end of file diff --git a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt new file mode 100644 index 0000000000..55520e8ade --- /dev/null +++ b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2022 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.nonquickstep + +import android.graphics.Rect +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.launcher3.DeviceProfileBaseTest +import com.android.launcher3.util.WindowBounds +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class HotseatWidthCalculationTest : DeviceProfileBaseTest() { + + /** + * This is a case when after setting the hotseat, the space needs to be recalculated + * but it doesn't need to change QSB width or remove icons + */ + @Test + fun distribute_border_space_when_space_is_enough_portrait() { + initializeVarsForTablet(isGestureMode = false) + windowBounds = WindowBounds(Rect(0, 0, 1800, 2560), Rect(0, 104, 0, 0)) + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.numShownHotseatIcons).isEqualTo(6) + assertThat(dp.hotseatBorderSpace).isEqualTo(145) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(177) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(177) + + assertThat(dp.isQsbInline).isFalse() + assertThat(dp.hotseatQsbWidth).isEqualTo(1445) + } + + /** + * This is a case when after setting the hotseat, and recalculating spaces + * it still needs to remove icons for everything to fit + */ + @Test + fun decrease_num_of_icons_when_not_enough_space_portrait() { + initializeVarsForTablet(isGestureMode = false) + windowBounds = WindowBounds(Rect(0, 0, 1300, 2560), Rect(0, 104, 0, 0)) + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.numShownHotseatIcons).isEqualTo(6) + assertThat(dp.hotseatBorderSpace).isEqualTo(94) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(121) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(121) + + assertThat(dp.isQsbInline).isFalse() + assertThat(dp.hotseatQsbWidth).isEqualTo(1058) + } + + /** + * This is a case when after setting the hotseat, the space needs to be recalculated + * but it doesn't need to change QSB width or remove icons + */ + @Test + fun distribute_border_space_when_space_is_enough_landscape() { + initializeVarsForTwoPanel(isGestureMode = false, isLandscape = true) + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.numShownHotseatIcons).isEqualTo(6) + assertThat(dp.hotseatBorderSpace).isEqualTo(105) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(370) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(370) + + assertThat(dp.isQsbInline).isFalse() + assertThat(dp.hotseatQsbWidth).isEqualTo(1467) + } + + /** + * This is a case when the hotseat spans a certain amount of columns + * and the nav buttons push the hotseat to the side, but not enough to change the border space. + */ + @Test + fun nav_buttons_dont_interfere_with_required_hotseat_width() { + initializeVarsForTablet(isGestureMode = false, isLandscape = true) + inv?.apply { + hotseatColumnSpan = IntArray(4) { 4 } + inlineQsb = BooleanArray(4) { false } + } + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.numShownHotseatIcons).isEqualTo(6) + assertThat(dp.hotseatBorderSpace).isEqualTo(100) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(668) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(668) + + assertThat(dp.isQsbInline).isFalse() + assertThat(dp.hotseatQsbWidth).isEqualTo(1224) + } + + /** + * This is a case when after setting the hotseat, the QSB width needs to be changed to fit + */ + @Test + fun decrease_qsb_when_not_enough_space_landscape() { + initializeVarsForTablet(isGestureMode = false, isLandscape = true) + windowBounds = WindowBounds(Rect(0, 0, 2460, 1600), Rect(0, 104, 0, 0)) + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.numShownHotseatIcons).isEqualTo(6) + assertThat(dp.hotseatBorderSpace).isEqualTo(96) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(643) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(643) + + assertThat(dp.isQsbInline).isFalse() + assertThat(dp.hotseatQsbWidth).isEqualTo(1174) + } + + /** + * This is a case when after setting the hotseat, changing QSB width, and recalculating spaces + * it still needs to remove icons for everything to fit + */ + @Test + fun decrease_num_of_icons_when_not_enough_space_landscape() { + initializeVarsForTablet(isGestureMode = false, isLandscape = true) + windowBounds = WindowBounds(Rect(0, 0, 2260, 1600), Rect(0, 104, 0, 0)) + val dp = newDP() + dp.isTaskbarPresentInApps = true + + assertThat(dp.hotseatBarEndOffset).isEqualTo(0) + assertThat(dp.numShownHotseatIcons).isEqualTo(6) + assertThat(dp.hotseatBorderSpace).isEqualTo(89) + + assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(589) + assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(589) + + assertThat(dp.isQsbInline).isFalse() + assertThat(dp.hotseatQsbWidth).isEqualTo(1081) + } +}