Moving various launcher binding logic, outside LauncherModel
This brings the BgCallbacks closer to a repository pattern making is easier to switch eventually
Bug: 390572144
Flag: EXEMPT refactor
Test: Updated AsyncBindingTest to use real ModelCalbacks
Change-Id: I9c932b00ea8ac7330473b9c0f5d778453fe7a390
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
index b77c43f..7c53360 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduController.java
@@ -33,7 +33,6 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.util.IntArray;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.Snackbar;
@@ -57,7 +56,6 @@
private HotseatEduDialog mActiveDialog;
private ArrayList<ItemInfo> mNewItems = new ArrayList<>();
- private IntArray mNewScreens = null;
HotseatEduController(Launcher launcher) {
mLauncher = launcher;
@@ -96,7 +94,6 @@
}
if (pageId == -1) {
pageId = mLauncher.getModel().getModelDbController().getNewScreenId();
- mNewScreens = IntArray.wrap(pageId);
}
boolean isPortrait = !mLauncher.getDeviceProfile().isVerticalBarLayout();
int hotseatItemsNum = mLauncher.getDeviceProfile().numShownHotseatIcons;
@@ -117,18 +114,7 @@
void moveHotseatItems() {
mHotseat.removeAllViewsInLayout();
if (!mNewItems.isEmpty()) {
- int lastPage = mNewItems.get(mNewItems.size() - 1).screenId;
- ArrayList<ItemInfo> animated = new ArrayList<>();
- ArrayList<ItemInfo> nonAnimated = new ArrayList<>();
-
- for (ItemInfo info : mNewItems) {
- if (info.screenId == lastPage) {
- animated.add(info);
- } else {
- nonAnimated.add(info);
- }
- }
- mLauncher.bindAppsAdded(mNewScreens, nonAnimated, animated);
+ mLauncher.bindItemsAdded(mNewItems);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 836c06c..b610f67 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -29,12 +29,12 @@
import com.android.launcher3.celllayout.CellInfo;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
+import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.taskbar.TaskbarView.TaskbarLayoutParams;
import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.PackageUserKey;
@@ -42,7 +42,6 @@
import com.android.quickstep.util.GroupTask;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -68,7 +67,6 @@
// Used to defer any UI updates during the SUW unstash animation.
private boolean mDeferUpdatesForSUW;
private Runnable mDeferredUpdates;
- private boolean mBindingItems = false;
public TaskbarModelCallbacks(
TaskbarActivityContext context, TaskbarView container) {
@@ -81,31 +79,25 @@
}
@Override
- public void startBinding() {
- mBindingItems = true;
+ public void bindCompleteModel(IntSparseArrayMap<ItemInfo> itemIdMap,
+ List<FixedContainerItems> extraItems, StringCache stringCache, boolean isBindingSync) {
mHotseatItems.clear();
mPredictedItems = Collections.emptyList();
- }
+ handleItemsAdded(itemIdMap);
- @Override
- public void finishBindingItems(IntSet pagesBoundFirst) {
- mBindingItems = false;
+ for (FixedContainerItems item: extraItems) {
+ if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) {
+ mPredictedItems = item.items;
+ } else if (item.containerId == Favorites.CONTAINER_PREDICTION) {
+ mControllers.taskbarAllAppsController.setPredictedApps(item.items);
+ }
+ }
commitItemsToUI();
}
@Override
- public void bindAppsAdded(IntArray newScreens, ArrayList<ItemInfo> addNotAnimated,
- ArrayList<ItemInfo> addAnimated) {
- boolean add1 = handleItemsAdded(addNotAnimated);
- boolean add2 = handleItemsAdded(addAnimated);
- if (add1 || add2) {
- commitItemsToUI();
- }
- }
-
- @Override
- public void bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons) {
- if (handleItemsAdded(shortcuts)) {
+ public void bindItemsAdded(List<ItemInfo> items) {
+ if (handleItemsAdded(items)) {
commitItemsToUI();
}
}
@@ -184,10 +176,6 @@
}
private void commitItemsToUI() {
- if (mBindingItems) {
- return;
- }
-
ItemInfo[] hotseatItemInfos =
new ItemInfo[mContext.getDeviceProfile().numShownHotseatIcons];
int predictionSize = mPredictedItems.size();
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
index 61d7c77..7be58fb 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
@@ -33,6 +33,8 @@
import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.dagger.LauncherComponentProvider.appComponent
import com.android.launcher3.model.BgDataModel
+import com.android.launcher3.model.BgDataModel.FixedContainerItems
+import com.android.launcher3.model.StringCache
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.TaskItemInfo
import com.android.launcher3.model.data.WorkspaceItemInfo
@@ -55,6 +57,7 @@
import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
import com.android.launcher3.util.AllModulesForTest
import com.android.launcher3.util.FakePrefsModule
+import com.android.launcher3.util.IntSparseArrayMap
import com.android.launcher3.util.LauncherMultivalentJUnit
import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
import com.android.launcher3.util.Preconditions.assertNotNull
@@ -566,7 +569,7 @@
taskbarView.updateItems(hotseatItems, recentAppsController.shownTasks)
modelCallback.recentAppsController = recentAppsController
context.baseContext.appComponent.launcherAppState.model.addCallbacksAndLoad(modelCallback)
- modelCallback.bindItems(hotseatItems.toList(), false)
+ modelCallback.bindItemsAdded(hotseatItems.toList())
return taskbarView
}
@@ -691,9 +694,16 @@
var hotseatItems = mutableListOf<WorkspaceItemInfo>()
var recentAppsController: TaskbarRecentAppsController? = null
- override fun bindItems(shortcuts: List<ItemInfo>, forceAnimateIcons: Boolean) {
+ override fun bindCompleteModel(
+ itemIdMap: IntSparseArrayMap<ItemInfo>,
+ extraItems: MutableList<FixedContainerItems>,
+ stringCache: StringCache,
+ isBindingSync: Boolean,
+ ) = bindItemsAdded(itemIdMap.toList())
+
+ override fun bindItemsAdded(items: List<ItemInfo>) {
runOnMainSync {
- shortcuts
+ items
.filter { item ->
item is WorkspaceItemInfo &&
!hotseatItems.any { it.targetPackage == item.targetPackage }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2d77762..0dd3ff2 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -189,7 +189,6 @@
import com.android.launcher3.dragndrop.LauncherDragController;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.icons.IconCache;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
@@ -202,6 +201,7 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent;
import com.android.launcher3.model.BgDataModel.Callbacks;
+import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.StringCache;
@@ -230,8 +230,8 @@
import com.android.launcher3.util.CannedAnimationCoordinator;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ContextTracker;
-import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInflater;
import com.android.launcher3.util.KeyboardShortcutsDelegate;
import com.android.launcher3.util.LauncherBindableItemsContainer;
@@ -285,7 +285,6 @@
import java.util.Set;
import java.util.function.Predicate;
import java.util.function.Supplier;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
@@ -372,7 +371,6 @@
private LauncherModel mModel;
private ModelWriter mModelWriter;
- private IconCache mIconCache;
private LauncherAccessibilityDelegate mAccessibilityDelegate;
private PopupDataProvider mPopupDataProvider;
@@ -525,7 +523,6 @@
initDeviceProfile(idp);
idp.addOnChangeListener(this);
mSharedPrefs = LauncherPrefs.getPrefs(this);
- mIconCache = app.getIconCache();
mAccessibilityDelegate = createAccessibilityDelegate();
initDragController();
@@ -2200,60 +2197,21 @@
}
@Override
- public IntSet getPagesToBindSynchronously(IntArray orderedScreenIds) {
- return mModelCallbacks.getPagesToBindSynchronously(orderedScreenIds);
+ public void bindCompleteModelAsync(IntSparseArrayMap<ItemInfo> itemIdMap,
+ List<FixedContainerItems> extraItems, StringCache stringCache, boolean isBindingSync) {
+ mModelCallbacks.bindCompleteModelAsync(itemIdMap, extraItems, stringCache, isBindingSync);
}
@Override
- public void startBinding() {
- mModelCallbacks.startBinding();
+ public void bindItemsAdded(@NonNull List<ItemInfo> items) {
+ mModelCallbacks.bindItemsAdded(items);
}
- @Override
- public void bindScreens(IntArray orderedScreenIds) {
- mModelCallbacks.bindScreens(orderedScreenIds);
- }
-
- /**
- * Remove odd number because they are already included when isTwoPanels and add the pair screen
- * if not present.
- */
- private IntArray filterTwoPanelScreenIds(IntArray orderedScreenIds) {
- IntSet screenIds = IntSet.wrap(orderedScreenIds);
- orderedScreenIds.forEach(screenId -> {
- if (screenId % 2 == 1) {
- screenIds.remove(screenId);
- // In case the pair is not added, add it
- if (!mWorkspace.containsScreenId(screenId - 1)) {
- screenIds.add(screenId - 1);
- }
- }
- });
- return screenIds.getArray();
- }
-
- @Override
- public void bindAppsAdded(IntArray newScreens, ArrayList<ItemInfo> addNotAnimated,
- ArrayList<ItemInfo> addAnimated) {
- mModelCallbacks.bindAppsAdded(newScreens, addNotAnimated, addAnimated);
- }
-
- /**
- * Bind the items start-end from the list.
- *
- * Implementation of the method from LauncherModel.Callbacks.
- */
- @Override
- public void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) {
- bindInflatedItems(items.stream()
- .map(i -> Pair.create(i, getItemInflater().inflateItem(i)))
- .collect(Collectors.toList()),
- forceAnimateIcons ? new AnimatorSet() : null);
- }
-
- @Override
- public void bindInflatedItems(List<Pair<ItemInfo, View>> items) {
- bindInflatedItems(items, null);
+ /** Inflates the binds the provided item using animation */
+ public void inflateAndBindItemWithAnimation(ItemInfo info) {
+ bindInflatedItems(
+ Collections.singletonList(Pair.create(info, getItemInflater().inflateItem(info))),
+ new AnimatorSet());
}
/**
@@ -2365,6 +2323,9 @@
return info;
}
+ /** Called when a new LauncherModel data binding is starting */
+ public void startBinding() { }
+
/**
* Call back when ModelCallbacks finish binding the Launcher data.
*/
@@ -2379,19 +2340,11 @@
.logCardinality(workspaceItemCount)
.logEnd(LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_WORKSPACE_LOADER_ASYNC);
}
- MAIN_EXECUTOR.getHandler().postAtFrontOfQueue(() -> {
+ MAIN_EXECUTOR.getHandler().postAtFrontOfQueue(() ->
mStartupLatencyLogger
.logEnd(LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION)
.log()
- .reset();
- });
- }
-
- @Override
- public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks,
- RunnableList onCompleteSignal, int workspaceItemCount, boolean isBindSync) {
- mModelCallbacks.onInitialBindComplete(boundPages, pendingTasks, onCompleteSignal,
- workspaceItemCount, isBindSync);
+ .reset());
if (mIsColdStartupAfterReboot) {
Trace.endAsyncSection(COLD_STARTUP_TRACE_METHOD_NAME,
COLD_STARTUP_TRACE_COOKIE);
@@ -2404,7 +2357,7 @@
* Implementation of the method from LauncherModel.Callbacks.
*/
public void finishBindingItems(IntSet pagesBoundFirst) {
- mModelCallbacks.finishBindingItems(pagesBoundFirst);
+ TestEventEmitter.sendEvent(TestEvent.WORKSPACE_FINISH_LOADING);
}
private boolean canAnimatePageChange() {
@@ -3056,7 +3009,6 @@
return super.getStatsLogManager().withDefaultInstanceId(mAllAppsSessionLogId);
}
- @Override
@NonNull
public ItemInflater<Launcher> getItemInflater() {
return mItemInflater;
diff --git a/src/com/android/launcher3/LauncherModel.kt b/src/com/android/launcher3/LauncherModel.kt
index 6d35de5..b3e9905 100644
--- a/src/com/android/launcher3/LauncherModel.kt
+++ b/src/com/android/launcher3/LauncherModel.kt
@@ -48,7 +48,6 @@
import com.android.launcher3.pm.UserCache
import com.android.launcher3.shortcuts.ShortcutRequest
import com.android.launcher3.util.DaggerSingletonTracker
-import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.util.PackageUserKey
import java.io.PrintWriter
@@ -281,9 +280,6 @@
val bindAllCallbacks = wasRunning || !bindDirectly || newCallbacks.isEmpty()
val callbacksList = if (bindAllCallbacks) callbacks else newCallbacks
if (callbacksList.isNotEmpty()) {
- // Clear any pending bind-runnables from the synchronized load process.
- callbacksList.forEach { MAIN_EXECUTOR.execute(it::clearPendingBinds) }
-
val launcherBinder = binderFactory.createBinder(callbacksList)
if (bindDirectly) {
// Divide the set of loaded items into those that we are binding synchronously,
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index cc5ac49..d0490c7 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -1,25 +1,39 @@
package com.android.launcher3
-import android.annotation.TargetApi
-import android.os.Build
+import android.animation.AnimatorSet
+import android.os.CancellationSignal
import android.os.Trace
import android.util.Log
+import android.util.Pair
+import androidx.annotation.AnyThread
import androidx.annotation.UiThread
+import androidx.annotation.VisibleForTesting
+import com.android.launcher3.BuildConfig.QSB_ON_FIRST_SCREEN
import com.android.launcher3.LauncherConstants.TraceEvents
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
import com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET
import com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID
import com.android.launcher3.allapps.AllAppsStore
import com.android.launcher3.config.FeatureFlags
-import com.android.launcher3.debug.TestEventEmitter
-import com.android.launcher3.debug.TestEventEmitter.TestEvent
import com.android.launcher3.model.BgDataModel
+import com.android.launcher3.model.BgDataModel.FixedContainerItems
+import com.android.launcher3.model.ItemInstallQueue
+import com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING
+import com.android.launcher3.model.ModelUtils.WIDGET_FILTER
+import com.android.launcher3.model.ModelUtils.currentScreenContentFilter
import com.android.launcher3.model.StringCache
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.popup.PopupContainerWithArrow
import com.android.launcher3.util.ComponentKey
+import com.android.launcher3.util.Executors
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.IntArray as LIntArray
+import com.android.launcher3.util.IntArray
import com.android.launcher3.util.IntSet as LIntSet
+import com.android.launcher3.util.IntSet
+import com.android.launcher3.util.IntSparseArrayMap
import com.android.launcher3.util.ItemInfoMatcher
import com.android.launcher3.util.PackageUserKey
import com.android.launcher3.util.Preconditions
@@ -28,19 +42,19 @@
import com.android.launcher3.util.ViewOnDrawExecutor
import com.android.launcher3.widget.PendingAddWidgetInfo
import com.android.launcher3.widget.model.WidgetsListBaseEntry
+import java.util.concurrent.Executor
+import java.util.concurrent.atomic.AtomicReference
import java.util.function.Predicate
-private const val TAG = "ModelCallbacks"
-
class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks {
- var synchronouslyBoundPages = LIntSet()
- var pagesToBindSynchronously = LIntSet()
+ private var activeBindTask = AtomicReference(CancellationSignal())
+ var synchronouslyBoundPages = IntSet()
+ var pagesToBindSynchronously = IntSet()
var stringCache: StringCache? = null
var pendingExecutor: ViewOnDrawExecutor? = null
-
var workspaceLoading = true
/**
@@ -48,7 +62,7 @@
*
* Implementation of the method from LauncherModel.Callbacks.
*/
- override fun startBinding() {
+ private fun startBinding() {
TraceHelper.INSTANCE.beginSection("startBinding")
// Floating panels (except the full widget sheet) are associated with individual icons. If
// we are starting a fresh bind, close all such panels as all the icons are about
@@ -74,11 +88,11 @@
" and is setting to ${launcher.deviceProfile.isVerticalBarLayout}",
)
launcher.hotseat?.resetLayout(launcher.deviceProfile.isVerticalBarLayout)
+ launcher.startBinding()
TraceHelper.INSTANCE.endSection()
}
- @TargetApi(Build.VERSION_CODES.S)
- override fun onInitialBindComplete(
+ private fun onInitialBindComplete(
boundPages: LIntSet,
pendingTasks: RunnableList,
onCompleteSignal: RunnableList,
@@ -123,7 +137,7 @@
*
* Implementation of the method from LauncherModel.Callbacks.
*/
- override fun finishBindingItems(pagesBoundFirst: LIntSet?) {
+ private fun finishBindingItems(pagesBoundFirst: IntSet?) {
TraceHelper.INSTANCE.beginSection("finishBindingItems")
val deviceProfile = launcher.deviceProfile
launcher.workspace.restoreInstanceStateForRemainingPages()
@@ -137,7 +151,7 @@
// Since we are just resetting the current page without user interaction,
// override the previous page so we don't log the page switch.
launcher.workspace.setCurrentPage(currentPage, currentPage /* overridePrevPage */)
- pagesToBindSynchronously = LIntSet()
+ pagesToBindSynchronously = IntSet()
// Cache one page worth of icons
launcher.viewCache.setCacheSize(
@@ -151,14 +165,14 @@
/*pause=*/ false,
deviceProfile.isTwoPanels,
)
- TestEventEmitter.sendEvent(TestEvent.WORKSPACE_FINISH_LOADING)
+ launcher.finishBindingItems(pagesBoundFirst)
}
/**
* Clear any pending bind callbacks. This is called when is loader is planning to perform a full
* rebind from scratch.
*/
- override fun clearPendingBinds() {
+ fun clearPendingBinds() {
pendingExecutor?.cancel() ?: return
pendingExecutor = null
@@ -213,7 +227,7 @@
.filter { workspace.isContainerSupported(it.container) }
.let {
if (it.isNotEmpty()) {
- launcher.bindItems(it, false)
+ bindItems(it, false)
}
}
workspace.stripEmptyScreens()
@@ -236,7 +250,7 @@
}
/** Returns the ids of the workspaces to bind. */
- override fun getPagesToBindSynchronously(orderedScreenIds: LIntArray): LIntSet {
+ private fun getPagesToBindSynchronously(orderedScreenIds: IntArray): IntSet {
// If workspace binding is still in progress, getCurrentPageScreenIds won't be
// accurate, and we should use mSynchronouslyBoundPages that's set during initial binding.
val visibleIds =
@@ -246,7 +260,7 @@
else -> synchronouslyBoundPages
}
// Launcher IntArray has the same name as Kotlin IntArray
- val result = LIntSet()
+ val result = IntSet()
if (visibleIds.isEmpty) {
return result
}
@@ -301,7 +315,7 @@
)
}
- override fun bindScreens(orderedScreenIds: LIntArray) {
+ private fun bindScreens(orderedScreenIds: LIntArray) {
launcher.workspace.pageIndicator.setPauseScroll(
/*pause=*/ true,
launcher.deviceProfile.isTwoPanels,
@@ -325,26 +339,38 @@
launcher.workspace.unlockWallpaperFromDefaultPageOnNextLayout()
}
- override fun bindAppsAdded(
- newScreens: LIntArray?,
- addNotAnimated: java.util.ArrayList<ItemInfo?>?,
- addAnimated: java.util.ArrayList<ItemInfo?>?,
- ) {
- // Add the new screens
- if (newScreens != null) {
- // newScreens can contain an empty right panel that is already bound, but not known
- // by BgDataModel.
- newScreens.removeAllValues(launcher.workspace.mScreenOrder)
- bindAddScreens(newScreens)
+ override fun bindItemsAdded(items: List<ItemInfo>) {
+ val newScreens = LIntSet()
+ val nonAnimatedItems = mutableListOf<ItemInfo>()
+ val animatedItems = mutableListOf<ItemInfo>()
+ val folderItems = mutableListOf<ItemInfo>()
+ val lastScreen =
+ items
+ .maxByOrNull { if (it.container == CONTAINER_DESKTOP) it.screenId else 0 }
+ ?.screenId ?: 0
+
+ items.forEach {
+ when (it.container) {
+ CONTAINER_HOTSEAT -> nonAnimatedItems.add(it)
+ CONTAINER_DESKTOP -> {
+ newScreens.add(it.screenId)
+ if (it.screenId == lastScreen) animatedItems.add(it)
+ else nonAnimatedItems.add(it)
+ }
+ else -> folderItems.add(it)
+ }
}
+ launcher.workspace.mScreenOrder.forEach { newScreens.remove(it) }
+ if (!newScreens.isEmpty) bindAddScreens(newScreens.array)
+
// We add the items without animation on non-visible pages, and with
// animations on the new page (which we will try and snap to).
- if (!addNotAnimated.isNullOrEmpty()) {
- launcher.bindItems(addNotAnimated, false)
+ if (nonAnimatedItems.isNotEmpty()) {
+ bindItems(nonAnimatedItems, false)
}
- if (!addAnimated.isNullOrEmpty()) {
- launcher.bindItems(addAnimated, true)
+ if (animatedItems.isNotEmpty()) {
+ bindItems(animatedItems, true)
}
// Remove the extra empty screen
@@ -398,5 +424,188 @@
launcher.appsView.updateWorkUI()
}
- override fun getItemInflater() = launcher.itemInflater
+ /** Bind the items start-end from the list. */
+ @VisibleForTesting
+ fun bindItems(items: List<ItemInfo>, forceAnimateIcons: Boolean) {
+ launcher.bindInflatedItems(
+ items.map { Pair.create(it, launcher.itemInflater.inflateItem(it)) },
+ if (forceAnimateIcons) AnimatorSet() else null,
+ )
+ }
+
+ @AnyThread
+ override fun bindCompleteModelAsync(
+ itemIdMap: IntSparseArrayMap<ItemInfo>,
+ extraItems: List<FixedContainerItems?>,
+ stringCache: StringCache,
+ isBindingSync: Boolean,
+ ) {
+ val taskTracker = CancellationSignal()
+ activeBindTask.getAndSet(taskTracker).cancel()
+
+ val inflater = launcher.itemInflater
+
+ fun executeCallbacksTask(executor: Executor = MAIN_EXECUTOR, task: () -> Unit) {
+ executor.execute {
+ if (taskTracker.isCanceled) {
+ Log.d(TAG, "Too many consecutive reloads, skipping obsolete data-bind")
+ } else {
+ task.invoke()
+ }
+ }
+ }
+
+ // Tries to inflate the items asynchronously and bind. Returns true on success or false if
+ // async-binding is not supported in this case
+ fun inflateAsyncAndBind(items: List<ItemInfo>, executor: Executor) {
+ if (taskTracker.isCanceled) {
+ Log.d(TAG, "Too many consecutive reloads, skipping obsolete view inflation")
+ return
+ }
+
+ val bindItems = items.map { Pair.create(it, inflater.inflateItem(it, null)) }
+ if (bindItems.isNotEmpty())
+ executeCallbacksTask(executor) { launcher.bindInflatedItems(bindItems, null) }
+ }
+
+ fun bindItemsInChunks(items: List<ItemInfo>, chuckSize: Int, executor: Executor) {
+ // Bind the workspace items
+ val itemCount = items.size
+ var i = 0
+ while (i < itemCount) {
+ val start = i
+ val end = (start + chuckSize).coerceAtMost(itemCount)
+ executeCallbacksTask(executor) { bindItems(items.subList(start, end), false) }
+ i = end
+ }
+ }
+
+ MAIN_EXECUTOR.execute { clearPendingBinds() }
+
+ val orderedScreenIds =
+ IntSet()
+ .apply {
+ itemIdMap.forEach { if (it.container == CONTAINER_DESKTOP) add(it.screenId) }
+ if ((QSB_ON_FIRST_SCREEN && !SHOULD_SHOW_FIRST_PAGE_WIDGET) || isEmpty)
+ add(Workspace.FIRST_SCREEN_ID)
+ }
+ .array
+ val currentScreenIds = getPagesToBindSynchronously(orderedScreenIds)
+
+ fun setupPendingBind(pendingExecutor: Executor) {
+ executeCallbacksTask(pendingExecutor) { launcher.bindStringCache(stringCache) }
+ executeCallbacksTask(pendingExecutor) { finishBindingItems(currentScreenIds) }
+ pendingExecutor.execute {
+ ItemInstallQueue.INSTANCE[launcher].resumeModelPush(FLAG_LOADER_RUNNING)
+ }
+ }
+
+ // Separate the items that are on the current screen, and all the other remaining items
+ val currentWorkspaceItems = ArrayList<ItemInfo>()
+ val otherWorkspaceItems = ArrayList<ItemInfo>()
+ val currentAppWidgets = ArrayList<ItemInfo>()
+ val otherAppWidgets = ArrayList<ItemInfo>()
+
+ val currentScreenCheck = currentScreenContentFilter(currentScreenIds)
+ itemIdMap.forEach { item: ItemInfo ->
+ if (currentScreenCheck.test(item)) {
+ (if (WIDGET_FILTER.test(item)) currentAppWidgets else currentWorkspaceItems).add(
+ item
+ )
+ } else if (item.container == CONTAINER_DESKTOP) {
+ (if (WIDGET_FILTER.test(item)) otherAppWidgets else otherWorkspaceItems).add(item)
+ }
+ }
+
+ sortWorkspaceItemsSpatially(currentWorkspaceItems)
+ sortWorkspaceItemsSpatially(otherWorkspaceItems)
+
+ // Tell the workspace that we're about to start binding items
+ executeCallbacksTask {
+ clearPendingBinds()
+ startBinding()
+ }
+
+ // Bind workspace screens
+ executeCallbacksTask { bindScreens(orderedScreenIds) }
+
+ // Load items on the current page.
+ if (Flags.enableWorkspaceInflation()) {
+ inflateAsyncAndBind(currentWorkspaceItems, MAIN_EXECUTOR)
+ inflateAsyncAndBind(currentAppWidgets, MAIN_EXECUTOR)
+ } else {
+ bindItemsInChunks(currentWorkspaceItems, ITEMS_CHUNK, MAIN_EXECUTOR)
+ bindItemsInChunks(currentAppWidgets, 1, MAIN_EXECUTOR)
+ }
+ extraItems.forEach {
+ it?.let { executeCallbacksTask { launcher.bindExtraContainerItems(it) } }
+ }
+
+ val pendingTasks = RunnableList()
+ val pendingExecutor = Executor { pendingTasks.add(it) }
+
+ val onCompleteSignal = RunnableList()
+ onCompleteSignal.add { Log.d(TAG, "Calling onCompleteSignal") }
+
+ if (Flags.enableWorkspaceInflation()) {
+ Log.d(TAG, "Starting async inflation")
+ Executors.MODEL_EXECUTOR.execute {
+ inflateAsyncAndBind(otherWorkspaceItems, pendingExecutor)
+ inflateAsyncAndBind(otherAppWidgets, pendingExecutor)
+ setupPendingBind(pendingExecutor)
+
+ // Wait for the async inflation to complete and then notify the completion
+ // signal on UI thread.
+ MAIN_EXECUTOR.execute { onCompleteSignal.executeAllAndDestroy() }
+ }
+ } else {
+ Log.d(TAG, "Starting sync inflation")
+ bindItemsInChunks(otherWorkspaceItems, ITEMS_CHUNK, pendingExecutor)
+ bindItemsInChunks(otherAppWidgets, 1, pendingExecutor)
+ setupPendingBind(pendingExecutor)
+ onCompleteSignal.executeAllAndDestroy()
+ }
+
+ val workspaceItemCount = itemIdMap.size()
+ executeCallbacksTask {
+ onInitialBindComplete(
+ currentScreenIds,
+ pendingTasks,
+ onCompleteSignal,
+ workspaceItemCount,
+ isBindingSync,
+ )
+ }
+ }
+
+ /**
+ * Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to right)
+ */
+ private fun sortWorkspaceItemsSpatially(workspaceItems: MutableList<ItemInfo>) {
+ val idp = launcher.deviceProfile.inv
+ val screenCols = idp.numColumns
+ val screenCellCount = idp.numColumns * idp.numRows
+ workspaceItems.sortWith { lhs: ItemInfo, rhs: ItemInfo ->
+ when {
+ // Between containers, order by hotseat, desktop
+ lhs.container != rhs.container -> lhs.container.compareTo(rhs.container)
+
+ // Within workspace, order by their spatial position in that container
+ lhs.container == CONTAINER_DESKTOP ->
+ compareValuesBy(lhs, rhs) {
+ it.screenId * screenCellCount + it.cellY * screenCols + it.cellX
+ }
+
+ // We currently use the screen id as the rank
+ lhs.container == CONTAINER_HOTSEAT -> lhs.screenId.compareTo(rhs.screenId)
+
+ else -> 0
+ }
+ }
+ }
+
+ companion object {
+ private const val TAG = "ModelCallbacks"
+ private const val ITEMS_CHUNK: Int = 6 // batch size for the workspace icons
+ }
}
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index e16a296..fd596bd 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -536,7 +536,7 @@
// Bind the item in next frame so that if a new workspace page was created,
// it will get laid out.
new Handler().post(() -> {
- mContext.bindItems(Collections.singletonList(item), true);
+ mContext.inflateAndBindItemWithAnimation(item);
announceConfirmation(R.string.item_moved);
});
return true;
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index c91e783..f71d505 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -28,7 +28,6 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.DeepShortcutView;
-import java.util.Collections;
import java.util.List;
/**
@@ -64,7 +63,7 @@
mContext.getModelWriter().addItemToDatabase(info,
LauncherSettings.Favorites.CONTAINER_DESKTOP,
screenId, coordinates[0], coordinates[1]);
- mContext.bindItems(Collections.singletonList(info), true);
+ mContext.inflateAndBindItemWithAnimation(info);
AbstractFloatingView.closeAllOpenViews(mContext);
}));
return true;
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index dfba4bb..abcc0cb 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -28,12 +28,10 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.LauncherModel.CallbackTask;
import com.android.launcher3.LauncherModel.ModelUpdateTask;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.logging.FileLog;
-import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.ItemInfo;
@@ -207,26 +205,7 @@
}
if (!addedItemsFinal.isEmpty()) {
- taskController.scheduleCallbackTask(new CallbackTask() {
- @Override
- public void execute(@NonNull Callbacks callbacks) {
- final ArrayList<ItemInfo> addAnimated = new ArrayList<>();
- final ArrayList<ItemInfo> addNotAnimated = new ArrayList<>();
- if (!addedItemsFinal.isEmpty()) {
- ItemInfo info = addedItemsFinal.get(addedItemsFinal.size() - 1);
- int lastScreenId = info.screenId;
- for (ItemInfo i : addedItemsFinal) {
- if (i.screenId == lastScreenId) {
- addAnimated.add(i);
- } else {
- addNotAnimated.add(i);
- }
- }
- }
- callbacks.bindAppsAdded(addedWorkspaceScreensFinal,
- addNotAnimated, addAnimated);
- }
- });
+ taskController.scheduleCallbackTask(cb -> cb.bindItemsAdded(addedItemsFinal));
}
}
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index 5b95e37..dc4b6f0 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -17,41 +17,24 @@
package com.android.launcher3.model;
import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED;
-import static com.android.launcher3.Flags.enableWorkspaceInflation;
-import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
-import static com.android.launcher3.model.ItemInstallQueue.FLAG_LOADER_RUNNING;
-import static com.android.launcher3.model.ModelUtils.WIDGET_FILTER;
-import static com.android.launcher3.model.ModelUtils.currentScreenContentFilter;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.content.Context;
import android.os.Trace;
import android.util.Log;
-import android.util.Pair;
-import android.view.View;
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherModel.CallbackTask;
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dagger.ApplicationContext;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.IntSparseArrayMap;
-import com.android.launcher3.util.ItemInflater;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.LooperIdleLock;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.RunnableList;
import com.android.launcher3.widget.model.WidgetsListBaseEntriesBuilder;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
@@ -61,13 +44,10 @@
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.concurrent.Executor;
-import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -76,12 +56,10 @@
public class BaseLauncherBinder {
protected static final String TAG = "LauncherBinder";
- private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons
protected final LooperExecutor mUiExecutor;
private final Context mContext;
- private final InvariantDeviceProfile mIDP;
private final LauncherModel mModel;
protected final BgDataModel mBgDataModel;
private final AllAppsList mBgAllAppsList;
@@ -93,14 +71,12 @@
@AssistedInject
public BaseLauncherBinder(
@ApplicationContext Context context,
- InvariantDeviceProfile idp,
LauncherModel model,
BgDataModel dataModel,
AllAppsList allAppsList,
@Assisted Callbacks[] callbacksList) {
mUiExecutor = MAIN_EXECUTOR;
mContext = context;
- mIDP = idp;
mModel = model;
mBgDataModel = dataModel;
mBgAllAppsList = allAppsList;
@@ -115,24 +91,22 @@
try {
// Save a copy of all the bg-thread collections
IntSparseArrayMap<ItemInfo> itemsIdMap;
- final IntArray orderedScreenIds = new IntArray();
ArrayList<FixedContainerItems> extraItems = new ArrayList<>();
- final int workspaceItemCount;
+ StringCache stringCache;
+
synchronized (mBgDataModel) {
itemsIdMap = mBgDataModel.itemsIdMap.clone();
- orderedScreenIds.addAll(mBgDataModel.collectWorkspaceScreens());
mBgDataModel.extraItems.forEach(extraItems::add);
if (incrementBindId) {
mBgDataModel.lastBindId++;
mBgDataModel.lastLoadId = mModel.getLastLoadId();
}
mMyBindingId = mBgDataModel.lastBindId;
- workspaceItemCount = mBgDataModel.itemsIdMap.size();
+ stringCache = mBgDataModel.stringCache.clone();
}
for (Callbacks cb : mCallbacksList) {
- new UnifiedWorkspaceBinder(cb, itemsIdMap, extraItems, orderedScreenIds)
- .bind(isBindSync, workspaceItemCount);
+ cb.bindCompleteModelAsync(itemsIdMap, extraItems, stringCache, isBindSync);
}
} finally {
Trace.endSection();
@@ -190,41 +164,6 @@
executeCallbacksTask(c -> c.bindSmartspaceWidget(), mUiExecutor);
}
- /**
- * Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to right)
- */
- protected void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {
- final int screenCols = mIDP.numColumns;
- final int screenCellCount = mIDP.numColumns * mIDP.numRows;
- Collections.sort(workspaceItems, (lhs, rhs) -> {
- if (lhs.container == rhs.container) {
- // Within containers, order by their spatial position in that container
- switch (lhs.container) {
- case LauncherSettings.Favorites.CONTAINER_DESKTOP: {
- int lr = (lhs.screenId * screenCellCount + lhs.cellY * screenCols
- + lhs.cellX);
- int rr = (rhs.screenId * screenCellCount + +rhs.cellY * screenCols
- + rhs.cellX);
- return Integer.compare(lr, rr);
- }
- case LauncherSettings.Favorites.CONTAINER_HOTSEAT: {
- // We currently use the screen id as the rank
- return Integer.compare(lhs.screenId, rhs.screenId);
- }
- default:
- if (FeatureFlags.IS_STUDIO_BUILD) {
- throw new RuntimeException(
- "Unexpected container type when sorting workspace items.");
- }
- return 0;
- }
- } else {
- // Between containers, order by hotseat, desktop
- return Integer.compare(lhs.container, rhs.container);
- }
- });
- }
-
protected void executeCallbacksTask(CallbackTask task, Executor executor) {
executor.execute(() -> {
if (mMyBindingId != mBgDataModel.lastBindId) {
@@ -248,152 +187,6 @@
}
return idleLock;
}
-
- private class UnifiedWorkspaceBinder {
-
- private final Callbacks mCallbacks;
-
- private final IntSparseArrayMap<ItemInfo> mItemIdMap;
- private final IntArray mOrderedScreenIds;
- private final ArrayList<FixedContainerItems> mExtraItems;
-
- UnifiedWorkspaceBinder(
- Callbacks callbacks,
- IntSparseArrayMap<ItemInfo> itemIdMap,
- ArrayList<FixedContainerItems> extraItems,
- IntArray orderedScreenIds) {
- mCallbacks = callbacks;
- mItemIdMap = itemIdMap;
- mExtraItems = extraItems;
- mOrderedScreenIds = orderedScreenIds;
- }
-
- private void bind(boolean isBindSync, int workspaceItemCount) {
- final IntSet currentScreenIds =
- mCallbacks.getPagesToBindSynchronously(mOrderedScreenIds);
- Objects.requireNonNull(currentScreenIds, "Null screen ids provided by " + mCallbacks);
-
- // Separate the items that are on the current screen, and all the other remaining items
- ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<>();
- ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<>();
- ArrayList<ItemInfo> currentAppWidgets = new ArrayList<>();
- ArrayList<ItemInfo> otherAppWidgets = new ArrayList<>();
-
- Predicate<ItemInfo> currentScreenCheck = currentScreenContentFilter(currentScreenIds);
- mItemIdMap.forEach(item -> {
- if (currentScreenCheck.test(item)) {
- (WIDGET_FILTER.test(item) ? currentAppWidgets : currentWorkspaceItems)
- .add(item);
- } else if (item.container == CONTAINER_DESKTOP) {
- (WIDGET_FILTER.test(item) ? otherAppWidgets : otherWorkspaceItems).add(item);
- }
- });
- sortWorkspaceItemsSpatially(currentWorkspaceItems);
- sortWorkspaceItemsSpatially(otherWorkspaceItems);
-
- // 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);
-
- ItemInflater inflater = mCallbacks.getItemInflater();
-
- // Load items on the current page.
- if (enableWorkspaceInflation() && inflater != null) {
- inflateAsyncAndBind(currentWorkspaceItems, inflater, mUiExecutor);
- inflateAsyncAndBind(currentAppWidgets, inflater, mUiExecutor);
- } else {
- bindItemsInChunks(currentWorkspaceItems, ITEMS_CHUNK, mUiExecutor);
- bindItemsInChunks(currentAppWidgets, 1, mUiExecutor);
- }
- mExtraItems.forEach(item ->
- executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor));
-
- RunnableList pendingTasks = new RunnableList();
- Executor pendingExecutor = pendingTasks::add;
-
- RunnableList onCompleteSignal = new RunnableList();
- onCompleteSignal.add(() -> Log.d(TAG, "Calling onCompleteSignal"));
-
- if (enableWorkspaceInflation() && inflater != null) {
- Log.d(TAG, "Starting async inflation");
- MODEL_EXECUTOR.execute(() -> {
- inflateAsyncAndBind(otherWorkspaceItems, inflater, pendingExecutor);
- inflateAsyncAndBind(otherAppWidgets, inflater, pendingExecutor);
- setupPendingBind(currentScreenIds, pendingExecutor);
-
- // Wait for the async inflation to complete and then notify the completion
- // signal on UI thread.
- MAIN_EXECUTOR.execute(onCompleteSignal::executeAllAndDestroy);
- });
- } else {
- Log.d(TAG, "Starting sync inflation");
- bindItemsInChunks(otherWorkspaceItems, ITEMS_CHUNK, pendingExecutor);
- bindItemsInChunks(otherAppWidgets, 1, pendingExecutor);
- setupPendingBind(currentScreenIds, pendingExecutor);
- onCompleteSignal.executeAllAndDestroy();
- }
-
- executeCallbacksTask(c -> c.onInitialBindComplete(currentScreenIds, pendingTasks,
- onCompleteSignal, workspaceItemCount, isBindSync), mUiExecutor);
- }
-
- private void setupPendingBind(
- IntSet currentScreenIds,
- Executor pendingExecutor) {
- StringCache cacheClone = mBgDataModel.stringCache.clone();
- executeCallbacksTask(c -> c.bindStringCache(cacheClone), pendingExecutor);
-
- executeCallbacksTask(c -> c.finishBindingItems(currentScreenIds), pendingExecutor);
- pendingExecutor.execute(() -> ItemInstallQueue.INSTANCE.get(mContext)
- .resumeModelPush(FLAG_LOADER_RUNNING));
- }
-
- /**
- * Tries to inflate the items asynchronously and bind. Returns true on success or false if
- * async-binding is not supported in this case.
- */
- private void inflateAsyncAndBind(
- List<ItemInfo> items, @NonNull ItemInflater inflater, Executor executor) {
- if (mMyBindingId != mBgDataModel.lastBindId) {
- Log.d(TAG, "Too many consecutive reloads, skipping obsolete view inflation");
- return;
- }
-
- List<Pair<ItemInfo, View>> bindItems = items.stream()
- .map(i -> Pair.create(i, inflater.inflateItem(i, null)))
- .collect(Collectors.toList());
- executeCallbacksTask(c -> c.bindInflatedItems(bindItems), executor);
- }
-
- private void bindItemsInChunks(
- List<ItemInfo> workspaceItems, int chunkCount, Executor executor) {
- // Bind the workspace items
- int count = workspaceItems.size();
- for (int i = 0; i < count; i += chunkCount) {
- final int start = i;
- final int chunkSize = (i + chunkCount <= count) ? chunkCount : (count - i);
- executeCallbacksTask(
- c -> c.bindItems(workspaceItems.subList(start, start + chunkSize), false),
- executor);
- }
- }
-
- protected void executeCallbacksTask(CallbackTask task, Executor executor) {
- executor.execute(() -> {
- if (mMyBindingId != mBgDataModel.lastBindId) {
- Log.d(TAG, "Too many consecutive reloads, skipping obsolete data-bind");
- return;
- }
- task.execute(mCallbacks);
- });
- }
- }
-
@AssistedFactory
public interface BaseLauncherBinderFactory {
BaseLauncherBinder createBinder(Callbacks[] callbacks);
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 9189eb8..5e0f8a0 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -25,6 +25,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
import static com.android.launcher3.shortcuts.ShortcutRequest.PINNED;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
@@ -35,9 +36,8 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
-import android.view.View;
+import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -66,9 +66,7 @@
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.IntSparseArrayMap;
-import com.android.launcher3.util.ItemInflater;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.RunnableList;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import java.io.PrintWriter;
@@ -439,41 +437,31 @@
int FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED = 1 << 4;
/**
- * Returns an IntSet of page ids to bind first, synchronously if possible
- * or an empty IntSet
- * @param orderedScreenIds All the page ids to be bound
+ * Does a complete model rebind. The callback can be called on any thread and it is up to
+ * the client to move the executor to appropriate thread
*/
- @NonNull
- default IntSet getPagesToBindSynchronously(IntArray orderedScreenIds) {
- return new IntSet();
+ @AnyThread
+ default void bindCompleteModelAsync(IntSparseArrayMap<ItemInfo> itemIdMap,
+ List<FixedContainerItems> extraItems, StringCache stringCache,
+ boolean isBindingSync) {
+ MAIN_EXECUTOR.execute(
+ () -> bindCompleteModel(itemIdMap, extraItems, stringCache, isBindingSync));
}
- default void clearPendingBinds() { }
- default void startBinding() { }
+ default void bindCompleteModel(IntSparseArrayMap<ItemInfo> itemIdMap,
+ List<FixedContainerItems> extraItems, StringCache stringCache,
+ boolean isBindingSync) { }
- @Nullable
- default ItemInflater getItemInflater() {
- return null;
- }
-
- default void bindItems(@NonNull List<ItemInfo> shortcuts, boolean forceAnimateIcons) { }
- /** Alternate method to bind preinflated views */
- default void bindInflatedItems(@NonNull List<Pair<ItemInfo, View>> items) { }
-
- default void bindScreens(IntArray orderedScreenIds) { }
- default void finishBindingItems(IntSet pagesBoundFirst) { }
- default void bindAppsAdded(IntArray newScreens,
- ArrayList<ItemInfo> addNotAnimated, ArrayList<ItemInfo> addAnimated) { }
+ default void bindItemsAdded(@NonNull List<ItemInfo> items) { }
+ /** Called when a runtime property of the ItemInfo is updated due to some system event */
+ default void bindItemsUpdated(Set<ItemInfo> updates) { }
+ default void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { }
/**
* Binds updated incremental download progress
*/
default void bindIncrementalDownloadProgressUpdated(AppInfo app) { }
- /** Called when a runtime property of the ItemInfo is updated due to some system event */
- default void bindItemsUpdated(Set<ItemInfo> updates) { }
- default void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { }
-
/**
* Binds the app widgets to the providers that share widgets with the UI.
*/
@@ -481,14 +469,6 @@
default void bindSmartspaceWidget() { }
- /** Called when workspace has been bound. */
- default void onInitialBindComplete(@NonNull IntSet boundPages,
- @NonNull RunnableList pendingTasks,
- @NonNull RunnableList onCompleteSignal,
- int workspaceItemCount, boolean isBindSync) {
- pendingTasks.executeAllAndDestroy();
- }
-
default void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMap) { }
/**
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 01e1730..d591a75 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -242,7 +242,7 @@
updateItemInfoProps(item, container, screenId, cellX, cellY);
item.id = mModel.getModelDbController().generateNewItemId();
- notifyOtherCallbacks(c -> c.bindItems(Collections.singletonList(item), false));
+ notifyOtherCallbacks(c -> c.bindItemsAdded(Collections.singletonList(item)));
ModelVerifier verifier = new ModelVerifier();
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
index 54efccd..8c0f837 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
@@ -235,11 +235,6 @@
}
@Override
- public void startBinding() {
- mDragController.cancelDrag();
- }
-
- @Override
public void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMap) {
mPopupDataProvider.setDeepShortcutMap(deepShortcutMap);
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
index 6d366db..d19048d 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
@@ -61,8 +61,7 @@
val addedItems = testAddItems(nonEmptyScreenIds, itemToAdd)
assertThat(addedItems.size).isEqualTo(1)
- assertThat(addedItems.first().itemInfo.screenId).isEqualTo(1)
- assertThat(addedItems.first().isAnimated).isTrue()
+ assertThat(addedItems.first().screenId).isEqualTo(1)
verifyItemSpaceFinderCall(nonEmptyScreenIds, numberOfExpectedCall = 1)
}
@@ -75,8 +74,7 @@
val addedItems = testAddItems(nonEmptyScreenIds, *itemsToAdd)
assertThat(addedItems.size).isEqualTo(1)
- assertThat(addedItems.first().itemInfo.screenId).isEqualTo(1)
- assertThat(addedItems.first().isAnimated).isTrue()
+ assertThat(addedItems.first().screenId).isEqualTo(1)
verifyItemSpaceFinderCall(nonEmptyScreenIds, numberOfExpectedCall = 1)
}
@@ -102,8 +100,7 @@
val addedItems = testAddItems(nonEmptyScreenIds, itemToAdd)
assertThat(addedItems.size).isEqualTo(1)
- assertThat(addedItems.first().itemInfo.screenId).isEqualTo(2)
- assertThat(addedItems.first().isAnimated).isTrue()
+ assertThat(addedItems.first().screenId).isEqualTo(2)
verifyItemSpaceFinderCall(nonEmptyScreenIds, numberOfExpectedCall = 1)
}
@@ -120,14 +117,12 @@
assertThat(addedItems.size).isEqualTo(3)
// Items that are added to the first screen should not be animated
- val itemsAddedToFirstScreen = addedItems.filter { it.itemInfo.screenId == 1 }
+ val itemsAddedToFirstScreen = addedItems.filter { it.screenId == 1 }
assertThat(itemsAddedToFirstScreen.size).isEqualTo(1)
- assertThat(itemsAddedToFirstScreen.first().isAnimated).isFalse()
// Items that are added to the second screen should be animated
- val itemsAddedToSecondScreen = addedItems.filter { it.itemInfo.screenId == 2 }
+ val itemsAddedToSecondScreen = addedItems.filter { it.screenId == 2 }
assertThat(itemsAddedToSecondScreen.size).isEqualTo(2)
- itemsAddedToSecondScreen.forEach { assertThat(it.isAnimated).isTrue() }
verifyItemSpaceFinderCall(nonEmptyScreenIds, numberOfExpectedCall = 3)
}
@@ -160,11 +155,11 @@
private fun testAddItems(
nonEmptyScreenIds: List<Int>,
vararg itemsToAdd: WorkspaceItemInfo,
- ): List<AddedItem> {
+ ): List<ItemInfo> {
setupWorkspaces(nonEmptyScreenIds)
val task = newTask(*itemsToAdd)
- val addedItems = mutableListOf<AddedItem>()
+ val addedItems = mutableListOf<ItemInfo>()
runOnExecutorSync(Executors.MODEL_EXECUTOR) {
mDataModelCallbacks.addedItems.clear()
@@ -187,18 +182,11 @@
.let { AddWorkspaceItemsTask(it, mWorkspaceItemSpaceFinder) }
}
-private data class AddedItem(val itemInfo: ItemInfo, val isAnimated: Boolean)
-
private class MyCallbacks : BgDataModel.Callbacks {
- val addedItems = mutableListOf<AddedItem>()
+ val addedItems = mutableListOf<ItemInfo>()
- override fun bindAppsAdded(
- newScreens: IntArray?,
- addNotAnimated: ArrayList<ItemInfo>,
- addAnimated: ArrayList<ItemInfo>,
- ) {
- addedItems.addAll(addAnimated.map { AddedItem(it, true) })
- addedItems.addAll(addNotAnimated.map { AddedItem(it, false) })
+ override fun bindItemsAdded(items: List<ItemInfo>) {
+ addedItems.addAll(items)
}
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
index 9f55f39..61d96ba 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/AsyncBindingTest.kt
@@ -17,45 +17,52 @@
package com.android.launcher3.model
import android.os.Looper
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
-import android.util.Pair
import android.util.SparseArray
import android.view.View
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.launcher3.Flags
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.Launcher
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherModel
-import com.android.launcher3.model.BgDataModel.Callbacks
+import com.android.launcher3.ModelCallbacks
import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.pageindicators.PageIndicatorDots
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
-import com.android.launcher3.util.IntArray
import com.android.launcher3.util.IntSet
import com.android.launcher3.util.ItemInflater
import com.android.launcher3.util.LauncherLayoutBuilder
import com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE
import com.android.launcher3.util.ModelTestExtensions.loadModelSync
-import com.android.launcher3.util.RunnableList
import com.android.launcher3.util.SandboxApplication
+import com.android.launcher3.util.TestUtil.runOnExecutorSync
import com.android.launcher3.util.rule.LayoutProviderRule
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Answers
import org.mockito.Mock
import org.mockito.MockitoAnnotations
-import org.mockito.Spy
import org.mockito.kotlin.any
+import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.argThat
import org.mockito.kotlin.atLeastOnce
+import org.mockito.kotlin.clearInvocations
import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.isNull
import org.mockito.kotlin.never
-import org.mockito.kotlin.reset
+import org.mockito.kotlin.spy
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@@ -69,8 +76,13 @@
@get:Rule val context = SandboxApplication().withModelDependency()
@get:Rule val layoutProvider = LayoutProviderRule(context)
- @Spy private var callbacks = MyCallbacks()
@Mock private lateinit var itemInflater: ItemInflater<*>
+ // PageIndicatorDots need to be mocked separately as Workspace uses generics and doesn't define
+ // the actual class of PageIndicator being used
+ @Mock private lateinit var pageIndicatorDots: PageIndicatorDots
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS) private lateinit var launcher: Launcher
+
+ private lateinit var callbacks: ModelCallbacks
private val inflationLooper = SparseArray<Looper>()
@@ -79,7 +91,6 @@
@Before
fun setUp() {
- setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
MockitoAnnotations.initMocks(this)
doAnswer { i ->
@@ -89,6 +100,13 @@
.whenever(itemInflater)
.inflateItem(any(), isNull())
+ doReturn(itemInflater).whenever(launcher).itemInflater
+ doReturn(InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context))
+ .whenever(launcher)
+ .deviceProfile
+ launcher.workspace.apply { doReturn(pageIndicatorDots).whenever(this).getPageIndicator() }
+ doReturn(context).whenever(launcher).applicationContext
+
// Set up the workspace with 3 pages of apps
layoutProvider.setupDefaultLayoutProvider(
LauncherLayoutBuilder()
@@ -103,30 +121,29 @@
.atWorkspace(0, 1, 2)
.putApp(TEST_PACKAGE, TEST_PACKAGE)
)
+ callbacks =
+ spy(ModelCallbacks(launcher).apply { pagesToBindSynchronously = IntSet.wrap(0) })
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
fun test_bind_normally_without_itemInflater() {
MAIN_EXECUTOR.execute { model.addCallbacksAndLoad(callbacks) }
waitForLoaderAndTempMainThread()
- verify(callbacks, never()).bindInflatedItems(any())
verify(callbacks, atLeastOnce()).bindItems(any(), any())
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
fun test_bind_inflates_item_on_background() {
- callbacks.inflater = itemInflater
MAIN_EXECUTOR.execute { model.addCallbacksAndLoad(callbacks) }
waitForLoaderAndTempMainThread()
verify(callbacks, never()).bindItems(any(), any())
- verify(callbacks, times(1)).bindInflatedItems(argThat { t -> t.size == 2 })
-
- // Verify remaining items are bound using pendingTasks
- reset(callbacks)
- MAIN_EXECUTOR.submit(callbacks.pendingTasks!!::executeAllAndDestroy).get()
- verify(callbacks, times(1)).bindInflatedItems(argThat { t -> t.size == 3 })
+ // First 2 items were bound and eventually remaining items were bound
+ verify(launcher, times(1)).bindInflatedItems(argThat { size == 2 }, anyOrNull())
+ verify(launcher, times(1)).bindInflatedItems(argThat { size == 3 }, anyOrNull())
// Verify that all items were inflated on the background thread
assertEquals(5, inflationLooper.size())
@@ -134,31 +151,34 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
fun test_bind_sync_partially_inflates_on_background() {
model.loadModelSync()
assertTrue(model.isModelLoaded())
- callbacks.inflater = itemInflater
- val firstPageBindIds = IntSet()
+ val firstPageBindIds = mutableSetOf<Int>()
+ runOnExecutorSync(MAIN_EXECUTOR) {
+ model.addCallbacksAndLoad(callbacks)
+ verify(callbacks, never()).bindItems(any(), any())
+ verify(launcher, times(1))
+ .bindInflatedItems(
+ argThat {
+ firstPageBindIds.addAll(map { it.first.id })
+ size == 2
+ },
+ anyOrNull(),
+ )
- MAIN_EXECUTOR.submit {
- model.addCallbacksAndLoad(callbacks)
- verify(callbacks, never()).bindItems(any(), any())
- verify(callbacks, times(1))
- .bindInflatedItems(
- argThat { t ->
- t.forEach { firstPageBindIds.add(it.first.id) }
- t.size == 2
- }
- )
-
- // Verify that onInitialBindComplete is called and the binding is not yet complete
- assertFalse(callbacks.onCompleteSignal!!.isDestroyed)
- }
- .get()
+ // Verify that onInitialBindComplete is called and the binding is not yet complete
+ assertNotNull(callbacks.pendingExecutor)
+ clearInvocations(launcher)
+ }
waitForLoaderAndTempMainThread()
- assertTrue(callbacks.onCompleteSignal!!.isDestroyed)
+
+ // Verify remaining 3 times are bound using pending tasks
+ assertNull(callbacks.pendingExecutor)
+ verify(launcher, times(1)).bindInflatedItems(argThat { t -> t.size == 3 }, anyOrNull())
// Verify that firstPageBindIds are loaded on the main thread and remaining
// on the background thread.
@@ -168,45 +188,12 @@
assertEquals(MAIN_EXECUTOR.looper, inflationLooper.valueAt(i))
else assertEquals(MODEL_EXECUTOR.looper, inflationLooper.valueAt(i))
}
-
- MAIN_EXECUTOR.submit {
- reset(callbacks)
- callbacks.pendingTasks!!.executeAllAndDestroy()
- // Verify remaining 3 times are bound using pending tasks
- verify(callbacks, times(1)).bindInflatedItems(argThat { t -> t.size == 3 })
- }
- .get()
}
private fun waitForLoaderAndTempMainThread() {
- MAIN_EXECUTOR.submit {}.get()
- MODEL_EXECUTOR.submit {}.get()
- MAIN_EXECUTOR.submit {}.get()
- }
-
- class MyCallbacks : Callbacks {
-
- var inflater: ItemInflater<*>? = null
- var pendingTasks: RunnableList? = null
- var onCompleteSignal: RunnableList? = null
-
- override fun bindItems(shortcuts: MutableList<ItemInfo>, forceAnimateIcons: Boolean) {}
-
- override fun bindInflatedItems(items: MutableList<Pair<ItemInfo, View>>) {}
-
- override fun getPagesToBindSynchronously(orderedScreenIds: IntArray?) = IntSet.wrap(0)
-
- override fun onInitialBindComplete(
- boundPages: IntSet,
- pendingTasks: RunnableList,
- onCompleteSignal: RunnableList,
- workspaceItemCount: Int,
- isBindSync: Boolean,
- ) {
- this.pendingTasks = pendingTasks
- this.onCompleteSignal = onCompleteSignal
+ repeat(5) {
+ runOnExecutorSync(MAIN_EXECUTOR) {}
+ runOnExecutorSync(MODEL_EXECUTOR) {}
}
-
- override fun getItemInflater() = inflater
}
}
diff --git a/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java b/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
index 3115899..d64049d 100644
--- a/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
+++ b/tests/src/com/android/launcher3/model/ModelMultiCallbacksTest.java
@@ -32,14 +32,13 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.model.BgDataModel.Callbacks;
+import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.Executors;
-import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SandboxApplication;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.rule.LayoutProviderRule;
@@ -49,7 +48,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -83,17 +81,16 @@
Executors.MAIN_EXECUTOR.execute(() -> getModel().addCallbacksAndLoad(cb1));
waitForLoaderAndTempMainThread();
- cb1.verifySynchronouslyBound(3);
+ cb1.verifyItemsBound(3);
// Add a new callback
cb1.reset();
MyCallbacks cb2 = spy(MyCallbacks.class);
- cb2.mPageToBindSync = IntSet.wrap(2);
Executors.MAIN_EXECUTOR.execute(() -> getModel().addCallbacksAndLoad(cb2));
waitForLoaderAndTempMainThread();
- assertFalse(cb1.bindStarted);
- cb2.verifySynchronouslyBound(3);
+ assertNull(cb1.mItems);
+ cb2.verifyItemsBound(3);
// Remove callbacks
cb1.reset();
@@ -102,14 +99,14 @@
// No effect on callbacks when removing an callback
Executors.MAIN_EXECUTOR.execute(() -> getModel().removeCallbacks(cb2));
waitForLoaderAndTempMainThread();
- assertNull(cb1.mPendingTasks);
- assertNull(cb2.mPendingTasks);
+ assertNull(cb1.mItems);
+ assertNull(cb2.mItems);
// Reloading only loads registered callbacks
getModel().startLoader();
waitForLoaderAndTempMainThread();
- cb1.verifySynchronouslyBound(3);
- assertNull(cb2.mPendingTasks);
+ cb1.verifyItemsBound(3);
+ assertNull(cb2.mItems);
}
@Test
@@ -173,30 +170,16 @@
private abstract static class MyCallbacks implements Callbacks {
- final List<ItemInfo> mItems = new ArrayList<>();
- IntSet mPageToBindSync = IntSet.wrap(0);
- IntSet mPageBoundSync = new IntSet();
- RunnableList mPendingTasks;
+ List<ItemInfo> mItems = null;
AppInfo[] mAppInfos;
- boolean bindStarted;
MyCallbacks() { }
@Override
- public void startBinding() {
- bindStarted = true;
- }
-
- @Override
- public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks,
- RunnableList onCompleteSignal, int workspaceItemCount, boolean isBindSync) {
- mPageBoundSync = boundPages;
- mPendingTasks = pendingTasks;
- }
-
- @Override
- public void bindItems(List<ItemInfo> shortcuts, boolean forceAnimateIcons) {
- mItems.addAll(shortcuts);
+ public void bindCompleteModel(IntSparseArrayMap<ItemInfo> itemIdMap,
+ List<FixedContainerItems> extraItems, StringCache stringCache,
+ boolean isBindingSync) {
+ mItems = itemIdMap.stream().toList();
}
@Override
@@ -205,29 +188,13 @@
mAppInfos = apps;
}
- @Override
- public IntSet getPagesToBindSynchronously(IntArray orderedScreenIds) {
- return mPageToBindSync;
- }
-
public void reset() {
- mItems.clear();
- mPageBoundSync = new IntSet();
- mPendingTasks = null;
+ mItems = null;
mAppInfos = null;
- bindStarted = false;
}
- public void verifySynchronouslyBound(int totalItems) {
- // Verify that the requested page is bound synchronously
- assertTrue(bindStarted);
- assertEquals(mPageToBindSync, mPageBoundSync);
- assertEquals(mItems.size(), 1);
- assertEquals(IntSet.wrap(mItems.get(0).screenId), mPageBoundSync);
- assertNotNull(mPendingTasks);
-
- // Verify that all other pages are bound properly
- mPendingTasks.executeAllAndDestroy();
+ public void verifyItemsBound(int totalItems) {
+ assertNotNull(mItems);
assertEquals(mItems.size(), totalItems);
}
@@ -236,9 +203,5 @@
.map(ai -> ai.getTargetComponent().getPackageName())
.collect(Collectors.toSet());
}
-
- public void verifyApps(String... apps) {
- assertTrue(allApps().containsAll(Arrays.asList(apps)));
- }
}
}