Merge "Sending original motion events to launcher overlay along with inferred values" into main
diff --git a/Android.bp b/Android.bp
index 61042f6..4354b66 100644
--- a/Android.bp
+++ b/Android.bp
@@ -203,6 +203,7 @@
         "animationlib",
         "com_android_launcher3_flags_lib",
         "com_android_wm_shell_flags_lib",
+        "android.appwidget.flags-aconfig-java",
     ],
     sdk_version: "current",
     min_sdk_version: min_launcher3_sdk_version,
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 6d899d9..d379132 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -150,6 +150,13 @@
 }
 
 flag {
+    name: "enable_generated_previews"
+    namespace: "launcher"
+    description: "Enables support for RemoteViews previews in the widget picker."
+    bug: "306546610"
+}
+
+flag {
   name: "enable_categorized_widget_suggestions"
   namespace: "launcher"
   description: "Enables widget suggestions in widget picker to be displayed in categories"
diff --git a/quickstep/res/layout/keyboard_quick_switch_view.xml b/quickstep/res/layout/keyboard_quick_switch_view.xml
index 5af8d51..3256b0b 100644
--- a/quickstep/res/layout/keyboard_quick_switch_view.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_view.xml
@@ -43,7 +43,7 @@
             android:layout_height="@dimen/keyboard_quick_switch_no_recent_items_icon_size"
             android:layout_marginBottom="@dimen/keyboard_quick_switch_no_recent_items_icon_margin"
             android:src="@drawable/ic_empty_recents"
-            android:tint="?androidprv:attr/materialColorOnSurfaceInverse"
+            android:tint="?androidprv:attr/materialColorOnSurface"
             android:importantForAccessibility="no"
 
             app:layout_constraintVertical_chainStyle="packed"
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 325c255..14f615e 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -105,6 +105,8 @@
     <string name="back_gesture_feedback_cancelled">Make sure you swipe from the right or left edge to the middle of the screen and let go</string>
     <!-- Feedback shown after completing the back gesture step if the user is following the full gesture tutorial flow. [CHAR LIMIT=100] -->
     <string name="back_gesture_feedback_complete_with_overview_follow_up">You learned how to swipe from the right to go back. Next up, learn how to switch apps.</string>
+    <!-- Feedback shown after completing the back gesture step if the user is following the full gesture tutorial flow. [CHAR LIMIT=100] -->
+    <string name="back_gesture_feedback_complete_with_follow_up">You completed the go back gesture. Next up, learn how to switch apps.</string>
     <!-- Feedback shown after completing the back gesture step if the user started this tutorial individually. [CHAR LIMIT=100] -->
     <string name="back_gesture_feedback_complete_without_follow_up">You completed the go back gesture</string>
     <!-- Feedback shown during interactive parts of Back gesture tutorial when the gesture is within the nav bar region. [CHAR LIMIT=100] -->
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index bdc86b2..350c752 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -273,7 +273,7 @@
     </style>
 
     <style name="KeyboardQuickSwitchText.OnBackground" parent="KeyboardQuickSwitchText">
-        <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceInverse</item>
+        <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
     </style>
 
     <style name="GestureTutorialActivity" parent="@style/AppTheme">
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 7a69c55..747c9cb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -803,6 +803,11 @@
     private void addJankMonitorListener(
             AnimatorSet animator, boolean expanding, @StashAnimation int animationType) {
         View v = mControllers.taskbarActivityContext.getDragLayer();
+        if (!v.isAttachedToWindow()) {
+            // If the task bar drag layer is not attached to window, we don't need to monitor jank
+            // (actually we can't pass in an unattached view either).
+            return;
+        }
         int action = expanding ? InteractionJankMonitor.CUJ_TASKBAR_EXPAND :
                 InteractionJankMonitor.CUJ_TASKBAR_COLLAPSE;
         animator.addListener(new AnimatorListenerAdapter() {
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 404bca9..6757cd8 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -85,7 +85,9 @@
     public int getSuccessFeedbackSubtitle() {
         return mTutorialFragment.isAtFinalStep()
                 ? R.string.back_gesture_feedback_complete_without_follow_up
-                : R.string.back_gesture_feedback_complete_with_overview_follow_up;
+                : ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
+                        ? R.string.back_gesture_feedback_complete_with_follow_up
+                        : R.string.back_gesture_feedback_complete_with_overview_follow_up;
     }
 
     @Override
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index 87cbdd1..fc50853 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -6,7 +6,6 @@
 import android.view.Surface.Rotation
 import android.view.View
 import android.view.ViewGroup
-import android.widget.FrameLayout
 import android.widget.ImageView
 import android.widget.LinearLayout
 import android.widget.Space
@@ -14,7 +13,9 @@
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.R
 import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION
-import com.android.launcher3.taskbar.TaskbarManager
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_CONTEXTUAL_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_NAV_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_START_CONTEXTUAL_BUTTONS
 import com.android.systemui.shared.rotation.RotationButton
 import java.lang.IllegalStateException
 import org.junit.Assume.assumeTrue
@@ -52,11 +53,11 @@
         whenever(mockNavLayout.findViewById<View>(R.id.recent_apps)).thenReturn(mockRecentsButton)
 
         // Init top level layout
-        whenever(mockParentButtonContainer.findViewById<LinearLayout>(R.id.end_nav_buttons))
+        whenever(mockParentButtonContainer.requireViewById<LinearLayout>(ID_END_NAV_BUTTONS))
             .thenReturn(mockNavLayout)
-        whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.end_contextual_buttons))
+        whenever(mockParentButtonContainer.requireViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS))
             .thenReturn(mockEndContextualLayout)
-        whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.start_contextual_buttons))
+        whenever(mockParentButtonContainer.requireViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS))
             .thenReturn(mockStartContextualLayout)
     }
 
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index d124746..99fca62 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -441,17 +441,35 @@
             @Override
             public void execute(@NonNull final LauncherAppState app,
                     @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
+                IconCache iconCache = app.getIconCache();
                 final IntSet removedIds = new IntSet();
+                HashSet<WorkspaceItemInfo> archivedItemsToCacheRefresh = new HashSet<>();
+                HashSet<String> archivedPackagesToCacheRefresh = new HashSet<>();
                 synchronized (dataModel) {
                     for (ItemInfo info : dataModel.itemsIdMap) {
                         if (info instanceof WorkspaceItemInfo
                                 && ((WorkspaceItemInfo) info).hasPromiseIconUi()
                                 && user.equals(info.user)
-                                && info.getIntent() != null
-                                && TextUtils.equals(packageName, info.getIntent().getPackage())) {
-                            removedIds.add(info.id);
+                                && info.getIntent() != null) {
+                            if (TextUtils.equals(packageName, info.getIntent().getPackage())) {
+                                removedIds.add(info.id);
+                            }
+                            if (((WorkspaceItemInfo) info).isArchived()) {
+                                WorkspaceItemInfo workspaceItem = (WorkspaceItemInfo) info;
+                                // Remove package cache icon for archived app in case of a session
+                                // failure.
+                                mApp.getIconCache().removeIconsForPkg(packageName, user);
+                                // Refresh icons on the workspace for archived apps.
+                                iconCache.getTitleAndIcon(workspaceItem,
+                                        workspaceItem.usingLowResIcon());
+                                archivedPackagesToCacheRefresh.add(packageName);
+                                archivedItemsToCacheRefresh.add(workspaceItem);
+                            }
                         }
                     }
+                    if (!archivedPackagesToCacheRefresh.isEmpty()) {
+                        apps.updateIconsAndLabels(archivedPackagesToCacheRefresh, user);
+                    }
                 }
 
                 if (!removedIds.isEmpty()) {
@@ -459,6 +477,10 @@
                             ItemInfoMatcher.ofItemIds(removedIds),
                             "removed because install session failed");
                 }
