diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 7a16e1f1a9..fd9ff50910 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -28,6 +28,7 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE; import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE; import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType; import static com.android.launcher3.BuildConfig.APPLICATION_ID; +import static com.android.launcher3.BuildConfig.QSB_ON_FIRST_SCREEN; import static com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY; import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WIDGET_TRANSITION; import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; @@ -44,7 +45,7 @@ import static com.android.launcher3.LauncherState.NO_SCALE; import static com.android.launcher3.LauncherState.SPRING_LOADED; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID; -import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions; +import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL; import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE; import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE; import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget; @@ -426,6 +427,8 @@ public class Launcher extends StatefulActivity private BaseSearchConfig mBaseSearchConfig; private StartupLatencyLogger mStartupLatencyLogger; private CellPosMapper mCellPosMapper = CellPosMapper.DEFAULT; + private boolean mIsFirstPagePinnedItemEnabled = QSB_ON_FIRST_SCREEN + && !ENABLE_SMARTSPACE_REMOVAL.get(); private final CannedAnimationCoordinator mAnimationCoordinator = new CannedAnimationCoordinator(this); @@ -1318,7 +1321,9 @@ public class Launcher extends StatefulActivity // 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.bindAndInitFirstWorkspaceScreen(); + if (!ENABLE_SMARTSPACE_REMOVAL.get()) { + mWorkspace.bindAndInitFirstWorkspaceScreen(); + } mDragController.addDragListener(mWorkspace); // Get the search/delete/uninstall bar @@ -2158,16 +2163,23 @@ public class Launcher extends StatefulActivity TraceHelper.INSTANCE.endSection(); } + @Override + public void setIsFirstPagePinnedItemEnabled(boolean isFirstPagePinnedItemEnabled) { + mIsFirstPagePinnedItemEnabled = isFirstPagePinnedItemEnabled; + mWorkspace.bindAndInitFirstWorkspaceScreen(); + } + @Override public void bindScreens(IntArray orderedScreenIds) { mWorkspace.mPageIndicator.setAreScreensBinding(true); int firstScreenPosition = 0; if ((FeatureFlags.QSB_ON_FIRST_SCREEN + && mIsFirstPagePinnedItemEnabled && !shouldShowFirstPageWidget()) && orderedScreenIds.indexOf(FIRST_SCREEN_ID) != firstScreenPosition) { orderedScreenIds.removeValue(FIRST_SCREEN_ID); orderedScreenIds.add(firstScreenPosition, FIRST_SCREEN_ID); - } else if ((!FeatureFlags.QSB_ON_FIRST_SCREEN + } else if (((!FeatureFlags.QSB_ON_FIRST_SCREEN && !mIsFirstPagePinnedItemEnabled) || shouldShowFirstPageWidget()) && orderedScreenIds.isEmpty()) { // If there are no screens, we need to have an empty screen @@ -2218,6 +2230,7 @@ public class Launcher extends StatefulActivity for (int i = 0; i < count; i++) { int screenId = orderedScreenIds.get(i); if (FeatureFlags.QSB_ON_FIRST_SCREEN + && mIsFirstPagePinnedItemEnabled && !shouldShowFirstPageWidget() && screenId == FIRST_SCREEN_ID) { // No need to bind the first screen, as its always bound. @@ -3406,6 +3419,10 @@ public class Launcher extends StatefulActivity // Overridden } + public boolean getIsFirstPagePinnedItemEnabled() { + return mIsFirstPagePinnedItemEnabled; + } + /** * Returns the animation coordinator for playing one-off animations */ diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 9db8c82a03..ab41a31ffc 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -21,6 +21,8 @@ import static android.content.Context.RECEIVER_EXPORTED; import static com.android.launcher3.LauncherPrefs.ICON_STATE; import static com.android.launcher3.LauncherPrefs.THEMED_ICONS; +import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL; +import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI; @@ -123,6 +125,23 @@ public class LauncherAppState implements SafeCloseable { .addUserEventListener(mModel::onUserEvent); mOnTerminateCallback.add(userChangeListener::close); + if (ENABLE_SMARTSPACE_REMOVAL.get()) { + OnSharedPreferenceChangeListener firstPagePinnedItemListener = + new OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged( + SharedPreferences sharedPreferences, String key) { + if (SMARTSPACE_ON_HOME_SCREEN.equals(key)) { + mModel.forceReload(); + } + } + }; + LauncherPrefs.getPrefs(mContext).registerOnSharedPreferenceChangeListener( + firstPagePinnedItemListener); + mOnTerminateCallback.add(() -> LauncherPrefs.getPrefs(mContext) + .unregisterOnSharedPreferenceChangeListener(firstPagePinnedItemListener)); + } + LockedUserState.get(context).runOnUserUnlocked(() -> { CustomWidgetManager cwm = CustomWidgetManager.INSTANCE.get(mContext); cwm.setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index c20d602996..eeb5fe0a56 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -28,6 +28,7 @@ import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.SPRING_LOADED; import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe; import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback; +import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL; import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE; import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; @@ -596,18 +597,19 @@ public class Workspace extends PagedView * Initializes and binds the first page */ public void bindAndInitFirstWorkspaceScreen() { - if (!FeatureFlags.QSB_ON_FIRST_SCREEN + if ((!FeatureFlags.QSB_ON_FIRST_SCREEN + || !mLauncher.getIsFirstPagePinnedItemEnabled()) || shouldShowFirstPageWidget()) { + mFirstPagePinnedItem = null; return; } // Add the first page CellLayout firstPage = insertNewWorkspaceScreen(Workspace.FIRST_SCREEN_ID, getChildCount()); - // Always add a first page pinned widget on the first screen. if (mFirstPagePinnedItem == null) { // In transposed layout, we add the first page pinned widget in the Grid. // As workspace does not touch the edges, we do not need a full - // width first page pinned widget. + // width first page pinned item. mFirstPagePinnedItem = LayoutInflater.from(getContext()) .inflate(R.layout.search_container_workspace, firstPage, false); } @@ -627,7 +629,7 @@ public class Workspace extends PagedView // transition animations competing with us changing the scroll when we add pages disableLayoutTransitions(); - // Recycle the first page pinned widget + // Recycle the first page pinned item if (mFirstPagePinnedItem != null) { ((ViewGroup) mFirstPagePinnedItem.getParent()).removeView(mFirstPagePinnedItem); } @@ -638,12 +640,14 @@ public class Workspace extends PagedView mScreenOrder.clear(); mWorkspaceScreens.clear(); + // Ensure that the first page is always present + if (!ENABLE_SMARTSPACE_REMOVAL.get()) { + bindAndInitFirstWorkspaceScreen(); + } + // Remove any deferred refresh callbacks mLauncher.mHandler.removeCallbacksAndMessages(DeferredWidgetRefresh.class); - // Ensure that the first page is always present - bindAndInitFirstWorkspaceScreen(); - // Re-enable the layout transitions enableLayoutTransitions(); } @@ -802,6 +806,13 @@ public class Workspace extends PagedView // and we store them as extra empty screens. for (int i = 0; i < finalScreens.size(); i++) { int screenId = finalScreens.keyAt(i); + + // We don't want to remove the first screen even if it's empty because that's where + // first page pinned item would go if it gets turned back on. + if (ENABLE_SMARTSPACE_REMOVAL.get() && screenId == FIRST_SCREEN_ID) { + continue; + } + CellLayout screen = finalScreens.get(screenId); mWorkspaceScreens.remove(screenId); diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index 7ce5c20a51..3330448919 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -527,7 +527,7 @@ public class LauncherPreviewRenderer extends ContextWrapper } // Add first page QSB - if (FeatureFlags.QSB_ON_FIRST_SCREEN + if (FeatureFlags.QSB_ON_FIRST_SCREEN && dataModel.isFirstPagePinnedItemEnabled && !shouldShowFirstPageWidget()) { CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID); View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen, false); diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java index 74212059e2..9b2344d2ad 100644 --- a/src/com/android/launcher3/model/BaseLauncherBinder.java +++ b/src/com/android/launcher3/model/BaseLauncherBinder.java @@ -16,6 +16,7 @@ package com.android.launcher3.model; +import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL; import static com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING; import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; @@ -293,6 +294,10 @@ public abstract class BaseLauncherBinder { executeCallbacksTask(c -> { c.clearPendingBinds(); c.startBinding(); + if (ENABLE_SMARTSPACE_REMOVAL.get()) { + c.setIsFirstPagePinnedItemEnabled( + mBgDataModel.isFirstPagePinnedItemEnabled); + } }, mUiExecutor); // Bind workspace screens diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java index 0ffedc8c1a..54ecc00c59 100644 --- a/src/com/android/launcher3/model/BgDataModel.java +++ b/src/com/android/launcher3/model/BgDataModel.java @@ -17,6 +17,8 @@ package com.android.launcher3.model; import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY; +import static com.android.launcher3.BuildConfig.QSB_ON_FIRST_SCREEN; +import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL; import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget; import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS; import static com.android.launcher3.shortcuts.ShortcutRequest.PINNED; @@ -130,6 +132,8 @@ public class BgDataModel { * Load id for which the callbacks were successfully bound */ public int lastLoadId = -1; + public boolean isFirstPagePinnedItemEnabled = QSB_ON_FIRST_SCREEN + && !ENABLE_SMARTSPACE_REMOVAL.get(); /** * Clears all the data @@ -489,6 +493,7 @@ public class BgDataModel { default void bindItems(List shortcuts, boolean forceAnimateIcons) { } default void bindScreens(IntArray orderedScreenIds) { } + default void setIsFirstPagePinnedItemEnabled(boolean isFirstPagePinnedItemEnabled) { } default void finishBindingItems(IntSet pagesBoundFirst) { } default void preAddApps() { } default void bindAppsAdded(IntArray newScreens, diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java index eed4ee6b4d..efd5574519 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java +++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java @@ -18,7 +18,9 @@ package com.android.launcher3.model; import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; import static com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE; +import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL; import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget; +import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN; import static com.android.launcher3.provider.LauncherDbUtils.copyTable; import static com.android.launcher3.provider.LauncherDbUtils.dropTable; @@ -38,6 +40,7 @@ import android.util.Log; import androidx.annotation.NonNull; import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.LauncherPrefs; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; @@ -330,6 +333,8 @@ public class GridSizeMigrationUtil { final Point trg = new Point(trgX, trgY); final Point next = new Point(0, screenId == 0 && (FeatureFlags.QSB_ON_FIRST_SCREEN + && (!ENABLE_SMARTSPACE_REMOVAL.get() || LauncherPrefs.getPrefs(destReader.mContext) + .getBoolean(SMARTSPACE_ON_HOME_SCREEN, true)) && !shouldShowFirstPageWidget()) ? 1 /* smartspace */ : 0); List existedEntries = destReader.mWorkspaceEntriesByScreenId.get(screenId); diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 9c4cd46af4..4370043569 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -471,7 +471,7 @@ public class LoaderCursor extends CursorWrapper { // cause the item loading to get skipped ShortcutKey.fromItemInfo(info); } - if (checkItemPlacement(info)) { + if (checkItemPlacement(info, dataModel.isFirstPagePinnedItemEnabled)) { dataModel.addItem(mContext, info, false, logger); } else { markDeleted("Item position overlap"); @@ -481,7 +481,7 @@ public class LoaderCursor extends CursorWrapper { /** * check & update map of what's occupied; used to discard overlapping/invalid items */ - protected boolean checkItemPlacement(ItemInfo item) { + protected boolean checkItemPlacement(ItemInfo item, boolean isFirstPagePinnedItemEnabled) { int containerIndex = item.screenId; if (item.container == Favorites.CONTAINER_HOTSEAT) { final GridOccupancy hotseatOccupancy = @@ -530,7 +530,7 @@ public class LoaderCursor extends CursorWrapper { if (!mOccupied.containsKey(item.screenId)) { GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1); if (item.screenId == Workspace.FIRST_SCREEN_ID && (FeatureFlags.QSB_ON_FIRST_SCREEN - && !shouldShowFirstPageWidget())) { + && !shouldShowFirstPageWidget() && isFirstPagePinnedItemEnabled)) { // Mark the first X columns (X is width of the search container) in the first row as // occupied (if the feature is enabled) in order to account for the search // container. diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 15666cf6f0..6ab8fc50a4 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -19,6 +19,7 @@ package com.android.launcher3.model; import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN; import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE; import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME; +import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL; import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION; import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION; @@ -119,6 +120,7 @@ import java.util.concurrent.CancellationException; */ public class LoaderTask implements Runnable { private static final String TAG = "LoaderTask"; + public static final String SMARTSPACE_ON_HOME_SCREEN = "pref_smartspace_home_screen"; private static final boolean DEBUG = true; @@ -368,6 +370,9 @@ public class LoaderTask implements Runnable { mModelDelegate.markActive(); logASplit("workspaceDelegateItems"); } + mBgDataModel.isFirstPagePinnedItemEnabled = FeatureFlags.QSB_ON_FIRST_SCREEN + && (!ENABLE_SMARTSPACE_REMOVAL.get() || LauncherPrefs.getPrefs( + mApp.getContext()).getBoolean(SMARTSPACE_ON_HOME_SCREEN, true)); } private void loadWorkspaceImpl( diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java index 544ed6b01d..389ec5c09c 100644 --- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -175,7 +175,7 @@ public class LoaderCursorTest { // Item outside screen bounds are not placed assertFalse(mLoaderCursor.checkItemPlacement( - newItemInfo(4, 4, 1, 1, CONTAINER_DESKTOP, 1))); + newItemInfo(4, 4, 1, 1, CONTAINER_DESKTOP, 1), true)); } @Test @@ -186,22 +186,22 @@ public class LoaderCursorTest { // Overlapping mItems are not placed assertTrue(mLoaderCursor.checkItemPlacement( - newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1))); + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1), true)); assertFalse(mLoaderCursor.checkItemPlacement( - newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1))); + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1), true)); assertTrue(mLoaderCursor.checkItemPlacement( - newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2))); + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2), true)); assertFalse(mLoaderCursor.checkItemPlacement( - newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2))); + newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2), true)); assertTrue(mLoaderCursor.checkItemPlacement( - newItemInfo(1, 1, 1, 1, CONTAINER_DESKTOP, 1))); + newItemInfo(1, 1, 1, 1, CONTAINER_DESKTOP, 1), true)); assertTrue(mLoaderCursor.checkItemPlacement( - newItemInfo(2, 2, 2, 2, CONTAINER_DESKTOP, 1))); + newItemInfo(2, 2, 2, 2, CONTAINER_DESKTOP, 1), true)); assertFalse(mLoaderCursor.checkItemPlacement( - newItemInfo(3, 2, 1, 2, CONTAINER_DESKTOP, 1))); + newItemInfo(3, 2, 1, 2, CONTAINER_DESKTOP, 1), true)); } @Test @@ -212,12 +212,12 @@ public class LoaderCursorTest { // Hotseat mItems are only placed based on screenId assertTrue(mLoaderCursor.checkItemPlacement( - newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 1))); + newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 1), true)); assertTrue(mLoaderCursor.checkItemPlacement( - newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 2))); + newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 2), true)); assertFalse(mLoaderCursor.checkItemPlacement( - newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 3))); + newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 3), true)); } private ItemInfo newItemInfo(int cellX, int cellY, int spanX, int spanY,