Merge "Refactor Workspace Loading / Processing code." into tm-qpr-dev
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index ad6ce7d..2e1318b 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -112,10 +112,23 @@
     }
 
     @Override
-    @WorkerThread
-    public void loadItems(UserManagerState ums, Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
+    public void loadHotseatItems(UserManagerState ums,
+            Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
         // TODO: Implement caching and preloading
-        super.loadItems(ums, pinnedShortcuts);
+        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);
+    }
+
+    @Override
+    public void loadAllAppsItems(UserManagerState ums,
+            Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) {
+        // TODO: Implement caching and preloading
+        super.loadAllAppsItems(ums, pinnedShortcuts);
 
         WorkspaceItemFactory allAppsFactory = new WorkspaceItemFactory(mApp, ums, pinnedShortcuts,
                 mIDP.numDatabaseAllAppsColumns, mAllAppsState.containerId);
@@ -123,17 +136,22 @@
                 mAllAppsState.containerId, mAllAppsState.storage.read(mApp.getContext(),
                 allAppsFactory, ums.allUsers::get));
         mDataModel.extraItems.put(mAllAppsState.containerId, allAppsPredictionItems);
+    }
 
-        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);
+    @Override
+    public void loadWidgetsRecommendationItems() {
+        // TODO: Implement caching and preloading
+        super.loadWidgetsRecommendationItems();
 
         // 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<>()));
+    }
+
+    @Override
+    public void markActive() {
+        super.markActive();
         mActive = true;
     }
 
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 6c62b31..0a6a7cd 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -37,7 +37,6 @@
 
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.Workspace;
@@ -72,24 +71,32 @@
     private final IconCache mIconCache;
     private final InvariantDeviceProfile mIDP;
 
-    private final IntArray itemsToRemove = new IntArray();
-    private final IntArray restoredRows = new IntArray();
-    private final IntSparseArrayMap<GridOccupancy> occupied = new IntSparseArrayMap<>();
+    private final IntArray mItemsToRemove = new IntArray();
+    private final IntArray mRestoredRows = new IntArray();
+    private final IntSparseArrayMap<GridOccupancy> mOccupied = new IntSparseArrayMap<>();
 
-    private final int iconPackageIndex;
-    private final int iconResourceIndex;
-    private final int iconIndex;
-    public final int titleIndex;
+    private final int mIconPackageIndex;
+    private final int mIconResourceIndex;
+    private final int mIconIndex;
+    public final int mTitleIndex;
 
-    private final int idIndex;
-    private final int containerIndex;
-    private final int itemTypeIndex;
-    private final int screenIndex;
-    private final int cellXIndex;
-    private final int cellYIndex;
-    private final int profileIdIndex;
-    private final int restoredIndex;
-    private final int intentIndex;
+    private final int mIdIndex;
+    private final int mContainerIndex;
+    private final int mItemTypeIndex;
+    private final int mScreenIndex;
+    private final int mCellXIndex;
+    private final int mCellYIndex;
+    private final int mProfileIdIndex;
+    private final int mRestoredIndex;
+    private final int mIntentIndex;
+
+    private final int mAppWidgetIdIndex;
+    private final int mAppWidgetProviderIndex;
+    private final int mSpanXIndex;
+    private final int mSpanYIndex;
+    private final int mRankIndex;
+    private final int mOptionsIndex;
+    private final int mAppWidgetSourceIndex;
 
     @Nullable
     private LauncherActivityInfo mActivityInfo;
@@ -114,20 +121,28 @@
         mPM = mContext.getPackageManager();
 
         // Init column indices
-        iconIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
-        iconPackageIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
-        iconResourceIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
-        titleIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
+        mIconIndex = getColumnIndexOrThrow(Favorites.ICON);
+        mIconPackageIndex = getColumnIndexOrThrow(Favorites.ICON_PACKAGE);
+        mIconResourceIndex = getColumnIndexOrThrow(Favorites.ICON_RESOURCE);
+        mTitleIndex = getColumnIndexOrThrow(Favorites.TITLE);
 
-        idIndex = getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
-        containerIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
-        itemTypeIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
-        screenIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
-        cellXIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
-        cellYIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
-        profileIdIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE_ID);
-        restoredIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.RESTORED);
-        intentIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
+        mIdIndex = getColumnIndexOrThrow(Favorites._ID);
+        mContainerIndex = getColumnIndexOrThrow(Favorites.CONTAINER);
+        mItemTypeIndex = getColumnIndexOrThrow(Favorites.ITEM_TYPE);
+        mScreenIndex = getColumnIndexOrThrow(Favorites.SCREEN);
+        mCellXIndex = getColumnIndexOrThrow(Favorites.CELLX);
+        mCellYIndex = getColumnIndexOrThrow(Favorites.CELLY);
+        mProfileIdIndex = getColumnIndexOrThrow(Favorites.PROFILE_ID);
+        mRestoredIndex = getColumnIndexOrThrow(Favorites.RESTORED);
+        mIntentIndex = getColumnIndexOrThrow(Favorites.INTENT);
+
+        mAppWidgetIdIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_ID);
+        mAppWidgetProviderIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER);
+        mSpanXIndex = getColumnIndexOrThrow(Favorites.SPANX);
+        mSpanYIndex = getColumnIndexOrThrow(Favorites.SPANY);
+        mRankIndex = getColumnIndexOrThrow(Favorites.RANK);
+        mOptionsIndex = getColumnIndexOrThrow(Favorites.OPTIONS);
+        mAppWidgetSourceIndex = getColumnIndexOrThrow(Favorites.APPWIDGET_SOURCE);
     }
 
     @Override
@@ -137,18 +152,18 @@
             mActivityInfo = null;
 
             // Load common properties.
-            itemType = getInt(itemTypeIndex);
-            container = getInt(containerIndex);
-            id = getInt(idIndex);
-            serialNumber = getInt(profileIdIndex);
+            itemType = getInt(mItemTypeIndex);
+            container = getInt(mContainerIndex);
+            id = getInt(mIdIndex);
+            serialNumber = getInt(mProfileIdIndex);
             user = allUsers.get(serialNumber);
