Removing support for lagacy shortcuts

> Addition/removal of  shortcus is already removed. This just
  cleans up the unused code path

Bug: 275875209
Test: Updated tests
Flag: N/A
Change-Id: I8ab7f57b693f996920e50e8beecafcffab5167e9
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index a8b7698..b059cbd 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -337,7 +337,6 @@
         if (getTag() instanceof WorkspaceItemInfo) {
             WorkspaceItemInfo info = (WorkspaceItemInfo) getTag();
             isBadged = !Process.myUserHandle().equals(info.user)
-                    || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
                     || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
         }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index ef63b3b..8ff0969 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -25,7 +25,6 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.NO_OFFSET;
@@ -283,7 +282,6 @@
 
         if (mAllAppsPredictions != null
                 && (info.itemType == ITEM_TYPE_APPLICATION
-                || info.itemType == ITEM_TYPE_SHORTCUT
                 || info.itemType == ITEM_TYPE_DEEP_SHORTCUT)) {
             int count = mAllAppsPredictions.items.size();
             for (int i = 0; i < count; i++) {
@@ -1162,7 +1160,6 @@
         }
         switch (info.itemType) {
             case Favorites.ITEM_TYPE_APPLICATION:
-            case Favorites.ITEM_TYPE_SHORTCUT:
             case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
             case Favorites.ITEM_TYPE_APPWIDGET:
                 // Fall through and continue if it's an app, shortcut, or widget
diff --git a/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
index 83341cb..b12d98b 100644
--- a/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
+++ b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
@@ -20,6 +20,7 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
 import static com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -40,11 +41,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.icons.ComponentWithLabel;
-import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
+import com.android.launcher3.util.LauncherLayoutBuilder;
 import com.android.launcher3.util.LauncherModelHelper;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -53,8 +52,6 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
 import java.util.Arrays;
 import java.util.List;
@@ -76,17 +73,9 @@
     private LauncherModelHelper mModelHelper;
     private UserHandle mUserHandle;
 
-    @Mock
-    private IconCache mIconCache;
-
     @Before
     public void setup() throws Exception {
         mModelHelper = new LauncherModelHelper();
-        MockitoAnnotations.initMocks(this);
-        doAnswer(invocation -> {
-            ComponentWithLabel componentWithLabel = invocation.getArgument(0);
-            return componentWithLabel.getComponent().getShortClassName();
-        }).when(mIconCache).getTitleNoCache(any());
 
         mUserHandle = myUserHandle();
         mApp1Provider1 = createAppWidgetProviderInfo(
@@ -114,16 +103,12 @@
                     .collect(Collectors.toList());
         }).when(manager).getInstalledProvidersForPackage(any(), eq(myUserHandle()));
 
-        // 2 widgets, app4/provider1 & app5/provider1, have already been added to the workspace.
-        mModelHelper.initializeData("widgets_predication_update_task_data");
-
+        LauncherLayoutBuilder builder = new LauncherLayoutBuilder()
+                .atWorkspace(0, 1, 2).putWidget("app4", "provider1", 1, 1)
+                .atWorkspace(0, 1, 3).putWidget("app5", "provider1", 1, 1);
+        mModelHelper.setupDefaultLayoutProvider(builder);
         MAIN_EXECUTOR.submit(() -> mModelHelper.getModel().addCallbacks(mCallback)).get();
-        MODEL_EXECUTOR.post(() -> mModelHelper.getBgDataModel().widgetsModel.update(
-                LauncherAppState.getInstance(mModelHelper.sandboxContext),
-                /* packageUser= */ null));
-
-        MODEL_EXECUTOR.submit(() -> { }).get();
-        MAIN_EXECUTOR.submit(() -> { }).get();
+        mModelHelper.loadModelSync();
     }
 
     @After
@@ -132,65 +117,72 @@
     }
 
     @Test
-    public void widgetsRecommendationRan_shouldOnlyReturnNotAddedWidgetsInAppPredictionOrder()
-            throws Exception {
-        // WHEN newPredicationTask is executed with app predication of 5 apps.
-        AppTarget app1 = new AppTarget(new AppTargetId("app1"), "app1", "provider1",
-                mUserHandle);
-        AppTarget app2 = new AppTarget(new AppTargetId("app2"), "app2", "provider1",
-                mUserHandle);
-        AppTarget app3 = new AppTarget(new AppTargetId("app3"), "app3", "className",
-                mUserHandle);
-        AppTarget app4 = new AppTarget(new AppTargetId("app4"), "app4", "provider1",
-                mUserHandle);
-        AppTarget app5 = new AppTarget(new AppTargetId("app5"), "app5", "provider1",
-                mUserHandle);
-        mModelHelper.executeTaskForTest(
-                newWidgetsPredicationTask(List.of(app5, app3, app2, app4, app1)))
-                .forEach(Runnable::run);
+    public void widgetsRecommendationRan_shouldOnlyReturnNotAddedWidgetsInAppPredictionOrder() {
+        // Run on model executor so that no other task runs in the middle.
+        runOnExecutorSync(MODEL_EXECUTOR, () -> {
+            // WHEN newPredicationTask is executed with app predication of 5 apps.
+            AppTarget app1 = new AppTarget(new AppTargetId("app1"), "app1", "provider1",
+                    mUserHandle);
+            AppTarget app2 = new AppTarget(new AppTargetId("app2"), "app2", "provider1",
+                    mUserHandle);
+            AppTarget app3 = new AppTarget(new AppTargetId("app3"), "app3", "className",
+                    mUserHandle);
+            AppTarget app4 = new AppTarget(new AppTargetId("app4"), "app4", "provider1",
+                    mUserHandle);
+            AppTarget app5 = new AppTarget(new AppTargetId("app5"), "app5", "provider1",
+                    mUserHandle);
+            mCallback.mRecommendedWidgets = null;
+            mModelHelper.getModel().enqueueModelUpdateTask(
+                    newWidgetsPredicationTask(List.of(app5, app3, app2, app4, app1)));
+            runOnExecutorSync(MAIN_EXECUTOR, () -> { });
 
-        // THEN only 2 widgets are returned because
-        // 1. app5/provider1 & app4/provider1 have already been added to workspace. They are
-        //    excluded from the result.
-        // 2. app3 doesn't have a widget.
-        // 3. only 1 widget is picked from app1 because we only want to promote one widget per app.
-        List<PendingAddWidgetInfo> recommendedWidgets = mCallback.mRecommendedWidgets.items
-                .stream()
-                .map(itemInfo -> (PendingAddWidgetInfo) itemInfo)
-                .collect(Collectors.toList());
-        assertThat(recommendedWidgets).hasSize(2);
-        assertWidgetInfo(recommendedWidgets.get(0).info, mApp2Provider1);
-        assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider1);
+            // THEN only 2 widgets are returned because
+            // 1. app5/provider1 & app4/provider1 have already been added to workspace. They are
+            //    excluded from the result.
+            // 2. app3 doesn't have a widget.
+            // 3. only 1 widget is picked from app1 because we only want to promote one widget per app.
+            List<PendingAddWidgetInfo> recommendedWidgets = mCallback.mRecommendedWidgets.items
+                    .stream()
+                    .map(itemInfo -> (PendingAddWidgetInfo) itemInfo)
+                    .collect(Collectors.toList());
+            assertThat(recommendedWidgets).hasSize(2);
+            assertWidgetInfo(recommendedWidgets.get(0).info, mApp2Provider1);
+            assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider1);
+        });
     }
 
     @Test
-    public void widgetsRecommendationRan_shouldReturnPackageWidgetsWhenEmpty()
-            throws Exception {
+    public void widgetsRecommendationRan_shouldReturnPackageWidgetsWhenEmpty() {
+        runOnExecutorSync(MODEL_EXECUTOR, () -> {
 
-        // Not installed widget
-        AppTarget widget1 = new AppTarget(new AppTargetId("app1"), "app1", "provider3",
-                mUserHandle);
-        // Not installed app
-        AppTarget widget3 = new AppTarget(new AppTargetId("app2"), "app3", "provider1",
-                mUserHandle);
-        // Workspace added widgets
-        AppTarget widget4 = new AppTarget(new AppTargetId("app4"), "app4", "provider1",
-                mUserHandle);
-        AppTarget widget5 = new AppTarget(new AppTargetId("app5"), "app5", "provider1",
-                mUserHandle);
-        mModelHelper.executeTaskForTest(
-                newWidgetsPredicationTask(List.of(widget5, widget3, widget4, widget1)))
-                .forEach(Runnable::run);
+            // Not installed widget
+            AppTarget widget1 = new AppTarget(new AppTargetId("app1"), "app1", "provider3",
+                    mUserHandle);
+            // Not installed app
+            AppTarget widget3 = new AppTarget(new AppTargetId("app2"), "app3", "provider1",
+                    mUserHandle);
+            // Workspace added widgets
+            AppTarget widget4 = new AppTarget(new AppTargetId("app4"), "app4", "provider1",
+                    mUserHandle);
+            AppTarget widget5 = new AppTarget(new AppTargetId("app5"), "app5", "provider1",
+                    mUserHandle);
 
-        // THEN only 2 widgets are returned because the launcher only filters out non-exist widgets.
-        List<PendingAddWidgetInfo> recommendedWidgets = mCallback.mRecommendedWidgets.items
-                .stream()
-                .map(itemInfo -> (PendingAddWidgetInfo) itemInfo)
-                .collect(Collectors.toList());
-        assertThat(recommendedWidgets).hasSize(2);
-        // Another widget from the same package
-        assertWidgetInfo(recommendedWidgets.get(0).info, mApp4Provider2);
-        assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider1);
+            mCallback.mRecommendedWidgets = null;
+            mModelHelper.getModel().enqueueModelUpdateTask(
+                    newWidgetsPredicationTask(List.of(widget5, widget3, widget4, widget1)));
+            runOnExecutorSync(MAIN_EXECUTOR, () -> { });
+
+            // THEN only 2 widgets are returned because the launcher only filters out
+            // non-exist widgets.
+            List<PendingAddWidgetInfo> recommendedWidgets = mCallback.mRecommendedWidgets.items
+                    .stream()
+                    .map(itemInfo -> (PendingAddWidgetInfo) itemInfo)
+                    .collect(Collectors.toList());
+            assertThat(recommendedWidgets).hasSize(2);
+            // Another widget from the same package
+            assertWidgetInfo(recommendedWidgets.get(0).info, mApp4Provider2);
+            assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider1);
+        });
     }
 
     private void assertWidgetInfo(
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0b75c45..5af8e1e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1928,7 +1928,7 @@
             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
                 addAppWidgetFromDrop((PendingAddWidgetInfo) info);
                 break;
-            case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+            case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
                 processShortcutFromDrop((PendingAddShortcutInfo) info);
                 break;
             default:
@@ -2435,7 +2435,6 @@
             final View view;
             switch (item.itemType) {
                 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
-                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                 case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT: {
                     WorkspaceItemInfo info = (WorkspaceItemInfo) item;
                     view = createShortcut(info);
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 4d15ac7..cc1c0f5 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -104,6 +104,8 @@
         });
 
         mContext.getSystemService(LauncherApps.class).registerCallback(mModel);
+        mOnTerminateCallback.add(() ->
+                mContext.getSystemService(LauncherApps.class).unregisterCallback(mModel));
 
         SimpleBroadcastReceiver modelChangeReceiver =
                 new SimpleBroadcastReceiver(mModel::onBroadcastIntent);
@@ -123,8 +125,9 @@
         mOnTerminateCallback.add(userChangeListener::close);
 
         LockedUserState.get(context).runOnUserUnlocked(() -> {
-            CustomWidgetManager.INSTANCE.get(mContext)
-                    .setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts);
+            CustomWidgetManager cwm = CustomWidgetManager.INSTANCE.get(mContext);
+            cwm.setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts);
+            mOnTerminateCallback.add(() -> cwm.setWidgetRefreshCallback(null));
 
             IconObserver observer = new IconObserver();
             SafeCloseable iconChangeTracker = mIconProvider.registerIconChangeListener(
@@ -159,6 +162,7 @@
         mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext),
                 iconCacheFileName != null);
         mOnTerminateCallback.add(mIconCache::close);
