Loading src/com/android/launcher3/config/FeatureFlags.java +5 −0 Original line number Diff line number Diff line Loading @@ -378,6 +378,11 @@ public final class FeatureFlags { "Enables taskbar pinning to allow user to switch between transient and persistent " + "taskbar flavors"); public static final BooleanFlag ENABLE_WORKSPACE_LOADING_OPTIMIZATION = getDebugFlag(251502424, "ENABLE_WORKSPACE_LOADING_OPTIMIZATION", false, "load the current workspace screen " + "visible to the user before the rest rather than loading all of them at once." ); public static final BooleanFlag ENABLE_GRID_ONLY_OVERVIEW = getDebugFlag(270397206, "ENABLE_GRID_ONLY_OVERVIEW", false, "Enable a grid-only overview without a focused task."); Loading src/com/android/launcher3/model/BaseLauncherBinder.java +147 −3 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel.CallbackTask; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.BgDataModel.FixedContainerItems; Loading @@ -42,8 +43,10 @@ import com.android.launcher3.util.RunnableList; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; /** Loading Loading @@ -77,6 +80,36 @@ public abstract class BaseLauncherBinder { * Binds all loaded data to actual views on the main thread. */ public void bindWorkspace(boolean incrementBindId) { if (FeatureFlags.ENABLE_WORKSPACE_LOADING_OPTIMIZATION.get()) { DisjointWorkspaceBinder workspaceBinder = initWorkspaceBinder(incrementBindId, mBgDataModel.collectWorkspaceScreens()); workspaceBinder.bindCurrentWorkspacePages(); workspaceBinder.bindOtherWorkspacePages(); } else { bindWorkspaceAllAtOnce(incrementBindId); } } /** * Initializes the WorkspaceBinder for binding. * * @param incrementBindId this is used to stop previously started binding tasks that are * obsolete but still queued. * @param workspacePages this allows the Launcher to add the correct workspace screens. */ public DisjointWorkspaceBinder initWorkspaceBinder(boolean incrementBindId, IntArray workspacePages) { synchronized (mBgDataModel) { if (incrementBindId) { mBgDataModel.lastBindId++; } mMyBindingId = mBgDataModel.lastBindId; return new DisjointWorkspaceBinder(workspacePages); } } private void bindWorkspaceAllAtOnce(boolean incrementBindId) { // Save a copy of all the bg-thread collections ArrayList<ItemInfo> workspaceItems = new ArrayList<>(); ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>(); Loading @@ -95,7 +128,7 @@ public abstract class BaseLauncherBinder { } for (Callbacks cb : mCallbacksList) { new WorkspaceBinder(cb, mUiExecutor, mApp, mBgDataModel, mMyBindingId, new UnifiedWorkspaceBinder(cb, mUiExecutor, mApp, mBgDataModel, mMyBindingId, workspaceItems, appWidgets, extraItems, orderedScreenIds).bind(); } } Loading Loading @@ -180,7 +213,7 @@ public abstract class BaseLauncherBinder { return idleLock; } private class WorkspaceBinder { private class UnifiedWorkspaceBinder { private final Executor mUiExecutor; private final Callbacks mCallbacks; Loading @@ -194,7 +227,7 @@ public abstract class BaseLauncherBinder { private final IntArray mOrderedScreenIds; private final ArrayList<FixedContainerItems> mExtraItems; WorkspaceBinder(Callbacks callbacks, UnifiedWorkspaceBinder(Callbacks callbacks, Executor uiExecutor, LauncherAppState app, BgDataModel bgDataModel, Loading Loading @@ -320,4 +353,115 @@ public abstract class BaseLauncherBinder { }); } } private class DisjointWorkspaceBinder { private final IntArray mOrderedScreenIds; private final IntSet mCurrentScreenIds = new IntSet(); private final Set<Integer> mBoundItemIds = new HashSet<>(); protected DisjointWorkspaceBinder(IntArray orderedScreenIds) { mOrderedScreenIds = orderedScreenIds; for (Callbacks cb : mCallbacksList) { mCurrentScreenIds.addAll(cb.getPagesToBindSynchronously(orderedScreenIds)); } if (mCurrentScreenIds.size() == 0) { mCurrentScreenIds.add(Workspace.FIRST_SCREEN_ID); } } /** * Binds the currently loaded items in the Data Model. Also signals to the Callbacks[] * that these items have been bound and their respective screens are ready to be shown. * * If this method is called after all the items on the workspace screen have already been * loaded, it will bind all workspace items immediately, and bindOtherWorkspacePages() will * not bind any items. */ protected void bindCurrentWorkspacePages() { // Save a copy of all the bg-thread collections ArrayList<ItemInfo> workspaceItems; ArrayList<LauncherAppWidgetInfo> appWidgets; synchronized (mBgDataModel) { workspaceItems = new ArrayList<>(mBgDataModel.workspaceItems); appWidgets = new ArrayList<>(mBgDataModel.appWidgets); } workspaceItems.forEach(it -> mBoundItemIds.add(it.id)); appWidgets.forEach(it -> mBoundItemIds.add(it.id)); sortWorkspaceItemsSpatially(mApp.getInvariantDeviceProfile(), workspaceItems); // Tell the workspace that we're about to start binding items executeCallbacksTask(c -> { c.clearPendingBinds(); c.startBinding(); }, mUiExecutor); // Bind workspace screens executeCallbacksTask(c -> c.bindScreens(mOrderedScreenIds), mUiExecutor); bindWorkspaceItems(workspaceItems); bindAppWidgets(appWidgets); executeCallbacksTask(c -> { MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); c.onInitialBindComplete(mCurrentScreenIds, new RunnableList()); }, mUiExecutor); } protected void bindOtherWorkspacePages() { // Save a copy of all the bg-thread collections ArrayList<ItemInfo> workspaceItems; ArrayList<LauncherAppWidgetInfo> appWidgets; synchronized (mBgDataModel) { workspaceItems = new ArrayList<>(mBgDataModel.workspaceItems); appWidgets = new ArrayList<>(mBgDataModel.appWidgets); } workspaceItems.removeIf(it -> mBoundItemIds.contains(it.id)); appWidgets.removeIf(it -> mBoundItemIds.contains(it.id)); sortWorkspaceItemsSpatially(mApp.getInvariantDeviceProfile(), workspaceItems); bindWorkspaceItems(workspaceItems); bindAppWidgets(appWidgets); executeCallbacksTask(c -> c.finishBindingItems(mCurrentScreenIds), mUiExecutor); mUiExecutor.execute(() -> { MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); ItemInstallQueue.INSTANCE.get(mApp.getContext()) .resumeModelPush(FLAG_LOADER_RUNNING); }); for (Callbacks cb : mCallbacksList) { cb.bindStringCache(mBgDataModel.stringCache.clone()); } } private void bindWorkspaceItems(final ArrayList<ItemInfo> workspaceItems) { // Bind the workspace items int count = workspaceItems.size(); for (int i = 0; i < count; i += ITEMS_CHUNK) { final int start = i; final int chunkSize = (i + ITEMS_CHUNK <= count) ? ITEMS_CHUNK : (count - i); executeCallbacksTask( c -> c.bindItems(workspaceItems.subList(start, start + chunkSize), false), mUiExecutor); } } private void bindAppWidgets(List<LauncherAppWidgetInfo> appWidgets) { // Bind the widgets, one at a time int count = appWidgets.size(); for (int i = 0; i < count; i++) { final ItemInfo widget = appWidgets.get(i); executeCallbacksTask( c -> c.bindItems(Collections.singletonList(widget), false), mUiExecutor); } } } } Loading
src/com/android/launcher3/config/FeatureFlags.java +5 −0 Original line number Diff line number Diff line Loading @@ -378,6 +378,11 @@ public final class FeatureFlags { "Enables taskbar pinning to allow user to switch between transient and persistent " + "taskbar flavors"); public static final BooleanFlag ENABLE_WORKSPACE_LOADING_OPTIMIZATION = getDebugFlag(251502424, "ENABLE_WORKSPACE_LOADING_OPTIMIZATION", false, "load the current workspace screen " + "visible to the user before the rest rather than loading all of them at once." ); public static final BooleanFlag ENABLE_GRID_ONLY_OVERVIEW = getDebugFlag(270397206, "ENABLE_GRID_ONLY_OVERVIEW", false, "Enable a grid-only overview without a focused task."); Loading
src/com/android/launcher3/model/BaseLauncherBinder.java +147 −3 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherModel.CallbackTask; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Workspace; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.BgDataModel.Callbacks; import com.android.launcher3.model.BgDataModel.FixedContainerItems; Loading @@ -42,8 +43,10 @@ import com.android.launcher3.util.RunnableList; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.Executor; /** Loading Loading @@ -77,6 +80,36 @@ public abstract class BaseLauncherBinder { * Binds all loaded data to actual views on the main thread. */ public void bindWorkspace(boolean incrementBindId) { if (FeatureFlags.ENABLE_WORKSPACE_LOADING_OPTIMIZATION.get()) { DisjointWorkspaceBinder workspaceBinder = initWorkspaceBinder(incrementBindId, mBgDataModel.collectWorkspaceScreens()); workspaceBinder.bindCurrentWorkspacePages(); workspaceBinder.bindOtherWorkspacePages(); } else { bindWorkspaceAllAtOnce(incrementBindId); } } /** * Initializes the WorkspaceBinder for binding. * * @param incrementBindId this is used to stop previously started binding tasks that are * obsolete but still queued. * @param workspacePages this allows the Launcher to add the correct workspace screens. */ public DisjointWorkspaceBinder initWorkspaceBinder(boolean incrementBindId, IntArray workspacePages) { synchronized (mBgDataModel) { if (incrementBindId) { mBgDataModel.lastBindId++; } mMyBindingId = mBgDataModel.lastBindId; return new DisjointWorkspaceBinder(workspacePages); } } private void bindWorkspaceAllAtOnce(boolean incrementBindId) { // Save a copy of all the bg-thread collections ArrayList<ItemInfo> workspaceItems = new ArrayList<>(); ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>(); Loading @@ -95,7 +128,7 @@ public abstract class BaseLauncherBinder { } for (Callbacks cb : mCallbacksList) { new WorkspaceBinder(cb, mUiExecutor, mApp, mBgDataModel, mMyBindingId, new UnifiedWorkspaceBinder(cb, mUiExecutor, mApp, mBgDataModel, mMyBindingId, workspaceItems, appWidgets, extraItems, orderedScreenIds).bind(); } } Loading Loading @@ -180,7 +213,7 @@ public abstract class BaseLauncherBinder { return idleLock; } private class WorkspaceBinder { private class UnifiedWorkspaceBinder { private final Executor mUiExecutor; private final Callbacks mCallbacks; Loading @@ -194,7 +227,7 @@ public abstract class BaseLauncherBinder { private final IntArray mOrderedScreenIds; private final ArrayList<FixedContainerItems> mExtraItems; WorkspaceBinder(Callbacks callbacks, UnifiedWorkspaceBinder(Callbacks callbacks, Executor uiExecutor, LauncherAppState app, BgDataModel bgDataModel, Loading Loading @@ -320,4 +353,115 @@ public abstract class BaseLauncherBinder { }); } } private class DisjointWorkspaceBinder { private final IntArray mOrderedScreenIds; private final IntSet mCurrentScreenIds = new IntSet(); private final Set<Integer> mBoundItemIds = new HashSet<>(); protected DisjointWorkspaceBinder(IntArray orderedScreenIds) { mOrderedScreenIds = orderedScreenIds; for (Callbacks cb : mCallbacksList) { mCurrentScreenIds.addAll(cb.getPagesToBindSynchronously(orderedScreenIds)); } if (mCurrentScreenIds.size() == 0) { mCurrentScreenIds.add(Workspace.FIRST_SCREEN_ID); } } /** * Binds the currently loaded items in the Data Model. Also signals to the Callbacks[] * that these items have been bound and their respective screens are ready to be shown. * * If this method is called after all the items on the workspace screen have already been * loaded, it will bind all workspace items immediately, and bindOtherWorkspacePages() will * not bind any items. */ protected void bindCurrentWorkspacePages() { // Save a copy of all the bg-thread collections ArrayList<ItemInfo> workspaceItems; ArrayList<LauncherAppWidgetInfo> appWidgets; synchronized (mBgDataModel) { workspaceItems = new ArrayList<>(mBgDataModel.workspaceItems); appWidgets = new ArrayList<>(mBgDataModel.appWidgets); } workspaceItems.forEach(it -> mBoundItemIds.add(it.id)); appWidgets.forEach(it -> mBoundItemIds.add(it.id)); sortWorkspaceItemsSpatially(mApp.getInvariantDeviceProfile(), workspaceItems); // Tell the workspace that we're about to start binding items executeCallbacksTask(c -> { c.clearPendingBinds(); c.startBinding(); }, mUiExecutor); // Bind workspace screens executeCallbacksTask(c -> c.bindScreens(mOrderedScreenIds), mUiExecutor); bindWorkspaceItems(workspaceItems); bindAppWidgets(appWidgets); executeCallbacksTask(c -> { MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); c.onInitialBindComplete(mCurrentScreenIds, new RunnableList()); }, mUiExecutor); } protected void bindOtherWorkspacePages() { // Save a copy of all the bg-thread collections ArrayList<ItemInfo> workspaceItems; ArrayList<LauncherAppWidgetInfo> appWidgets; synchronized (mBgDataModel) { workspaceItems = new ArrayList<>(mBgDataModel.workspaceItems); appWidgets = new ArrayList<>(mBgDataModel.appWidgets); } workspaceItems.removeIf(it -> mBoundItemIds.contains(it.id)); appWidgets.removeIf(it -> mBoundItemIds.contains(it.id)); sortWorkspaceItemsSpatially(mApp.getInvariantDeviceProfile(), workspaceItems); bindWorkspaceItems(workspaceItems); bindAppWidgets(appWidgets); executeCallbacksTask(c -> c.finishBindingItems(mCurrentScreenIds), mUiExecutor); mUiExecutor.execute(() -> { MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); ItemInstallQueue.INSTANCE.get(mApp.getContext()) .resumeModelPush(FLAG_LOADER_RUNNING); }); for (Callbacks cb : mCallbacksList) { cb.bindStringCache(mBgDataModel.stringCache.clone()); } } private void bindWorkspaceItems(final ArrayList<ItemInfo> workspaceItems) { // Bind the workspace items int count = workspaceItems.size(); for (int i = 0; i < count; i += ITEMS_CHUNK) { final int start = i; final int chunkSize = (i + ITEMS_CHUNK <= count) ? ITEMS_CHUNK : (count - i); executeCallbacksTask( c -> c.bindItems(workspaceItems.subList(start, start + chunkSize), false), mUiExecutor); } } private void bindAppWidgets(List<LauncherAppWidgetInfo> appWidgets) { // Bind the widgets, one at a time int count = appWidgets.size(); for (int i = 0; i < count; i++) { final ItemInfo widget = appWidgets.get(i); executeCallbacksTask( c -> c.bindItems(Collections.singletonList(widget), false), mUiExecutor); } } } }