-            restoreFlag = getInt(restoredIndex);
+            restoreFlag = getInt(mRestoredIndex);
         }
         return result;
     }
 
     public Intent parseIntent() {
-        String intentDescription = getString(intentIndex);
+        String intentDescription = getString(mIntentIndex);
         try {
             return TextUtils.isEmpty(intentDescription) ?
                     null : Intent.parseUri(intentDescription, 0);
@@ -185,14 +200,14 @@
 
     public IconRequestInfo<WorkspaceItemInfo> createIconRequestInfo(
             WorkspaceItemInfo wai, boolean useLowResIcon) {
-        String packageName = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
-                ? getString(iconPackageIndex) : null;
-        String resourceName = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
-                ? getString(iconResourceIndex) : null;
-        byte[] iconBlob = itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
+        String packageName = itemType == Favorites.ITEM_TYPE_SHORTCUT
+                ? getString(mIconPackageIndex) : null;
+        String resourceName = itemType == Favorites.ITEM_TYPE_SHORTCUT
+                ? getString(mIconResourceIndex) : null;
+        byte[] iconBlob = itemType == Favorites.ITEM_TYPE_SHORTCUT
                 || itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
                 || restoreFlag != 0
-                ? getBlob(iconIndex) : null;
+                ? getBlob(mIconIndex) : null;
 
         return new IconRequestInfo<>(
                 wai, mActivityInfo, packageName, resourceName, iconBlob, useLowResIcon);
@@ -202,7 +217,70 @@
      * Returns the title or empty string
      */
     private String getTitle() {
-        return Utilities.trim(getString(titleIndex));
+        return Utilities.trim(getString(mTitleIndex));
+    }
+
+    /**
+     * When loading an app widget for the workspace, returns it's app widget id
+     */
+    public int getAppWidgetId() {
+        return getInt(mAppWidgetIdIndex);
+    }
+
+    /**
+     * When loading an app widget for the workspace, returns the widget provider
+     */
+    public String getAppWidgetProvider() {
+        return getString(mAppWidgetProviderIndex);
+    }
+
+    /**
+     * Returns the x position for the item in the cell layout's grid
+     */
+    public int getSpanX() {
+        return getInt(mSpanXIndex);
+    }
+
+    /**
+     * Returns the y position for the item in the cell layout's grid
+     */
+    public int getSpanY() {
+        return getInt(mSpanYIndex);
+    }
+
+    /**
+     * Returns the rank for the item
+     */
+    public int getRank() {
+        return getInt(mRankIndex);
+    }
+
+    /**
+     * Returns the options for the item
+     */
+    public int getOptions() {
+        return getInt(mOptionsIndex);
+    }
+
+    /**
+     * When loading an app widget for the workspace, returns it's app widget source
+     */
+    public int getAppWidgetSource() {
+        return getInt(mAppWidgetSourceIndex);
+    }
+
+    /**
+     * Returns the screen that the item is on
+     */
+    public int getScreen() {
+        return getInt(mScreenIndex);
+    }
+
+    /**
+     * Returns the UX container that the item is in
+     */
+    public int getContainer() {
+        return getInt(mContainerIndex);
     }
 
     /**
@@ -320,7 +398,7 @@
      */
     public void markDeleted(String reason) {
         FileLog.e(TAG, reason);
-        itemsToRemove.add(id);
+        mItemsToRemove.add(id);
     }
 
     /**
@@ -328,10 +406,10 @@
      * @return true is any item was removed.
      */
     public boolean commitDeleted() {
-        if (itemsToRemove.size() > 0) {
+        if (mItemsToRemove.size() > 0) {
             // Remove dead items
             mContext.getContentResolver().delete(mContentUri, Utilities.createDbSelectionQuery(
-                    LauncherSettings.Favorites._ID, itemsToRemove), null);
+                    Favorites._ID, mItemsToRemove), null);
             return true;
         }
         return false;
@@ -342,7 +420,7 @@
      */
     public void markRestored() {
         if (restoreFlag != 0) {
-            restoredRows.add(id);
+            mRestoredRows.add(id);
             restoreFlag = 0;
         }
     }
@@ -352,13 +430,13 @@
     }
 
     public void commitRestoredItems() {
-        if (restoredRows.size() > 0) {
+        if (mRestoredRows.size() > 0) {
             // Update restored items that no longer require special handling
             ContentValues values = new ContentValues();
-            values.put(LauncherSettings.Favorites.RESTORED, 0);
+            values.put(Favorites.RESTORED, 0);
             mContext.getContentResolver().update(mContentUri, values,
                     Utilities.createDbSelectionQuery(
-                            LauncherSettings.Favorites._ID, restoredRows), null);
+                            Favorites._ID, mRestoredRows), null);
         }
     }
 
@@ -366,8 +444,7 @@
      * Returns true is the item is on workspace or hotseat
      */
     public boolean isOnWorkspaceOrHotseat() {
-        return container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
-                container == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+        return container == Favorites.CONTAINER_DESKTOP || container == Favorites.CONTAINER_HOTSEAT;
     }
 
     /**
@@ -381,9 +458,9 @@
     public void applyCommonProperties(ItemInfo info) {
         info.id = id;
         info.container = container;
-        info.screenId = getInt(screenIndex);
-        info.cellX = getInt(cellXIndex);
-        info.cellY = getInt(cellYIndex);
+        info.screenId = getInt(mScreenIndex);
+        info.cellX = getInt(mCellXIndex);
+        info.cellY = getInt(mCellYIndex);
     }
 
     public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) {
@@ -396,7 +473,7 @@
      */
     public void checkAndAddItem(
             ItemInfo info, BgDataModel dataModel, LoaderMemoryLogger logger) {
-        if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+        if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
             // Ensure that it is a valid intent. An exception here will
             // cause the item loading to get skipped
             ShortcutKey.fromItemInfo(info);
@@ -413,9 +490,9 @@
      */
     protected boolean checkItemPlacement(ItemInfo item) {
         int containerIndex = item.screenId;
-        if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+        if (item.container == Favorites.CONTAINER_HOTSEAT) {
             final GridOccupancy hotseatOccupancy =
-                    occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT);
+                    mOccupied.get(Favorites.CONTAINER_HOTSEAT);
 
             if (item.screenId >= mIDP.numDatabaseHotseatIcons) {
                 Log.e(TAG, "Error loading shortcut " + item
@@ -438,19 +515,18 @@
             } else {
                 final GridOccupancy occupancy = new GridOccupancy(mIDP.numDatabaseHotseatIcons, 1);
                 occupancy.cells[item.screenId][0] = true;
-                occupied.put(LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy);
+                mOccupied.put(Favorites.CONTAINER_HOTSEAT, occupancy);
                 return true;
             }
-        } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+        } else if (item.container != Favorites.CONTAINER_DESKTOP) {
             // Skip further checking if it is not the hotseat or workspace container
             return true;
         }
 
         final int countX = mIDP.numColumns;
         final int countY = mIDP.numRows;
-        if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
-                item.cellX < 0 || item.cellY < 0 ||
-                item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {
+        if (item.container == Favorites.CONTAINER_DESKTOP && item.cellX < 0 || item.cellY < 0
+                || item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {
             Log.e(TAG, "Error loading shortcut " + item
                     + " into cell (" + containerIndex + "-" + item.screenId + ":"
                     + item.cellX + "," + item.cellY
@@ -458,7 +534,7 @@
             return false;
         }
 
-        if (!occupied.containsKey(item.screenId)) {
+        if (!mOccupied.containsKey(item.screenId)) {
             GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
             if (item.screenId == Workspace.FIRST_SCREEN_ID && FeatureFlags.QSB_ON_FIRST_SCREEN) {
                 // Mark the first X columns (X is width of the search container) in the first row as
@@ -468,9 +544,9 @@
                 int spanY = 1;
                 screen.markCells(0, 0, spanX, spanY, true);
             }
-            occupied.put(item.screenId, screen);
+            mOccupied.put(item.screenId, screen);
         }
-        final GridOccupancy occupancy = occupied.get(item.screenId);
+        final GridOccupancy occupancy = mOccupied.get(item.screenId);
 
         // Check if any workspace icons overlap with each other
         if (occupancy.isRegionVacant(item.cellX, item.cellY, item.spanX, item.spanY)) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 46a6a66..da9be49 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -58,7 +58,8 @@
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel;
-import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.LauncherSettings.Settings;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.Folder;
@@ -198,7 +199,7 @@
         }
 
         Object traceToken = TraceHelper.INSTANCE.beginSection(TAG);
-        TimingLogger logger = new TimingLogger(TAG, "run");
+        TimingLogger timingLogger = new TimingLogger(TAG, "run");
         LoaderMemoryLogger memoryLogger = new LoaderMemoryLogger();
         try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) {
             List<ShortcutInfo> allShortcuts = new ArrayList<>();
@@ -208,7 +209,7 @@
             } finally {
                 Trace.endSection();
             }
-            logASplit(logger, "loadWorkspace");
+            logASplit(timingLogger, "loadWorkspace");
 
             // 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
@@ -216,22 +217,23 @@
             // (e.g. both grid preview and minimal device mode uses a different db)
             if (mApp.getInvariantDeviceProfile().dbFile.equals(mDbName)) {
                 verifyNotStopped();
-                sanitizeData();
-                logASplit(logger, "sanitizeData");
+                sanitizeFolders(mItemsDeleted);
+                sanitizeWidgetsShortcutsAndPackages();
+                logASplit(timingLogger, "sanitizeData");
             }
 
             verifyNotStopped();
             mLauncherBinder.bindWorkspace(true /* incrementBindId */);
-            logASplit(logger, "bindWorkspace");
+            logASplit(timingLogger, "bindWorkspace");
 
             mModelDelegate.workspaceLoadComplete();
             // Notify the installer packages of packages with active installs on the first screen.
             sendFirstScreenActiveInstallsBroadcast();
-            logASplit(logger, "sendFirstScreenActiveInstallsBroadcast");
+            logASplit(timingLogger, "sendFirstScreenActiveInstallsBroadcast");
 
             // Take a break
             waitForIdle();
-            logASplit(logger, "step 1 complete");
+            logASplit(timingLogger, "step 1 complete");
             verifyNotStopped();
 
             // second step
@@ -242,11 +244,11 @@
             } finally {
                 Trace.endSection();
             }
-            logASplit(logger, "loadAllApps");
+            logASplit(timingLogger, "loadAllApps");
 
             verifyNotStopped();
             mLauncherBinder.bindAllApps();
-            logASplit(logger, "bindAllApps");
+            logASplit(timingLogger, "bindAllApps");
 
             verifyNotStopped();
             IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler();
@@ -254,69 +256,69 @@
             updateHandler.updateIcons(allActivityList,
                     LauncherActivityCachingLogic.newInstance(mApp.getContext()),
                     mApp.getModel()::onPackageIconsUpdated);
-            logASplit(logger, "update icon cache");
+            logASplit(timingLogger, "update icon cache");
 
             verifyNotStopped();
-            logASplit(logger, "save shortcuts in icon cache");
+            logASplit(timingLogger, "save shortcuts in icon cache");
             updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(),
                     mApp.getModel()::onPackageIconsUpdated);
 
             // Take a break
             waitForIdle();
-            logASplit(logger, "step 2 complete");
+            logASplit(timingLogger, "step 2 complete");
             verifyNotStopped();
 
             // third step
             List<ShortcutInfo> allDeepShortcuts = loadDeepShortcuts();
-            logASplit(logger, "loadDeepShortcuts");
+            logASplit(timingLogger, "loadDeepShortcuts");
 
             verifyNotStopped();
             mLauncherBinder.bindDeepShortcuts();
-            logASplit(logger, "bindDeepShortcuts");
+            logASplit(timingLogger, "bindDeepShortcuts");
 
             verifyNotStopped();
-            logASplit(logger, "save deep shortcuts in icon cache");
+            logASplit(timingLogger, "save deep shortcuts in icon cache");
             updateHandler.updateIcons(allDeepShortcuts,
                     new ShortcutCachingLogic(), (pkgs, user) -> { });
 
             // Take a break
             waitForIdle();
-            logASplit(logger, "step 3 complete");
+            logASplit(timingLogger, "step 3 complete");
             verifyNotStopped();
 
             // fourth step
             List<ComponentWithLabelAndIcon> allWidgetsList =
                     mBgDataModel.widgetsModel.update(mApp, null);
-            logASplit(logger, "load widgets");
+            logASplit(timingLogger, "load widgets");
 
             verifyNotStopped();
             mLauncherBinder.bindWidgets();
-            logASplit(logger, "bindWidgets");
+            logASplit(timingLogger, "bindWidgets");
             verifyNotStopped();
 
             updateHandler.updateIcons(allWidgetsList,
                     new ComponentWithIconCachingLogic(mApp.getContext(), true),
                     mApp.getModel()::onWidgetLabelsUpdated);
-            logASplit(logger, "save widgets in icon cache");
+            logASplit(timingLogger, "save widgets in icon cache");
 
             // fifth step
             loadFolderNames();
 
             verifyNotStopped();
             updateHandler.finish();
-            logASplit(logger, "finish icon update");
+            logASplit(timingLogger, "finish icon update");
 
             mModelDelegate.modelLoadComplete();
             transaction.commit();
             memoryLogger.clearLogs();
         } catch (CancellationException e) {
             // Loader stopped, ignore
-            logASplit(logger, "Cancelled");
+            logASplit(timingLogger, "Cancelled");
         } catch (Exception e) {
             memoryLogger.printLogs();
             throw e;
         } finally {
-            logger.dumpToLog();
+            timingLogger.dumpToLog();
         }
         TraceHelper.INSTANCE.endSection(traceToken);
     }