+        mOnTerminateCallback.add(mModel::destroy);
     }
 
     private void onNotificationSettingsChanged(boolean areNotificationDotsEnabled) {
@@ -180,9 +184,6 @@
      */
     @Override
     public void close() {
-        mModel.destroy();
-        mContext.getSystemService(LauncherApps.class).unregisterCallback(mModel);
-        CustomWidgetManager.INSTANCE.get(mContext).setWidgetRefreshCallback(null);
         mOnTerminateCallback.executeAllAndDestroy();
     }
 
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 7fda326..2397429 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -89,7 +89,9 @@
 
         /**
          * The gesture is an application created shortcut
+         * @deprecated This is no longer supported. Use {@link #ITEM_TYPE_DEEP_SHORTCUT} instead
          */
+        @Deprecated
         public static final int ITEM_TYPE_SHORTCUT = 1;
 
         /**
@@ -213,7 +215,6 @@
         public static final String itemTypeToString(int type) {
             switch(type) {
                 case ITEM_TYPE_APPLICATION: return "APP";
-                case ITEM_TYPE_SHORTCUT: return "SHORTCUT";
                 case ITEM_TYPE_FOLDER: return "FOLDER";
                 case ITEM_TYPE_APPWIDGET: return "WIDGET";
                 case ITEM_TYPE_CUSTOM_APPWIDGET: return "CUSTOMWIDGET";
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 73bb828..dbf0894 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1840,7 +1840,6 @@
                 != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION);
         boolean willBecomeShortcut =
                 (info.itemType == ITEM_TYPE_APPLICATION ||
-                        info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT ||
                         info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT);
 
         return (aboveShortcut && willBecomeShortcut);
@@ -2759,7 +2758,7 @@
             final PendingAddItemInfo pendingInfo = (PendingAddItemInfo) info;
 
             boolean findNearestVacantCell = true;
-            if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
+            if (pendingInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
                 mTargetCell = findNearestArea(touchXY[0], touchXY[1], spanX, spanY,
                         cellLayout, mTargetCell);
                 float distance = cellLayout.getDistanceFromWorkspaceCellVisualCenter(
@@ -2832,8 +2831,7 @@
             View view;
 
             switch (info.itemType) {
-                case ITEM_TYPE_APPLICATION:
-                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
+                case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
                 case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
                 case LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION:
                     if (info instanceof WorkspaceItemFactory) {
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 4ae54e6..f38cce1 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -881,7 +881,6 @@
         final ItemInfo item = d.dragInfo;
         final int itemType = item.itemType;
         return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
-                itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT ||
                 itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT));
     }
 
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 2c1100f..be643b3 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -260,7 +260,6 @@
     private boolean willAcceptItem(ItemInfo item) {
         final int itemType = item.itemType;
         return ((itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
-                itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT ||
                 itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) &&
                 item != mInfo && !mFolder.isOpen());
     }
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 47677ea..7241b17 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -34,13 +34,9 @@
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import android.content.ContextWrapper;
-import android.content.Intent;
 import android.content.res.TypedArray;
-import android.graphics.Color;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.ColorDrawable;
 import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
@@ -78,8 +74,6 @@
 import com.android.launcher3.celllayout.CellPosMapper;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.icons.BaseIconFactory;
-import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
@@ -183,7 +177,6 @@
     private final DeviceProfile mDp;
     private final DeviceProfile mDpOrig;
     private final Rect mInsets;
-    private final WorkspaceItemInfo mWorkspaceItemInfo;
     private final LayoutInflater mHomeElementInflater;
     private final InsettableFrameLayout mRootView;
     private final Hotseat mHotseat;
@@ -221,19 +214,6 @@
                 mDp.isTaskbarPresent ? 0 : currentWindowInsets.getSystemWindowInsetBottom());
         mDp.updateInsets(mInsets);
 
-        BaseIconFactory iconFactory =
-                new BaseIconFactory(context, mIdp.fillResIconDpi, mIdp.iconBitmapSize) { };
-        BitmapInfo iconInfo = iconFactory.createBadgedIconBitmap(
-                new AdaptiveIconDrawable(
-                        new ColorDrawable(Color.WHITE),
-                        new ColorDrawable(Color.WHITE)));
-
-        mWorkspaceItemInfo = new WorkspaceItemInfo();
-        mWorkspaceItemInfo.bitmap = iconInfo;
-        mWorkspaceItemInfo.intent = new Intent();
-        mWorkspaceItemInfo.contentDescription = mWorkspaceItemInfo.title =
-                context.getString(R.string.label_application);
-
         mHomeElementInflater = LayoutInflater.from(
                 new ContextThemeWrapper(this, R.style.HomeScreenElementTheme));
         mHomeElementInflater.setFactory2(this);
@@ -483,7 +463,6 @@
         for (ItemInfo itemInfo : currentWorkspaceItems) {
             switch (itemInfo.itemType) {
                 case Favorites.ITEM_TYPE_APPLICATION:
-                case Favorites.ITEM_TYPE_SHORTCUT:
                 case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
                     inflateAndAddIcon((WorkspaceItemInfo) itemInfo);
                     break;
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 27d1f78..5e86bd6 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -91,8 +91,7 @@
             List<ItemInfo> filteredItems = new ArrayList<>();
             for (Pair<ItemInfo, Object> entry : mItemList) {
                 ItemInfo item = entry.first;
-                if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION ||
-                        item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
+                if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
                     // Short-circuit this logic if the icon exists somewhere on the workspace
                     if (shortcutExists(dataModel, item.getIntent(), item.user)) {
                         continue;
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 0861e9d..5b0da5b 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -210,7 +210,6 @@
                     // Fall through.
                 }
                 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
-                case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                     workspaceItems.remove(item);
                     break;
                 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
@@ -245,7 +244,6 @@
                 break;
             case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
-            case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                 if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
                         item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
                     workspaceItems.add(item);
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index 9a6cde6..9d16610 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -455,7 +455,6 @@
                 try {
                     // calculate weight
                     switch (entry.itemType) {
-                        case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                         case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: {
                             entry.mIntent = c.getString(indexIntent);
@@ -531,7 +530,6 @@
                 try {
                     // calculate weight
                     switch (entry.itemType) {
-                        case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                         case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: {
                             entry.mIntent = c.getString(indexIntent);
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index fa0511c..9a3abd4 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -286,7 +286,6 @@
 
                     final WorkspaceItemInfo si = new WorkspaceItemInfo();
                     si.user = user;
-                    si.itemType = ITEM_TYPE_APPLICATION;
 
                     LauncherActivityInfo lai;
                     boolean usePackageIcon = laiList.isEmpty();
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 2054d93..33332f0 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -193,9 +193,7 @@
 
     public IconRequestInfo<WorkspaceItemInfo> createIconRequestInfo(
             WorkspaceItemInfo wai, boolean useLowResIcon) {
-        byte[] iconBlob = itemType == Favorites.ITEM_TYPE_SHORTCUT
-                || itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT
-                || restoreFlag != 0
+        byte[] iconBlob = itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT || restoreFlag != 0
                 ? getIconBlob() : null;
 
         return new IconRequestInfo<>(wai, mActivityInfo, iconBlob, useLowResIcon);
@@ -347,7 +345,6 @@
         }
 
         final WorkspaceItemInfo info = new WorkspaceItemInfo();
-        info.itemType = Favorites.ITEM_TYPE_APPLICATION;
         info.user = user;
         info.intent = newIntent;
 
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 1a8cf24..d2a8174 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -503,7 +503,6 @@
 
             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();
@@ -517,9 +516,8 @@
                     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");
+                    if (TextUtils.isEmpty(targetPkg)) {
+                        c.markDeleted("Shortcuts can't have null package");
                         return;
                     }
 
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index ddb8b05..f2afaeb 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -498,7 +498,6 @@
                                 modelItem.container == Favorites.CONTAINER_HOTSEAT)) {
                     switch (modelItem.itemType) {
                         case Favorites.ITEM_TYPE_APPLICATION:
-                        case Favorites.ITEM_TYPE_SHORTCUT:
                         case Favorites.ITEM_TYPE_DEEP_SHORTCUT:
                         case Favorites.ITEM_TYPE_FOLDER:
                             if (!mBgDataModel.workspaceItems.contains(modelItem)) {
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index bfb80b3..1c68292 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -30,7 +30,6 @@
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_TASK;
 import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.CONTAINER_NOT_SET;
 import static com.android.launcher3.shortcuts.ShortcutKey.EXTRA_SHORTCUT_ID;
@@ -87,7 +86,6 @@
 
     /**
      * One of {@link Favorites#ITEM_TYPE_APPLICATION},
-     * {@link Favorites#ITEM_TYPE_SHORTCUT},
      * {@link Favorites#ITEM_TYPE_DEEP_SHORTCUT}
      * {@link Favorites#ITEM_TYPE_FOLDER},
      * {@link Favorites#ITEM_TYPE_APP_PAIR},
@@ -361,13 +359,6 @@
                                 })
                                 .orElse(LauncherAtom.Shortcut.newBuilder()));
                 break;
-            case ITEM_TYPE_SHORTCUT:
-                itemBuilder
-                        .setShortcut(nullableComponent
-                                .map(component -> LauncherAtom.Shortcut.newBuilder()
-                                        .setShortcutName(component.flattenToShortString()))
-                                .orElse(LauncherAtom.Shortcut.newBuilder()));
-                break;
             case ITEM_TYPE_APPWIDGET:
                 itemBuilder
                         .setWidget(nullableComponent
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 01606d4..3ce194d 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -96,7 +96,7 @@
 
 
     public WorkspaceItemInfo() {
-        itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+        itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
     }
 
     public WorkspaceItemInfo(WorkspaceItemInfo info) {
@@ -205,8 +205,8 @@
     @Override
     public ComponentName getTargetComponent() {
         ComponentName cn = super.getTargetComponent();
-        if (cn == null && (itemType == Favorites.ITEM_TYPE_SHORTCUT || hasStatusFlag(
-                FLAG_SUPPORTS_WEB_UI | FLAG_AUTOINSTALL_ICON | FLAG_RESTORED_ICON))) {
+        if (cn == null && hasStatusFlag(
+                FLAG_SUPPORTS_WEB_UI | FLAG_AUTOINSTALL_ICON | FLAG_RESTORED_ICON)) {
             // Legacy shortcuts and promise icons with web UI may not have a componentName but just
             // a packageName. In that case create a empty componentName instead of adding additional
             // check everywhere.
diff --git a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
index b24ee34..06da8c5 100644
--- a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
+++ b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java
@@ -72,7 +72,7 @@
     }
 
     public int getItemType() {
-        return LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+        return LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
     }
 
     @Override
diff --git a/src/com/android/launcher3/util/IntArray.java b/src/com/android/launcher3/util/IntArray.java
index 1c78795..2498242 100644
--- a/src/com/android/launcher3/util/IntArray.java
+++ b/src/com/android/launcher3/util/IntArray.java
@@ -250,6 +250,11 @@
         return b.toString();
     }
 
+    @Override
+    public String toString() {
+        return "IntArray [" + toConcatString() + "]";
+    }
+
     public static IntArray fromConcatString(String concatString) {
         StringTokenizer tokenizer = new StringTokenizer(concatString, ",");
         int[] array = new int[tokenizer.countTokens()];
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index 0899a22..1cb9994 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -48,8 +48,8 @@
     }
 
     public T get(Context context) {
-        if (context instanceof SandboxContext) {
-            return ((SandboxContext) context).getObject(this, mProvider);
+        if (context instanceof SandboxContext sc) {
+            return sc.getObject(this);
         }
 
         if (mValue == null) {
@@ -131,24 +131,22 @@
          * Find a cached object from mObjectMap if we have already created one. If not, generate
          * an object using the provider.
          */
-        protected <T> T getObject(MainThreadInitializedObject<T> object,
-                ObjectProvider<T> provider) {
+        protected <T> T getObject(MainThreadInitializedObject<T> object) {
             synchronized (mDestroyLock) {
                 if (mDestroyed) {
                     Log.e(TAG, "Static object access with a destroyed context");
                 }
-
                 T t = (T) mObjectMap.get(object);
                 if (t != null) {
                     return t;
                 }
                 if (Looper.myLooper() == Looper.getMainLooper()) {
-                    t = createObject(provider);
+                    t = createObject(object);
                     // Check if we've explicitly allowed the object or if it's a SafeCloseable,
                     // it will get destroyed in onDestroy()
                     if (!mAllowedObjects.contains(object) && !(t instanceof SafeCloseable)) {
-                        throw new IllegalStateException(
-                                "Leaking unknown objects " + object + "  " + provider + " " + t);
+                        throw new IllegalStateException("Leaking unknown objects "
+                                + object + "  " + object.mProvider + " " + t);
                     }
                     mObjectMap.put(object, t);
                     mOrderedObjects.add(t);
@@ -157,15 +155,15 @@
             }
 
             try {
-                return MAIN_EXECUTOR.submit(() -> getObject(object, provider)).get();
+                return MAIN_EXECUTOR.submit(() -> getObject(object)).get();
             } catch (InterruptedException | ExecutionException e) {
                 throw new RuntimeException(e);
             }
         }
 
         @UiThread
-        protected <T> T createObject(ObjectProvider<T> provider) {
-            return provider.get(this);
+        protected <T> T createObject(MainThreadInitializedObject<T> object) {
+            return object.mProvider.get(this);
         }
     }
 }
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 515a2d8..3c8dfbb 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -332,6 +332,12 @@
             return null;
         }
 
+        boolean isShortcut = (item instanceof WorkspaceItemInfo)
+                && item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
+                && !((WorkspaceItemInfo) item).isPromise();
+        if (isShortcut && GO_DISABLE_WIDGETS) {
+            return null;
+        }
         ActivityOptionsWrapper options = v != null ? getActivityLaunchOptions(v, item)
                 : makeDefaultActivityOptions(item != null && item.animationType == DEFAULT_NO_ICON
                         ? SPLASH_SCREEN_STYLE_SOLID_COLOR : -1 /* SPLASH_SCREEN_STYLE_UNDEFINED */);
@@ -343,13 +349,11 @@
             intent.setSourceBounds(Utilities.getViewBounds(v));
         }
         try {
-            boolean isShortcut = (item instanceof WorkspaceItemInfo)
-                    && (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT
-                    || item.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT)
-                    && !((WorkspaceItemInfo) item).isPromise();
             if (isShortcut) {
-                // Shortcuts need some special checks due to legacy reasons.
-                startShortcutIntentSafely(intent, optsBundle, item);
+                String id = ((WorkspaceItemInfo) item).getDeepShortcutId();
+                String packageName = intent.getPackage();
+                ((Context) this).getSystemService(LauncherApps.class).startShortcut(
+                        packageName, id, intent.getSourceBounds(), optsBundle, user);
             } else if (user == null || user.equals(Process.myUserHandle())) {
                 // Could be launching some bookkeeping activity
                 context.startActivity(intent, optsBundle);
@@ -424,55 +428,6 @@
         return new ActivityOptionsWrapper(options, new RunnableList());
     }
 
-    /**
-     * Safely launches an intent for a shortcut.
-     *
-     * @param intent Intent to start.
-     * @param optsBundle Optional launch arguments.
-     * @param info Shortcut information.
-     */
-    default void startShortcutIntentSafely(Intent intent, Bundle optsBundle, ItemInfo info) {
-        try {
-            StrictMode.VmPolicy oldPolicy = StrictMode.getVmPolicy();
-            try {
-                // Temporarily disable deathPenalty on all default checks. For eg, shortcuts
-                // containing file Uri's would cause a crash as penaltyDeathOnFileUriExposure
-                // is enabled by default on NYC.
-                StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll()
-                        .penaltyLog().build());
-
-                if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
-                    String id = ((WorkspaceItemInfo) info).getDeepShortcutId();
-                    String packageName = intent.getPackage();
-                    startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user);
-                } else {
-                    // Could be launching some bookkeeping activity
-                    ((Context) this).startActivity(intent, optsBundle);
-                }
-            } finally {
-                StrictMode.setVmPolicy(oldPolicy);
-            }
-        } catch (SecurityException e) {
-            throw e;
-        }
-    }
-
-    /**
-     * A wrapper around the platform method with Launcher specific checks.
-     */
-    default void startShortcut(String packageName, String id, Rect sourceBounds,
-            Bundle startActivityOptions, UserHandle user) {
-        if (GO_DISABLE_WIDGETS) {
-            return;
-        }
-        try {
-            ((Context) this).getSystemService(LauncherApps.class).startShortcut(packageName, id,
-                    sourceBounds, startActivityOptions, user);
-        } catch (SecurityException | IllegalStateException e) {
-            Log.e(TAG, "Failed to start shortcut", e);
-        }
-    }
-
     default CellPosMapper getCellPosMapper() {
         return CellPosMapper.DEFAULT;
     }
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 4641e31..aebf752 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -290,7 +290,6 @@
     static WorkspaceItemInfo placeholderInfo(Intent intent) {
         WorkspaceItemInfo placeholderInfo = new WorkspaceItemInfo();
         placeholderInfo.intent = intent;
-        placeholderInfo.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
         placeholderInfo.container = LauncherSettings.Favorites.CONTAINER_SETTINGS;
         return placeholderInfo;
     }