+                if (!archivedItemsToCacheRefresh.isEmpty()) {
+                    bindUpdatedWorkspaceItems(archivedItemsToCacheRefresh.stream().toList());
+                    bindApplicationsIfNeeded();
+                }
             }
         });
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
index 7067fa2..911612f 100644
--- a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
+++ b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
@@ -71,7 +71,7 @@
 
         @Override
         protected int getVerticalSnapPreference() {
-            return SNAP_TO_START;
+            return SNAP_TO_ANY;
         }
 
         @Override
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index 051cf50..009a2aa6 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -93,11 +93,14 @@
      * Sets the current set of apps and sets mapping for {@link PackageUserKey} to Uid for
      * the current set of apps.
      *
-     * <p> Note that shouldPreinflate param should be set to {@code false} for taskbar, because this
-     * method is too late to preinflate all apps, as user will open all apps in the same frame.
+     * <p> Note that shouldPreinflate param should be set to {@code false} for taskbar, because
+     * this method is too late to preinflate all apps, as user will open all apps in the frame
+     *
+     * <p>Param: apps are required to be sorted using the comparator COMPONENT_KEY_COMPARATOR
+     * in order to enable binary search on the mApps store
      */
     public void setApps(@Nullable AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map,
-            boolean shouldPreinflate)  {
+            boolean shouldPreinflate) {
         mApps = apps == null ? EMPTY_ARRAY : apps;
         mModelFlags = flags;
         notifyUpdate();
diff --git a/src/com/android/launcher3/allapps/AppInfoComparator.java b/src/com/android/launcher3/allapps/AppInfoComparator.java
index 311a40e..a0867db 100644
--- a/src/com/android/launcher3/allapps/AppInfoComparator.java
+++ b/src/com/android/launcher3/allapps/AppInfoComparator.java
@@ -43,9 +43,7 @@
     @Override
     public int compare(AppInfo a, AppInfo b) {
         // Order by the title in the current locale
-        int result = mLabelComparator.compare(
-                a.title == null ? "" : a.title.toString(),
-                b.title == null ? "" : b.title.toString());
+        int result = mLabelComparator.compare(getSortingTitle(a), getSortingTitle(b));
         if (result != 0) {
             return result;
         }
@@ -64,4 +62,14 @@
             return aUserSerial.compareTo(bUserSerial);
         }
     }