@@ -326,9 +328,10 @@
         this.notify();
     }
 
-    private void loadWorkspace(List<ShortcutInfo> allDeepShortcuts, LoaderMemoryLogger logger) {
-        loadWorkspace(allDeepShortcuts, LauncherSettings.Favorites.CONTENT_URI,
-                null /* selection */, logger);
+    private void loadWorkspace(
+            List<ShortcutInfo> allDeepShortcuts, LoaderMemoryLogger memoryLogger) {
+        loadWorkspace(allDeepShortcuts, Favorites.CONTENT_URI,
+                null /* selection */, memoryLogger);
     }
 
     protected void loadWorkspace(
@@ -340,7 +343,7 @@
             List<ShortcutInfo> allDeepShortcuts,
             Uri contentUri,
             String selection,
-            @Nullable LoaderMemoryLogger logger) {
+            @Nullable LoaderMemoryLogger memoryLogger) {
         final Context context = mApp.getContext();
         final ContentResolver contentResolver = context.getContentResolver();
         final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
@@ -356,13 +359,11 @@
 
         if (clearDb) {
             Log.d(TAG, "loadWorkspace: resetting launcher database");
-            LauncherSettings.Settings.call(contentResolver,
-                    LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
+            Settings.call(contentResolver, Settings.METHOD_CREATE_EMPTY_DB);
         }
 
         Log.d(TAG, "loadWorkspace: loading default favorites");
-        LauncherSettings.Settings.call(contentResolver,
-                LauncherSettings.Settings.METHOD_LOAD_DEFAULT_FAVORITES);
+        Settings.call(contentResolver, Settings.METHOD_LOAD_DEFAULT_FAVORITES);
 
         synchronized (mBgDataModel) {
             mBgDataModel.clear();
@@ -380,24 +381,8 @@
                     contentResolver.query(contentUri, null, selection, null, null), contentUri,
                     mApp, mUserManagerState);
             final Bundle extras = c.getExtras();
-            mDbName = extras == null
-                    ? null : extras.getString(LauncherSettings.Settings.EXTRA_DB_NAME);
+            mDbName = extras == null ? null : extras.getString(Settings.EXTRA_DB_NAME);
             try {
-                final int appWidgetIdIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.APPWIDGET_ID);
-                final int appWidgetProviderIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.APPWIDGET_PROVIDER);
-                final int spanXIndex = c.getColumnIndexOrThrow
-                        (LauncherSettings.Favorites.SPANX);
-                final int spanYIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.SPANY);
-                final int rankIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.RANK);
-                final int optionsIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.OPTIONS);
-                final int sourceContainerIndex = c.getColumnIndexOrThrow(
-                        LauncherSettings.Favorites.APPWIDGET_SOURCE);
-
                 final LongSparseArray<Boolean> unlockedUsers = new LongSparseArray<>();
 
                 mUserManagerState.init(mUserCache, mUserManager);
@@ -425,437 +410,23 @@
                     unlockedUsers.put(serialNo, userUnlocked);
                 }
 