diff --git a/tests/res/raw/cache_data_updated_task_data.txt b/tests/res/raw/cache_data_updated_task_data.txt
deleted file mode 100644
index 603dbe3..0000000
--- a/tests/res/raw/cache_data_updated_task_data.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-# Model data used by CacheDataUpdatedTaskTest
-
-classMap s com.android.launcher3.model.data.WorkspaceItemInfo
-
-# Items for the BgDataModel
-
-# App shortcuts
-bgItem s itemType=0 title=app1-class1 intent=component=app1/class1 id=1
-bgItem s itemType=0 title=app1-class2 intent=component=app1/class2 id=2
-bgItem s itemType=0 title=app2-class1 intent=component=app2/class1 id=3
-bgItem s itemType=0 title=app2-class2 intent=component=app2/class2 id=4
-
-# Auto install app shortcut
-bgItem s itemType=0 status=2 title=app3-class1 intent=component=app3/class1 id=5
-bgItem s itemType=0 status=2 title=app3-class2 intent=component=app3/class2 id=6
-
-# Custom shortcuts
-bgItem s itemType=1 title=app1-shrt intent=component=app1/class3 id=7
-bgItem s itemType=1 title=app4-shrt intent=component=app4/class1 id=8
-
-# Restored custom shortcut
-bgItem s itemType=1 status=1 title=app3-shrt intent=component=app3/class3 id=9
-bgItem s itemType=1 status=1 title=app5-shrt intent=component=app5/class1 id=10
-
-allApps componentName=app1/class1 intent=component=app1/class1
-allApps componentName=app1/class2 intent=component=app1/class2
-allApps componentName=app2/class1 intent=component=app2/class1
-allApps componentName=app2/class2 intent=component=app2/class2
\ No newline at end of file
diff --git a/tests/res/raw/package_install_state_change_task_data.txt b/tests/res/raw/package_install_state_change_task_data.txt
deleted file mode 100644
index e82ea9d..0000000
--- a/tests/res/raw/package_install_state_change_task_data.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-# Model data used by PackageInstallStateChangeTaskTest
-
-classMap s com.android.launcher3.model.data.WorkspaceItemInfo
-classMap w com.android.launcher3.model.data.LauncherAppWidgetInfo
-
-# Items for the BgDataModel
-
-# App shortcuts
-bgItem s itemType=0 title=app1-class1 intent=component=app1/class1 id=1
-bgItem s itemType=0 title=app1-class2 intent=component=app1/class2 id=2
-bgItem s itemType=0 title=app2-class1 intent=component=app2/class1 id=3
-bgItem s itemType=0 title=app2-class2 intent=component=app2/class2 id=4
-
-# Promise icons for app3
-bgItem s itemType=0 status=2 title=app3-class1 intent=component=app3/class1 id=5
-bgItem s itemType=0 status=2 title=app3-class2 intent=component=app3/class2 id=6
-bgItem s itemType=1 status=1 title=app3-shrt intent=component=app3/class3 id=7
-
-# Promise icon for app4
-bgItem s itemType=1 status=1 title=app4-shrt intent=component=app4/class1 id=8
-
-# Widget
-bgItem w providerName=app4/provider1 id=9
-bgItem w providerName=app5/provider1 id=10
\ No newline at end of file
diff --git a/tests/res/raw/widgets_predication_update_task_data.txt b/tests/res/raw/widgets_predication_update_task_data.txt
deleted file mode 100644
index 941d195..0000000
--- a/tests/res/raw/widgets_predication_update_task_data.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-# Model data used by WidgetsPredictionUpdateTasksTest
-
-classMap s com.android.launcher3.model.data.WorkspaceItemInfo
-classMap w com.android.launcher3.model.data.LauncherAppWidgetInfo
-
-# Items for the BgDataModel
-
-# App shortcuts
-bgItem s itemType=0 title=app1-class1 intent=component=app1/class1 id=1
-bgItem s itemType=0 title=app1-class2 intent=component=app1/class2 id=2
-bgItem s itemType=0 title=app2-class1 intent=component=app2/class1 id=3
-bgItem s itemType=0 title=app2-class2 intent=component=app2/class2 id=4
-
-# Promise icons for app3
-bgItem s itemType=0 status=2 title=app3-class1 intent=component=app3/class1 id=5
-bgItem s itemType=0 status=2 title=app3-class2 intent=component=app3/class2 id=6
-bgItem s itemType=1 status=1 title=app3-shrt intent=component=app3/class3 id=7
-
-# Promise icon for app4
-bgItem s itemType=1 status=1 title=app4-shrt intent=component=app4/class1 id=8
-
-# Widget
-bgItem w providerName=app4/provider1 id=9
-bgItem w providerName=app5/provider1 id=10
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt b/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
index 03352fe..98191fe 100644
--- a/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
+++ b/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
@@ -17,17 +17,18 @@
 
 import android.content.ComponentName
 import android.content.Context
