Add smartspace as a widget to first page (implementation 2)

Flag: SMARTSPACE_AS_A_WIDGET
Test: verify that the smartspace gets replaced with a smartspace widget
Bug: 300140279
Change-Id: I42c170de5e2a9fd3d24d99bb8b09cf412c55e3a5
This commit is contained in:
fbaron
2023-09-25 11:34:56 -07:00
committed by Federico Baron
parent 94f7b53a54
commit e58aaf1802
16 changed files with 119 additions and 15 deletions
@@ -38,4 +38,8 @@ public class LauncherBinder extends BaseLauncherBinder {
@Override
public void bindWidgets() {
}
@Override
public void bindSmartspaceWidget() {
}
}
+45 -6
View File
@@ -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.TYPE_SNACKBAR;
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
import static com.android.launcher3.BuildConfig.APPLICATION_ID;
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;
@@ -43,9 +44,12 @@ import static com.android.launcher3.LauncherState.NO_OFFSET;
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.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE;
import static com.android.launcher3.config.FeatureFlags.SHOW_DOT_PAGINATION;
import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
import static com.android.launcher3.logging.StatsLogManager.EventEnum;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
@@ -2177,11 +2181,14 @@ public class Launcher extends StatefulActivity<LauncherState>
public void bindScreens(IntArray orderedScreenIds) {
mWorkspace.mPageIndicator.setAreScreensBinding(true);
int firstScreenPosition = 0;
if (FeatureFlags.QSB_ON_FIRST_SCREEN &&
orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != firstScreenPosition) {
orderedScreenIds.removeValue(Workspace.FIRST_SCREEN_ID);
orderedScreenIds.add(firstScreenPosition, Workspace.FIRST_SCREEN_ID);
} else if (!FeatureFlags.QSB_ON_FIRST_SCREEN && orderedScreenIds.isEmpty()) {
if ((FeatureFlags.QSB_ON_FIRST_SCREEN
&& !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
|| shouldShowFirstPageWidget())
&& orderedScreenIds.isEmpty()) {
// If there are no screens, we need to have an empty screen
mWorkspace.addExtraEmptyScreens();
}
@@ -2229,7 +2236,9 @@ public class Launcher extends StatefulActivity<LauncherState>
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
&& !shouldShowFirstPageWidget()
&& screenId == FIRST_SCREEN_ID) {
// No need to bind the first screen, as its always bound.
continue;
}
@@ -2929,6 +2938,36 @@ public class Launcher extends StatefulActivity<LauncherState>
mPopupDataProvider.setAllWidgets(allWidgets);
}
@Override
public void bindSmartspaceWidget() {
CellLayout cl = mWorkspace.getScreenWithId(FIRST_SCREEN_ID);
int spanX = InvariantDeviceProfile.INSTANCE.get(this).numSearchContainerColumns;
if (cl != null) {
for (int col = 0; col < spanX; col++) {
if (cl.isOccupied(col, 0)) {
return;
}
}
} else {
return;
}
WidgetsListBaseEntry widgetsListBaseEntry = getPopupDataProvider()
.getAllWidgets().stream().filter(
item -> item.mPkgItem.packageName.equals(
APPLICATION_ID))
.findFirst()
.orElse(null);
if (widgetsListBaseEntry != null) {
LauncherAppWidgetProviderInfo launcherAppWidgetProviderInfo =
widgetsListBaseEntry.mWidgets.get(0).widgetInfo;
PendingAddWidgetInfo info = new PendingAddWidgetInfo(launcherAppWidgetProviderInfo,
CONTAINER_DESKTOP);
addPendingItem(info, info.container, FIRST_SCREEN_ID, new int[]{0, 0}, info.spanX,
info.spanY);
}
}
@Override
public void bindStringCache(StringCache cache) {
mStringCache = cache;
@@ -21,6 +21,7 @@ import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN
import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
import com.android.launcher3.LauncherFiles.SHARED_PREFERENCES_KEY
import com.android.launcher3.allapps.WorkProfileManager
@@ -278,6 +279,7 @@ class LauncherPrefs(private val encryptedContext: Context) {
@JvmStatic fun get(context: Context): LauncherPrefs = INSTANCE.get(context)
const val TASKBAR_PINNING_KEY = "TASKBAR_PINNING_KEY"
const val SHOULD_SHOW_SMARTSPACE_KEY = "SHOULD_SHOW_SMARTSPACE_KEY"
@JvmField val ICON_STATE = nonRestorableItem(LauncherAppState.KEY_ICON_STATE, "", true)
@JvmField
val ALL_APPS_OVERVIEW_THRESHOLD =
@@ -292,6 +294,9 @@ class LauncherPrefs(private val encryptedContext: Context) {
@JvmField
val DEVICE_TYPE =
backedUpItem(DeviceGridState.KEY_DEVICE_TYPE, InvariantDeviceProfile.TYPE_PHONE, true)
@JvmField
val SHOULD_SHOW_SMARTSPACE =
backedUpItem("SHOULD_SHOW_SMARTSPACE_KEY", WIDGET_ON_FIRST_SCREEN, true)
@JvmField val DB_FILE = backedUpItem(DeviceGridState.KEY_DB_FILE, "", true)
@JvmField
val RESTORE_DEVICE =
+6 -2
View File
@@ -29,6 +29,7 @@ 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.FOLDABLE_SINGLE_PAGE;
import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT;
@@ -594,7 +595,8 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
* Initializes and binds the first page
*/
public void bindAndInitFirstWorkspaceScreen() {
if (!FeatureFlags.QSB_ON_FIRST_SCREEN) {
if (!FeatureFlags.QSB_ON_FIRST_SCREEN
|| shouldShowFirstPageWidget()) {
return;
}
@@ -1012,7 +1014,9 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
int id = mWorkspaceScreens.keyAt(i);
CellLayout cl = mWorkspaceScreens.valueAt(i);
// FIRST_SCREEN_ID can never be removed.
if ((!FeatureFlags.QSB_ON_FIRST_SCREEN || id > FIRST_SCREEN_ID)
if (((!FeatureFlags.QSB_ON_FIRST_SCREEN
|| shouldShowFirstPageWidget())
|| id > FIRST_SCREEN_ID)
&& cl.getShortcutsAndWidgets().getChildCount() == 0) {
removeScreens.add(id);
}
@@ -16,6 +16,7 @@
package com.android.launcher3.config;
import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
import static com.android.launcher3.config.FeatureFlags.FlagState.DISABLED;
import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED;
import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD;
@@ -177,6 +178,10 @@ public final class FeatureFlags {
public static final BooleanFlag SMARTSPACE_AS_A_WIDGET = getDebugFlag(299181941,
"SMARTSPACE_AS_A_WIDGET", DISABLED, "Enable SmartSpace as a widget");
public static boolean shouldShowFirstPageWidget() {
return SMARTSPACE_AS_A_WIDGET.get() && WIDGET_ON_FIRST_SCREEN;
}
// TODO(Block 10): Clean up flags
public static final BooleanFlag ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION = getDebugFlag(270614790,
"ENABLE_BACK_SWIPE_LAUNCHER_ANIMATION", DISABLED,
@@ -22,6 +22,7 @@ import static android.view.View.VISIBLE;
import static com.android.launcher3.DeviceProfile.DEFAULT_SCALE;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.model.ModelUtils.getMissingHotseatRanks;
@@ -526,7 +527,8 @@ public class LauncherPreviewRenderer extends ContextWrapper
}
// Add first page QSB
if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
if (FeatureFlags.QSB_ON_FIRST_SCREEN
&& !shouldShowFirstPageWidget()) {
CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID);
View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen, false);
CellLayoutLayoutParams lp = new CellLayoutLayoutParams(
@@ -171,6 +171,11 @@ public abstract class BaseLauncherBinder {
*/
public abstract void bindWidgets();
/**
* bindWidgets is abstract because it is a no-op for the go launcher.
*/
public abstract void bindSmartspaceWidget();
/**
* Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to right)
*/
@@ -17,6 +17,7 @@ package com.android.launcher3.model;
import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY;
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;
@@ -152,7 +153,9 @@ public class BgDataModel {
screenSet.add(item.screenId);
}
}
if (FeatureFlags.QSB_ON_FIRST_SCREEN || screenSet.isEmpty()) {
if ((FeatureFlags.QSB_ON_FIRST_SCREEN
&& !shouldShowFirstPageWidget())
|| screenSet.isEmpty()) {
screenSet.add(Workspace.FIRST_SCREEN_ID);
}
return screenSet.getArray();
@@ -505,6 +508,7 @@ public class BgDataModel {
default void bindRestoreItemsChange(HashSet<ItemInfo> updates) { }
default void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { }
default void bindAllWidgets(List<WidgetsListBaseEntry> widgets) { }
default void bindSmartspaceWidget() { }
/** Called when workspace has been bound. */
default void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks,
@@ -16,6 +16,7 @@
package com.android.launcher3.model;
import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb;
import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import android.content.ContentValues;
@@ -257,7 +258,8 @@ public class DatabaseHelper extends NoLocaleSQLiteHelper implements
Favorites.SCREEN, IntArray.wrap(-777, -778)), null);
}
case 30: {
if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
if (FeatureFlags.QSB_ON_FIRST_SCREEN
&& !shouldShowFirstPageWidget()) {
// Clean up first row in screen 0 as it might contain junk data.
Log.d(TAG, "Cleaning up first row");
db.delete(Favorites.TABLE_NAME,
@@ -18,6 +18,7 @@ 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.shouldShowFirstPageWidget;
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
@@ -327,7 +328,9 @@ public class GridSizeMigrationUtil {
@NonNull final List<DbEntry> sortedItemsToPlace, final boolean matchingScreenIdOnly) {
final GridOccupancy occupied = new GridOccupancy(trgX, trgY);
final Point trg = new Point(trgX, trgY);
final Point next = new Point(0, screenId == 0 && FeatureFlags.QSB_ON_FIRST_SCREEN
final Point next = new Point(0, screenId == 0
&& (FeatureFlags.QSB_ON_FIRST_SCREEN
&& !shouldShowFirstPageWidget())
? 1 /* smartspace */ : 0);
List<DbEntry> existedEntries = destReader.mWorkspaceEntriesByScreenId.get(screenId);
if (existedEntries != null) {
@@ -17,6 +17,7 @@
package com.android.launcher3.model;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
import android.content.ComponentName;
import android.content.ContentValues;
@@ -528,7 +529,8 @@ 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) {
if (item.screenId == Workspace.FIRST_SCREEN_ID && (FeatureFlags.QSB_ON_FIRST_SCREEN
&& !shouldShowFirstPageWidget())) {
// 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.
@@ -16,6 +16,7 @@
package com.android.launcher3.model;
import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
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;
@@ -57,6 +58,7 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
@@ -296,6 +298,19 @@ public class LoaderTask implements Runnable {
logASplit("bindWidgets");
verifyNotStopped();
if (LauncherPrefs.get(mApp.getContext()).get(LauncherPrefs.SHOULD_SHOW_SMARTSPACE)) {
mLauncherBinder.bindSmartspaceWidget();
// Turn off pref.
LauncherPrefs.get(mApp.getContext()).putSync(
LauncherPrefs.backedUpItem(
LauncherPrefs.SHOULD_SHOW_SMARTSPACE_KEY,
WIDGET_ON_FIRST_SCREEN,
true)
.to(false));
logASplit("bindSmartspaceWidget");
verifyNotStopped();
}
if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
mModelDelegate.loadAndBindOtherItems(mLauncherBinder.mCallbacksList);
logASplit("otherDelegateItems");
@@ -16,6 +16,7 @@
package com.android.launcher3.model;
import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
import android.util.LongSparseArray;
@@ -66,7 +67,8 @@ public class WorkspaceItemSpaceFinder {
int screenCount = workspaceScreens.size();
// First check the preferred screen.
IntSet screensToExclude = new IntSet();
if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
if (FeatureFlags.QSB_ON_FIRST_SCREEN
&& !shouldShowFirstPageWidget()) {
screensToExclude.add(FIRST_SCREEN_ID);
}
@@ -20,6 +20,8 @@ import static android.appwidget.AppWidgetManager.ACTION_APPWIDGET_BIND;
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_PROVIDER;
import static com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget;
import android.app.Activity;
import android.app.Fragment;
import android.app.SearchManager;
@@ -290,7 +292,7 @@ public class QsbContainerView extends FrameLayout {
}
public boolean isQsbEnabled() {
return FeatureFlags.QSB_ON_FIRST_SCREEN;
return FeatureFlags.QSB_ON_FIRST_SCREEN && !shouldShowFirstPageWidget();
}
protected Bundle createBindOptions() {
@@ -26,6 +26,11 @@ public final class BuildConfig {
*/
public static final boolean QSB_ON_FIRST_SCREEN = true;
/**
* Flag to state if the widget on the top of the first screen should be shown.
*/
public static final boolean WIDGET_ON_FIRST_SCREEN = false;
/**
* Flag to control various developer centric features
*/
@@ -51,4 +51,9 @@ public class LauncherBinder extends BaseLauncherBinder {
mBgDataModel.widgetsModel.getWidgetsListForPicker(mApp.getContext());
executeCallbacksTask(c -> c.bindAllWidgets(widgets), mUiExecutor);
}
@Override
public void bindSmartspaceWidget() {
executeCallbacksTask(c -> c.bindSmartspaceWidget(), mUiExecutor);
}
}