-                WorkspaceItemInfo info;
-                LauncherAppWidgetInfo appWidgetInfo;
-                LauncherAppWidgetProviderInfo widgetProviderInfo;
-                Intent intent;
-                String targetPkg;
                 List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos = new ArrayList<>();
 
                 while (!mStopped && c.moveToNext()) {
-                    try {
-                        if (c.user == null) {
-                            // User has been deleted, remove the item.
-                            c.markDeleted("User has been deleted");
-                            continue;
-                        }
-
-                        boolean allowMissingTarget = false;
-                        switch (c.itemType) {
-                        case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
-                        case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
-                        case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
-                            intent = c.parseIntent();
-                            if (intent == null) {
-                                c.markDeleted("Invalid or null intent");
-                                continue;
-                            }
-
-                            int disabledState = mUserManagerState.isUserQuiet(c.serialNumber)
-                                    ? WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0;
-                            ComponentName cn = intent.getComponent();
-                            targetPkg = cn == null ? intent.getPackage() : cn.getPackageName();
-
-                            if (TextUtils.isEmpty(targetPkg) &&
-                                    c.itemType != LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
-                                c.markDeleted("Only legacy shortcuts can have null package");
-                                continue;
-                            }
-
-                            // If there is no target package, its an implicit intent
-                            // (legacy shortcut) which is always valid
-                            boolean validTarget = TextUtils.isEmpty(targetPkg) ||
-                                    mLauncherApps.isPackageEnabled(targetPkg, c.user);
-
-                            // If it's a deep shortcut, we'll use pinned shortcuts to restore it
-                            if (cn != null && validTarget && c.itemType
-                                    != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                                // If the apk is present and the shortcut points to a specific
-                                // component.
-
-                                // If the component is already present
-                                if (mLauncherApps.isActivityEnabled(cn, c.user)) {
-                                    // no special handling necessary for this item
-                                    c.markRestored();
-                                } else {
-                                    // Gracefully try to find a fallback activity.
-                                    intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
-                                    if (intent != null) {
-                                        c.restoreFlag = 0;
-                                        c.updater().put(
-                                                LauncherSettings.Favorites.INTENT,
-                                                intent.toUri(0)).commit();
-                                        cn = intent.getComponent();
-                                    } else {
-                                        c.markDeleted("Unable to find a launch target");
-                                        continue;
-                                    }
-                                }
-                            }
-                            // else if cn == null => can't infer much, leave it
-                            // else if !validPkg => could be restored icon or missing sd-card
-
-                            if (!TextUtils.isEmpty(targetPkg) && !validTarget) {
-                                // Points to a valid app (superset of cn != null) but the apk
-                                // is not available.
-
-                                if (c.restoreFlag != 0) {
-                                    // Package is not yet available but might be
-                                    // installed later.
-                                    FileLog.d(TAG, "package not yet restored: " + targetPkg);
-
-                                    tempPackageKey.update(targetPkg, c.user);
-                                    if (c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED)) {
-                                        // Restore has started once.
-                                    } else if (installingPkgs.containsKey(tempPackageKey)) {
-                                        // App restore has started. Update the flag
-                                        c.restoreFlag |= WorkspaceItemInfo.FLAG_RESTORE_STARTED;
-                                        c.updater().put(LauncherSettings.Favorites.RESTORED,
-                                                c.restoreFlag).commit();
-                                    } else {
-                                        c.markDeleted("Unrestored app removed: " + targetPkg);
-                                        continue;
-                                    }
-                                } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
-                                    // Package is present but not available.
-                                    disabledState |= WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE;
-                                    // Add the icon on the workspace anyway.
-                                    allowMissingTarget = true;
-                                } else if (!isSdCardReady) {
-                                    // SdCard is not ready yet. Package might get available,
-                                    // once it is ready.
-                                    Log.d(TAG, "Missing pkg, will check later: " + targetPkg);
-                                    mPendingPackages.add(new PackageUserKey(targetPkg, c.user));
-                                    // Add the icon on the workspace anyway.
-                                    allowMissingTarget = true;
-                                } else {
-                                    // Do not wait for external media load anymore.
-                                    c.markDeleted("Invalid package removed: " + targetPkg);
-                                    continue;
-                                }
-                            }
-
-                            if ((c.restoreFlag & WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI) != 0) {
-                                validTarget = false;
-                            }
-
-                            if (validTarget) {
-                                // The shortcut points to a valid target (either no target
-                                // or something which is ready to be used)
-                                c.markRestored();
-                            }
-
-                            boolean useLowResIcon = !c.isOnWorkspaceOrHotseat();
-
-                            if (c.restoreFlag != 0) {
-                                // Already verified above that user is same as default user
-                                info = c.getRestoredItemInfo(intent);
-                            } else if (c.itemType ==
-                                    LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
-                                info = c.getAppShortcutInfo(
-                                        intent,
-                                        allowMissingTarget,
-                                        useLowResIcon,
-                                        !FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get());
-                            } else if (c.itemType ==
-                                    LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-
-                                ShortcutKey key = ShortcutKey.fromIntent(intent, c.user);
-                                if (unlockedUsers.get(c.serialNumber)) {
-                                    ShortcutInfo pinnedShortcut =
-                                            shortcutKeyToPinnedShortcuts.get(key);
-                                    if (pinnedShortcut == null) {
-                                        // The shortcut is no longer valid.
-                                        c.markDeleted("Pinned shortcut not found");
-                                        continue;
-                                    }
-                                    info = new WorkspaceItemInfo(pinnedShortcut, context);
-                                    // If the pinned deep shortcut is no longer published,
-                                    // use the last saved icon instead of the default.
-                                    mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon);
-
-                                    if (pmHelper.isAppSuspended(
-                                            pinnedShortcut.getPackage(), info.user)) {
-                                        info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
-                                    }
-                                    intent = info.getIntent();
-                                    allDeepShortcuts.add(pinnedShortcut);
-                                } else {
-                                    // Create a shortcut info in disabled mode for now.
-                                    info = c.loadSimpleWorkspaceItem();
-                                    info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
-                                }
-                            } else { // item type == ITEM_TYPE_SHORTCUT
-                                info = c.loadSimpleWorkspaceItem();
-
-                                // Shortcuts are only available on the primary profile
-                                if (!TextUtils.isEmpty(targetPkg)
-                                        && pmHelper.isAppSuspended(targetPkg, c.user)) {
-                                    disabledState |= FLAG_DISABLED_SUSPENDED;
-                                }
-                                info.options = c.getInt(optionsIndex);
-
-                                // App shortcuts that used to be automatically added to Launcher
-                                // didn't always have the correct intent flags set, so do that
-                                // here
-                                if (intent.getAction() != null &&
-                                    intent.getCategories() != null &&
-                                    intent.getAction().equals(Intent.ACTION_MAIN) &&
-                                    intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
-                                    intent.addFlags(
-                                        Intent.FLAG_ACTIVITY_NEW_TASK |
-                                        Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-                                }
-                            }
-
-                            if (info != null) {
-                                if (info.itemType
-                                        != LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                                    // Skip deep shortcuts; their title and icons have already been
-                                    // loaded above.
-                                    iconRequestInfos.add(
-                                            c.createIconRequestInfo(info, useLowResIcon));
-                                }
-
-                                c.applyCommonProperties(info);
-
-                                info.intent = intent;
-                                info.rank = c.getInt(rankIndex);
-                                info.spanX = 1;
-                                info.spanY = 1;
-                                info.runtimeStatusFlags |= disabledState;
-                                if (isSafeMode && !isSystemApp(context, intent)) {
-                                    info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;
-                                }
-                                    LauncherActivityInfo activityInfo = c.getLauncherActivityInfo();
-                                    if (activityInfo != null) {
-                                        info.setProgressLevel(
-                                                PackageManagerHelper
-                                                    .getLoadingProgress(activityInfo),
-                                                PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
-                                    }
-
-                                if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
-                                    tempPackageKey.update(targetPkg, c.user);
-                                    SessionInfo si = installingPkgs.get(tempPackageKey);
-                                        if (si == null) {
-                                            info.runtimeStatusFlags &=
-                                                ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
-                                        } else if (activityInfo == null) {
-                                            int installProgress = (int) (si.getProgress() * 100);
-
-                                            info.setProgressLevel(
-                                                    installProgress,
-                                                    PackageInstallInfo.STATUS_INSTALLING);
-                                        }
-                                }
-
-                                c.checkAndAddItem(info, mBgDataModel, logger);
-                            } else {
-                                throw new RuntimeException("Unexpected null WorkspaceItemInfo");
-                            }
-                            break;
-
-                        case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
-                            FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id);
-                            c.applyCommonProperties(folderInfo);
-
-                            // Do not trim the folder label, as is was set by the user.
-                            folderInfo.title = c.getString(c.titleIndex);
-                            folderInfo.spanX = 1;
-                            folderInfo.spanY = 1;
-                            folderInfo.options = c.getInt(optionsIndex);
-
-                            // no special handling required for restored folders
-                            c.markRestored();
-
-                            c.checkAndAddItem(folderInfo, mBgDataModel, logger);
-                            break;
-
-                        case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
-                            if (WidgetsModel.GO_DISABLE_WIDGETS) {
-                                c.markDeleted("Only legacy shortcuts can have null package");
-                                continue;
-                            }
-                            // Follow through
-                        case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
-                            // Read all Launcher-specific widget details
-                            boolean customWidget = c.itemType ==
-                                LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
-
-                            int appWidgetId = c.getInt(appWidgetIdIndex);
-                            String savedProvider = c.getString(appWidgetProviderIndex);
-                            final ComponentName component;
-
-                            boolean isSearchWidget = (c.getInt(optionsIndex)
-                                    & LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET) != 0;
-                            if (isSearchWidget) {
-                                component  = QsbContainerView.getSearchComponentName(context);
-                                if (component == null) {
-                                    c.markDeleted("Discarding SearchWidget without packagename ");
-                                    continue;
-                                }
-                            } else {
-                                component = ComponentName.unflattenFromString(savedProvider);
-                            }
-                            final boolean isIdValid = !c.hasRestoreFlag(
-                                    LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
-                            final boolean wasProviderReady = !c.hasRestoreFlag(
-                                    LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY);
-
-                            ComponentKey providerKey = new ComponentKey(component, c.user);
-                            if (!mWidgetProvidersMap.containsKey(providerKey)) {
-                                mWidgetProvidersMap.put(providerKey,
-                                        widgetHelper.findProvider(component, c.user));
-                            }
-                            final AppWidgetProviderInfo provider =
-                                    mWidgetProvidersMap.get(providerKey);
-
-                            final boolean isProviderReady = isValidProvider(provider);
-                            if (!isSafeMode && !customWidget &&
-                                    wasProviderReady && !isProviderReady) {
-                                c.markDeleted(
-                                        "Deleting widget that isn't installed anymore: "
-                                        + provider);
-                            } else {
-                                if (isProviderReady) {
-                                    appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
-                                            provider.provider);
-
-                                    // The provider is available. So the widget is either
-                                    // available or not available. We do not need to track
-                                    // any future restore updates.
-                                    int status = c.restoreFlag &
-                                            ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED &
-                                            ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
-                                    if (!wasProviderReady) {
-                                        // If provider was not previously ready, update the
-                                        // status and UI flag.
-
-                                        // Id would be valid only if the widget restore broadcast was received.
-                                        if (isIdValid) {
-                                            status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
-                                        }
-                                    }
-                                    appWidgetInfo.restoreStatus = status;
-                                } else {
-                                    Log.v(TAG, "Widget restore pending id=" + c.id
-                                            + " appWidgetId=" + appWidgetId
-                                            + " status =" + c.restoreFlag);
-                                    appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
-                                            component);
-                                    appWidgetInfo.restoreStatus = c.restoreFlag;
-
-                                    tempPackageKey.update(component.getPackageName(), c.user);
-                                    SessionInfo si =
-                                            installingPkgs.get(tempPackageKey);
-                                    Integer installProgress = si == null
-                                            ? null
-                                            : (int) (si.getProgress() * 100);
-
-                                    if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
-                                        // Restore has started once.
-                                    } else if (installProgress != null) {
-                                        // App restore has started. Update the flag
-                                        appWidgetInfo.restoreStatus |=
-                                                LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
-                                    } else if (!isSafeMode) {
-                                        c.markDeleted("Unrestored widget removed: " + component);
-                                        continue;
-                                    }
-
-                                    appWidgetInfo.installProgress =
-                                            installProgress == null ? 0 : installProgress;
-                                }
-                                if (appWidgetInfo.hasRestoreFlag(
-                                        LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
-                                    appWidgetInfo.bindOptions = c.parseIntent();
-                                }
-
-                                c.applyCommonProperties(appWidgetInfo);
-                                appWidgetInfo.spanX = c.getInt(spanXIndex);
-                                appWidgetInfo.spanY = c.getInt(spanYIndex);
-                                appWidgetInfo.options = c.getInt(optionsIndex);
-                                appWidgetInfo.user = c.user;
-                                appWidgetInfo.sourceContainer = c.getInt(sourceContainerIndex);
-
-                                if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) {
-                                    c.markDeleted("Widget has invalid size: "
-                                            + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY);
-                                    continue;
-                                }
-                                widgetProviderInfo =
-                                        widgetHelper.getLauncherAppWidgetInfo(appWidgetId);
-                                if (widgetProviderInfo != null
-                                        && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
-                                        || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
-                                    FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent()
-                                            + " minSizes not meet: span=" + appWidgetInfo.spanX
-                                            + "x" + appWidgetInfo.spanY + " minSpan="
-                                            + widgetProviderInfo.minSpanX + "x"
-                                            + widgetProviderInfo.minSpanY);
-                                    logWidgetInfo(mApp.getInvariantDeviceProfile(),
-                                            widgetProviderInfo);
-                                }
-                                if (!c.isOnWorkspaceOrHotseat()) {
-                                    c.markDeleted("Widget found where container != " +
-                                            "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
-                                    continue;
-                                }
-
-                                if (!customWidget) {
-                                    String providerName =
-                                            appWidgetInfo.providerName.flattenToString();
-                                    if (!providerName.equals(savedProvider) ||
-                                            (appWidgetInfo.restoreStatus != c.restoreFlag)) {
-                                        c.updater()
-                                                .put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
-                                                        providerName)
-                                                .put(LauncherSettings.Favorites.RESTORED,
-                                                        appWidgetInfo.restoreStatus)
-                                                .commit();
-                                    }
-                                }
-
-                                if (appWidgetInfo.restoreStatus !=
-                                        LauncherAppWidgetInfo.RESTORE_COMPLETED) {
-                                    appWidgetInfo.pendingItemInfo = WidgetsModel.newPendingItemInfo(
-                                            mApp.getContext(),
-                                            appWidgetInfo.providerName,
-                                            appWidgetInfo.user);
-                                    mIconCache.getTitleAndIconForApp(
-                                            appWidgetInfo.pendingItemInfo, false);
-                                }
-
-                                c.checkAndAddItem(appWidgetInfo, mBgDataModel);
-                            }
-                            break;
-                        }
-                    } catch (Exception e) {
-                        Log.e(TAG, "Desktop items loading interrupted", e);
-                    }
+                    processWorkspaceItem(c, memoryLogger, installingPkgs, isSdCardReady,
+                            tempPackageKey, widgetHelper, pmHelper, shortcutKeyToPinnedShortcuts,
+                            iconRequestInfos, unlockedUsers, isSafeMode, allDeepShortcuts);
                 }