-import android.content.Intent
 import android.graphics.Rect
 import com.android.launcher3.InvariantDeviceProfile
 import com.android.launcher3.LauncherAppState
-import com.android.launcher3.LauncherSettings
+import com.android.launcher3.model.data.AppInfo
 import com.android.launcher3.model.data.WorkspaceItemInfo
-import com.android.launcher3.util.ContentWriter
 import com.android.launcher3.util.GridOccupancy
 import com.android.launcher3.util.IntArray
 import com.android.launcher3.util.IntSparseArrayMap
+import com.android.launcher3.util.LauncherLayoutBuilder
 import com.android.launcher3.util.LauncherModelHelper
+import com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY
+import com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE
 import java.util.UUID
 
 /** Base class for workspace related tests. */
@@ -38,6 +39,7 @@
         val nonEmptyScreenSpaces = listOf(Rect(1, 2, 3, 4))
     }
 
+    protected lateinit var mLayoutBuilder: LauncherLayoutBuilder
     protected lateinit var mTargetContext: Context
     protected lateinit var mIdp: InvariantDeviceProfile
     protected lateinit var mAppState: LauncherAppState
@@ -47,6 +49,7 @@
     protected lateinit var mScreenOccupancy: IntSparseArrayMap<GridOccupancy>
 
     open fun setup() {
+        mLayoutBuilder = LauncherLayoutBuilder()
         mModelHelper = LauncherModelHelper()
         mTargetContext = mModelHelper.sandboxContext
         mIdp = InvariantDeviceProfile.INSTANCE[mTargetContext]
@@ -64,10 +67,11 @@
 
     /** Sets up workspaces with the given screen IDs with some items and a 2x2 space. */
     fun setupWorkspaces(screenIdsWithItems: List<Int>) {
-        var nextItemId = 1
-        screenIdsWithItems.forEach { screenId ->
-            nextItemId = setupWorkspace(nextItemId, screenId, nonEmptyScreenSpaces)
-        }
+        screenIdsWithItems.forEach { screenId -> setupWorkspace(screenId, nonEmptyScreenSpaces) }
+        mModelHelper.setupDefaultLayoutProvider(mLayoutBuilder)
+        mIdp.numRows = 5
+        mIdp.numColumns = mIdp.numRows
+        mModelHelper.loadModelSync()
     }
 
     /**
@@ -78,30 +82,23 @@
         screen1: List<Rect>? = null,
         screen2: List<Rect>? = null,
         screen3: List<Rect>? = null,
-    ) = listOf(screen0, screen1, screen2, screen3).let(this::setupWithSpaces)
+    ) {
+        listOf(screen0, screen1, screen2, screen3).let(this::setupWithSpaces)
+        mModelHelper.setupDefaultLayoutProvider(mLayoutBuilder)
+        mIdp.numRows = 5
+        mIdp.numColumns = mIdp.numRows
+        mModelHelper.loadModelSync()
+    }
 
     private fun setupWithSpaces(workspaceSpaces: List<List<Rect>?>) {
-        var nextItemId = 1
         workspaceSpaces.forEachIndexed { screenId, spaces ->
             if (spaces != null) {
-                nextItemId = setupWorkspace(nextItemId, screenId, spaces)
+                setupWorkspace(screenId, spaces)
             }
         }
     }
 
-    private fun setupWorkspace(startId: Int, screenId: Int, spaces: List<Rect>): Int {
-        return mModelHelper.executeSimpleTask { dataModel ->
-            writeWorkspaceWithSpaces(dataModel, startId, screenId, spaces)
-        }
-    }
-
-    private fun writeWorkspaceWithSpaces(
-        bgDataModel: BgDataModel,
-        itemStartId: Int,
-        screenId: Int,
-        spaces: List<Rect>,
-    ): Int {
-        var itemId = itemStartId
+    private fun setupWorkspace(screenId: Int, spaces: List<Rect>) {
         val occupancy = GridOccupancy(mIdp.numColumns, mIdp.numRows)
         occupancy.markCells(0, 0, mIdp.numColumns, mIdp.numRows, true)
         spaces.forEach { spaceRect -> occupancy.markCells(spaceRect, false) }
@@ -109,35 +106,22 @@
         mScreenOccupancy.append(screenId, occupancy)
         for (x in 0 until mIdp.numColumns) {
             for (y in 0 until mIdp.numRows) {
-                if (!occupancy.cells[x][y]) {
-                    continue
+                if (occupancy.cells[x][y]) {
+                    mLayoutBuilder.atWorkspace(x, y, screenId).putApp(TEST_PACKAGE, TEST_ACTIVITY)
                 }
-                val info = getExistingItem()
-                info.id = itemId++
-                info.screenId = screenId
-                info.cellX = x
-                info.cellY = y
-                info.container = LauncherSettings.Favorites.CONTAINER_DESKTOP
-                bgDataModel.addItem(mTargetContext, info, false)
-                val writer = ContentWriter(mTargetContext)
-                info.writeToValues(writer)
-                writer.put(LauncherSettings.Favorites._ID, info.id)
-                mTargetContext.contentResolver.insert(
-                    LauncherSettings.Favorites.CONTENT_URI,
-                    writer.getValues(mTargetContext)
-                )
             }
         }
-        return itemId
     }
 
     fun getExistingItem() =
-        WorkspaceItemInfo().apply { intent = Intent().setComponent(ComponentName("a", "b")) }
+        WorkspaceItemInfo().apply {
+            intent = AppInfo.makeLaunchIntent(ComponentName(TEST_PACKAGE, TEST_ACTIVITY))
+        }
 
     fun getNewItem(): WorkspaceItemInfo {
         val itemPackage = UUID.randomUUID().toString()
         return WorkspaceItemInfo().apply {
-            intent = Intent().setComponent(ComponentName(itemPackage, itemPackage))
+            intent = AppInfo.makeLaunchIntent(ComponentName(itemPackage, itemPackage))
         }
     }
 }
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
index 6636b8a..1155227 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
@@ -23,7 +23,7 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.util.Executors
 import com.android.launcher3.util.IntArray
-import com.android.launcher3.util.IntSet
+import com.android.launcher3.util.TestUtil.runOnExecutorSync
 import com.android.launcher3.util.any
 import com.android.launcher3.util.eq
 import com.android.launcher3.util.same
@@ -32,8 +32,6 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
@@ -46,11 +44,7 @@
 @RunWith(AndroidJUnit4::class)
 class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
 
-    @Captor private lateinit var mAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
-
-    @Captor private lateinit var mNotAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
-
-    @Mock private lateinit var mDataModelCallbacks: BgDataModel.Callbacks
+    private lateinit var mDataModelCallbacks: MyCallbacks
 
     @Mock private lateinit var mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder
 
@@ -58,7 +52,7 @@
     override fun setup() {
         super.setup()
         MockitoAnnotations.initMocks(this)
-        whenever(mDataModelCallbacks.getPagesToBindSynchronously(any())).thenReturn(IntSet())
+        mDataModelCallbacks = MyCallbacks()
         Executors.MAIN_EXECUTOR.submit { mModelHelper.model.addCallbacks(mDataModelCallbacks) }
             .get()
     }
@@ -105,7 +99,7 @@
         val addedItems = testAddItems(nonEmptyScreenIds, itemToAdd)
 
         assertThat(addedItems.size).isEqualTo(0)
-        verifyZeroInteractions(mWorkspaceItemSpaceFinder, mDataModelCallbacks)
+        verifyZeroInteractions(mWorkspaceItemSpaceFinder)
     }
 
     @Test
@@ -191,22 +185,14 @@
     ): List<AddedItem> {
         setupWorkspaces(nonEmptyScreenIds)
         val task = newTask(*itemsToAdd)
-        var updateCount = 0
-        mModelHelper.executeTaskForTest(task).forEach {
-            updateCount++
-            it.run()
-        }
 
         val addedItems = mutableListOf<AddedItem>()
-        if (updateCount > 0) {
-            verify(mDataModelCallbacks)
-                .bindAppsAdded(
-                    any(),
-                    mNotAnimatedItemArgumentCaptor.capture(),
-                    mAnimatedItemArgumentCaptor.capture()
-                )
-            addedItems.addAll(mAnimatedItemArgumentCaptor.value.map { AddedItem(it, true) })
-            addedItems.addAll(mNotAnimatedItemArgumentCaptor.value.map { AddedItem(it, false) })
+
+        runOnExecutorSync(Executors.MODEL_EXECUTOR) {
+            mDataModelCallbacks.addedItems.clear()
+            mModelHelper.model.enqueueModelUpdateTask(task)
+            runOnExecutorSync(Executors.MAIN_EXECUTOR) {}
+            addedItems.addAll(mDataModelCallbacks.addedItems)
         }
 
         return addedItems
@@ -224,3 +210,17 @@
 }
 
 private data class AddedItem(val itemInfo: ItemInfo, val isAnimated: Boolean)
+
+private class MyCallbacks : BgDataModel.Callbacks {
+
+    val addedItems = mutableListOf<AddedItem>()
+
+    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) })
+    }
+}
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index f55b244..f771052 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -1,32 +1,31 @@
 package com.android.launcher3.model;
 
+import static android.os.Process.myUserHandle;
+
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY;
+import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY2;
+import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY3;
+import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
+import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotSame;
 import static org.junit.Assert.assertTrue;
 
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Color;
-import android.os.Process;
-import android.os.UserHandle;
-import android.os.UserManager;
 
-import androidx.annotation.NonNull;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.icons.cache.CachingLogic;
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.LauncherLayoutBuilder;
 import com.android.launcher3.util.LauncherModelHelper;
+import com.android.launcher3.util.PackageUserKey;
 
 import org.junit.After;
 import org.junit.Before;
@@ -35,6 +34,7 @@
 
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.List;
 
 /**
  * Tests for {@link CacheDataUpdatedTask}
@@ -43,49 +43,40 @@
 @RunWith(AndroidJUnit4.class)
 public class CacheDataUpdatedTaskTest {
 
-    private static final String NEW_LABEL_PREFIX = "new-label-";
+    private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
+    private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
 
     private LauncherModelHelper mModelHelper;
+    private Context mContext;
+
+    private int mSession1;
 
     @Before
     public void setup() throws Exception {
         mModelHelper = new LauncherModelHelper();
-        mModelHelper.initializeData("cache_data_updated_task_data");
+        mContext = mModelHelper.sandboxContext;
+        mSession1 = mModelHelper.createInstallerSession(PENDING_APP_1);
+        mModelHelper.createInstallerSession(PENDING_APP_2);
 
-        // Add placeholder entries in the cache to simulate update
-        Context context = mModelHelper.sandboxContext;
-        IconCache iconCache = LauncherAppState.getInstance(context).getIconCache();
-        CachingLogic<ItemInfo> placeholderLogic = new CachingLogic<ItemInfo>() {
-            @Override
-            @NonNull
-            public ComponentName getComponent(@NonNull ItemInfo info) {
-                return info.getTargetComponent();
-            }
+        LauncherLayoutBuilder builder = new LauncherLayoutBuilder()
+                .atHotseat(1).putFolder("MyFolder")
+                .addApp(TEST_PACKAGE, TEST_ACTIVITY)    // 2
+                .addApp(TEST_PACKAGE, TEST_ACTIVITY2)   // 3
+                .addApp(TEST_PACKAGE, TEST_ACTIVITY3)   // 4
 
-            @NonNull
-            @Override
-            public UserHandle getUser(@NonNull ItemInfo info) {
-                return info.user;
-            }
+                // Pending App 1
+                .addApp(PENDING_APP_1, TEST_ACTIVITY)   // 5
+                .addApp(PENDING_APP_1, TEST_ACTIVITY2)  // 6
+                .addApp(PENDING_APP_1, TEST_ACTIVITY3)  // 7
 
-            @NonNull
-            @Override
-            public CharSequence getLabel(@NonNull ItemInfo info) {
-                return NEW_LABEL_PREFIX + info.id;
-            }
-
-            @NonNull
-            @Override
-            public BitmapInfo loadIcon(@NonNull Context context, @NonNull ItemInfo info) {
-                return BitmapInfo.of(Bitmap.createBitmap(1, 1, Config.ARGB_8888), Color.RED);
-            }
-        };
-
-        UserManager um = context.getSystemService(UserManager.class);
-        for (ItemInfo info : mModelHelper.getBgDataModel().itemsIdMap) {
-            iconCache.addIconToDBAndMemCache(info, placeholderLogic, new PackageInfo(),
-                    um.getSerialNumberForUser(info.user), true);
-        }
+                // Pending App 2
+                .addApp(PENDING_APP_2, TEST_ACTIVITY)   // 8
+                .addApp(PENDING_APP_2, TEST_ACTIVITY2)  // 9
+                .addApp(PENDING_APP_2, TEST_ACTIVITY3)  // 10
+                .build();
+        mModelHelper.setupDefaultLayoutProvider(builder);
+        mModelHelper.loadModelSync();
+        assertEquals(10, mModelHelper.getBgDataModel().itemsIdMap.size());
     }
 
     @After
@@ -94,27 +85,63 @@
     }
 
     private CacheDataUpdatedTask newTask(int op, String... pkg) {
-        return new CacheDataUpdatedTask(op, Process.myUserHandle(),
+        return new CacheDataUpdatedTask(op, myUserHandle(),
                 new HashSet<>(Arrays.asList(pkg)));
     }
 
     @Test
-    public void testCacheUpdate_update_apps() throws Exception {
-        // Clear all icons from apps list so that its easy to check what was updated
-        for (AppInfo info : mModelHelper.getAllAppsList().data) {
-            info.bitmap = BitmapInfo.LOW_RES_INFO;
-        }
+    public void testCacheUpdate_update_apps() {
+        // Run on model executor so that no other task runs in the middle.
+        runOnExecutorSync(MODEL_EXECUTOR, () -> {
+            // Clear all icons from apps list so that its easy to check what was updated
+            allItems().forEach(wi -> wi.bitmap = BitmapInfo.LOW_RES_INFO);
 
-        mModelHelper.executeTaskForTest(newTask(CacheDataUpdatedTask.OP_CACHE_UPDATE, "app1"));
+            mModelHelper.getModel().enqueueModelUpdateTask(
+                    newTask(CacheDataUpdatedTask.OP_CACHE_UPDATE, TEST_PACKAGE));
 
-        // Verify that only the app icons of app1 (id 1 & 2) are updated. Custom shortcut (id 7)
-        // is not updated
-        verifyUpdate(1, 2);
+            // Verify that only the app icons of TEST_PACKAGE (id 2, 3, 4) are updated.
+            verifyUpdate(2, 3, 4);
+        });
+    }
 
-        // Verify that only app1 var updated in allAppsList
-        assertFalse(mModelHelper.getAllAppsList().data.isEmpty());
-        for (AppInfo info : mModelHelper.getAllAppsList().data) {
-            if (info.componentName.getPackageName().equals("app1")) {
+    @Test
+    public void testSessionUpdate_ignores_normal_apps() {
+        // Run on model executor so that no other task runs in the middle.
+        runOnExecutorSync(MODEL_EXECUTOR, () -> {
+            // Clear all icons from apps list so that its easy to check what was updated
+            allItems().forEach(wi -> wi.bitmap = BitmapInfo.LOW_RES_INFO);
+
+            mModelHelper.getModel().enqueueModelUpdateTask(
+                    newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, TEST_PACKAGE));
+
+            // TEST_PACKAGE has no restored shortcuts. Verify that nothing was updated.
+            verifyUpdate();
+        });
+    }
+
+    @Test
+    public void testSessionUpdate_updates_pending_apps() {
+        // Run on model executor so that no other task runs in the middle.
+        runOnExecutorSync(MODEL_EXECUTOR, () -> {
+            LauncherAppState.getInstance(mContext).getIconCache().updateSessionCache(
+                    new PackageUserKey(PENDING_APP_1, myUserHandle()),
+                    mContext.getPackageManager().getPackageInstaller().getSessionInfo(mSession1));
+
+            // Clear all icons from apps list so that its easy to check what was updated
+            allItems().forEach(wi -> wi.bitmap = BitmapInfo.LOW_RES_INFO);
+
+            mModelHelper.getModel().enqueueModelUpdateTask(
+                    newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, PENDING_APP_1));
+
+            // Only restored apps from PENDING_APP_1 (id 5, 6, 7) are updated
+            verifyUpdate(5, 6, 7);
+        });
+    }
+
+    private void verifyUpdate(int... idsUpdated) {
+        IntSet updates = IntSet.wrap(idsUpdated);
+        for (WorkspaceItemInfo info : allItems()) {
+            if (updates.contains(info.id)) {
                 assertFalse(info.bitmap.isNullOrLowRes());
             } else {
                 assertTrue(info.bitmap.isNullOrLowRes());
@@ -122,33 +149,7 @@
         }
     }
 
-    @Test
-    public void testSessionUpdate_ignores_normal_apps() throws Exception {
-        mModelHelper.executeTaskForTest(newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, "app1"));
-
-        // app1 has no restored shortcuts. Verify that nothing was updated.
-        verifyUpdate();
-    }
-
-    @Test
-    public void testSessionUpdate_updates_pending_apps() throws Exception {
-        mModelHelper.executeTaskForTest(newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, "app3"));
-
-        // app3 has only restored apps (id 5, 6) and shortcuts (id 9). Verify that only apps were
-        // were updated
-        verifyUpdate(5, 6);
-    }
-
-    private void verifyUpdate(Integer... idsUpdated) {
-        HashSet<Integer> updates = new HashSet<>(Arrays.asList(idsUpdated));
-        for (ItemInfo info : mModelHelper.getBgDataModel().itemsIdMap) {
-            if (updates.contains(info.id)) {
-                assertEquals(NEW_LABEL_PREFIX + info.id, info.title);
-                assertFalse(((WorkspaceItemInfo) info).bitmap.isNullOrLowRes());
-            } else {
-                assertNotSame(NEW_LABEL_PREFIX + info.id, info.title);
-                assertTrue(((WorkspaceItemInfo) info).bitmap.isNullOrLowRes());
-            }
-        }
+    private List<WorkspaceItemInfo> allItems() {
+        return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).contents;
     }
 }
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
index 3b480ca..4fa5352 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
+++ b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
@@ -24,7 +24,6 @@
 import android.os.Process
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.InvariantDeviceProfile
 import com.android.launcher3.LauncherPrefs
 import com.android.launcher3.LauncherPrefs.Companion.WORKSPACE_SIZE
@@ -108,8 +107,8 @@
     fun testMigration() {
         // Src Hotseat icons
         addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE)
-        addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE)
-        addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE)
+        addItem(ITEM_TYPE_DEEP_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE)
+        addItem(ITEM_TYPE_DEEP_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE)
         addItem(ITEM_TYPE_APPLICATION, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE)
         // Src grid icons
         // _ _ _ _ _
@@ -124,7 +123,7 @@
         addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 4, 3, testPackage9, 9, TMP_TABLE)
 
         // Dest hotseat icons
-        addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2)
+        addItem(ITEM_TYPE_DEEP_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2)
         // Dest grid icons
         addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage10)
 
@@ -219,8 +218,8 @@
         // Hotseat items in grid A
         // 1 2 _ 3 4
         addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE)
-        addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE)
-        addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE)
+        addItem(ITEM_TYPE_DEEP_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE)
+        addItem(ITEM_TYPE_DEEP_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE)
         addItem(ITEM_TYPE_APPLICATION, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE)
         // Workspace items in grid A
         // _ _ _ _ _
@@ -235,7 +234,7 @@
 
         // Hotseat items in grid B
         // 2 _ _ _
-        addItem(ITEM_TYPE_SHORTCUT, 0, CONTAINER_HOTSEAT, 0, 0, testPackage2)
+        addItem(ITEM_TYPE_DEEP_SHORTCUT, 0, CONTAINER_HOTSEAT, 0, 0, testPackage2)
         // Workspace items in grid B
         // _ _ _ _
         // _ _ _ 10
@@ -291,7 +290,7 @@
                 null
             )
                 ?: throw IllegalStateException()
-        var locMap = parseLocMap(context, c)
+        var locMap = parseLocMap(c)
         // Expected items in grid B
         // _ _ _ _
         // 5 6 7 8
@@ -348,7 +347,7 @@
                 null
             )
                 ?: throw IllegalStateException()
-        locMap = parseLocMap(context, c)
+        locMap = parseLocMap(c)
         // Expected workspace items in grid A
         // _ _ _ _ _
         // _ _ _ _ 5
@@ -410,7 +409,7 @@
                 null
             )
                 ?: throw IllegalStateException()
-        locMap = parseLocMap(context, c)
+        locMap = parseLocMap(c)
         // Expected workspace items in grid B
         // _ _ _ _
         // 5 6 _ 8
@@ -436,7 +435,7 @@
         c.close()
     }
 
-    private fun parseLocMap(context: Context, c: Cursor): Map<String, Triple<Int, Int, Int>> {
+    private fun parseLocMap(c: Cursor): Map<String, Triple<Int, Int, Int>> {
         // Check workspace items
         val intentIndex = c.getColumnIndex(INTENT)
         val screenIndex = c.getColumnIndex(SCREEN)
@@ -465,7 +464,16 @@
                     1,
                     TMP_TABLE
                 ),
-                addItem(ITEM_TYPE_SHORTCUT, 1, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE),
+                addItem(
+                    ITEM_TYPE_DEEP_SHORTCUT,
+                    1,
+                    CONTAINER_HOTSEAT,
+                    0,
+                    0,
+                    testPackage2,
+                    2,
+                    TMP_TABLE
+                ),
                 addItem(
                     ITEM_TYPE_APPLICATION,
                     2,
@@ -476,7 +484,16 @@
                     3,
                     TMP_TABLE
                 ),
-                addItem(ITEM_TYPE_SHORTCUT, 3, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE)
+                addItem(
+                    ITEM_TYPE_DEEP_SHORTCUT,
+                    3,
+                    CONTAINER_HOTSEAT,
+                    0,
+                    0,
+                    testPackage4,
+                    4,
+                    TMP_TABLE
+                )
             )
         val numSrcDatabaseHotseatIcons = srcHotseatItems.size
         idp.numDatabaseHotseatIcons = 6
@@ -532,9 +549,9 @@
     @Test
     fun migrateFromLargerHotseat() {
         addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE)
-        addItem(ITEM_TYPE_SHORTCUT, 2, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE)
+        addItem(ITEM_TYPE_DEEP_SHORTCUT, 2, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE)
         addItem(ITEM_TYPE_APPLICATION, 3, CONTAINER_HOTSEAT, 0, 0, testPackage3, 3, TMP_TABLE)
-        addItem(ITEM_TYPE_SHORTCUT, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE)
+        addItem(ITEM_TYPE_DEEP_SHORTCUT, 4, CONTAINER_HOTSEAT, 0, 0, testPackage4, 4, TMP_TABLE)
         addItem(ITEM_TYPE_APPLICATION, 5, CONTAINER_HOTSEAT, 0, 0, testPackage5, 5, TMP_TABLE)
 
         idp.numDatabaseHotseatIcons = 4
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
index 78812c0..544ed6b 100644
--- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -30,7 +30,7 @@
 import static com.android.launcher3.LauncherSettings.Favorites.INTENT;
 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.ITEM_TYPE_DEEP_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;
@@ -158,13 +158,13 @@
 
     @Test
     public void loadSimpleShortcut() {
-        initCursor(ITEM_TYPE_SHORTCUT, "my-shortcut");
+        initCursor(ITEM_TYPE_DEEP_SHORTCUT, "my-shortcut");
         assertTrue(mLoaderCursor.moveToNext());
 
         WorkspaceItemInfo info = mLoaderCursor.loadSimpleWorkspaceItem();
         assertTrue(mApp.getIconCache().isDefaultIcon(info.bitmap, info.user));
         assertEquals("my-shortcut", info.title);
-        assertEquals(ITEM_TYPE_SHORTCUT, info.itemType);
+        assertEquals(ITEM_TYPE_DEEP_SHORTCUT, info.itemType);
     }
 
     @Test
diff --git a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
index 519191e..4ba61ac 100644
--- a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
@@ -1,5 +1,12 @@
 package com.android.launcher3.model;
 
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY;
+import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY2;
+import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY3;
+import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
+import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
+
 import static org.junit.Assert.assertEquals;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -9,6 +16,8 @@
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.PackageInstallInfo;
+import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.LauncherLayoutBuilder;
 import com.android.launcher3.util.LauncherModelHelper;
 
 import org.junit.After;
@@ -16,9 +25,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.Arrays;
-import java.util.HashSet;
-
 /**
  * Tests for {@link PackageInstallStateChangedTask}
  */
@@ -26,12 +32,36 @@
 @RunWith(AndroidJUnit4.class)
 public class PackageInstallStateChangedTaskTest {
 
+    private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
+    private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
+
     private LauncherModelHelper mModelHelper;
+    private IntSet mDownloadingApps;
 
     @Before
     public void setup() throws Exception {
         mModelHelper = new LauncherModelHelper();
-        mModelHelper.initializeData("package_install_state_change_task_data");
+        mModelHelper.createInstallerSession(PENDING_APP_1);
+        mModelHelper.createInstallerSession(PENDING_APP_2);
+
+        LauncherLayoutBuilder builder = new LauncherLayoutBuilder()
+                .atWorkspace(0, 0, 1).putApp(TEST_PACKAGE, TEST_ACTIVITY)               // 1
+                .atWorkspace(0, 0, 2).putApp(TEST_PACKAGE, TEST_ACTIVITY2)              // 2
+                .atWorkspace(0, 0, 3).putApp(TEST_PACKAGE, TEST_ACTIVITY3)              // 3
+
+                .atWorkspace(0, 0, 4).putApp(PENDING_APP_1, TEST_ACTIVITY)              // 4
+                .atWorkspace(0, 0, 5).putApp(PENDING_APP_1, TEST_ACTIVITY2)             // 5
+                .atWorkspace(0, 0, 6).putApp(PENDING_APP_1, TEST_ACTIVITY3)             // 6
+                .atWorkspace(0, 0, 7).putWidget(PENDING_APP_1, "pending.widget", 1, 1)  // 7
+
+                .atWorkspace(0, 0, 8).putApp(PENDING_APP_2, TEST_ACTIVITY)              // 8
+                .atWorkspace(0, 0, 9).putApp(PENDING_APP_2, TEST_ACTIVITY2)             // 9
+                .atWorkspace(0, 0, 10).putApp(PENDING_APP_2, TEST_ACTIVITY3);           // 10
+
+        mDownloadingApps = IntSet.wrap(4, 5, 6, 7, 8, 9, 10);
+        mModelHelper.setupDefaultLayoutProvider(builder);
+        mModelHelper.loadModelSync();
+        assertEquals(10, mModelHelper.getBgDataModel().itemsIdMap.size());
     }
 
     @After
@@ -47,36 +77,45 @@
     }
 
     @Test
-    public void testSessionUpdate_ignore_installed() throws Exception {
-        mModelHelper.executeTaskForTest(newTask("app1", 30));
+    public void testSessionUpdate_ignore_installed() {
+        // Run on model executor so that no other task runs in the middle.
+        runOnExecutorSync(MODEL_EXECUTOR, () -> {
+            mModelHelper.getModel().enqueueModelUpdateTask(newTask(TEST_PACKAGE, 30));
 
-        // No shortcuts were updated
-        verifyProgressUpdate(0);
+            // No shortcuts were updated
+            verifyProgressUpdate(0);
+        });
     }
 
     @Test
-    public void testSessionUpdate_shortcuts_updated() throws Exception {
-        mModelHelper.executeTaskForTest(newTask("app3", 30));
+    public void testSessionUpdate_shortcuts_updated() {
+        // Run on model executor so that no other task runs in the middle.
+        runOnExecutorSync(MODEL_EXECUTOR, () -> {
+            mModelHelper.getModel().enqueueModelUpdateTask(newTask(PENDING_APP_1, 30));
 
-        verifyProgressUpdate(30, 5, 6, 7);
+            verifyProgressUpdate(30, 4, 5, 6, 7);
+        });
     }
 
     @Test
-    public void testSessionUpdate_widgets_updated() throws Exception {
-        mModelHelper.executeTaskForTest(newTask("app4", 30));
+    public void testSessionUpdate_widgets_updated() {
+        // Run on model executor so that no other task runs in the middle.
+        runOnExecutorSync(MODEL_EXECUTOR, () -> {
+            mModelHelper.getModel().enqueueModelUpdateTask(newTask(PENDING_APP_2, 30));
 
-        verifyProgressUpdate(30, 8, 9);
+            verifyProgressUpdate(30, 8, 9, 10);
+        });
     }
 
-    private void verifyProgressUpdate(int progress, Integer... idsUpdated) {
-        HashSet<Integer> updates = new HashSet<>(Arrays.asList(idsUpdated));
+    private void verifyProgressUpdate(int progress, int... idsUpdated) {
+        IntSet updates = IntSet.wrap(idsUpdated);
         for (ItemInfo info : mModelHelper.getBgDataModel().itemsIdMap) {
-            if (info instanceof WorkspaceItemInfo) {
-                assertEquals(updates.contains(info.id) ? progress: 100,
-                        ((WorkspaceItemInfo) info).getProgressLevel());
+            int expectedProgress = updates.contains(info.id) ? progress
+                    : (mDownloadingApps.contains(info.id) ? 0 : 100);
+            if (info instanceof WorkspaceItemInfo wi) {
+                assertEquals(expectedProgress, wi.getProgressLevel());
             } else {
-                assertEquals(updates.contains(info.id) ? progress: -1,
-                        ((LauncherAppWidgetInfo) info).installProgress);
+                assertEquals(expectedProgress, ((LauncherAppWidgetInfo) info).installProgress);
             }
         }
     }
diff --git a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
index 2f57634..8e4e998 100644
--- a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -87,9 +87,8 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        whenever(context.getObject(eq(WindowManagerProxy.INSTANCE), any()))
-            .thenReturn(windowManagerProxy)
-        whenever(context.getObject(eq(LauncherPrefs.INSTANCE), any())).thenReturn(launcherPrefs)
+        whenever(context.getObject(eq(WindowManagerProxy.INSTANCE))).thenReturn(windowManagerProxy)
+        whenever(context.getObject(eq(LauncherPrefs.INSTANCE))).thenReturn(launcherPrefs)
 
         // Mock WindowManagerProxy
         val displayInfo =
diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
index 976afcd..9dc04a1 100644
--- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -15,34 +15,31 @@
  */
 package com.android.launcher3.util;
 
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL;
+
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
-import static com.android.launcher3.LauncherSettings.Favorites.CONTENT_URI;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
 
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
 
-import android.content.ComponentName;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
-import android.content.res.Resources;
-import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Color;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
-import android.os.Process;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
 import android.util.ArrayMap;
@@ -57,13 +54,10 @@
 import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherProvider;
-import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.model.AllAppsList;
 import com.android.launcher3.model.BgDataModel;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.ItemInstallQueue;
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.testing.TestInformationProvider;
@@ -72,37 +66,25 @@
 import com.android.launcher3.util.window.WindowManagerProxy;
 import com.android.launcher3.widget.custom.CustomWidgetManager;
 
-import org.mockito.ArgumentCaptor;
-
-import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.io.InputStreamReader;
+import java.io.IOException;
 import java.io.OutputStreamWriter;
-import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
-import java.util.function.Function;
 
 /**
  * Utility class to help manage Launcher Model and related objects for test.
  */
 public class LauncherModelHelper {
 
-    public static final int DESKTOP = LauncherSettings.Favorites.CONTAINER_DESKTOP;
-    public static final int HOTSEAT = LauncherSettings.Favorites.CONTAINER_HOTSEAT;
-
-    public static final int APP_ICON = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
-    public static final int SHORTCUT = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
-    public static final int NO__ICON = -1;
-
-    public static final String TEST_PACKAGE = testContext().getPackageName();
+    public static final String TEST_PACKAGE = getInstrumentation().getContext().getPackageName();
     public static final String TEST_ACTIVITY = "com.android.launcher3.tests.Activity2";
+    public static final String TEST_ACTIVITY2 = "com.android.launcher3.tests.Activity3";
+    public static final String TEST_ACTIVITY3 = "com.android.launcher3.tests.Activity4";
 
     // Authority for providing a test default-workspace-layout data.
     private static final String TEST_PROVIDER_AUTHORITY =
@@ -110,39 +92,18 @@
     private static final int DEFAULT_BITMAP_SIZE = 10;
     private static final int DEFAULT_GRID_SIZE = 4;
 
-    private final HashMap<Class, HashMap<String, Field>> mFieldCache = new HashMap<>();
-    private final MockContentResolver mMockResolver = new MockContentResolver();
-    public final TestLauncherProvider provider;
     public final SandboxModelContext sandboxContext;
 
-    public final long defaultProfileId;
+    private final RunnableList mDestroyTask = new RunnableList();
 
     private BgDataModel mDataModel;
-    private AllAppsList mAllAppsList;
 
     public LauncherModelHelper() {
-        Context context = getApplicationContext();
-        // System settings cache content provider. Ensure that they are statically initialized
-        Settings.Secure.getString(context.getContentResolver(), "test");
-        Settings.System.getString(context.getContentResolver(), "test");
-        Settings.Global.getString(context.getContentResolver(), "test");
-
-        provider = new TestLauncherProvider();
         sandboxContext = new SandboxModelContext();
-        defaultProfileId = UserCache.INSTANCE.get(sandboxContext)
-                .getSerialNumberForUser(Process.myUserHandle());
-        setupProvider(LauncherProvider.AUTHORITY, provider);
     }
 
     public void setupProvider(String authority, ContentProvider provider) {
-        ProviderInfo providerInfo = new ProviderInfo();
-        providerInfo.authority = authority;
-        providerInfo.applicationInfo = sandboxContext.getApplicationInfo();
-        provider.attachInfo(sandboxContext, providerInfo);
-        mMockResolver.addProvider(providerInfo.authority, provider);
-        doReturn(providerInfo)
-                .when(sandboxContext.mPm)
-                .resolveContentProvider(eq(authority), anyInt());
+        sandboxContext.setupProvider(authority, provider);
     }
 
     public LauncherModel getModel() {
@@ -151,16 +112,35 @@
 
     public synchronized BgDataModel getBgDataModel() {
         if (mDataModel == null) {
-            mDataModel = ReflectionHelpers.getField(getModel(), "mBgDataModel");
+            getModel().enqueueModelUpdateTask(new ModelUpdateTask() {
+                @Override
+                public void init(@NonNull LauncherAppState app, @NonNull LauncherModel model,
+                        @NonNull BgDataModel dataModel, @NonNull AllAppsList allAppsList,
+                        @NonNull Executor uiExecutor) {
+                    mDataModel = dataModel;
+                }
+
+                @Override
+                public void run() { }
+            });
         }
         return mDataModel;
     }
 
-    public synchronized AllAppsList getAllAppsList() {
-        if (mAllAppsList == null) {
-            mAllAppsList = ReflectionHelpers.getField(getModel(), "mBgAllAppsList");
-        }
-        return mAllAppsList;
+    /**
+     * Creates a installer session for the provided package.
+     */
+    public int createInstallerSession(String pkg) throws IOException {
+        SessionParams sp = new SessionParams(MODE_FULL_INSTALL);
+        sp.setAppPackageName(pkg);
+        Bitmap icon = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
+        icon.eraseColor(Color.RED);
+        sp.setAppIcon(icon);
+        sp.setAppLabel(pkg);
+        PackageInstaller pi = sandboxContext.getPackageManager().getPackageInstaller();
+        int sessionId = pi.createSession(sp);
+        mDestroyTask.add(() -> pi.abandonSession(sessionId));
+        return sessionId;
     }
 
     public void destroy() {
@@ -175,6 +155,8 @@
         waitOrThrow(l1);
         sandboxContext.onDestroy();
         l2.countDown();
+
+        mDestroyTask.executeAllAndDestroy();
     }
 
     private void waitOrThrow(CountDownLatch latch) {
@@ -186,184 +168,6 @@
     }
 
     /**
-     * Synchronously executes the task and returns all the UI callbacks posted.
-     */
-    public List<Runnable> executeTaskForTest(ModelUpdateTask task) throws Exception {
-        LauncherModel model = getModel();
-        if (!model.isModelLoaded()) {
-            ReflectionHelpers.setField(model, "mModelLoaded", true);
-        }
-        Executor mockExecutor = mock(Executor.class);
-        model.enqueueModelUpdateTask(new ModelUpdateTask() {
-            @Override
-            public void init(@NonNull final LauncherAppState app,
-                    @NonNull final LauncherModel model, @NonNull final BgDataModel dataModel,
-                    @NonNull final AllAppsList allAppsList, @NonNull final Executor uiExecutor) {
-                task.init(app, model, dataModel, allAppsList, mockExecutor);
-            }
-
-            @Override
-            public void run() {
-                task.run();
-            }
-        });
-        MODEL_EXECUTOR.submit(() -> null).get();
-
-        ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
-        verify(mockExecutor, atLeast(0)).execute(captor.capture());
-        return captor.getAllValues();
-    }
-
-    /**
-     * Synchronously executes a task on the model
-     */
-    public <T> T executeSimpleTask(Function<BgDataModel, T> task) throws Exception {
-        BgDataModel dataModel = getBgDataModel();
-        return MODEL_EXECUTOR.submit(() -> task.apply(dataModel)).get();
-    }
-
-    /**
-     * Initializes mock data for the test.
-     */
-    public void initializeData(String resourceName) throws Exception {
-        BgDataModel bgDataModel = getBgDataModel();
-        AllAppsList allAppsList = getAllAppsList();
-
-        MODEL_EXECUTOR.submit(() -> {
-            // Copy apk from resources to a local file and install from there.
-            Resources resources = testContext().getResources();
-            int resId = resources.getIdentifier(
-                    resourceName, "raw", testContext().getPackageName());
-            try (BufferedReader reader = new BufferedReader(new InputStreamReader(
-                    resources.openRawResource(resId)))) {
-                String line;
-                HashMap<String, Class> classMap = new HashMap<>();
-                while ((line = reader.readLine()) != null) {
-                    line = line.trim();
-                    if (line.startsWith("#") || line.isEmpty()) {
-                        continue;
-                    }
-                    String[] commands = line.split(" ");
-                    switch (commands[0]) {
-                        case "classMap":
-                            classMap.put(commands[1], Class.forName(commands[2]));
-                            break;
-                        case "bgItem":
-                            bgDataModel.addItem(sandboxContext,
-                                    (ItemInfo) initItem(classMap.get(commands[1]), commands, 2),
-                                    false);
-                            break;
-                        case "allApps":
-                            allAppsList.add((AppInfo) initItem(AppInfo.class, commands, 1), null);
-                            break;
-                    }
-                }
-            } catch (Exception e) {
-                throw new RuntimeException(e);
-            }
-        }).get();
-    }
-
-    private Object initItem(Class clazz, String[] fieldDef, int startIndex) throws Exception {
-        HashMap<String, Field> cache = mFieldCache.get(clazz);
-        if (cache == null) {
-            cache = new HashMap<>();
-            Class c = clazz;
-            while (c != null) {
-                for (Field f : c.getDeclaredFields()) {
-                    f.setAccessible(true);
-                    cache.put(f.getName(), f);
-                }
-                c = c.getSuperclass();
-            }
-            mFieldCache.put(clazz, cache);
-        }
-
-        Object item = clazz.newInstance();
-        for (int i = startIndex; i < fieldDef.length; i++) {
-            String[] fieldData = fieldDef[i].split("=", 2);
-            Field f = cache.get(fieldData[0]);
-            Class type = f.getType();
-            if (type == int.class || type == long.class) {
-                f.set(item, Integer.parseInt(fieldData[1]));
-            } else if (type == CharSequence.class || type == String.class) {
-                f.set(item, fieldData[1]);
-            } else if (type == Intent.class) {
-                if (!fieldData[1].startsWith("#Intent")) {
-                    fieldData[1] = "#Intent;" + fieldData[1] + ";end";
-                }
-                f.set(item, Intent.parseUri(fieldData[1], 0));
-            } else if (type == ComponentName.class) {
-                f.set(item, ComponentName.unflattenFromString(fieldData[1]));
-            } else {
-                throw new Exception("Added parsing logic for "
-                        + f.getName() + " of type " + f.getType());
-            }
-        }
-        return item;
-    }
-
-    public int addItem(int type, int screen, int container, int x, int y) {
-        return addItem(type, screen, container, x, y, defaultProfileId, TEST_PACKAGE);
-    }
-
-    public int addItem(int type, int screen, int container, int x, int y, long profileId) {
-        return addItem(type, screen, container, x, y, profileId, TEST_PACKAGE);
-    }
-
-    public int addItem(int type, int screen, int container, int x, int y, String packageName) {
-        return addItem(type, screen, container, x, y, defaultProfileId, packageName);
-    }
-
-    public int addItem(int type, int screen, int container, int x, int y, String packageName,
-            int id, Uri contentUri) {
-        addItem(type, screen, container, x, y, defaultProfileId, packageName, id, contentUri);
-        return id;
-    }
-
-    /**
-     * Adds a mock item in the DB.
-     * @param type {@link #APP_ICON} or {@link #SHORTCUT} or >= 2 for
-     *             folder (where the type represents the number of items in the folder).
-     */
-    public int addItem(int type, int screen, int container, int x, int y, long profileId,
-            String packageName) {
-        int id = LauncherSettings.Settings.call(sandboxContext.getContentResolver(),
-                LauncherSettings.Settings.METHOD_NEW_ITEM_ID)
-                .getInt(LauncherSettings.Settings.EXTRA_VALUE);
-        addItem(type, screen, container, x, y, profileId, packageName, id, CONTENT_URI);
-        return id;
-    }
-
-    public void addItem(int type, int screen, int container, int x, int y, long profileId,
-            String packageName, int id, Uri contentUri) {
-        ContentValues values = new ContentValues();
-        values.put(LauncherSettings.Favorites._ID, id);
-        values.put(LauncherSettings.Favorites.CONTAINER, container);
-        values.put(LauncherSettings.Favorites.SCREEN, screen);
-        values.put(LauncherSettings.Favorites.CELLX, x);
-        values.put(LauncherSettings.Favorites.CELLY, y);
-        values.put(LauncherSettings.Favorites.SPANX, 1);
-        values.put(LauncherSettings.Favorites.SPANY, 1);
-        values.put(LauncherSettings.Favorites.PROFILE_ID, profileId);
-
-        if (type == APP_ICON || type == SHORTCUT) {
-            values.put(LauncherSettings.Favorites.ITEM_TYPE, type);
-            values.put(LauncherSettings.Favorites.INTENT,
-                    new Intent(Intent.ACTION_MAIN).setPackage(packageName).toUri(0));
-        } else {
-            values.put(LauncherSettings.Favorites.ITEM_TYPE,
-                    LauncherSettings.Favorites.ITEM_TYPE_FOLDER);
-            // Add folder items.
-            for (int i = 0; i < type; i++) {
-                addItem(APP_ICON, 0, id, 0, 0, profileId);
-            }
-        }
-
-        sandboxContext.getContentResolver().insert(contentUri, values);
-    }
-
-    /**
      * Sets up a mock provider to load the provided layout by default, next time the layout loads
      */
     public LauncherModelHelper setupDefaultLayoutProvider(LauncherLayoutBuilder builder)
@@ -394,6 +198,9 @@
             }
         };
         setupProvider(TEST_PROVIDER_AUTHORITY, cp);
+        mDestroyTask.add(() -> runOnExecutorSync(MODEL_EXECUTOR, () ->
+                UiDevice.getInstance(getInstrumentation()).executeShellCommand(
+                        "settings delete secure launcher3.layout.provider")));
         return this;
     }
 
@@ -402,46 +209,16 @@
      */
     public void loadModelSync() throws ExecutionException, InterruptedException {
         Callbacks mockCb = new Callbacks() { };
-        Executors.MAIN_EXECUTOR.submit(() -> getModel().addCallbacksAndLoad(mockCb)).get();
+        MAIN_EXECUTOR.submit(() -> getModel().addCallbacksAndLoad(mockCb)).get();
 
         Executors.MODEL_EXECUTOR.submit(() -> { }).get();
-        Executors.MAIN_EXECUTOR.submit(() -> { }).get();
-        Executors.MAIN_EXECUTOR.submit(() -> getModel().removeCallbacks(mockCb)).get();
+        MAIN_EXECUTOR.submit(() -> { }).get();
+        MAIN_EXECUTOR.submit(() -> getModel().removeCallbacks(mockCb)).get();
     }
 
-    /**
-     * An extension of LauncherProvider backed up by in-memory database.
-     */
-    public static class TestLauncherProvider extends LauncherProvider {
+    public static class SandboxModelContext extends SandboxContext {
 
-        @Override
-        public boolean onCreate() {
-            return true;
-        }
-
-        public SQLiteDatabase getDb() {
-            return getModelDbController().getDb();
-        }
-    }
-
-    public static boolean deleteContents(File dir) {
-        File[] files = dir.listFiles();
-        boolean success = true;
-        if (files != null) {
-            for (File file : files) {
-                if (file.isDirectory()) {
-                    success &= deleteContents(file);
-                }
-                if (!file.delete()) {
-                    success = false;
-                }
-            }
-        }
-        return success;
-    }
-
-    public class SandboxModelContext extends SandboxContext {
-
+        private final MockContentResolver mMockResolver = new MockContentResolver();
         private final ArrayMap<String, Object> mSpiedServices = new ArrayMap<>();
         private final PackageManager mPm;
         private final File mDbDir;
@@ -453,8 +230,31 @@
                     DisplayController.INSTANCE, CustomWidgetManager.INSTANCE,
                     SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE, LockedUserState.INSTANCE,
                     ItemInstallQueue.INSTANCE, WindowManagerProxy.INSTANCE);
+
+            // System settings cache content provider. Ensure that they are statically initialized
+            Settings.Secure.getString(
+                    ApplicationProvider.getApplicationContext().getContentResolver(), "test");
+            Settings.System.getString(
+                    ApplicationProvider.getApplicationContext().getContentResolver(), "test");
+            Settings.Global.getString(
+                    ApplicationProvider.getApplicationContext().getContentResolver(), "test");
+
             mPm = spy(getBaseContext().getPackageManager());
             mDbDir = new File(getCacheDir(), UUID.randomUUID().toString());
+            setupProvider(LauncherProvider.AUTHORITY, new LauncherProvider() {
+                @Override
+                public boolean onCreate() {
+                    return true;
+                }
+            });
+        }
+
+        @Override
+        protected <T> T createObject(MainThreadInitializedObject<T> object) {
+            if (object == LauncherAppState.INSTANCE) {
+                return (T) new LauncherAppState(this, null /* iconCacheFileName */);
+            }
+            return super.createObject(object);
         }
 
         public SandboxModelContext allow(MainThreadInitializedObject object) {
@@ -505,9 +305,30 @@
             mSpiedServices.put(name, result);
             return result;
         }
-    }
 
-    private static Context testContext() {
-        return getInstrumentation().getContext();
+        public void setupProvider(String authority, ContentProvider provider) {
+            ProviderInfo providerInfo = new ProviderInfo();
+            providerInfo.authority = authority;
+            providerInfo.applicationInfo = getApplicationInfo();
+            provider.attachInfo(this, providerInfo);
+            mMockResolver.addProvider(providerInfo.authority, provider);
+            doReturn(providerInfo).when(mPm).resolveContentProvider(eq(authority), anyInt());
+        }
+
+        private static boolean deleteContents(File dir) {
+            File[] files = dir.listFiles();
+            boolean success = true;
+            if (files != null) {
+                for (File file : files) {
+                    if (file.isDirectory()) {
+                        success &= deleteContents(file);
+                    }
+                    if (!file.delete()) {
+                        success = false;
+                    }
+                }
+            }
+            return success;
+        }
     }
 }
diff --git a/tests/src/com/android/launcher3/util/TestUtil.java b/tests/src/com/android/launcher3/util/TestUtil.java
index 4981795..e2c1fde 100644
--- a/tests/src/com/android/launcher3/util/TestUtil.java
+++ b/tests/src/com/android/launcher3/util/TestUtil.java
@@ -53,6 +53,7 @@
 import java.io.OutputStream;
 import java.security.MessageDigest;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
 import java.util.function.Predicate;
 import java.util.function.ToIntFunction;
 
@@ -154,6 +155,30 @@
             Settings.Secure.putString(context.getContentResolver(), LAYOUT_DIGEST_KEY, null);
     }
 
+    /**
+     * Utility method to run a task synchronously which converts any exceptions to RuntimeException
+     */
+    public static void runOnExecutorSync(ExecutorService executor, UncheckedRunnable task) {
+        try {
+            executor.submit(() -> {
+                try {
+                    task.run();
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }).get();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** Interface to indicate a runnable which can throw any exception. */
+    public interface UncheckedRunnable {
+        /** Method to run the task */
+        void run() throws Exception;
+    }
+
+
     private static class PackageInstallCheck extends LauncherApps.Callback
             implements AutoCloseable {