+
+    private String getSortingTitle(AppInfo info) {
+        if (info.appTitle != null) {
+            return info.appTitle.toString();
+        }
+        if (info.title != null) {
+            return info.title.toString();
+        }
+        return "";
+    }
 }
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 2f7f51e..d8fa90a 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -219,7 +219,19 @@
         CacheEntry entry = cacheLocked(application.componentName,
                 application.user, () -> null, mLauncherActivityInfoCachingLogic,
                 false, application.usingLowResIcon());
-        if (entry.bitmap != null && !isDefaultIcon(entry.bitmap, application.user)) {
+        if (entry.bitmap == null || isDefaultIcon(entry.bitmap, application.user)) {
+            return;
+        }
+
+        boolean preferPackageIcon = application.isArchived();
+        if (preferPackageIcon) {
+            String packageName = application.getTargetPackage();
+            CacheEntry packageEntry =
+                    cacheLocked(new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
+                            application.user, () -> null, mLauncherActivityInfoCachingLogic,
+                            false, application.usingLowResIcon());
+            applyPackageEntry(packageEntry, application, entry);
+        } else {
             applyCacheEntry(entry, application);
         }
     }
@@ -227,10 +239,14 @@
     /**
      * Fill in {@param info} with the icon and label for {@param activityInfo}
      */