-                if (FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get()) {
-                    Trace.beginSection("LoadWorkspaceIconsInBulk");
-                    try {
-                        mIconCache.getTitlesAndIconsInBulk(iconRequestInfos);
-                        for (IconRequestInfo<WorkspaceItemInfo> iconRequestInfo :
-                                iconRequestInfos) {
-                            WorkspaceItemInfo wai = iconRequestInfo.itemInfo;
-                            if (mIconCache.isDefaultIcon(wai.bitmap, wai.user)) {
-                                iconRequestInfo.loadWorkspaceIcon(mApp.getContext());
-                            }
-                        }
-                    } finally {
-                        Trace.endSection();
-                    }
-                }
+                maybeLoadWorkspaceIconsInBulk(iconRequestInfos);
             } finally {
                 IOUtils.closeSilently(c);
             }
 
             // Load delegate items
-            mModelDelegate.loadItems(mUserManagerState, shortcutKeyToPinnedShortcuts);
+            mModelDelegate.loadHotseatItems(mUserManagerState, shortcutKeyToPinnedShortcuts);
+            mModelDelegate.loadAllAppsItems(mUserManagerState, shortcutKeyToPinnedShortcuts);
+            mModelDelegate.loadWidgetsRecommendationItems();
+            mModelDelegate.markActive();
 
             // Load string cache
             mModelDelegate.loadStringCache(mBgDataModel.stringCache);
