diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index 2e1318b019..bc97df1fea 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -48,11 +48,15 @@ import android.os.UserHandle; import android.util.Log; import android.util.StatsEvent; +import androidx.annotation.AnyThread; +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.InstanceIdSequence; @@ -62,6 +66,7 @@ import com.android.launcher3.model.data.FolderInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.shortcuts.ShortcutKey; +import com.android.launcher3.util.Executors; import com.android.launcher3.util.IntSparseArrayMap; import com.android.launcher3.util.PersistedItemArray; import com.android.quickstep.logging.SettingsChangeLogger; @@ -111,45 +116,80 @@ public class QuickstepModelDelegate extends ModelDelegate { mStatsManager = context.getSystemService(StatsManager.class); } + @CallSuper @Override - public void loadHotseatItems(UserManagerState ums, - Map pinnedShortcuts) { - // TODO: Implement caching and preloading - super.loadHotseatItems(ums, pinnedShortcuts); - - WorkspaceItemFactory hotseatFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, - mIDP.numDatabaseHotseatIcons, mHotseatState.containerId); - FixedContainerItems hotseatItems = new FixedContainerItems(mHotseatState.containerId, - mHotseatState.storage.read(mApp.getContext(), hotseatFactory, ums.allUsers::get)); - mDataModel.extraItems.put(mHotseatState.containerId, hotseatItems); + public void loadAndBindWorkspaceItems(@NonNull UserManagerState ums, + @NonNull BgDataModel.Callbacks[] callbacks, + @NonNull Map pinnedShortcuts) { + loadAndBindItems(ums, pinnedShortcuts, callbacks, mIDP.numDatabaseHotseatIcons, + mHotseatState); } + @CallSuper @Override - public void loadAllAppsItems(UserManagerState ums, - Map pinnedShortcuts) { - // TODO: Implement caching and preloading - super.loadAllAppsItems(ums, pinnedShortcuts); - - WorkspaceItemFactory allAppsFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, - mIDP.numDatabaseAllAppsColumns, mAllAppsState.containerId); - FixedContainerItems allAppsPredictionItems = new FixedContainerItems( - mAllAppsState.containerId, mAllAppsState.storage.read(mApp.getContext(), - allAppsFactory, ums.allUsers::get)); - mDataModel.extraItems.put(mAllAppsState.containerId, allAppsPredictionItems); + public void loadAndBindAllAppsItems(@NonNull UserManagerState ums, + @NonNull BgDataModel.Callbacks[] callbacks, + @NonNull Map pinnedShortcuts) { + loadAndBindItems(ums, pinnedShortcuts, callbacks, mIDP.numDatabaseAllAppsColumns, + mAllAppsState); } - @Override - public void loadWidgetsRecommendationItems() { + @WorkerThread + private void loadAndBindItems(@NonNull UserManagerState ums, + @NonNull Map pinnedShortcuts, + @NonNull BgDataModel.Callbacks[] callbacks, + int numColumns, @NonNull PredictorState state) { // TODO: Implement caching and preloading - super.loadWidgetsRecommendationItems(); + + WorkspaceItemFactory factory = + new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, numColumns, state.containerId); + FixedContainerItems fci = new FixedContainerItems(state.containerId, + state.storage.read(mApp.getContext(), factory, ums.allUsers::get)); + if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + bindPredictionItems(callbacks, fci); + } + mDataModel.extraItems.put(state.containerId, fci); + } + + @CallSuper + @Override + public void loadAndBindOtherItems(@NonNull BgDataModel.Callbacks[] callbacks) { + FixedContainerItems widgetPredictionFCI = new FixedContainerItems( + mWidgetsRecommendationState.containerId, new ArrayList<>()); // Widgets prediction isn't used frequently. And thus, it is not persisted on disk. - mDataModel.extraItems.put(mWidgetsRecommendationState.containerId, - new FixedContainerItems(mWidgetsRecommendationState.containerId, - new ArrayList<>())); + mDataModel.extraItems.put(mWidgetsRecommendationState.containerId, widgetPredictionFCI); + + bindPredictionItems(callbacks, widgetPredictionFCI); + loadStringCache(mDataModel.stringCache); + } + + @AnyThread + private void bindPredictionItems(@NonNull BgDataModel.Callbacks[] callbacks, + @NonNull FixedContainerItems fci) { + Executors.MAIN_EXECUTOR.execute(() -> { + for (BgDataModel.Callbacks c : callbacks) { + c.bindExtraContainerItems(fci); + } + }); } @Override + @WorkerThread + public void bindAllModelExtras(@NonNull BgDataModel.Callbacks[] callbacks) { + Iterable containerItems; + synchronized (mDataModel.extraItems) { + containerItems = mDataModel.extraItems.clone(); + } + Executors.MAIN_EXECUTOR.execute(() -> { + for (BgDataModel.Callbacks c : callbacks) { + for (FixedContainerItems fci : containerItems) { + c.bindExtraContainerItems(fci); + } + } + }); + } + public void markActive() { super.markActive(); mActive = true; diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index ad95f7e240..06ac44a744 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -421,6 +421,9 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi launcherBinder.bindAllApps(); launcherBinder.bindDeepShortcuts(); launcherBinder.bindWidgets(); + if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + mModelDelegate.bindAllModelExtras(callbacksList); + } return true; } else { stopLoader(); diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 6f1dfe9968..ead81d621c 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -380,6 +380,11 @@ public final class FeatureFlags { "load the current workspace screen visible to the user before the rest rather than " + "loading all of them at once."); + public static final BooleanFlag CHANGE_MODEL_DELEGATE_LOADING_ORDER = getDebugFlag(251502424, + "CHANGE_MODEL_DELEGATE_LOADING_ORDER", DISABLED, + "changes the timing of the loading and binding of delegate items during " + + "data preparation for loading the home screen"); + public static final BooleanFlag ENABLE_GRID_ONLY_OVERVIEW = getDebugFlag(270397206, "ENABLE_GRID_ONLY_OVERVIEW", DISABLED, "Enable a grid-only overview without a focused task."); diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java index 0767e69378..372e9bf2e9 100644 --- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java +++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java @@ -229,8 +229,8 @@ public class PreviewSurfaceRenderer { query += " or " + LauncherSettings.Favorites.SCREEN + " = " + Workspace.SECOND_SCREEN_ID; } - loadWorkspace(new ArrayList<>(), LauncherSettings.Favorites.PREVIEW_CONTENT_URI, - query); + loadWorkspaceForPreviewSurfaceRenderer(new ArrayList<>(), + LauncherSettings.Favorites.PREVIEW_CONTENT_URI, query); final SparseArray spanInfo = getLoadedLauncherWidgetInfo(previewContext.getBaseContext()); diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java index 91ace27459..358992e974 100644 --- a/src/com/android/launcher3/model/BaseLauncherBinder.java +++ b/src/com/android/launcher3/model/BaseLauncherBinder.java @@ -63,7 +63,7 @@ public abstract class BaseLauncherBinder { protected final BgDataModel mBgDataModel; private final AllAppsList mBgAllAppsList; - private final Callbacks[] mCallbacksList; + final Callbacks[] mCallbacksList; private int mMyBindingId; @@ -293,8 +293,10 @@ public abstract class BaseLauncherBinder { // Load items on the current page. bindWorkspaceItems(currentWorkspaceItems, mUiExecutor); bindAppWidgets(currentAppWidgets, mUiExecutor); - mExtraItems.forEach(item -> - executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor)); + if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + mExtraItems.forEach(item -> + executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor)); + } RunnableList pendingTasks = new RunnableList(); Executor pendingExecutor = pendingTasks::add; @@ -382,14 +384,22 @@ public abstract class BaseLauncherBinder { // Save a copy of all the bg-thread collections ArrayList workspaceItems; ArrayList appWidgets; + ArrayList fciList = new ArrayList<>(); synchronized (mBgDataModel) { workspaceItems = new ArrayList<>(mBgDataModel.workspaceItems); appWidgets = new ArrayList<>(mBgDataModel.appWidgets); + if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + mBgDataModel.extraItems.forEach(fciList::add); + } } workspaceItems.forEach(it -> mBoundItemIds.add(it.id)); appWidgets.forEach(it -> mBoundItemIds.add(it.id)); + if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + fciList.forEach(item -> + executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor)); + } sortWorkspaceItemsSpatially(mApp.getInvariantDeviceProfile(), workspaceItems); diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index da9be499c8..f8376e8cda 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -138,6 +138,7 @@ public class LoaderTask implements Runnable { private final UserManagerState mUserManagerState = new UserManagerState(); protected final Map mWidgetProvidersMap = new ArrayMap<>(); + private Map mShortcutKeyToPinnedShortcuts; private boolean mStopped; @@ -211,6 +212,14 @@ public class LoaderTask implements Runnable { } logASplit(timingLogger, "loadWorkspace"); + if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + verifyNotStopped(); + mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState, + mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); + mModelDelegate.markActive(); + logASplit(timingLogger, "workspaceDelegateItems"); + } + // Sanitize data re-syncs widgets/shortcuts based on the workspace loaded from db. // sanitizeData should not be invoked if the workspace is loaded from a db different // from the main db as defined in the invariant device profile. @@ -246,6 +255,11 @@ public class LoaderTask implements Runnable { } logASplit(timingLogger, "loadAllApps"); + if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + mModelDelegate.loadAndBindAllAppsItems(mUserManagerState, + mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); + logASplit(timingLogger, "allAppsDelegateItems"); + } verifyNotStopped(); mLauncherBinder.bindAllApps(); logASplit(timingLogger, "bindAllApps"); @@ -296,6 +310,12 @@ public class LoaderTask implements Runnable { logASplit(timingLogger, "bindWidgets"); verifyNotStopped(); + if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + mModelDelegate.loadAndBindOtherItems(mLauncherBinder.mCallbacksList); + logASplit(timingLogger, "otherDelegateItems"); + verifyNotStopped(); + } + updateHandler.updateIcons(allWidgetsList, new ComponentWithIconCachingLogic(mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated); @@ -334,9 +354,14 @@ public class LoaderTask implements Runnable { null /* selection */, memoryLogger); } - protected void loadWorkspace( + protected void loadWorkspaceForPreviewSurfaceRenderer( List allDeepShortcuts, Uri contentUri, String selection) { loadWorkspace(allDeepShortcuts, contentUri, selection, null); + if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState, + mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); + mModelDelegate.markActive(); + } } protected void loadWorkspace( @@ -376,7 +401,7 @@ public class LoaderTask implements Runnable { final PackageUserKey tempPackageKey = new PackageUserKey(null, null); mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs); - Map shortcutKeyToPinnedShortcuts = new HashMap<>(); + mShortcutKeyToPinnedShortcuts = new HashMap<>(); final LoaderCursor c = new LoaderCursor( contentResolver.query(contentUri, null, selection, null, null), contentUri, mApp, mUserManagerState); @@ -397,7 +422,7 @@ public class LoaderTask implements Runnable { .query(ShortcutRequest.PINNED); if (pinnedShortcuts.wasSuccess()) { for (ShortcutInfo shortcut : pinnedShortcuts) { - shortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut), + mShortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut), shortcut); } } else { @@ -414,7 +439,7 @@ public class LoaderTask implements Runnable { while (!mStopped && c.moveToNext()) { processWorkspaceItem(c, memoryLogger, installingPkgs, isSdCardReady, - tempPackageKey, widgetHelper, pmHelper, shortcutKeyToPinnedShortcuts, + tempPackageKey, widgetHelper, pmHelper, iconRequestInfos, unlockedUsers, isSafeMode, allDeepShortcuts); } maybeLoadWorkspaceIconsInBulk(iconRequestInfos); @@ -422,14 +447,14 @@ public class LoaderTask implements Runnable { IOUtils.closeSilently(c); } - // Load delegate items - mModelDelegate.loadHotseatItems(mUserManagerState, shortcutKeyToPinnedShortcuts); - mModelDelegate.loadAllAppsItems(mUserManagerState, shortcutKeyToPinnedShortcuts); - mModelDelegate.loadWidgetsRecommendationItems(); - mModelDelegate.markActive(); - - // Load string cache - mModelDelegate.loadStringCache(mBgDataModel.stringCache); + if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { + mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState, + mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); + mModelDelegate.loadAndBindAllAppsItems(mUserManagerState, + mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts); + mModelDelegate.loadAndBindOtherItems(mLauncherBinder.mCallbacksList); + mModelDelegate.markActive(); + } // Break early if we've stopped loading if (mStopped) { @@ -474,7 +499,6 @@ public class LoaderTask implements Runnable { PackageUserKey tempPackageKey, WidgetManagerHelper widgetHelper, PackageManagerHelper pmHelper, - Map shortcutKeyToPinnedShortcuts, List> iconRequestInfos, LongSparseArray unlockedUsers, boolean isSafeMode, @@ -603,7 +627,7 @@ public class LoaderTask implements Runnable { } else if (c.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) { ShortcutKey key = ShortcutKey.fromIntent(intent, c.user); if (unlockedUsers.get(c.serialNumber)) { - ShortcutInfo pinnedShortcut = shortcutKeyToPinnedShortcuts.get(key); + ShortcutInfo pinnedShortcut = mShortcutKeyToPinnedShortcuts.get(key); if (pinnedShortcut == null) { // The shortcut is no longer valid. c.markDeleted("Pinned shortcut not found"); diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java index 0639a6cbe2..7e7bfb398f 100644 --- a/src/com/android/launcher3/model/ModelDelegate.java +++ b/src/com/android/launcher3/model/ModelDelegate.java @@ -20,6 +20,7 @@ import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermis import android.content.Context; import android.content.pm.ShortcutInfo; +import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import com.android.launcher3.LauncherAppState; @@ -68,9 +69,7 @@ public class ModelDelegate implements ResourceBasedOverride { this.mContext = context; } - /** - * Called periodically to validate and update any data - */ + /** Called periodically to validate and update any data */ @WorkerThread public void validateData() { if (hasShortcutsPermission(mApp.getContext()) @@ -79,36 +78,32 @@ public class ModelDelegate implements ResourceBasedOverride { } } - /** - * Load hot seat items if any in the data model - */ + /** Load workspace items (for example, those in the hot seat) if any in the data model */ @WorkerThread - public void loadHotseatItems(UserManagerState ums, - Map pinnedShortcuts) { } + public void loadAndBindWorkspaceItems(@NonNull UserManagerState ums, + @NonNull BgDataModel.Callbacks[] callbacks, + @NonNull Map pinnedShortcuts) { } - /** - * Load all apps items if any in the data model - */ + /** Load all apps items if any in the data model */ @WorkerThread - public void loadAllAppsItems(UserManagerState ums, - Map pinnedShortcuts) { } + public void loadAndBindAllAppsItems(@NonNull UserManagerState ums, + @NonNull BgDataModel.Callbacks[] callbacks, + @NonNull Map pinnedShortcuts) { } - /** - * Load widget recommendation items if any in the data model - */ + /** Load other items like widget recommendations if any in the data model */ @WorkerThread - public void loadWidgetsRecommendationItems() { } + public void loadAndBindOtherItems(@NonNull BgDataModel.Callbacks[] callbacks) { } - /** - * Marks the ModelDelegate as active - */ + /** binds everything not bound by launcherBinder */ + @WorkerThread + public void bindAllModelExtras(@NonNull BgDataModel.Callbacks[] callbacks) { } + + /** Marks the ModelDelegate as active */ public void markActive() { } - /** - * Load String cache - */ + /** Load String cache */ @WorkerThread - public void loadStringCache(StringCache cache) { + public void loadStringCache(@NonNull StringCache cache) { cache.loadStrings(mContext); }