Add a resource override for providing default widgets filter.
The implementation in this CL is no-op i.e. all widgets will be shown
Bug: 356127021
Flag: com.android.launcher3.enable_tiered_widgets_by_default_in_picker
Test: Verified with other child cls
Change-Id: I0a6f8973dc8ec58fd87d29b3f291b5e290ea988d
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 983cf8d..6446f7b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2629,8 +2629,9 @@
* See {@code LauncherBindingDelegate}
*/
@Override
- public void bindAllWidgets(final List<WidgetsListBaseEntry> allWidgets) {
- mModelCallbacks.bindAllWidgets(allWidgets);
+ public void bindAllWidgets(@NonNull final List<WidgetsListBaseEntry> allWidgets,
+ @NonNull final List<WidgetsListBaseEntry> defaultWidgets) {
+ mModelCallbacks.bindAllWidgets(allWidgets, defaultWidgets);
}
@Override
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index b6da164..01d0a74 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -48,6 +48,7 @@
import com.android.launcher3.icons.LauncherIconProvider;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.ModelLauncherCallbacks;
+import com.android.launcher3.model.WidgetsFilterDataProvider;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.InstallSessionTracker;
@@ -197,7 +198,8 @@
mIconProvider = new LauncherIconProvider(context);
mIconCache = new IconCache(mContext, mInvariantDeviceProfile,
iconCacheFileName, mIconProvider);
- mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext),
+ mModel = new LauncherModel(context, this, mIconCache,
+ WidgetsFilterDataProvider.Companion.newInstance(context), new AppFilter(mContext),
PackageManagerHelper.INSTANCE.get(context), iconCacheFileName != null);
mOnTerminateCallback.add(mIconCache::close);
mOnTerminateCallback.add(mModel::destroy);
diff --git a/src/com/android/launcher3/LauncherModel.kt b/src/com/android/launcher3/LauncherModel.kt
index 85ecd58..b56df46 100644
--- a/src/com/android/launcher3/LauncherModel.kt
+++ b/src/com/android/launcher3/LauncherModel.kt
@@ -42,6 +42,7 @@
import com.android.launcher3.model.ReloadStringCacheTask
import com.android.launcher3.model.ShortcutsChangedTask
import com.android.launcher3.model.UserLockStateChangedTask
+import com.android.launcher3.model.WidgetsFilterDataProvider
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.pm.UserCache
@@ -66,6 +67,7 @@
private val context: Context,
private val mApp: LauncherAppState,
private val iconCache: IconCache,
+ private val widgetsFilterDataProvider: WidgetsFilterDataProvider,
appFilter: AppFilter,
mPmHelper: PackageManagerHelper,
isPrimaryInstance: Boolean,
@@ -140,6 +142,11 @@
owner: BgDataModel.Callbacks?,
) = ModelWriter(mApp.context, this, mBgDataModel, verifyChanges, cellPosMapper, owner)
+ /** Returns the [WidgetsFilterDataProvider] that manages widget filters. */
+ fun getWidgetsFilterDataProvider(): WidgetsFilterDataProvider {
+ return widgetsFilterDataProvider
+ }
+
/** Called when the icon for an app changes, outside of package event */
@WorkerThread
fun onAppIconChanged(packageName: String, user: UserHandle) {
@@ -160,7 +167,10 @@
/** Called when the model is destroyed */
fun destroy() {
mModelDestroyed = true
- MODEL_EXECUTOR.execute(modelDelegate::destroy)
+ MODEL_EXECUTOR.execute {
+ modelDelegate.destroy()
+ widgetsFilterDataProvider.destroy()
+ }
}
fun onBroadcastIntent(intent: Intent) {
@@ -312,6 +322,7 @@
mBgDataModel,
this.modelDelegate,
launcherBinder,
+ widgetsFilterDataProvider,
)
// Always post the loader task, instead of running directly
@@ -417,6 +428,14 @@
}
}
+ /** Called when the widget filters are refreshed and available to bind to the model. */
+ fun onWidgetFiltersLoaded() {
+ enqueueModelUpdateTask { taskController, dataModel, _ ->
+ dataModel.widgetsModel.updateWidgetFilters(widgetsFilterDataProvider)
+ taskController.bindUpdatedWidgets(dataModel)
+ }
+ }
+
fun enqueueModelUpdateTask(task: ModelUpdateTask) {
if (mModelDestroyed) {
return
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index 496d517..5d32525 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -252,8 +252,11 @@
PopupContainerWithArrow.dismissInvalidPopup(launcher)
}
- override fun bindAllWidgets(allWidgets: List<WidgetsListBaseEntry>) {
- launcher.widgetPickerDataProvider.setWidgets(allWidgets, /* defaultWidgets= */ listOf())
+ override fun bindAllWidgets(
+ allWidgets: List<WidgetsListBaseEntry>,
+ defaultWidgets: List<WidgetsListBaseEntry>,
+ ) {
+ launcher.widgetPickerDataProvider.setWidgets(allWidgets, defaultWidgets)
}
/** Returns the ids of the workspaces to bind. */
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 1dd7d45..94c36c0 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -305,7 +305,9 @@
bgModel,
LauncherAppState.getInstance(previewContext).getModel().getModelDelegate(),
new BaseLauncherBinder(LauncherAppState.getInstance(previewContext), bgModel,
- /* bgAllAppsList= */ null, new Callbacks[0])) {
+ /* bgAllAppsList= */ null, new Callbacks[0]),
+ LauncherAppState.getInstance(
+ previewContext).getModel().getWidgetsFilterDataProvider()) {
@Override
public void run() {
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index b51f855..c251114 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -24,6 +24,8 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static java.util.Collections.emptyList;
+
import android.os.Process;
import android.os.Trace;
import android.util.Log;
@@ -43,6 +45,7 @@
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
+import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
@@ -62,6 +65,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -162,9 +166,17 @@
if (!WIDGETS_ENABLED) {
return;
}
+ Map<PackageItemInfo, List<WidgetItem>>
+ widgetsByPackageItem = mBgDataModel.widgetsModel.getWidgetsByPackageItem();
List<WidgetsListBaseEntry> widgets = new WidgetsListBaseEntriesBuilder(mApp.getContext())
- .build(mBgDataModel.widgetsModel.getWidgetsByPackageItem());
- executeCallbacksTask(c -> c.bindAllWidgets(widgets), mUiExecutor);
+ .build(widgetsByPackageItem);
+ Predicate<WidgetItem> filter = mBgDataModel.widgetsModel.getDefaultWidgetsFilter();
+ List<WidgetsListBaseEntry> defaultWidgets =
+ filter != null ? new WidgetsListBaseEntriesBuilder(
+ mApp.getContext()).build(widgetsByPackageItem,
+ mBgDataModel.widgetsModel.getDefaultWidgetsFilter()) : emptyList();
+
+ executeCallbacksTask(c -> c.bindAllWidgets(widgets, defaultWidgets), mUiExecutor);
}
/**
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 9a9fa5b..b9b1e98 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -537,7 +537,13 @@
default void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) { }
default void bindRestoreItemsChange(HashSet<ItemInfo> updates) { }
default void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { }
- default void bindAllWidgets(List<WidgetsListBaseEntry> widgets) { }
+
+ /**
+ * Binds the app widgets to the providers that share widgets with the UI.
+ */
+ default void bindAllWidgets(@NonNull List<WidgetsListBaseEntry> widgets,
+ @NonNull List<WidgetsListBaseEntry> defaultWidgets) {
+ }
default void bindSmartspaceWidget() { }
/** Called when workspace has been bound. */
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 06d8b59..a830c96 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.Flags.enableLauncherBrMetricsFixed;
import static com.android.launcher3.Flags.enableSmartspaceAsAWidget;
import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
+import static com.android.launcher3.Flags.enableTieredWidgetsByDefaultInPicker;
import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
@@ -142,6 +143,7 @@
private final UserManager mUserManager;
private final UserCache mUserCache;
private final PackageManagerHelper mPmHelper;
+ private final WidgetsFilterDataProvider mWidgetsFilterDataProvider;
private final InstallSessionHelper mSessionHelper;
private final IconCache mIconCache;
@@ -158,13 +160,16 @@
private String mDbName;
public LoaderTask(@NonNull LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel bgModel,
- ModelDelegate modelDelegate, @NonNull BaseLauncherBinder launcherBinder) {
- this(app, bgAllAppsList, bgModel, modelDelegate, launcherBinder, new UserManagerState());
+ ModelDelegate modelDelegate, @NonNull BaseLauncherBinder launcherBinder,
+ @NonNull WidgetsFilterDataProvider widgetsFilterDataProvider) {
+ this(app, bgAllAppsList, bgModel, modelDelegate, launcherBinder, widgetsFilterDataProvider,
+ new UserManagerState());
}
@VisibleForTesting
LoaderTask(@NonNull LauncherAppState app, AllAppsList bgAllAppsList, BgDataModel bgModel,
ModelDelegate modelDelegate, @NonNull BaseLauncherBinder launcherBinder,
+ WidgetsFilterDataProvider widgetsFilterDataProvider,
UserManagerState userManagerState) {
mApp = app;
mBgAllAppsList = bgAllAppsList;
@@ -179,6 +184,7 @@
mIconCache = mApp.getIconCache();
mUserManagerState = userManagerState;
mInstallingPkgsCached = null;
+ mWidgetsFilterDataProvider = widgetsFilterDataProvider;
}
protected synchronized void waitForIdle() {
@@ -330,7 +336,15 @@
verifyNotStopped();
// fourth step
- List<CachedObject> allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null);
+ WidgetsModel widgetsModel = mBgDataModel.widgetsModel;
+ if (enableTieredWidgetsByDefaultInPicker()) {
+ // Begin periodic refresh of filters
+ mWidgetsFilterDataProvider.initPeriodicDataRefresh(
+ mApp.getModel()::onWidgetFiltersLoaded);
+ // And, update model with currently cached data.
+ widgetsModel.updateWidgetFilters(mWidgetsFilterDataProvider);
+ }
+ List<CachedObject> allWidgetsList = widgetsModel.update(mApp, /*packageUser=*/null);
logASplit("load widgets");
verifyNotStopped();
diff --git a/src/com/android/launcher3/model/ModelTaskController.kt b/src/com/android/launcher3/model/ModelTaskController.kt
index cf2cadc..fc53343 100644
--- a/src/com/android/launcher3/model/ModelTaskController.kt
+++ b/src/com/android/launcher3/model/ModelTaskController.kt
@@ -35,7 +35,7 @@
val dataModel: BgDataModel,
val allAppsList: AllAppsList,
private val model: LauncherModel,
- private val uiExecutor: Executor
+ private val uiExecutor: Executor,
) {
/** Schedules a {@param task} to be executed on the current callbacks. */
@@ -79,10 +79,19 @@
}
fun bindUpdatedWidgets(dataModel: BgDataModel) {
- val widgets =
- WidgetsListBaseEntriesBuilder(app.context)
- .build(dataModel.widgetsModel.widgetsByPackageItem)
- scheduleCallbackTask { it.bindAllWidgets(widgets) }
+ val widgetsByPackageItem = dataModel.widgetsModel.widgetsByPackageItem
+ val allWidgets = WidgetsListBaseEntriesBuilder(app.context).build(widgetsByPackageItem)
+
+ val defaultWidgetsFilter = dataModel.widgetsModel.defaultWidgetsFilter
+ val defaultWidgets =
+ if (defaultWidgetsFilter != null) {
+ WidgetsListBaseEntriesBuilder(app.context)
+ .build(widgetsByPackageItem, defaultWidgetsFilter)
+ } else {
+ emptyList()
+ }
+
+ scheduleCallbackTask { it.bindAllWidgets(allWidgets, defaultWidgets) }
}
fun deleteAndBindComponentsRemoved(matcher: Predicate<ItemInfo?>, reason: String?) {
@@ -99,7 +108,7 @@
val packageUserKeyToUidMap =
apps.associateBy(
keySelector = { PackageUserKey(it.componentName!!.packageName, it.user) },
- valueTransform = { it.uid }
+ valueTransform = { it.uid },
)
scheduleCallbackTask { it.bindAllApplications(apps, flags, packageUserKeyToUidMap) }
}
diff --git a/src/com/android/launcher3/model/WidgetsFilterDataProvider.kt b/src/com/android/launcher3/model/WidgetsFilterDataProvider.kt
new file mode 100644
index 0000000..0571de3
--- /dev/null
+++ b/src/com/android/launcher3/model/WidgetsFilterDataProvider.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 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.model
+
+import android.content.Context
+import androidx.annotation.WorkerThread
+import com.android.launcher3.R
+import com.android.launcher3.util.ResourceBasedOverride
+import java.util.function.Predicate
+
+/** Helper for the widgets model to load the filters that can be applied to available widgets. */
+open class WidgetsFilterDataProvider(val context: Context) : ResourceBasedOverride {
+ /**
+ * Start regular periodic refresh of widget filtering data starting now (if not started
+ * already).
+ */
+ @WorkerThread
+ open fun initPeriodicDataRefresh(callback: WidgetsFilterLoadedCallback? = null) {
+ // no-op
+ }
+
+ /**
+ * Returns a filter that should be applied to the widget predictions.
+ *
+ * @return null if no filter needs to be applied
+ */
+ @WorkerThread open fun getPredictedWidgetsFilter(): Predicate<WidgetItem>? = null
+
+ /**
+ * Returns a filter that should be applied to the widgets list to see which widgets can be shown
+ * by default.
+ *
+ * @return null if no separate "default" list is supported
+ */
+ @WorkerThread open fun getDefaultWidgetsFilter(): Predicate<WidgetItem>? = null
+
+ /** Called when filter data provider is no longer needed. */
+ open fun destroy() {}
+
+ companion object {
+ /** Returns a new instance of the [WidgetsFilterDataProvider] based on resource override. */
+ fun newInstance(context: Context?): WidgetsFilterDataProvider {
+ return ResourceBasedOverride.Overrides.getObject(
+ WidgetsFilterDataProvider::class.java,
+ context,
+ R.string.widgets_filter_data_provider_class,
+ )
+ }
+ }
+}
+
+/** Interface for the model callback to be invoked when filters are loaded. */
+interface WidgetsFilterLoadedCallback {
+ /** Method called back when widget filters are loaded */
+ fun onWidgetsFilterLoaded()
+}
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index b450f46..01d4996 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -18,6 +18,8 @@
import android.util.Log;
import android.util.Pair;
+import androidx.annotation.AnyThread;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
@@ -65,6 +67,8 @@
/* Map of widgets and shortcuts that are tracked per package. */
private final Map<PackageItemInfo, List<WidgetItem>> mWidgetsByPackageItem = new HashMap<>();
+ @Nullable private Predicate<WidgetItem> mDefaultWidgetsFilter = null;
+ @Nullable private Predicate<WidgetItem> mPredictedWidgetsFilter = null;
/**
* Returns all widgets keyed by their component key.
@@ -92,6 +96,37 @@
}
/**
+ * Returns widget filter that can be applied to {@link WidgetItem}s to check if they can be
+ * shown in the default widgets list.
+ * <p>Returns null if filtering isn't available</p>
+ */
+ @AnyThread
+ public @Nullable Predicate<WidgetItem> getDefaultWidgetsFilter() {
+ return mDefaultWidgetsFilter;
+ }
+
+ /**
+ * Returns widget filter that can be applied to {@link WidgetItem}s to check if they can be
+ * part of widget predictions.
+ * <p>Returns null if filter isn't available</p>
+ */
+ @AnyThread
+ public @Nullable Predicate<WidgetItem> getPredictedWidgetsFilter() {
+ return mPredictedWidgetsFilter;
+ }
+
+ /**
+ * Updates model with latest filter data in cache.
+ */
+ public void updateWidgetFilters(@NonNull WidgetsFilterDataProvider widgetsFilterDataProvider) {
+ if (!WIDGETS_ENABLED) {
+ return;
+ }
+ mDefaultWidgetsFilter = widgetsFilterDataProvider.getDefaultWidgetsFilter();
+ mPredictedWidgetsFilter = widgetsFilterDataProvider.getPredictedWidgetsFilter();
+ }
+
+ /**
* @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise
* only widgets and shortcuts associated with the package/user are.
*/
@@ -299,7 +334,7 @@
if (pInfo == null) {
pInfo = new PackageItemInfo(key.mPackageName, key.mWidgetCategory, key.mUser);
pInfo.user = key.mUser;
- mMap.put(key, pInfo);
+ mMap.put(key, pInfo);
}
return pInfo;
}