@@ -885,7 +456,7 @@
                     info.rank = rank;
 
                     if (info.usingLowResIcon()
-                            && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+                            && info.itemType == Favorites.ITEM_TYPE_APPLICATION
                             && verifier.isItemInPreview(info.rank)) {
                         mIconCache.getTitleAndIcon(info, false);
                     }
@@ -896,6 +467,418 @@
         }
     }
 
+    private void processWorkspaceItem(LoaderCursor c,
+            LoaderMemoryLogger memoryLogger,
+            HashMap<PackageUserKey, SessionInfo> installingPkgs,
+            boolean isSdCardReady,
+            PackageUserKey tempPackageKey,
+            WidgetManagerHelper widgetHelper,
+            PackageManagerHelper pmHelper,
+            Map<ShortcutKey, ShortcutInfo> shortcutKeyToPinnedShortcuts,
+            List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos,
+            LongSparseArray<Boolean> unlockedUsers,
+            boolean isSafeMode,
+            List<ShortcutInfo> allDeepShortcuts) {
+
+        try {
+            if (c.user == null) {
+                // User has been deleted, remove the item.
+                c.markDeleted("User has been deleted");
+                return;
+            }
+
+            boolean allowMissingTarget = false;
+            switch (c.itemType) {
+                case Favorites.ITEM_TYPE_SHORTCUT:
+                case Favorites.ITEM_TYPE_APPLICATION:
+                case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
+                    Intent intent = c.parseIntent();
+                    if (intent == null) {
+                        c.markDeleted("Invalid or null intent");
+                        return;
+                    }
+
+                    int disabledState = mUserManagerState.isUserQuiet(c.serialNumber)
+                            ? WorkspaceItemInfo.FLAG_DISABLED_QUIET_USER : 0;
+                    ComponentName cn = intent.getComponent();
+                    String targetPkg = cn == null ? intent.getPackage() : cn.getPackageName();
+
+                    if (TextUtils.isEmpty(targetPkg)
+                            && c.itemType != Favorites.ITEM_TYPE_SHORTCUT) {
+                        c.markDeleted("Only legacy shortcuts can have null package");
+                        return;
+                    }
+
+                    // If there is no target package, it's an implicit intent
+                    // (legacy shortcut) which is always valid
+                    boolean validTarget = TextUtils.isEmpty(targetPkg)
+                            || mLauncherApps.isPackageEnabled(targetPkg, c.user);
+
+                    // If it's a deep shortcut, we'll use pinned shortcuts to restore it
+                    if (cn != null && validTarget && c.itemType
+                            != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+                        // If the apk is present and the shortcut points to a specific component.
+
+                        // If the component is already present
+                        if (mLauncherApps.isActivityEnabled(cn, c.user)) {
+                            // no special handling necessary for this item
+                            c.markRestored();
+                        } else {
+                            // Gracefully try to find a fallback activity.
+                            intent = pmHelper.getAppLaunchIntent(targetPkg, c.user);
+                            if (intent != null) {
+                                c.restoreFlag = 0;
+                                c.updater().put(
+                                        Favorites.INTENT,
+                                        intent.toUri(0)).commit();
+                                cn = intent.getComponent();
+                            } else {
+                                c.markDeleted("Unable to find a launch target");
+                                return;
+                            }
+                        }
+                    }
+                    // else if cn == null => can't infer much, leave it
+                    // else if !validPkg => could be restored icon or missing sd-card
+
+                    if (!TextUtils.isEmpty(targetPkg) && !validTarget) {
+                        // Points to a valid app (superset of cn != null) but the apk
+                        // is not available.
+
+                        if (c.restoreFlag != 0) {
+                            // Package is not yet available but might be
+                            // installed later.
+                            FileLog.d(TAG, "package not yet restored: " + targetPkg);
+
+                            tempPackageKey.update(targetPkg, c.user);
+                            if (c.hasRestoreFlag(WorkspaceItemInfo.FLAG_RESTORE_STARTED)) {
+                                // Restore has started once.
+                            } else if (installingPkgs.containsKey(tempPackageKey)) {
+                                // App restore has started. Update the flag
+                                c.restoreFlag |= WorkspaceItemInfo.FLAG_RESTORE_STARTED;
+                                c.updater().put(Favorites.RESTORED,
+                                        c.restoreFlag).commit();
+                            } else {
+                                c.markDeleted("Unrestored app removed: " + targetPkg);
+                                return;
+                            }
+                        } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
+                            // Package is present but not available.
+                            disabledState |= WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE;
+                            // Add the icon on the workspace anyway.
+                            allowMissingTarget = true;
+                        } else if (!isSdCardReady) {
+                            // SdCard is not ready yet. Package might get available,
+                            // once it is ready.
+                            Log.d(TAG, "Missing pkg, will check later: " + targetPkg);
+                            mPendingPackages.add(new PackageUserKey(targetPkg, c.user));
+                            // Add the icon on the workspace anyway.
+                            allowMissingTarget = true;
+                        } else {
+                            // Do not wait for external media load anymore.
+                            c.markDeleted("Invalid package removed: " + targetPkg);
+                            return;
+                        }
+                    }
+
+                    if ((c.restoreFlag & WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI) != 0) {
+                        validTarget = false;
+                    }
+
+                    if (validTarget) {
+                        // The shortcut points to a valid target (either no target
+                        // or something which is ready to be used)
+                        c.markRestored();
+                    }
+
+                    boolean useLowResIcon = !c.isOnWorkspaceOrHotseat();
+
+                    WorkspaceItemInfo info;
+                    if (c.restoreFlag != 0) {
+                        // Already verified above that user is same as default user
+                        info = c.getRestoredItemInfo(intent);
+                    } else if (c.itemType == Favorites.ITEM_TYPE_APPLICATION) {
+                        info = c.getAppShortcutInfo(intent, allowMissingTarget, useLowResIcon,
+                                !FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get());
+                    } 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);
+                            if (pinnedShortcut == null) {
+                                // The shortcut is no longer valid.
+                                c.markDeleted("Pinned shortcut not found");
+                                return;
+                            }
+                            info = new WorkspaceItemInfo(pinnedShortcut, mApp.getContext());
+                            // If the pinned deep shortcut is no longer published,
+                            // use the last saved icon instead of the default.
+                            mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon);
+
+                            if (pmHelper.isAppSuspended(
+                                    pinnedShortcut.getPackage(), info.user)) {
+                                info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
+                            }
+                            intent = info.getIntent();
+                            allDeepShortcuts.add(pinnedShortcut);
+                        } else {
+                            // Create a shortcut info in disabled mode for now.
+                            info = c.loadSimpleWorkspaceItem();
+                            info.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER;
+                        }
+                    } else { // item type == ITEM_TYPE_SHORTCUT
+                        info = c.loadSimpleWorkspaceItem();
+
+                        // Shortcuts are only available on the primary profile
+                        if (!TextUtils.isEmpty(targetPkg)
+                                && pmHelper.isAppSuspended(targetPkg, c.user)) {
+                            disabledState |= FLAG_DISABLED_SUSPENDED;
+                        }
+                        info.options = c.getOptions();
+
+                        // App shortcuts that used to be automatically added to Launcher
+                        // didn't always have the correct intent flags set, so do that here
+                        if (intent.getAction() != null
+                                && intent.getCategories() != null
+                                && intent.getAction().equals(Intent.ACTION_MAIN)
+                                && intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
+                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+                        }
+                    }
+
+                    if (info != null) {
+                        if (info.itemType != Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+                            // Skip deep shortcuts; their title and icons have already been
+                            // loaded above.
+                            iconRequestInfos.add(c.createIconRequestInfo(info, useLowResIcon));
+                        }
+
+                        c.applyCommonProperties(info);
+
+                        info.intent = intent;
+                        info.rank = c.getRank();
+                        info.spanX = 1;
+                        info.spanY = 1;
+                        info.runtimeStatusFlags |= disabledState;
+                        if (isSafeMode && !isSystemApp(mApp.getContext(), intent)) {
+                            info.runtimeStatusFlags |= FLAG_DISABLED_SAFEMODE;
+                        }
+                        LauncherActivityInfo activityInfo = c.getLauncherActivityInfo();
+                        if (activityInfo != null) {
+                            info.setProgressLevel(
+                                    PackageManagerHelper.getLoadingProgress(activityInfo),
+                                    PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
+                        }
+
+                        if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
+                            tempPackageKey.update(targetPkg, c.user);
+                            SessionInfo si = installingPkgs.get(tempPackageKey);
+                            if (si == null) {
+                                info.runtimeStatusFlags
+                                        &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
+                            } else if (activityInfo == null) {
+                                int installProgress = (int) (si.getProgress() * 100);
+
+                                info.setProgressLevel(installProgress,
+                                        PackageInstallInfo.STATUS_INSTALLING);
+                            }
+                        }
+
+                        c.checkAndAddItem(info, mBgDataModel, memoryLogger);
+                    } else {
+                        throw new RuntimeException("Unexpected null WorkspaceItemInfo");
+                    }
+                    break;
+
+                case Favorites.ITEM_TYPE_FOLDER:
+                    FolderInfo folderInfo = mBgDataModel.findOrMakeFolder(c.id);
+                    c.applyCommonProperties(folderInfo);
+
+                    // Do not trim the folder label, as is was set by the user.
+                    folderInfo.title = c.getString(c.mTitleIndex);
+                    folderInfo.spanX = 1;
+                    folderInfo.spanY = 1;
+                    folderInfo.options = c.getOptions();
+
+                    // no special handling required for restored folders
+                    c.markRestored();
+
+                    c.checkAndAddItem(folderInfo, mBgDataModel, memoryLogger);
+                    break;
+
+                case Favorites.ITEM_TYPE_APPWIDGET:
+                    if (WidgetsModel.GO_DISABLE_WIDGETS) {
+                        c.markDeleted("Only legacy shortcuts can have null package");
+                        return;
+                    }
+                    // Follow through
+                case Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
+                    // Read all Launcher-specific widget details
+                    boolean customWidget = c.itemType
+                            == Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
+
+                    int appWidgetId = c.getAppWidgetId();
+                    String savedProvider = c.getAppWidgetProvider();
+                    final ComponentName component;
+
+                    if ((c.getOptions() & LauncherAppWidgetInfo.OPTION_SEARCH_WIDGET) != 0) {
+                        component  = QsbContainerView.getSearchComponentName(mApp.getContext());
+                        if (component == null) {
+                            c.markDeleted("Discarding SearchWidget without packagename ");
+                            return;
+                        }
+                    } else {
+                        component = ComponentName.unflattenFromString(savedProvider);
+                    }
+                    final boolean isIdValid =
+                            !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
+                    final boolean wasProviderReady =
+                            !c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY);
+
+                    ComponentKey providerKey = new ComponentKey(component, c.user);
+                    if (!mWidgetProvidersMap.containsKey(providerKey)) {
+                        mWidgetProvidersMap.put(providerKey,
+                                widgetHelper.findProvider(component, c.user));
+                    }
+                    final AppWidgetProviderInfo provider = mWidgetProvidersMap.get(providerKey);
+
+                    final boolean isProviderReady = isValidProvider(provider);
+                    if (!isSafeMode && !customWidget && wasProviderReady && !isProviderReady) {
+                        c.markDeleted("Deleting widget that isn't installed anymore: " + provider);
+                    } else {
+                        LauncherAppWidgetInfo appWidgetInfo;
+                        if (isProviderReady) {
+                            appWidgetInfo =
+                                    new LauncherAppWidgetInfo(appWidgetId, provider.provider);
+
+                            // The provider is available. So the widget is either
+                            // available or not available. We do not need to track
+                            // any future restore updates.
+                            int status = c.restoreFlag
+                                    & ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
+                                    & ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
+                            if (!wasProviderReady) {
+                                // If provider was not previously ready, update status and UI flag.
+
+                                // Id would be valid only if the widget restore broadcast received.
+                                if (isIdValid) {
+                                    status |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
+                                }
+                            }
+                            appWidgetInfo.restoreStatus = status;
+                        } else {
+                            Log.v(TAG, "Widget restore pending id=" + c.id
+                                    + " appWidgetId=" + appWidgetId
+                                    + " status =" + c.restoreFlag);
+                            appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, component);
+                            appWidgetInfo.restoreStatus = c.restoreFlag;
+
+                            tempPackageKey.update(component.getPackageName(), c.user);
+                            SessionInfo si = installingPkgs.get(tempPackageKey);
+                            Integer installProgress = si == null
+                                    ? null
+                                    : (int) (si.getProgress() * 100);
+
+                            if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
+                                // Restore has started once.
+                            } else if (installProgress != null) {
+                                // App restore has started. Update the flag
+                                appWidgetInfo.restoreStatus
+                                        |= LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
+                            } else if (!isSafeMode) {
+                                c.markDeleted("Unrestored widget removed: " + component);
+                                return;
+                            }
+
+                            appWidgetInfo.installProgress =
+                                    installProgress == null ? 0 : installProgress;
+                        }
+                        if (appWidgetInfo.hasRestoreFlag(
+                                LauncherAppWidgetInfo.FLAG_DIRECT_CONFIG)) {
+                            appWidgetInfo.bindOptions = c.parseIntent();
+                        }
+
+                        c.applyCommonProperties(appWidgetInfo);
+                        appWidgetInfo.spanX = c.getSpanX();
+                        appWidgetInfo.spanY = c.getSpanY();
+                        appWidgetInfo.options = c.getOptions();
+                        appWidgetInfo.user = c.user;
+                        appWidgetInfo.sourceContainer = c.getAppWidgetSource();
+
+                        if (appWidgetInfo.spanX <= 0 || appWidgetInfo.spanY <= 0) {
+                            c.markDeleted("Widget has invalid size: "
+                                    + appWidgetInfo.spanX + "x" + appWidgetInfo.spanY);
+                            return;
+                        }
+                        LauncherAppWidgetProviderInfo widgetProviderInfo =
+                                widgetHelper.getLauncherAppWidgetInfo(appWidgetId);
+                        if (widgetProviderInfo != null
+                                && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
+                                || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
+                            FileLog.d(TAG, "Widget " + widgetProviderInfo.getComponent()
+                                    + " minSizes not meet: span=" + appWidgetInfo.spanX
+                                    + "x" + appWidgetInfo.spanY + " minSpan="
+                                    + widgetProviderInfo.minSpanX + "x"
+                                    + widgetProviderInfo.minSpanY);
+                            logWidgetInfo(mApp.getInvariantDeviceProfile(),
+                                    widgetProviderInfo);
+                        }
+                        if (!c.isOnWorkspaceOrHotseat()) {
+                            c.markDeleted("Widget found where container != CONTAINER_DESKTOP"
+                                    + "nor CONTAINER_HOTSEAT - ignoring!");
+                            return;
+                        }
+
+                        if (!customWidget) {
+                            String providerName = appWidgetInfo.providerName.flattenToString();
+                            if (!providerName.equals(savedProvider)
+                                    || (appWidgetInfo.restoreStatus != c.restoreFlag)) {
+                                c.updater()
+                                        .put(Favorites.APPWIDGET_PROVIDER,
+                                                providerName)
+                                        .put(Favorites.RESTORED,
+                                                appWidgetInfo.restoreStatus)
+                                        .commit();
+                            }
+                        }
+
+                        if (appWidgetInfo.restoreStatus
+                                != LauncherAppWidgetInfo.RESTORE_COMPLETED) {
+                            appWidgetInfo.pendingItemInfo = WidgetsModel.newPendingItemInfo(
+                                    mApp.getContext(),
+                                    appWidgetInfo.providerName,
+                                    appWidgetInfo.user);
+                            mIconCache.getTitleAndIconForApp(
+                                    appWidgetInfo.pendingItemInfo, false);
+                        }
+
+                        c.checkAndAddItem(appWidgetInfo, mBgDataModel);
+                    }
+                    break;
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Desktop items loading interrupted", e);
+        }
+    }
+
+    private void maybeLoadWorkspaceIconsInBulk(
+            List<IconRequestInfo<WorkspaceItemInfo>> iconRequestInfos) {
+        if (FeatureFlags.ENABLE_BULK_WORKSPACE_ICON_LOADING.get()) {
+            Trace.beginSection("LoadWorkspaceIconsInBulk");
+            try {
+                mIconCache.getTitlesAndIconsInBulk(iconRequestInfos);
+                for (IconRequestInfo<WorkspaceItemInfo> iconRequestInfo : iconRequestInfos) {
+                    WorkspaceItemInfo wai = iconRequestInfo.itemInfo;
+                    if (mIconCache.isDefaultIcon(wai.bitmap, wai.user)) {
+                        iconRequestInfo.loadWorkspaceIcon(mApp.getContext());
+                    }
+                }
+            } finally {
+                Trace.endSection();
+            }
+        }
+    }
+
     private void setIgnorePackages(IconCacheUpdateHandler updateHandler) {
         // Ignore packages which have a promise icon.
         synchronized (mBgDataModel) {
@@ -917,15 +900,12 @@
         }
     }
 