+    @SuppressWarnings("NewApi")
     public synchronized void getTitleAndIcon(ItemInfoWithIcon info,
             LauncherActivityInfo activityInfo, boolean useLowResIcon) {
+        boolean isAppArchived = Utilities.enableSupportForArchiving() && activityInfo != null
+                && activityInfo.getActivityInfo().isArchived;
         // If we already have activity info, no need to use package icon
-        getTitleAndIcon(info, () -> activityInfo, false, useLowResIcon);
+        getTitleAndIcon(info, () -> activityInfo, isAppArchived, useLowResIcon,
+                isAppArchived);
     }
 
     /**
@@ -309,7 +325,7 @@
         } else {
             Intent intent = info.getIntent();
             getTitleAndIcon(info, () -> mLauncherApps.resolveActivity(intent, info.user),
-                    true, useLowResIcon);
+                    true, useLowResIcon, info.isArchived());
         }
     }
 
@@ -334,6 +350,28 @@
     }
 
     /**
+     * Fill in {@param mWorkspaceItemInfo} with the icon and label for {@param info}
+     */
+    public synchronized void getTitleAndIcon(
+            @NonNull ItemInfoWithIcon infoInOut,
+            @NonNull Supplier<LauncherActivityInfo> activityInfoProvider,
+            boolean usePkgIcon, boolean useLowResIcon, boolean preferPackageEntry) {
+        CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), infoInOut.user,
+                activityInfoProvider, mLauncherActivityInfoCachingLogic, usePkgIcon,
+                useLowResIcon);
+        if (preferPackageEntry) {
+            String packageName = infoInOut.getTargetPackage();
+            CacheEntry packageEntry = cacheLocked(
+                    new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
+                    infoInOut.user, activityInfoProvider, mLauncherActivityInfoCachingLogic,
+                    usePkgIcon, useLowResIcon);
+            applyPackageEntry(packageEntry, infoInOut, entry);
+        } else {
+            applyCacheEntry(entry, infoInOut);
+        }
+    }
+
+    /**
      * Creates an sql cursor for a query of a set of ItemInfoWithIcon icons and titles.
      *
      * @param iconRequestInfos List of IconRequestInfos representing titles and icons to query.
@@ -551,6 +589,19 @@
         }
     }
 
+    protected void applyPackageEntry(@NonNull final CacheEntry packageEntry,
+            @NonNull final ItemInfoWithIcon info, @NonNull final CacheEntry fallbackEntry) {
+        info.title = Utilities.trim(packageEntry.title);
+        info.appTitle = Utilities.trim(fallbackEntry.title);
+        info.contentDescription = packageEntry.contentDescription;
+        info.bitmap = packageEntry.bitmap;
+        if (packageEntry.bitmap == null) {
+            // TODO: entry.bitmap can never be null, so this should not happen at all.
+            Log.wtf(TAG, "Cannot find bitmap from the cache, default icon was loaded.");
+            info.bitmap = getDefaultIcon(info.user);
+        }
+    }
+
     public Drawable getFullResIcon(LauncherActivityInfo info) {
         return mIconProvider.getIcon(info, mIconDpi);
     }
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index c99b889..ddf4023 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -1,5 +1,9 @@
 package com.android.launcher3.model;
 
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX;
+
 import static com.android.launcher3.Utilities.ATLEAST_S;
 
 import android.annotation.SuppressLint;
@@ -7,13 +11,19 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
+import android.util.SparseArray;
+import android.widget.RemoteViews;
 
+import androidx.core.os.BuildCompat;
+
+import com.android.launcher3.Flags;
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.pm.ShortcutConfigActivityInfo;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.WidgetManagerHelper;
 
 /**
  * An wrapper over various items displayed in a widget picker,
@@ -28,9 +38,11 @@
     public final String label;
     public final CharSequence description;
     public final int spanX, spanY;
+    public final SparseArray<RemoteViews> generatedPreviews;
 
     public WidgetItem(LauncherAppWidgetProviderInfo info,
-            InvariantDeviceProfile idp, IconCache iconCache, Context context) {
+            InvariantDeviceProfile idp, IconCache iconCache, Context context,
+            WidgetManagerHelper helper) {
         super(info.provider, info.getProfile());
 
         label = iconCache.getTitleNoCache(info);
@@ -40,6 +52,27 @@
 
         spanX = Math.min(info.spanX, idp.numColumns);
         spanY = Math.min(info.spanY, idp.numRows);
+
+        if (BuildCompat.isAtLeastV() && Flags.enableGeneratedPreviews()) {
+            generatedPreviews = new SparseArray<>(3);
+            for (int widgetCategory : new int[] {
+                    WIDGET_CATEGORY_HOME_SCREEN,
+                    WIDGET_CATEGORY_KEYGUARD,
+                    WIDGET_CATEGORY_SEARCHBOX,
+            }) {
+                if ((widgetCategory & widgetInfo.generatedPreviewCategories) != 0) {
+                    generatedPreviews.put(widgetCategory,
+                            helper.loadGeneratedPreview(widgetInfo, widgetCategory));
+                }
+            }
+        } else {
+            generatedPreviews = null;
+        }
+    }
+
+    public WidgetItem(LauncherAppWidgetProviderInfo info,
+            InvariantDeviceProfile idp, IconCache iconCache, Context context) {
+        this(info, idp, iconCache, context, new WidgetManagerHelper(context));
     }
 
     public WidgetItem(ShortcutConfigActivityInfo info, IconCache iconCache, PackageManager pm) {
@@ -50,6 +83,7 @@
         widgetInfo = null;
         activityInfo = info;
         spanX = spanY = 1;
+        generatedPreviews = null;
     }
 
     /**
@@ -78,4 +112,15 @@
     public boolean isShortcut() {
         return activityInfo != null;
     }
+
+    /**
+     * Returns whether this {@link WidgetItem} has a generated preview for the given widget
+     * category.
+     */
+    public boolean hasGeneratedPreview(int widgetCategory) {
+        if (!Flags.enableGeneratedPreviews() || generatedPreviews == null) {
+            return false;
+        }
+        return generatedPreviews.contains(widgetCategory);
+    }
 }
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 86393a0..55849c2 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -160,6 +160,13 @@
     public CharSequence title;
 
     /**
+     * Optionally set: The appTitle might e.g. be different if {@code title} is used to
+     * display progress (e.g. Downloading..).
+     */
+    @Nullable
+    public CharSequence appTitle;
+
+    /**
      * Content description of the item.
      */
     @Nullable
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 8f5e2b6..c75f9d1 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.widget;
 
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
+
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
 import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.fromProviderInfo;
 import static com.android.launcher3.widget.util.WidgetSizes.getWidgetItemSizePx;
