diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java index 699ce9783c..5f62749590 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -66,9 +66,9 @@ public class OverviewState extends LauncherState { @Override public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) { RecentsView recentsView = launcher.getOverviewPanel(); - float workspacePageWidth = launcher.getDeviceProfile().getWorkspaceWidth(); + float workspacePageHeight = launcher.getDeviceProfile().getCellLayoutHeight(); recentsView.getTaskSize(sTempRect); - float scale = (float) sTempRect.width() / workspacePageWidth; + float scale = (float) sTempRect.height() / workspacePageHeight; float parallaxFactor = 0.5f; return new ScaleAndTranslation(scale, 0, -getDefaultSwipeHeight(launcher) * parallaxFactor); } diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 88030ae61f..561f9b937c 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -501,7 +501,7 @@ public class DeviceProfile { */ private int calculateQsbWidth() { if (isQsbInline) { - int columns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns; + int columns = getPanelCount() * inv.numColumns; return getIconToIconWidthForColumns(columns) - iconSizePx * numShownHotseatIcons - hotseatBorderSpace * numShownHotseatIcons; @@ -665,11 +665,10 @@ public class DeviceProfile { updateIconSize(1f, res); updateWorkspacePadding(); - Point workspacePadding = getTotalWorkspacePadding(); // Check to see if the icons fit within the available height. float usedHeight = getCellLayoutHeightSpecification(); - final int maxHeight = getWorkspaceHeight(workspacePadding); + final int maxHeight = getCellLayoutHeight(); float extraHeight = Math.max(0, maxHeight - usedHeight); float scaleY = maxHeight / usedHeight; boolean shouldScale = scaleY < 1f; @@ -702,7 +701,7 @@ public class DeviceProfile { } private int getCellLayoutWidthSpecification() { - int numColumns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns; + int numColumns = getPanelCount() * inv.numColumns; return (cellWidthPx * numColumns) + (cellLayoutBorderSpacePx.x * (numColumns - 1)) + cellLayoutPaddingPx.left + cellLayoutPaddingPx.right; } @@ -902,18 +901,20 @@ public class DeviceProfile { result = new Point(); } - // Since we are only concerned with the overall padding, layout direction does - // not matter. - Point padding = getTotalWorkspacePadding(); - - int numColumns = isTwoPanels ? inv.numColumns * 2 : inv.numColumns; - int screenWidthPx = getWorkspaceWidth(padding); - result.x = calculateCellWidth(screenWidthPx, cellLayoutBorderSpacePx.x, numColumns); - int screenHeightPx = getWorkspaceHeight(padding); - result.y = calculateCellHeight(screenHeightPx, cellLayoutBorderSpacePx.y, inv.numRows); + result.x = calculateCellWidth(getShortcutAndWidgetContainerWidth(), + cellLayoutBorderSpacePx.x, inv.numColumns); + result.y = calculateCellHeight(getShortcutAndWidgetContainerHeight(), + cellLayoutBorderSpacePx.y, inv.numRows); return result; } + /** + * Gets the number of panels within the workspace. + */ + public int getPanelCount() { + return isTwoPanels ? 2 : 1; + } + /** * Gets the space in px from the bottom of last item in the vertical-bar hotseat to the * bottom of the screen. @@ -932,7 +933,7 @@ public class DeviceProfile { /** * Gets the scaled top of the workspace in px for the spring-loaded edit state. */ - public float getWorkspaceSpringLoadShrunkTop() { + public float getCellLayoutSpringLoadShrunkTop() { workspaceSpringLoadShrunkTop = mInsets.top + dropTargetBarTopMarginPx + dropTargetBarSizePx + dropTargetBarBottomMarginPx; return workspaceSpringLoadShrunkTop; @@ -941,7 +942,7 @@ public class DeviceProfile { /** * Gets the scaled bottom of the workspace in px for the spring-loaded edit state. */ - private float getWorkspaceSpringLoadShrunkBottom() { + private float getCellLayoutSpringLoadShrunkBottom() { int topOfHotseat = hotseatBarSizePx + springLoadedHotseatBarTopMarginPx; workspaceSpringLoadShrunkBottom = heightPx - (isVerticalBarLayout() ? getVerticalHotseatLastItemBottomOffset() @@ -960,9 +961,8 @@ public class DeviceProfile { * Gets the scale of the workspace for the spring-loaded edit state. */ public float getWorkspaceSpringLoadScale() { - float cellLayoutHeight = availableHeightPx - workspacePadding.top - workspacePadding.bottom; - float scale = (getWorkspaceSpringLoadShrunkBottom() - getWorkspaceSpringLoadShrunkTop()) - / cellLayoutHeight; + float scale = (getCellLayoutSpringLoadShrunkBottom() - getCellLayoutSpringLoadShrunkTop()) + / getCellLayoutHeight(); scale = Math.min(scale, 1f); // Reduce scale if next pages would not be visible after scaling the workspace @@ -976,19 +976,55 @@ public class DeviceProfile { return scale; } + /** + * Gets the width of the Workspace, aka a scrollable page of the homescreen. + */ public int getWorkspaceWidth() { - return getWorkspaceWidth(getTotalWorkspacePadding()); + return availableWidthPx; } - public int getWorkspaceWidth(Point workspacePadding) { - int cellLayoutTotalPadding = - (isTwoPanels ? 2 : 1) * (cellLayoutPaddingPx.left + cellLayoutPaddingPx.right); - return availableWidthPx - workspacePadding.x - cellLayoutTotalPadding; + /** + * Gets the height of the Workspace, aka a scrollable page of the homescreen. + */ + public int getWorkspaceHeight() { + return availableHeightPx; } - private int getWorkspaceHeight(Point workspacePadding) { - return availableHeightPx - workspacePadding.y - (cellLayoutPaddingPx.top - + cellLayoutPaddingPx.bottom); + /** + * Gets the width of a single Cell Layout, aka a single panel within a Workspace. + * + *

This is the width of a Workspace, less its horizontal padding. Note that two-panel + * layouts have two Cell Layouts per workspace. + */ + public int getCellLayoutWidth() { + return (getWorkspaceWidth() - getTotalWorkspacePadding().x) / getPanelCount(); + } + + /** + * Gets the height of a single Cell Layout, aka a single panel within a Workspace. + * + *

This is the height of a Workspace, less its vertical padding. + */ + public int getCellLayoutHeight() { + return getWorkspaceHeight() - getTotalWorkspacePadding().y; + } + + /** + * Gets the width of the container holding the shortcuts and widgets. + * + *

This is the width of one Cell Layout less its horizontal padding. + */ + public int getShortcutAndWidgetContainerWidth() { + return getCellLayoutWidth() - (cellLayoutPaddingPx.left + cellLayoutPaddingPx.right); + } + + /** + * Gets the height of the container holding the shortcuts and widgets. + * + *

This is the height of one Cell Layout less its vertical padding. + */ + public int getShortcutAndWidgetContainerHeight() { + return getCellLayoutHeight() - (cellLayoutPaddingPx.top + cellLayoutPaddingPx.bottom); } public Point getTotalWorkspacePadding() { diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java index 15cdc20cef..a205ab55ca 100644 --- a/src/com/android/launcher3/states/SpringLoadedState.java +++ b/src/com/android/launcher3/states/SpringLoadedState.java @@ -51,7 +51,7 @@ public class SpringLoadedState extends LauncherState { return super.getWorkspaceScaleAndTranslation(launcher); } - float shrunkTop = grid.getWorkspaceSpringLoadShrunkTop(); + float shrunkTop = grid.getCellLayoutSpringLoadShrunkTop(); float scale = grid.getWorkspaceSpringLoadScale(); float halfHeight = ws.getHeight() / 2; diff --git a/tests/src/com/android/launcher3/DeviceProfileGridDimensionsTest.kt b/tests/src/com/android/launcher3/DeviceProfileGridDimensionsTest.kt new file mode 100644 index 0000000000..63abc7d650 --- /dev/null +++ b/tests/src/com/android/launcher3/DeviceProfileGridDimensionsTest.kt @@ -0,0 +1,258 @@ +/* + * 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 android.graphics.PointF +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.launcher3.util.WindowBounds +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] grid dimensions. + * + * This includes workspace, cell layout, shortcut and widget container, cell sizes, etc. + */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class DeviceProfileGridDimensionsTest : DeviceProfileBaseTest() { + + @Test + fun getWorkspaceWidth_twoPanelLandscapeScalable4By4GridTablet_workspaceWidthIsFullPage() { + val tabletWidth = 2560 + val tabletHeight = 1600 + val availableWidth = 2560 + val availableHeight = 1500 + windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0) + useTwoPanels = true + whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true) + whenever(info.getDensityDpi()).thenReturn(320) + inv = getScalable4By4InvariantDeviceProfile() + + val dp = newDP() + + val expectedWorkspaceWidth = availableWidth + assertThat(dp.workspaceWidth).isEqualTo(expectedWorkspaceWidth) + } + + @Test + fun getWorkspaceHeight_twoPanelLandscapeScalable4By4GridTablet_workspaceHeightIsFullPage() { + val tabletWidth = 2560 + val tabletHeight = 1600 + val availableWidth = 2560 + val availableHeight = 1500 + windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0) + useTwoPanels = true + whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true) + whenever(info.getDensityDpi()).thenReturn(320) + inv = getScalable4By4InvariantDeviceProfile() + + val dp = newDP() + + val expectedWorkspaceHeight = availableHeight + assertThat(dp.workspaceHeight).isEqualTo(expectedWorkspaceHeight) + } + + @Test + fun getCellLayoutWidth_twoPanelLandscapeScalable4By4GridTablet_equalsSinglePanelWidth() { + val tabletWidth = 2560 + val tabletHeight = 1600 + val availableWidth = 2560 + val availableHeight = 1500 + windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0) + useTwoPanels = true + whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true) + whenever(info.getDensityDpi()).thenReturn(320) + inv = getScalable4By4InvariantDeviceProfile() + + val dp = newDP() + + val expectedWorkspaceWidth = availableWidth + val expectedCellLayoutWidth = + (expectedWorkspaceWidth - (dp.workspacePadding.right + dp.workspacePadding.left)) / + dp.panelCount + assertThat(dp.cellLayoutWidth).isEqualTo(expectedCellLayoutWidth) + } + + @Test + fun getCellLayoutHeight_twoPanelLandscapeScalable4By4GridTablet_equalsSinglePanelHeight() { + val tabletWidth = 2560 + val tabletHeight = 1600 + val availableWidth = 2560 + val availableHeight = 1500 + windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0) + useTwoPanels = true + whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true) + whenever(info.getDensityDpi()).thenReturn(320) + inv = getScalable4By4InvariantDeviceProfile() + + val dp = newDP() + + val expectedWorkspaceHeight = availableHeight + val expectedCellLayoutHeight = + expectedWorkspaceHeight - (dp.workspacePadding.top + dp.workspacePadding.bottom) + assertThat(dp.cellLayoutHeight).isEqualTo(expectedCellLayoutHeight) + } + + @Test + fun getShortcutAndWidgetContainerWidth_twoPanelLandscapeScalable4By4GridTablet_equalsIconsPlusBorderSpacesWidth() { + val tabletWidth = 2560 + val tabletHeight = 1600 + val availableWidth = 2560 + val availableHeight = 1500 + windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0) + useTwoPanels = true + whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true) + whenever(info.getDensityDpi()).thenReturn(320) + inv = getScalable4By4InvariantDeviceProfile() + + val dp = newDP() + + val expectedWorkspaceWidth = availableWidth + val expectedCellLayoutWidth = + (expectedWorkspaceWidth - (dp.workspacePadding.right + dp.workspacePadding.left)) / + dp.panelCount + val expectedShortcutAndWidgetContainerWidth = expectedCellLayoutWidth - + (dp.cellLayoutPaddingPx.left + dp.cellLayoutPaddingPx.right) + assertThat(dp.shortcutAndWidgetContainerWidth).isEqualTo(expectedShortcutAndWidgetContainerWidth) + } + + @Test + fun getShortcutAndWidgetContainerHeight_twoPanelLandscapeScalable4By4GridTablet_equalsIconsPlusBorderSpacesHeight() { + val tabletWidth = 2560 + val tabletHeight = 1600 + val availableWidth = 2560 + val availableHeight = 1500 + windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0) + useTwoPanels = true + whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true) + whenever(info.getDensityDpi()).thenReturn(320) + inv = getScalable4By4InvariantDeviceProfile() + + val dp = newDP() + + val expectedWorkspaceHeight = availableHeight + val expectedCellLayoutHeight = + expectedWorkspaceHeight - (dp.workspacePadding.top + dp.workspacePadding.bottom) + val expectedShortcutAndWidgetContainerHeight = expectedCellLayoutHeight - + (dp.cellLayoutPaddingPx.top + dp.cellLayoutPaddingPx.bottom) + assertThat(dp.shortcutAndWidgetContainerHeight).isEqualTo( + expectedShortcutAndWidgetContainerHeight) + } + + @Test + fun getCellSize_twoPanelLandscapeScalable4By4GridTablet_equalsSinglePanelWidth() { + val tabletWidth = 2560 + val tabletHeight = 1600 + val availableWidth = 2560 + val availableHeight = 1500 + windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0) + useTwoPanels = true + whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true) + whenever(info.getDensityDpi()).thenReturn(320) + inv = getScalable4By4InvariantDeviceProfile() + + val dp = newDP() + + val expectedWorkspaceWidth = availableWidth + val expectedCellLayoutWidth = + (expectedWorkspaceWidth - (dp.workspacePadding.right + dp.workspacePadding.left)) / + dp.panelCount + val expectedShortcutAndWidgetContainerWidth = + expectedCellLayoutWidth - + (dp.cellLayoutPaddingPx.left + dp.cellLayoutPaddingPx.right) + assertThat(dp.getCellSize().x).isEqualTo( + (expectedShortcutAndWidgetContainerWidth - + ((inv!!.numColumns - 1) * dp.cellLayoutBorderSpacePx.x)) / inv!!.numColumns) + val expectedWorkspaceHeight = availableHeight + val expectedCellLayoutHeight = + expectedWorkspaceHeight - (dp.workspacePadding.top + dp.workspacePadding.bottom) + val expectedShortcutAndWidgetContainerHeight = expectedCellLayoutHeight - + (dp.cellLayoutPaddingPx.top + dp.cellLayoutPaddingPx.bottom) + assertThat(dp.getCellSize().y).isEqualTo( + (expectedShortcutAndWidgetContainerHeight - + ((inv!!.numRows - 1) * dp.cellLayoutBorderSpacePx.y)) / inv!!.numRows) + } + + @Test + fun getPanelCount_twoPanelLandscapeScalable4By4GridTablet_equalsTwoPanels() { + val tabletWidth = 2560 + val tabletHeight = 1600 + val availableWidth = 2560 + val availableHeight = 1500 + windowBounds = WindowBounds(tabletWidth, tabletHeight, availableWidth, availableHeight, 0) + useTwoPanels = true + whenever(info.isTablet(ArgumentMatchers.any())).thenReturn(true) + whenever(info.getDensityDpi()).thenReturn(320) + inv = getScalable4By4InvariantDeviceProfile() + + val dp = newDP() + + assertThat(dp.panelCount).isEqualTo(2) + } + + fun getScalable4By4InvariantDeviceProfile(): InvariantDeviceProfile { + return InvariantDeviceProfile().apply { + isScalable = true + numColumns = 4 + numRows = 4 + numShownHotseatIcons = 4 + numDatabaseHotseatIcons = 6 + numShrunkenHotseatIcons = 5 + horizontalMargin = FloatArray(4) { 22f } + borderSpaces = listOf( + PointF(16f, 16f), + PointF(16f, 16f), + PointF(16f, 16f), + PointF(16f, 16f) + ).toTypedArray() + allAppsBorderSpaces = listOf( + PointF(16f, 16f), + PointF(16f, 16f), + PointF(16f, 16f), + PointF(16f, 16f) + ).toTypedArray() + hotseatBorderSpaces = FloatArray(4) { 16f } + hotseatColumnSpan = IntArray(4) { 4 } + iconSize = FloatArray(4) { 56f } + allAppsIconSize = FloatArray(4) { 56f } + iconTextSize = FloatArray(4) { 14f } + allAppsIconTextSize = FloatArray(4) { 14f } + minCellSize = listOf( + PointF(64f, 83f), + PointF(64f, 83f), + PointF(64f, 83f), + PointF(64f, 83f) + ).toTypedArray() + allAppsCellSize = listOf( + PointF(64f, 83f), + PointF(64f, 83f), + PointF(64f, 83f), + PointF(64f, 83f) + ).toTypedArray() + inlineQsb = booleanArrayOf( + false, + false, + false, + false + ) + } + } +} \ No newline at end of file