-    private void sanitizeData() {
-        Context context = mApp.getContext();
-        ContentResolver contentResolver = context.getContentResolver();
-        if (mItemsDeleted) {
+    private void sanitizeFolders(boolean itemsDeleted) {
+        if (itemsDeleted) {
             // Remove any empty folder
-            int[] deletedFolderIds = LauncherSettings.Settings
-                    .call(contentResolver,
-                            LauncherSettings.Settings.METHOD_DELETE_EMPTY_FOLDERS)
-                    .getIntArray(LauncherSettings.Settings.EXTRA_VALUE);
+            int[] deletedFolderIds = Settings.call(mApp.getContext().getContentResolver(),
+                            Settings.METHOD_DELETE_EMPTY_FOLDERS)
+                    .getIntArray(Settings.EXTRA_VALUE);
             synchronized (mBgDataModel) {
                 for (int folderId : deletedFolderIds) {
                     mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId));
@@ -933,11 +913,16 @@
                     mBgDataModel.itemsIdMap.remove(folderId);
                 }
             }
-
         }
+    }
+
+    private void sanitizeWidgetsShortcutsAndPackages() {
+        Context context = mApp.getContext();
+        ContentResolver contentResolver = context.getContentResolver();
+
         // Remove any ghost widgets
-        LauncherSettings.Settings.call(contentResolver,
-                LauncherSettings.Settings.METHOD_REMOVE_GHOST_WIDGETS);
+        Settings.call(contentResolver,
+                Settings.METHOD_REMOVE_GHOST_WIDGETS);
 
         // Update pinned state of model shortcuts
         mBgDataModel.updateShortcutPinnedState(context);
@@ -1107,10 +1092,12 @@
         FileLog.d(TAG, widgetDimension.toString());
     }
 