@@ -44,6 +46,7 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.CheckLongPressHelper;
+import com.android.launcher3.Flags;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.icons.FastBitmapDrawable;
@@ -241,6 +244,11 @@
             mAppWidgetHostViewPreview = createAppWidgetHostView(context);
             setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, item.widgetInfo,
                     mRemoteViewsPreview);
+        } else if (Flags.enableGeneratedPreviews()
+                && item.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)) {
+            mAppWidgetHostViewPreview = createAppWidgetHostView(context);
+            setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, item.widgetInfo,
+                    item.generatedPreviews.get(WIDGET_CATEGORY_HOME_SCREEN));
         } else if (item.hasPreviewLayout()) {
             // If the context is a Launcher activity, DragView will show mAppWidgetHostViewPreview
             // as a preview during drag & drop. And thus, we should use LauncherAppWidgetHostView,
diff --git a/src/com/android/launcher3/widget/WidgetManagerHelper.java b/src/com/android/launcher3/widget/WidgetManagerHelper.java
index 058523b..52767a4 100644
--- a/src/com/android/launcher3/widget/WidgetManagerHelper.java
+++ b/src/com/android/launcher3/widget/WidgetManagerHelper.java
@@ -24,8 +24,11 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.UserHandle;
+import android.widget.RemoteViews;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 
 import com.android.launcher3.model.WidgetsModel;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -130,6 +133,23 @@
                 appWidgetId).getBoolean(WIDGET_OPTION_RESTORE_COMPLETED);
     }
 
+
+    /**
+     * Load RemoteViews preview for this provider if available.
+     *
+     * @param info The provider info for the widget you want to preview.
+     * @param widgetCategory The widget category for which you want to display previews.
+     *
+     * @return Returns the widget preview that matches selected category, if available.
+     */
+    @Nullable
+    @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+    public RemoteViews loadGeneratedPreview(@NonNull AppWidgetProviderInfo info,
+            int widgetCategory) {
+        if (!android.appwidget.flags.Flags.generatedPreviews()) return null;
+        return mAppWidgetManager.getWidgetPreview(info.provider, info.getProfile(), widgetCategory);
+    }
+
     private static Stream<AppWidgetProviderInfo> allWidgetsSteam(Context context) {
         AppWidgetManager awm = context.getSystemService(AppWidgetManager.class);
         return Stream.concat(
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 4c5bfd8..8b983fc 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -147,7 +147,8 @@
                         LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo);
 
                 widgetsAndShortcuts.add(new WidgetItem(
-                        launcherWidgetInfo, idp, app.getIconCache(), app.getContext()));
+                        launcherWidgetInfo, idp, app.getIconCache(), app.getContext(),
+                        widgetManager));
                 updatedItems.add(launcherWidgetInfo);
             }
 
@@ -206,6 +207,7 @@
 
     public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
             LauncherAppState app) {
+        WidgetManagerHelper widgetManager = new WidgetManagerHelper(app.getContext());
         for (Entry<PackageItemInfo, List<WidgetItem>> entry : mWidgetsList.entrySet()) {
             if (packageNames.contains(entry.getKey().packageName)) {
                 List<WidgetItem> items = entry.getValue();
@@ -219,7 +221,7 @@
                         } else {
                             items.set(i, new WidgetItem(item.widgetInfo,
                                     app.getInvariantDeviceProfile(), app.getIconCache(),
-                                    app.getContext()));
+                                    app.getContext(), widgetManager));
                         }
                     }
                 }
@@ -337,4 +339,4 @@
             return mMap.values();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/tests/Android.bp b/tests/Android.bp
index ed8609e..9ce0777 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -127,6 +127,7 @@
         "testables",
         "com_android_launcher3_flags_lib",
         "com_android_wm_shell_flags_lib",
