diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 061d869f4a..a0d15da333 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1180,6 +1180,7 @@ public class Launcher extends StatefulActivity implements Launche // Until the workspace is bound, ensure that we keep the wallpaper offset locked to the // default state, otherwise we will update to the wrong offsets in RTL mWorkspace.lockWallpaperToDefaultPage(); + mWorkspace.bindAndInitLeftPanel(); mWorkspace.bindAndInitFirstWorkspaceScreen(null /* recycled qsb */); mDragController.addDragListener(mWorkspace); @@ -2091,11 +2092,16 @@ public class Launcher extends StatefulActivity implements Launche @Override public void bindScreens(IntArray orderedScreenIds) { - // Make sure the first screen is always at the start. + // Make sure the first screen is at the start if there's no widget panel, + // or on the second place if the first is the widget panel + boolean isLeftPanelShown = + mWorkspace.mWorkspaceScreens.containsKey(Workspace.LEFT_PANEL_ID); + int firstScreenPosition = isLeftPanelShown && orderedScreenIds.size() > 1 ? 1 : 0; + if (FeatureFlags.QSB_ON_FIRST_SCREEN && - orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != 0) { + orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != firstScreenPosition) { orderedScreenIds.removeValue(Workspace.FIRST_SCREEN_ID); - orderedScreenIds.add(0, Workspace.FIRST_SCREEN_ID); + orderedScreenIds.add(firstScreenPosition, Workspace.FIRST_SCREEN_ID); } else if (!FeatureFlags.QSB_ON_FIRST_SCREEN && orderedScreenIds.isEmpty()) { // If there are no screens, we need to have an empty screen mWorkspace.addExtraEmptyScreen(); @@ -2112,10 +2118,17 @@ public class Launcher extends StatefulActivity implements Launche int count = orderedScreenIds.size(); for (int i = 0; i < count; i++) { int screenId = orderedScreenIds.get(i); - if (!FeatureFlags.QSB_ON_FIRST_SCREEN || screenId != Workspace.FIRST_SCREEN_ID) { + if (FeatureFlags.QSB_ON_FIRST_SCREEN && screenId == Workspace.FIRST_SCREEN_ID) { // No need to bind the first screen, as its always bound. - mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(screenId); + continue; } + + if (screenId == Workspace.LEFT_PANEL_ID) { + // No need to bind the left panel, as its always bound. + continue; + } + + mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(screenId); } } @@ -2190,6 +2203,11 @@ public class Launcher extends StatefulActivity implements Launche continue; } + // Skip if the item is on the left widget panel but the panel is not shown + if (item.screenId == Workspace.LEFT_PANEL_ID && !getDeviceProfile().isTwoPanels) { + continue; + } + final View view; switch (item.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index d2dfb7bd95..204913a96c 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -17,6 +17,7 @@ package com.android.launcher3; import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE; + import static com.android.launcher3.anim.Interpolators.SCROLL; import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled; import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType; diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index bcddf3475a..aba8a40665 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -17,6 +17,7 @@ package com.android.launcher3; import static androidx.annotation.VisibleForTesting.PROTECTED; + import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; import static com.android.launcher3.LauncherState.ALL_APPS; @@ -315,18 +316,34 @@ public class Workspace extends PagedView // Increase our bottom insets so we don't overlap with the taskbar. mInsets.bottom += grid.nonOverlappingTaskbarInset; - if (isTwoPanelEnabled()) { + if (grid.isTwoPanels) { setPageSpacing(0); // we have two pages and we don't want any spacing - } else if (mWorkspaceFadeInAdjacentScreens) { - // In landscape mode the page spacing is set to the default. - setPageSpacing(grid.edgeMarginPx); + + // Add left widget panel if it isn't already there + if (!mWorkspaceScreens.containsKey(LEFT_PANEL_ID)) { + int newCurrentPage = mCurrentPage + 1; + bindAndInitLeftPanel(); + setCurrentPage(newCurrentPage); + } } else { - // In portrait, we want the pages spaced such that there is no - // overhang of the previous / next page into the current page viewport. - // We assume symmetrical padding in portrait mode. - int maxInsets = Math.max(insets.left, insets.right); - int maxPadding = Math.max(grid.edgeMarginPx, padding.left + 1); - setPageSpacing(Math.max(maxInsets, maxPadding)); + if (mWorkspaceFadeInAdjacentScreens) { + // In landscape mode the page spacing is set to the default. + setPageSpacing(grid.edgeMarginPx); + } else { + // In portrait, we want the pages spaced such that there is no + // overhang of the previous / next page into the current page viewport. + // We assume symmetrical padding in portrait mode. + int maxInsets = Math.max(insets.left, insets.right); + int maxPadding = Math.max(grid.edgeMarginPx, padding.left + 1); + setPageSpacing(Math.max(maxInsets, maxPadding)); + } + + // Remove left widget panel if it is present + if (mWorkspaceScreens.containsKey(LEFT_PANEL_ID)) { + int newCurrentPage = mCurrentPage - 1; + removeLeftPanel(); + setCurrentPage(newCurrentPage); + } } int paddingLeftRight = grid.cellLayoutPaddingLeftRightPx; @@ -557,7 +574,7 @@ public class Workspace extends PagedView return; } // Add the first page - CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, 0); + CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, getChildCount()); // Always add a QSB on the first screen. if (qsb == null) { // In transposed layout, we add the QSB in the Grid. As workspace does not touch the @@ -576,6 +593,19 @@ public class Workspace extends PagedView } } + /** + * Initializes and binds the left panel + */ + public void bindAndInitLeftPanel() { + if (!FeatureFlags.QSB_ON_FIRST_SCREEN || !isTwoPanelEnabled() + || mWorkspaceScreens.containsKey(Workspace.LEFT_PANEL_ID)) { + return; + } + + insertNewWorkspaceScreen(Workspace.LEFT_PANEL_ID, getChildCount()); + mLauncher.getModelWriter().setLeftPanelShown(true); + } + public void removeAllWorkspaceScreens() { // Disable all layout transitions before removing all pages to ensure that we don't get the // transition animations competing with us changing the scroll when we add pages @@ -597,6 +627,7 @@ public class Workspace extends PagedView mLauncher.mHandler.removeCallbacksAndMessages(DeferredWidgetRefresh.class); // Ensure that the first page is always present + bindAndInitLeftPanel(); bindAndInitFirstWorkspaceScreen(qsb); // Re-enable the layout transitions @@ -617,6 +648,18 @@ public class Workspace extends PagedView insertNewWorkspaceScreen(screenId, getChildCount()); } + private void removeLeftPanel() { + if (!mWorkspaceScreens.containsKey(LEFT_PANEL_ID)) { + return; + } + mLauncher.getModelWriter().setLeftPanelShown(false); + CellLayout leftPanel = mWorkspaceScreens.get(LEFT_PANEL_ID); + mWorkspaceScreens.remove(LEFT_PANEL_ID); + removeView(leftPanel); + mScreenOrder.removeValue(LEFT_PANEL_ID); + updatePageScrollValues(); + } + public CellLayout insertNewWorkspaceScreen(int screenId, int insertIndex) { if (mWorkspaceScreens.containsKey(screenId)) { throw new RuntimeException("Screen id " + screenId + " already exists!"); diff --git a/src/com/android/launcher3/WorkspaceLayoutManager.java b/src/com/android/launcher3/WorkspaceLayoutManager.java index d6302ce580..326e3c343a 100644 --- a/src/com/android/launcher3/WorkspaceLayoutManager.java +++ b/src/com/android/launcher3/WorkspaceLayoutManager.java @@ -32,6 +32,8 @@ public interface WorkspaceLayoutManager { int EXTRA_EMPTY_SCREEN_ID = -201; // The is the first screen. It is always present, even if its empty. int FIRST_SCREEN_ID = 0; + // This panel is shown on the first page if the panel count is greater than 1. + int LEFT_PANEL_ID = -777; /** * At bind time, we use the rank (screenId) to compute x and y for hotseat items. diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 037f408ab1..0740a30f21 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -116,6 +116,11 @@ public class BgDataModel { */ public int lastBindId = 0; + /** + * Value that indicates if left widget panel is shown or not. + */ + public boolean isLeftPanelShown = false; + /** * Clears all the data */ @@ -141,6 +146,14 @@ public class BgDataModel { if (FeatureFlags.QSB_ON_FIRST_SCREEN || screenSet.isEmpty()) { screenSet.add(Workspace.FIRST_SCREEN_ID); } + + if (isLeftPanelShown) { + // We should add it even though there are no items on it. + screenSet.add(Workspace.LEFT_PANEL_ID); + } else { + // We should NOT add it even though there are items on it. + screenSet.remove(Workspace.LEFT_PANEL_ID); + } return screenSet.getArray(); } diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java index 080ce20f31..2b93118192 100644 --- a/src/com/android/launcher3/model/ModelWriter.java +++ b/src/com/android/launcher3/model/ModelWriter.java @@ -112,6 +112,13 @@ public class ModelWriter { } } + /** + * Sets the value that indicates if left widget panel is shown or not. + */ + public void setLeftPanelShown(boolean value) { + mBgDataModel.isLeftPanelShown = value; + } + private void checkItemInfoLocked(int itemId, ItemInfo item, StackTraceElement[] stackTrace) { ItemInfo modelItem = mBgDataModel.itemsIdMap.get(itemId); if (modelItem != null && item != modelItem) {