-    private static void logASplit(final TimingLogger logger, final String label) {
-        logger.addSplit(label);
-        if (DEBUG) {
-            Log.d(TAG, label);
+    private static void logASplit(@Nullable TimingLogger timingLogger, String label) {
+        if (timingLogger != null) {
+            timingLogger.addSplit(label);
+            if (DEBUG) {
+                Log.d(TAG, label);
+            }
         }
     }
 }
diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java
index 3bd9470..0639a6c 100644
--- a/src/com/android/launcher3/model/ModelDelegate.java
+++ b/src/com/android/launcher3/model/ModelDelegate.java
@@ -80,10 +80,29 @@
     }
 
     /**
-     * Load delegate items if any in the data model
+     * Load hot seat items if any in the data model
      */
     @WorkerThread
-    public void loadItems(UserManagerState ums, Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
+    public void loadHotseatItems(UserManagerState ums,
+            Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
+
+    /**
+     * Load all apps items if any in the data model
+     */
+    @WorkerThread
+    public void loadAllAppsItems(UserManagerState ums,
+            Map<ShortcutKey, ShortcutInfo> pinnedShortcuts) { }
+
+    /**
+     * Load widget recommendation items if any in the data model
+     */
+    @WorkerThread
+    public void loadWidgetsRecommendationItems() { }
+
+    /**
+     * Marks the ModelDelegate as active
+     */
+    public void markActive() { }
 
     /**
      * Load String cache
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index 6444ef6..7ab86ad 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -18,6 +18,9 @@
 
 import static androidx.test.InstrumentationRegistry.getContext;
 
+import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_ID;
+import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_PROVIDER;
+import static com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_SOURCE;
 import static com.android.launcher3.LauncherSettings.Favorites.CELLX;
 import static com.android.launcher3.LauncherSettings.Favorites.CELLY;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER;
@@ -30,9 +33,13 @@
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.OPTIONS;
 import static com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID;
+import static com.android.launcher3.LauncherSettings.Favorites.RANK;
 import static com.android.launcher3.LauncherSettings.Favorites.RESTORED;
 import static com.android.launcher3.LauncherSettings.Favorites.SCREEN;
+import static com.android.launcher3.LauncherSettings.Favorites.SPANX;
+import static com.android.launcher3.LauncherSettings.Favorites.SPANY;
 import static com.android.launcher3.LauncherSettings.Favorites.TITLE;
 import static com.android.launcher3.LauncherSettings.Favorites._ID;
 import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY;
@@ -92,7 +99,9 @@
         mCursor = new MatrixCursor(new String[] {
                 ICON, ICON_PACKAGE, ICON_RESOURCE, TITLE,
                 _ID, CONTAINER, ITEM_TYPE, PROFILE_ID,
-                SCREEN, CELLX, CELLY, RESTORED, INTENT
+                SCREEN, CELLX, CELLY, RESTORED, INTENT,
+                APPWIDGET_ID, APPWIDGET_PROVIDER, SPANX,
+                SPANY, RANK, OPTIONS, APPWIDGET_SOURCE
         });
 
         UserManagerState ums = new UserManagerState();