+        "android.appwidget.flags-aconfig-java",
     ],
     manifest: "AndroidManifest-common.xml",
     platform_apis: true,
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 978e1f2..679bd01 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -193,6 +193,7 @@
 
     protected AbstractLauncherUiTest() {
         mLauncher.enableCheckEventsForSuccessfulGestures();
+        mLauncher.setAnomalyChecker(AbstractLauncherUiTest::verifyKeyguardInvisible);
         try {
             mDevice.setOrientationNatural();
         } catch (RemoteException e) {
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index cdde605..e17994c 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -204,6 +204,9 @@
 
     private LogEventChecker mEventChecker;
 
+    // UI anomaly checker provided by the test.
+    private Runnable mTestAnomalyChecker;
+
     private boolean mCheckEventsForSuccessfulGestures = false;
     private Runnable mOnLauncherCrashed;
 
@@ -573,8 +576,31 @@
         checkForAnomaly(false, false);
     }
 
+    /**
+     * Allows the test to provide a pluggable anomaly checker. It’s supposed to throw an exception
+     * if the check fails. The test may provide its own anomaly checker, for example, if it wants to
+     * check for an anomaly that’s recognized by the standard TAPL anomaly checker, but wants a
+     * custom error message, such as adding information whether the keyguard is seen for the first
+     * time during the shard execution.
+     */
+    public void setAnomalyChecker(Runnable anomalyChecker) {
+        mTestAnomalyChecker = anomalyChecker;
+    }
+
+    /**
+     * Verifies that there are no visible UI anomalies. An "anomaly" is a state of UI that should
+     * never happen during the text execution. Anomaly is something different from just “regular”
+     * unexpected state of the Launcher such as when we see Workspace after swiping up to All Apps.
+     * Workspace is a normal state. We can contrast this with an anomaly, when, for example, we see
+     * a lock screen. Launcher tests can never bring the lock screen, so the very presence of the
+     * lock screen is an indication that something went very wrong, and perhaps is caused by reasons
+     * outside of the Launcher and its tests, perhaps, by a crash in System UI. Diagnosing anomalies
+     * helps to understand faster whether the problem is in the Launcher or its tests, or outside.
+     */
     public void checkForAnomaly(
             boolean ignoreNavmodeChangeStates, boolean ignoreOnlySystemUiViews) {
+        if (mTestAnomalyChecker != null) mTestAnomalyChecker.run();
+
         final String systemAnomalyMessage =
                 getSystemAnomalyMessage(ignoreNavmodeChangeStates, ignoreOnlySystemUiViews);
         if (systemAnomalyMessage != null) {
diff --git a/tests/res/layout/test_layout_appwidget_red.xml b/tests/res/layout/test_layout_appwidget_red.xml
index 48d3e81..0f2bda3 100644
--- a/tests/res/layout/test_layout_appwidget_red.xml
+++ b/tests/res/layout/test_layout_appwidget_red.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/content"
     android:orientation="vertical"
     android:background="#FFFF0000"
     android:layout_width="match_parent"
diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
index 6fce4c6..0f23165 100644
--- a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
+++ b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
@@ -25,6 +25,7 @@
 
 import android.content.Intent;
 import android.platform.test.annotations.PlatinumTest;
+import android.platform.test.rule.ScreenRecordRule;
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -130,6 +131,7 @@
     @Test
     @PortraitLandscape
     @PlatinumTest(focusArea = "launcher")
+    @ScreenRecordRule.ScreenRecord // b/322228038
     public void testAllAppsFromHome() {
         // Test opening all apps
         assertNotNull("switchToAllApps() returned null",
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index f771052..6c35f68 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -2,21 +2,33 @@
 
 import static android.os.Process.myUserHandle;
 
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
 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.DUMMY_CLASS_NAME;
+import static com.android.launcher3.util.TestUtil.DUMMY_PACKAGE;
 import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
+import androidx.test.uiautomator.UiDevice;
 
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.icons.BitmapInfo;
@@ -26,12 +38,15 @@
 import com.android.launcher3.util.LauncherLayoutBuilder;
 import com.android.launcher3.util.LauncherModelHelper;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.TestUtil;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -43,9 +58,18 @@
 @RunWith(AndroidJUnit4.class)
 public class CacheDataUpdatedTaskTest {
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule =
+            DeviceFlagsValueProvider.createCheckFlagsRule();
+
     private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
     private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
 
+    private static final String ARCHIVED_PACKAGE = DUMMY_PACKAGE;
+    private static final String ARCHIVED_CLASS_NAME = DUMMY_CLASS_NAME;
+    private static final String ARCHIVED_TITLE = "Aardwolf";
+
+
     private LauncherModelHelper mModelHelper;
     private Context mContext;
 
@@ -57,6 +81,7 @@
         mContext = mModelHelper.sandboxContext;
         mSession1 = mModelHelper.createInstallerSession(PENDING_APP_1);
         mModelHelper.createInstallerSession(PENDING_APP_2);
+        TestUtil.installDummyApp();
 
         LauncherLayoutBuilder builder = new LauncherLayoutBuilder()
                 .atHotseat(1).putFolder("MyFolder")
@@ -73,14 +98,22 @@
                 .addApp(PENDING_APP_2, TEST_ACTIVITY)   // 8
                 .addApp(PENDING_APP_2, TEST_ACTIVITY2)  // 9
                 .addApp(PENDING_APP_2, TEST_ACTIVITY3)  // 10
+
+                // Dummy Test Package
+                .addApp(ARCHIVED_PACKAGE, ARCHIVED_CLASS_NAME) // 11
                 .build();
         mModelHelper.setupDefaultLayoutProvider(builder);
         mModelHelper.loadModelSync();
-        assertEquals(10, mModelHelper.getBgDataModel().itemsIdMap.size());
+        assertEquals(11, mModelHelper.getBgDataModel().itemsIdMap.size());
+
+        UiDevice device = UiDevice.getInstance(getInstrumentation());
+        assertThat(device.executeShellCommand(String.format("pm archive %s", ARCHIVED_PACKAGE)))
+                .isEqualTo("Success\n");
     }
 
     @After
-    public void tearDown() {
+    public void tearDown() throws IOException {
+        TestUtil.uninstallDummyApp();
         mModelHelper.destroy();
     }
 
@@ -138,6 +171,47 @@
         });
     }
 
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
+    public void testSessionUpdate_archivedApps_sessionInfoPrioritized() {
+        // 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);
+            int mSession2 = mModelHelper.createInstallerSession(ARCHIVED_PACKAGE);
+            mModelHelper.getModel().enqueueModelUpdateTask(
+                    newTask(CacheDataUpdatedTask.OP_CACHE_UPDATE, ARCHIVED_PACKAGE));
+            List<Integer> pendingArchivedAppIds = List.of(11);
+            // Mark the app items as archived.
+            allItems().forEach(wi -> {
+                if (pendingArchivedAppIds.contains(wi.id)) {
+                    wi.runtimeStatusFlags |= FLAG_ARCHIVED;
+                }
+            });
+            // Before cache is updated with sessionInfo, confirm the title.
+            for (WorkspaceItemInfo info : allItems()) {
+                if (pendingArchivedAppIds.contains(info.id)) {
+                    assertEquals(info.title, ARCHIVED_TITLE);
+                }
+            }
+
+            // Update the cache with session details.
+            LauncherAppState.getInstance(mContext).getIconCache().updateSessionCache(
+                    new PackageUserKey(ARCHIVED_PACKAGE, myUserHandle()),
+                    mContext.getPackageManager().getPackageInstaller().getSessionInfo(mSession2));
+
+            // Trigger a refresh for workspace itemInfo objects.
+            mModelHelper.getModel().enqueueModelUpdateTask(
+                    newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, ARCHIVED_PACKAGE));
+            // Verify the new title from session is applied to the iconInfo.
+            for (WorkspaceItemInfo info : allItems()) {
+                if (pendingArchivedAppIds.contains(info.id)) {
+                    assertEquals(info.title, ARCHIVED_PACKAGE);
+                }
+            }
+        });
+    }
+
     private void verifyUpdate(int... idsUpdated) {
         IntSet updates = IntSet.wrap(idsUpdated);
         for (WorkspaceItemInfo info : allItems()) {
diff --git a/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt b/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
new file mode 100644
index 0000000..11855e6
--- /dev/null
+++ b/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
@@ -0,0 +1,142 @@
+package com.android.launcher3.widget
+
+import android.appwidget.AppWidgetProviderInfo
+import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN
+import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD
+import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
+import android.view.LayoutInflater
+import android.widget.RemoteViews
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.Flags.FLAG_ENABLE_GENERATED_PREVIEWS
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.icons.IconCache
+import com.android.launcher3.icons.IconProvider
+import com.android.launcher3.model.WidgetItem
+import com.android.launcher3.tests.R
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.Executors
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class GeneratedPreviewTest {
+    @get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+    private val providerName =
+        ComponentName(
+            "com.android.launcher3.tests",
+            "com.android.launcher3.testcomponent.AppWidgetNoConfig"
+        )
+    private val generatedPreviewLayout = R.layout.test_layout_appwidget_blue
+    private lateinit var context: Context
+    private lateinit var generatedPreview: RemoteViews
+    private lateinit var widgetCell: WidgetCell
+    private lateinit var helper: WidgetManagerHelper
+    private lateinit var appWidgetProviderInfo: LauncherAppWidgetProviderInfo
+    private lateinit var widgetItem: WidgetItem
+
+    @Before
+    fun setup() {
+        context = getApplicationContext()
+        generatedPreview = RemoteViews(context.packageName, generatedPreviewLayout)
+        widgetCell =
+            LayoutInflater.from(ActivityContextWrapper(context))
+                .inflate(com.android.launcher3.R.layout.widget_cell, null) as WidgetCell
+        appWidgetProviderInfo =
+            AppWidgetProviderInfo()
+                .apply {
+                    generatedPreviewCategories = WIDGET_CATEGORY_HOME_SCREEN
+                    provider = providerName
+                    providerInfo = ActivityInfo().apply { applicationInfo = ApplicationInfo() }
+                }
+                .let { LauncherAppWidgetProviderInfo.fromProviderInfo(context, it) }
+        helper =
+            object : WidgetManagerHelper(context) {
+                override fun loadGeneratedPreview(
+                    info: AppWidgetProviderInfo,
+                    widgetCategory: Int
+                ) =
+                    generatedPreview.takeIf {
+                        info === appWidgetProviderInfo &&
+                            widgetCategory == WIDGET_CATEGORY_HOME_SCREEN
+                    }
+            }
+        createWidgetItem()
+    }
+
+    private fun createWidgetItem() {
+        Executors.MODEL_EXECUTOR.submit {
+                val idp = InvariantDeviceProfile()
+                widgetItem =
+                    WidgetItem(
+                        appWidgetProviderInfo,
+                        idp,
+                        IconCache(context, idp, null, IconProvider(context)),
+                        context,
+                        helper,
+                    )
+            }
+            .get()
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetItem_hasGeneratedPreview() {
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isTrue()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetItem_hasGeneratedPreview_noPreview() {
+        appWidgetProviderInfo.generatedPreviewCategories = 0
+        createWidgetItem()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isFalse()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
+    }
+
+    @Test
+    @RequiresFlagsDisabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetItem_hasGeneratedPreview_flagDisabled() {
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isFalse()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
+        assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
+    }
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetItem_getGeneratedPreview() {
+        val preview = widgetItem.generatedPreviews.get(WIDGET_CATEGORY_HOME_SCREEN)
+        assertThat(preview).isEqualTo(generatedPreview)
+    }
+
+    @Test
+    @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetCell_showGeneratedPreview() {
+        widgetCell.applyFromCellItem(widgetItem)
+        assertThat(widgetCell.appWidgetHostViewPreview).isNotNull()
+        assertThat(widgetCell.appWidgetHostViewPreview?.appWidgetInfo)
+            .isEqualTo(appWidgetProviderInfo)
+    }
+
+    @Test
+    @RequiresFlagsDisabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+    fun widgetCell_showGeneratedPreview_flagDisabled() {
+        widgetCell.applyFromCellItem(widgetItem)
+        assertThat(widgetCell.appWidgetHostViewPreview).isNull()
+    }
+}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index 60590e7..0286279 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -52,6 +52,7 @@
 import com.android.launcher3.util.WidgetUtils;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.WidgetCell;
+import com.android.launcher3.widget.WidgetManagerHelper;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 
 import org.junit.Before;
@@ -137,6 +138,7 @@
     }
 
     private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
+        WidgetManagerHelper widgetManager = new WidgetManagerHelper(mContext);
         ArrayList<WidgetItem> widgetItems = new ArrayList<>();
         for (int i = 0; i < numOfWidgets; i++) {
             ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
@@ -144,7 +146,7 @@
 
             widgetItems.add(new WidgetItem(
                     LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
-                    mTestProfile, mIconCache, mContext));
+                    mTestProfile, mIconCache, mContext, widgetManager));
         }
         return widgetItems;
     }