Revert "Unifying various model update callbacks into one"

Revert submission 31445615-model-callbacks

Reason for revert: <Droidmonitor crested revert due to b/393222548. Will be verified through ABTD for stanadard investigation.>

Reverted changes: /q/submissionid:31445615-model-callbacks

Change-Id: If6893a125756e5abfbb215af377576429bb1c91b
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 6815f97..f905c5f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -25,6 +25,7 @@
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
@@ -38,9 +39,9 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.function.Predicate;
 
 /**
@@ -113,9 +114,15 @@
         return modified;
     }
 
+
     @Override
-    public void bindItemsUpdated(Set<ItemInfo> updates) {
-        updateContainerItems(updates, mContext);
+    public void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) {
+        updateWorkspaceItems(updated, mContext);
+    }
+
+    @Override
+    public void bindRestoreItemsChange(HashSet<ItemInfo> updates) {
+        updateRestoreItems(updates, mContext);
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 9b7bb1c..a85e5e0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -214,7 +214,7 @@
         boolean animate = shouldAnimateIconChange(info);
         Drawable oldIcon = getIcon();
         int oldPlateColor = mPlateColor.currentColor;
-        applyFromWorkspaceItem(info);
+        applyFromWorkspaceItem(info, null);
 
         setContentDescription(
                 mIsPinned ? info.contentDescription :
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index d3684b2..315096c 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -29,7 +29,6 @@
 import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -64,7 +63,6 @@
 import android.widget.TextView;
 
 import androidx.annotation.DrawableRes;
-import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 import androidx.annotation.VisibleForTesting;
@@ -368,6 +366,11 @@
         mDotScaleAnim.start();
     }
 
+    @UiThread
+    public void applyFromWorkspaceItem(WorkspaceItemInfo info) {
+        applyFromWorkspaceItem(info, null);
+    }
+
     @Override
     public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
         if (delegate instanceof BaseAccessibilityDelegate) {
@@ -381,10 +384,10 @@
     }
 
     @UiThread
-    public void applyFromWorkspaceItem(WorkspaceItemInfo info) {
+    public void applyFromWorkspaceItem(WorkspaceItemInfo info, PreloadIconDrawable icon) {
         applyIconAndLabel(info);
         setItemInfo(info);
-
+        applyLoadingState(icon);
         applyDotState(info, false /* animate */);
         setDownloadStateContentDescription(info, info.getProgressLevel());
     }
@@ -392,11 +395,17 @@
     @UiThread
     public void applyFromApplicationInfo(AppInfo info) {
         applyIconAndLabel(info);
+
+        // We don't need to check the info since it's not a WorkspaceItemInfo
         setItemInfo(info);
 
+
         // Verify high res immediately
         verifyHighRes();
 
+        if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
+            applyProgressLevel();
+        }
         applyDotState(info, false /* animate */);
         setDownloadStateContentDescription(info, info.getProgressLevel());
     }
@@ -440,50 +449,6 @@
     @VisibleForTesting
     @UiThread
     public void applyIconAndLabel(ItemInfoWithIcon info) {
-        FastBitmapDrawable oldIcon = mIcon;
-        if (!canReuseIcon(info)) {
-            setNonPendingIcon(info);
-        }
-        applyLabel(info);
-        maybeApplyProgressLevel(info, oldIcon);
-    }
-
-    /**
-     * Check if we can reuse icon so that any animation is preserved
-     */
-    private boolean canReuseIcon(ItemInfoWithIcon info) {
-        return mIcon instanceof PreloadIconDrawable p
-                && p.hasNotCompleted() && p.isSameInfo(info.bitmap);
-    }
-
-    /**
-     * Apply progress level to the icon if necessary
-     */
-    private void maybeApplyProgressLevel(ItemInfoWithIcon info, FastBitmapDrawable oldIcon) {
-        if (!shouldApplyProgressLevel(info, oldIcon)) {
-            return;
-        }
-        PreloadIconDrawable pendingIcon = applyProgressLevel(info);
-        boolean isNoLongerPending = info instanceof WorkspaceItemInfo wii
-                ? !wii.hasPromiseIconUi() : !info.isArchived();
-        if (isNoLongerPending && info.getProgressLevel() == 100 && pendingIcon != null) {
-            pendingIcon.maybePerformFinishedAnimation(
-                    (oldIcon instanceof PreloadIconDrawable p) ? p : pendingIcon,
-                    () -> setNonPendingIcon(
-                            (getTag() instanceof ItemInfoWithIcon iiwi) ? iiwi : info));
-        }
-    }
-
-    /**
-     * Check if progress level should be applied to the icon
-     */
-    private boolean shouldApplyProgressLevel(ItemInfoWithIcon info, FastBitmapDrawable oldIcon) {
-        return (info.runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0
-                || (info instanceof WorkspaceItemInfo wii && wii.hasPromiseIconUi())
-                || (oldIcon instanceof PreloadIconDrawable p && p.hasNotCompleted());
-    }
-
-    private void setNonPendingIcon(ItemInfoWithIcon info) {
         ThemeManager themeManager = ThemeManager.INSTANCE.get(getContext());
         int flags = (shouldUseTheme()
                 && themeManager.isMonoThemeEnabled()) ? FLAG_THEMED : 0;
@@ -498,6 +463,7 @@
         mDotParams.appColor = iconDrawable.getIconColor();
         mDotParams.dotColor = Themes.getAttrColor(getContext(), R.attr.notificationDotColor);
         setIcon(iconDrawable);
+        applyLabel(info);
     }
 
     protected boolean shouldUseTheme() {
@@ -1104,10 +1070,38 @@
         mLongPressHelper.cancelLongPress();
     }
 
+    /**
+     * Applies the loading progress value to the progress bar.
+     *
+     * If this app is installing, the progress bar will be updated with the installation progress.
+     * If this app is installed and downloading incrementally, the progress bar will be updated
+     * with the total download progress.
+     */
+    public void applyLoadingState(PreloadIconDrawable icon) {
+        if (getTag() instanceof ItemInfoWithIcon) {
+            WorkspaceItemInfo info = (WorkspaceItemInfo) getTag();
+            if ((info.runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0
+                    || info.hasPromiseIconUi()
+                    || (info.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0
+                    || (icon != null)) {
+                updateProgressBarUi(info.getProgressLevel() == 100 ? icon : null);
+            }
+        }
+    }
+
+    private void updateProgressBarUi(PreloadIconDrawable oldIcon) {
+        FastBitmapDrawable originalIcon = mIcon;
+        PreloadIconDrawable preloadDrawable = applyProgressLevel();
+        if (preloadDrawable != null && oldIcon != null) {
+            preloadDrawable.maybePerformFinishedAnimation(oldIcon, () -> setIcon(originalIcon));
+        }
+    }
+
     /** Applies the given progress level to the this icon's progress bar. */
     @Nullable
-    private PreloadIconDrawable applyProgressLevel(ItemInfoWithIcon info) {
-        if (info.isInactiveArchive()) {
+    public PreloadIconDrawable applyProgressLevel() {
+        if (!(getTag() instanceof ItemInfoWithIcon info)
+                || ((ItemInfoWithIcon) getTag()).isInactiveArchive()) {
             return null;
         }
 
@@ -1121,16 +1115,23 @@
             setContentDescription(getContext()
                     .getString(R.string.app_waiting_download_title, info.title));
         }
-        PreloadIconDrawable pid;
-        if (mIcon instanceof PreloadIconDrawable p) {
-            pid = p;
-            pid.setLevel(progressLevel);
-            pid.setIsDisabled(isIconDisabled(info));
-        } else {
-            pid = makePreloadIcon(info);
-            setIcon(pid);
+        if (mIcon != null) {
+            PreloadIconDrawable preloadIconDrawable;
+            if (mIcon instanceof PreloadIconDrawable) {
+                preloadIconDrawable = (PreloadIconDrawable) mIcon;
+                preloadIconDrawable.setLevel(progressLevel);
+                preloadIconDrawable.setIsDisabled(isIconDisabled(info));
+            } else {
+                preloadIconDrawable = makePreloadIcon();
+                setIcon(preloadIconDrawable);
+                if (info.isArchived() && Flags.useNewIconForArchivedApps()) {
+                    // reapply text without cloud icon as soon as unarchiving is triggered
+                    applyLabel(info);
+                }
+            }
+            return preloadIconDrawable;
         }
-        return pid;
+        return null;
     }
 
     /**
@@ -1139,11 +1140,11 @@
      */
     @Nullable
     public PreloadIconDrawable makePreloadIcon() {
-        return getTag() instanceof ItemInfoWithIcon info ? makePreloadIcon(info) : null;
-    }
+        if (!(getTag() instanceof ItemInfoWithIcon)) {
+            return null;
+        }
 
-    @NonNull
-    private PreloadIconDrawable makePreloadIcon(ItemInfoWithIcon info) {
+        ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
         int progressLevel = info.getProgressLevel();
         final PreloadIconDrawable preloadDrawable = newPendingIcon(getContext(), info);
 
@@ -1162,7 +1163,7 @@
 
 
     public void applyDotState(ItemInfo itemInfo, boolean animate) {
-        if (mIcon != null) {
+        if (mIcon instanceof FastBitmapDrawable) {
             boolean wasDotted = mDotInfo != null;
             mDotInfo = mActivity.getDotInfoForItem(itemInfo);
             boolean isDotted = mDotInfo != null;
@@ -1211,7 +1212,7 @@
                 setContentDescription(getContext().getString(
                         R.string.app_archived_title, info.title));
             }
-        } else if ((info.runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK)
+        } else if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK)
                 != 0) {
             String percentageString = NumberFormat.getPercentInstance()
                     .format(progressLevel * 0.01);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 647d2ad..7df4014 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -277,11 +277,11 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
-import java.util.Set;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
@@ -2598,12 +2598,25 @@
         mModelCallbacks.bindIncrementalDownloadProgressUpdated(app);
     }
 
+    @Override
+    public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) {
+        mModelCallbacks.bindWidgetsRestored(widgets);
+    }
+
     /**
      * See {@code LauncherBindingDelegate}
      */
     @Override
-    public void bindItemsUpdated(Set<ItemInfo> updates) {
-        mModelCallbacks.bindItemsUpdated(updates);
+    public void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) {
+        mModelCallbacks.bindWorkspaceItemsChanged(updated);
+    }
+
+    /**
+     * See {@code LauncherBindingDelegate}
+     */
+    @Override
+    public void bindRestoreItemsChange(HashSet<ItemInfo> updates) {
+        mModelCallbacks.bindRestoreItemsChange(updates);
     }
 
     /**
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index 5338fb4..5d32525 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -17,6 +17,8 @@
 import com.android.launcher3.model.StringCache
 import com.android.launcher3.model.data.AppInfo
 import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.popup.PopupContainerWithArrow
 import com.android.launcher3.util.ComponentKey
 import com.android.launcher3.util.IntArray as LIntArray
@@ -213,13 +215,29 @@
         launcher.appsView.appsStore.updateProgressBar(app)
     }
 
+    override fun bindWidgetsRestored(widgets: ArrayList<LauncherAppWidgetInfo?>?) {
+        launcher.workspace.widgetsRestored(widgets)
+    }
+
+    /**
+     * Some shortcuts were updated in the background. Implementation of the method from
+     * LauncherModel.Callbacks.
+     *
+     * @param updated list of shortcuts which have changed.
+     */
+    override fun bindWorkspaceItemsChanged(updated: List<WorkspaceItemInfo?>) {
+        if (updated.isNotEmpty()) {
+            launcher.workspace.updateWorkspaceItems(updated, launcher)
+            PopupContainerWithArrow.dismissInvalidPopup(launcher)
+        }
+    }
+
     /**
      * Update the state of a package, typically related to install state. Implementation of the
      * method from LauncherModel.Callbacks.
      */
-    override fun bindItemsUpdated(updates: Set<ItemInfo>) {
-        launcher.workspace.updateContainerItems(updates, launcher)
-        PopupContainerWithArrow.dismissInvalidPopup(launcher)
+    override fun bindRestoreItemsChange(updates: HashSet<ItemInfo?>?) {
+        launcher.workspace.updateRestoreItems(updates, launcher)
     }
 
     /**
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7d82179..86c49d0 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -53,6 +53,8 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
 import android.os.Parcelable;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -123,9 +125,13 @@
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.WallpaperOffsetInterpolator;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.LauncherWidgetHolder;
+import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
 import com.android.launcher3.widget.NavigableAppWidgetHostView;
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
+import com.android.launcher3.widget.WidgetManagerHelper;
 import com.android.launcher3.widget.util.WidgetSizes;
 import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks;
 import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
@@ -658,6 +664,9 @@
             bindAndInitFirstWorkspaceScreen();
         }
 
+        // Remove any deferred refresh callbacks
+        mLauncher.mHandler.removeCallbacksAndMessages(DeferredWidgetRefresh.class);
+
         // Re-enable the layout transitions
         enableLayoutTransitions();
     }
@@ -3456,6 +3465,43 @@
         removeItemsByMatcher(matcher);
     }
 
+    public void widgetsRestored(final ArrayList<LauncherAppWidgetInfo> changedInfo) {
+        if (!changedInfo.isEmpty()) {
+            DeferredWidgetRefresh widgetRefresh = new DeferredWidgetRefresh(changedInfo,
+                    mLauncher.getAppWidgetHolder());
+
+            LauncherAppWidgetInfo item = changedInfo.get(0);
+            final AppWidgetProviderInfo widgetInfo;
+            WidgetManagerHelper widgetHelper = new WidgetManagerHelper(getContext());
+            if (item.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
+                widgetInfo = widgetHelper.findProvider(item.providerName, item.user);
+            } else {
+                widgetInfo = widgetHelper.getLauncherAppWidgetInfo(item.appWidgetId,
+                        item.getTargetComponent());
+            }
+
+            if (widgetInfo != null) {
+                // Re-inflate the widgets which have changed status
+                widgetRefresh.run();
+            } else {
+                // widgetRefresh will automatically run when the packages are updated.
+                // For now just update the progress bars
+                mapOverItems(new ItemOperator() {
+                    @Override
+                    public boolean evaluate(ItemInfo info, View view) {
+                        if (view instanceof PendingAppWidgetHostView
+                                && changedInfo.contains(info)) {
+                            ((LauncherAppWidgetInfo) info).installProgress = 100;
+                            ((PendingAppWidgetHostView) view).applyState();
+                        }
+                        // process all the shortcuts
+                        return false;
+                    }
+                });
+            }
+        }
+    }
+
     public boolean isOverlayShown() {
         return mOverlayShown;
     }
@@ -3562,6 +3608,62 @@
         return mLauncher.getCellPosMapper();
     }
 
+    /**
+     * Used as a workaround to ensure that the AppWidgetService receives the
+     * PACKAGE_ADDED broadcast before updating widgets.
+     */
+    private class DeferredWidgetRefresh implements Runnable, ProviderChangedListener {
+        private final ArrayList<LauncherAppWidgetInfo> mInfos;
+        private final LauncherWidgetHolder mWidgetHolder;
+        private final Handler mHandler;
+
+        private boolean mRefreshPending;
+
+        DeferredWidgetRefresh(ArrayList<LauncherAppWidgetInfo> infos,
+                              LauncherWidgetHolder holder) {
+            mInfos = infos;
+            mWidgetHolder = holder;
+            mHandler = mLauncher.mHandler;
+            mRefreshPending = true;
+
+            mWidgetHolder.addProviderChangeListener(this);
+            // Force refresh after 10 seconds, if we don't get the provider changed event.
+            // This could happen when the provider is no longer available in the app.
+            Message msg = Message.obtain(mHandler, this);
+            msg.obj = DeferredWidgetRefresh.class;
+            mHandler.sendMessageDelayed(msg, 10000);
+        }
+
+        @Override
+        public void run() {
+            mWidgetHolder.removeProviderChangeListener(this);
+            mHandler.removeCallbacks(this);
+
+            if (!mRefreshPending) {
+                return;
+            }
+
+            mRefreshPending = false;
+
+            ArrayList<PendingAppWidgetHostView> views = new ArrayList<>(mInfos.size());
+            mapOverItems((info, view) -> {
+                if (view instanceof PendingAppWidgetHostView && mInfos.contains(info)) {
+                    views.add((PendingAppWidgetHostView) view);
+                }
+                // process all children
+                return false;
+            });
+            for (PendingAppWidgetHostView view : views) {
+                view.reInflate();
+            }
+        }
+
+        @Override
+        public void notifyWidgetProvidersChanged() {
+            run();
+        }
+    }
+
     private class StateTransitionListener extends AnimatorListenerAdapter
             implements AnimatorUpdateListener {
 
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index d5a4022..9afe06c 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
 import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK;
 
 import android.content.Context;
 import android.os.UserHandle;
@@ -228,7 +229,11 @@
     public void updateProgressBar(AppInfo app) {
         updateAllIcons((child) -> {
             if (child.getTag() == app) {
-                child.applyFromApplicationInfo(app);
+                if ((app.runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) == 0) {
+                    child.applyFromApplicationInfo(app);
+                } else {
+                    child.applyProgressLevel();
+                }
             }
         });
     }
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index f189182..3464e9b 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -24,6 +24,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Context;
+import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
@@ -32,14 +33,12 @@
 import android.graphics.Rect;
 import android.util.Property;
 
-import androidx.annotation.VisibleForTesting;
 import androidx.core.graphics.ColorUtils;
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorListeners;
-import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.util.Themes;
@@ -64,6 +63,8 @@
 
     private static final int DEFAULT_PATH_SIZE = 100;
     private static final int MAX_PAINT_ALPHA = 255;
+    private static final int TRACK_ALPHA = (int) (0.27f * MAX_PAINT_ALPHA);
+    private static final int DISABLED_ICON_ALPHA = (int) (0.6f * MAX_PAINT_ALPHA);
 
     private static final long DURATION_SCALE = 500;
     private static final long SCALE_AND_ALPHA_ANIM_DURATION = 500;
@@ -283,25 +284,20 @@
                     (long) ((finalProgress - mInternalStateProgress) * DURATION_SCALE));
             mCurrentAnim.setInterpolator(LINEAR);
             if (isFinish) {
+                if (onFinishCallback != null) {
+                    mCurrentAnim.addListener(AnimatorListeners.forEndCallback(onFinishCallback));
+                }
                 mCurrentAnim.addListener(new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationEnd(Animator animation) {
                         mRanFinishAnimation = true;
                     }
                 });
-                if (onFinishCallback != null) {
-                    mCurrentAnim.addListener(AnimatorListeners.forEndCallback(onFinishCallback));
-                }
             }
             mCurrentAnim.start();
         }
     }
 
-    @VisibleForTesting
-    public ObjectAnimator getActiveAnimation() {
-        return mCurrentAnim;
-    }
-
     /**
      * Sets the internal progress and updates the UI accordingly
      *   for progress <= 0:
@@ -362,7 +358,8 @@
     @Override
     public FastBitmapConstantState newConstantState() {
         return new PreloadIconConstantState(
-                mBitmapInfo,
+                mBitmap,
+                mIconColor,
                 mItem,
                 mIndicatorColor,
                 new int[] {mSystemAccentColor, mSystemBackgroundColor},
@@ -380,13 +377,14 @@
         private final Path mShapePath;
 
         public PreloadIconConstantState(
-                BitmapInfo bitmapInfo,
+                Bitmap bitmap,
+                int iconColor,
                 ItemInfoWithIcon info,
                 int indicatorColor,
                 int[] preloadColors,
                 boolean isDarkMode,
                 Path shapePath) {
-            super(bitmapInfo);
+            super(bitmap, iconColor);
             mInfo = info;
             mIndicatorColor = indicatorColor;
             mPreloadColors = preloadColors;
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index ddc775d..a04cbfb 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -49,6 +49,7 @@
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.CollectionInfo;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.shortcuts.ShortcutKey;
@@ -69,6 +70,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -417,9 +419,9 @@
          * Binds updated incremental download progress
          */
         default void bindIncrementalDownloadProgressUpdated(AppInfo app) { }
-
-        /** Called when a runtime property of the ItemInfo is updated due to some system event */
-        default void bindItemsUpdated(Set<ItemInfo> updates) { }
+        default void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) { }
+        default void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets) { }
+        default void bindRestoreItemsChange(HashSet<ItemInfo> updates) { }
         default void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) { }
 
         /**
diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
index 48934e2..b544b91 100644
--- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java
+++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
@@ -15,9 +15,6 @@
  */
 package com.android.launcher3.model;
 
-import static com.android.launcher3.icons.cache.CacheLookupFlag.DEFAULT_LOOKUP_FLAG;
-import static com.android.launcher3.model.ModelUtils.WIDGET_FILTER;
-
 import android.content.ComponentName;
 import android.os.UserHandle;
 
@@ -26,8 +23,6 @@
 import com.android.launcher3.LauncherModel.ModelUpdateTask;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 
 import java.util.ArrayList;
@@ -60,7 +55,7 @@
     public void execute(@NonNull ModelTaskController taskController, @NonNull BgDataModel dataModel,
             @NonNull AllAppsList apps) {
         IconCache iconCache = taskController.getApp().getIconCache();
-        ArrayList<ItemInfo> updatedItems = new ArrayList<>();
+        ArrayList<WorkspaceItemInfo> updatedShortcuts = new ArrayList<>();
 
         synchronized (dataModel) {
             dataModel.forAllWorkspaceItemInfos(mUser, si -> {
@@ -69,25 +64,12 @@
                         && isValidShortcut(si) && cn != null
                         && mPackages.contains(cn.getPackageName())) {
                     iconCache.getTitleAndIcon(si, si.getMatchingLookupFlag());
-                    updatedItems.add(si);
+                    updatedShortcuts.add(si);
                 }
             });
-
-            dataModel.itemsIdMap.stream()
-                    .filter(WIDGET_FILTER)
-                    .filter(item -> mUser.equals(item.user))
-                    .map(item -> (LauncherAppWidgetInfo) item)
-                    .filter(widget -> mPackages.contains(widget.providerName.getPackageName())
-                            && widget.pendingItemInfo != null)
-                    .forEach(widget -> {
-                        iconCache.getTitleAndIconForApp(
-                                widget.pendingItemInfo, DEFAULT_LOOKUP_FLAG);
-                        updatedItems.add(widget);
-                    });
-
             apps.updateIconsAndLabels(mPackages, mUser);
         }
-        taskController.bindUpdatedWorkspaceItems(updatedItems);
+        taskController.bindUpdatedWorkspaceItems(updatedShortcuts);
         taskController.bindApplicationsIfNeeded();
     }
 
diff --git a/src/com/android/launcher3/model/ModelTaskController.kt b/src/com/android/launcher3/model/ModelTaskController.kt
index 40ea17d..fc53343 100644
--- a/src/com/android/launcher3/model/ModelTaskController.kt
+++ b/src/com/android/launcher3/model/ModelTaskController.kt
@@ -22,6 +22,7 @@
 import com.android.launcher3.celllayout.CellPosMapper
 import com.android.launcher3.model.BgDataModel.FixedContainerItems
 import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.util.PackageUserKey
 import com.android.launcher3.widget.model.WidgetsListBaseEntriesBuilder
 import java.util.Objects
@@ -50,17 +51,18 @@
      */
     fun getModelWriter() = model.getWriter(false /* verifyChanges */, CellPosMapper.DEFAULT, null)
 
-    fun bindUpdatedWorkspaceItems(allUpdates: Collection<ItemInfo>) {
+    fun bindUpdatedWorkspaceItems(allUpdates: List<WorkspaceItemInfo>) {
         // Bind workspace items
-        val workspaceUpdates = allUpdates.filter { it.id != ItemInfo.NO_ID }.toSet()
+        val workspaceUpdates =
+            allUpdates.stream().filter { info -> info.id != ItemInfo.NO_ID }.toList()
         if (workspaceUpdates.isNotEmpty()) {
-            scheduleCallbackTask { it.bindItemsUpdated(workspaceUpdates) }
+            scheduleCallbackTask { it.bindWorkspaceItemsChanged(workspaceUpdates) }
         }
 
         // Bind extra items if any
         allUpdates
             .stream()
-            .mapToInt { it.container }
+            .mapToInt { info: WorkspaceItemInfo -> info.container }
             .distinct()
             .mapToObj { dataModel.extraItems.get(it) }
             .filter { Objects.nonNull(it) }
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index a216042..4103937 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -99,7 +99,8 @@
                     });
 
             if (!updates.isEmpty()) {
-                taskController.bindUpdatedWorkspaceItems(updates);
+                taskController.scheduleCallbackTask(
+                        callbacks -> callbacks.bindRestoreItemsChange(updates));
             }
         }
     }
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 6bef292..1153f48 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -214,7 +214,8 @@
 
         // Update shortcut infos
         if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
-            final ArrayList<ItemInfo> updatedWorkspaceItems = new ArrayList<>();
+            final ArrayList<WorkspaceItemInfo> updatedWorkspaceItems = new ArrayList<>();
+            final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<>();
 
             // For system apps, package manager send OP_UPDATE when an app is enabled.
             final boolean isNewApkAvailable = mOp == OP_ADD || mOp == OP_UPDATE;
@@ -363,8 +364,8 @@
                             // if the widget has a config activity. In case there is no config
                             // activity, it will be marked as 'restored' during bind.
                             widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
-                            widgetInfo.installProgress = 100;
-                            updatedWorkspaceItems.add(widgetInfo);
+
+                            widgets.add(widgetInfo);
                             taskController.getModelWriter().updateItemInDatabase(widgetInfo);
                         });
             }
@@ -376,6 +377,10 @@
                         "removing shortcuts with invalid target components."
                                 + " ids=" + removedShortcuts);
             }
+
+            if (!widgets.isEmpty()) {
+                taskController.scheduleCallbackTask(c -> c.bindWidgetsRestored(widgets));
+            }
         }
 
         final HashSet<String> removedPackages = new HashSet<>();
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 381d17a..78709b8 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -228,9 +228,10 @@
     private static void onClickPendingAppItem(View v, Launcher launcher, String packageName,
             boolean downloadStarted) {
         ItemInfo item = (ItemInfo) v.getTag();
-        CompletableFuture<SessionInfo> siFuture = CompletableFuture.supplyAsync(() ->
-                InstallSessionHelper.INSTANCE.get(launcher)
-                        .getActiveSessionInfo(item.user, packageName),
+        CompletableFuture<SessionInfo> siFuture;
+        siFuture = CompletableFuture.supplyAsync(() ->
+                        InstallSessionHelper.INSTANCE.get(launcher)
+                                .getActiveSessionInfo(item.user, packageName),
                 UI_HELPER_EXECUTOR);
         Consumer<SessionInfo> marketLaunchAction = sessionInfo -> {
             if (sessionInfo != null) {
@@ -244,8 +245,8 @@
                 }
             }
             // Fallback to using custom market intent.
-            Intent intent = ApiWrapper.INSTANCE.get(launcher).getMarketSearchIntent(
-                    packageName, item.user);
+            Intent intent = ApiWrapper.INSTANCE.get(launcher).getAppMarketActivityIntent(
+                    packageName, Process.myUserHandle());
             launcher.startActivitySafely(v, intent, item);
         };
 
@@ -357,7 +358,9 @@
         // Check for abandoned promise
         if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()
                 && (!Flags.enableSupportForArchiving() || !shortcut.isArchived())) {
-            String packageName = shortcut.getTargetPackage();
+            String packageName = shortcut.getIntent().getComponent() != null
+                    ? shortcut.getIntent().getComponent().getPackageName()
+                    : shortcut.getIntent().getPackage();
             if (!TextUtils.isEmpty(packageName)) {
                 onClickPendingAppItem(
                         v,
diff --git a/src/com/android/launcher3/util/ApiWrapper.java b/src/com/android/launcher3/util/ApiWrapper.java
index d24d084..467a7ec 100644
--- a/src/com/android/launcher3/util/ApiWrapper.java
+++ b/src/com/android/launcher3/util/ApiWrapper.java
@@ -28,7 +28,6 @@
 import android.content.pm.ShortcutInfo;
 import android.graphics.drawable.ColorDrawable;
 import android.net.Uri;
-import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.ArrayMap;
@@ -121,21 +120,6 @@
      * Activity).
      */
     public Intent getAppMarketActivityIntent(String packageName, UserHandle user) {
-        return createMarketIntent(packageName);
-    }
-
-    /**
-     * Returns an intent which can be used to start a search for a package on app market
-     */
-    public Intent getMarketSearchIntent(String packageName, UserHandle user) {
-        // If we are search for the current user, just launch the market directly as the
-        // system won't have the installer details either
-        return  (Process.myUserHandle().equals(user))
-                ? createMarketIntent(packageName)
-                : getAppMarketActivityIntent(packageName, user);
-    }
-
-    private static Intent createMarketIntent(String packageName) {
         return new Intent(Intent.ACTION_VIEW)
                 .setData(new Uri.Builder()
                         .scheme("market")
diff --git a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
index 20e3eaf..02779ce 100644
--- a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
+++ b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
@@ -15,20 +15,24 @@
  */
 package com.android.launcher3.util;
 
+import android.graphics.drawable.Drawable;
 import android.view.View;
 
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.graphics.PreloadIconDrawable;
 import com.android.launcher3.model.data.AppPairInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.widget.PendingAppWidgetHostView;
 
-import java.util.Set;
+import java.util.HashSet;
+import java.util.List;
 
 /**
  * Interface representing a container which can bind Launcher items with some utility methods
@@ -37,22 +41,27 @@
 
     /**
      * Called to update workspace items as a result of
-     * {@link com.android.launcher3.model.BgDataModel.Callbacks#bindItemsUpdated(Set)}
+     * {@link com.android.launcher3.model.BgDataModel.Callbacks#bindWorkspaceItemsChanged(List)}
      */
-    default void updateContainerItems(Set<ItemInfo> updates, ActivityContext context) {
+    default void updateWorkspaceItems(List<WorkspaceItemInfo> shortcuts, ActivityContext context) {
+        final HashSet<WorkspaceItemInfo> updates = new HashSet<>(shortcuts);
         ItemOperator op = (info, v) -> {
-            if (v instanceof BubbleTextView shortcut
-                    && info instanceof WorkspaceItemInfo wii
-                    && updates.contains(info)) {
-                shortcut.applyFromWorkspaceItem(wii);
-            } else if (info instanceof FolderInfo && v instanceof FolderIcon folderIcon) {
-                folderIcon.updatePreviewItems(updates::contains);
+            if (v instanceof BubbleTextView && updates.contains(info)) {
+                WorkspaceItemInfo si = (WorkspaceItemInfo) info;
+                BubbleTextView shortcut = (BubbleTextView) v;
+                Drawable oldIcon = shortcut.getIcon();
+                boolean oldPromiseState = (oldIcon instanceof PreloadIconDrawable)
+                        && ((PreloadIconDrawable) oldIcon).hasNotCompleted();
+                shortcut.applyFromWorkspaceItem(
+                        si,
+                        si.isPromise() != oldPromiseState
+                                && oldIcon instanceof PreloadIconDrawable
+                                ? (PreloadIconDrawable) oldIcon
+                                : null);
+            } else if (info instanceof FolderInfo && v instanceof FolderIcon) {
+                ((FolderIcon) v).updatePreviewItems(updates::contains);
             } else if (info instanceof AppPairInfo && v instanceof AppPairIcon appPairIcon) {
                 appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
-            } else if (v instanceof PendingAppWidgetHostView pendingView
-                    && updates.contains(info)) {
-                pendingView.applyState();
-                pendingView.postProviderAvailabilityCheck();
             }
 
             // Iterate all items
@@ -67,6 +76,35 @@
     }
 
     /**
+     * Called to update restored items as a result of
+     * {@link com.android.launcher3.model.BgDataModel.Callbacks#bindRestoreItemsChange(HashSet)}}
+     */
+    default void updateRestoreItems(final HashSet<ItemInfo> updates, ActivityContext context) {
+        ItemOperator op = (info, v) -> {
+            if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView
+                    && updates.contains(info)) {
+                ((BubbleTextView) v).applyLoadingState(null);
+            } else if (v instanceof PendingAppWidgetHostView
+                    && info instanceof LauncherAppWidgetInfo
+                    && updates.contains(info)) {
+                ((PendingAppWidgetHostView) v).applyState();
+            } else if (v instanceof FolderIcon && info instanceof FolderInfo) {
+                ((FolderIcon) v).updatePreviewItems(updates::contains);
+            } else if (info instanceof AppPairInfo && v instanceof AppPairIcon appPairIcon) {
+                appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
+            }
+            // process all the shortcuts
+            return false;
+        };
+
+        mapOverItems(op);
+        Folder folder = Folder.getOpen(context);
+        if (folder != null) {
+            folder.iterateOverItems(op);
+        }
+    }
+
+    /**
      * Map the operator over the shortcuts and widgets.
      *
      * @param op the operator to map over the shortcuts
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index cd8e457..9c9b80d 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -21,7 +21,7 @@
 import static android.graphics.Paint.FILTER_BITMAP_FLAG;
 
 import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
-import static com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
+import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.appwidget.AppWidgetProviderInfo;
@@ -37,9 +37,6 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
 import android.text.Layout;
 import android.text.StaticLayout;
 import android.text.TextPaint;
@@ -63,10 +60,8 @@
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
 import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SafeCloseable;
 import com.android.launcher3.util.Themes;
-import com.android.launcher3.widget.LauncherWidgetHolder.ProviderChangedListener;
 
 import java.util.List;
 
@@ -86,8 +81,6 @@
     private final Matrix mMatrix = new Matrix();
     private final RectF mPreviewBitmapRect = new RectF();
     private final RectF mCanvasRect = new RectF();
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
-    private final RunnableList mOnDetachCleanup = new RunnableList();
 
     private final LauncherWidgetHolder mWidgetHolder;
     private final LauncherAppWidgetProviderInfo mAppwidget;
@@ -97,6 +90,7 @@
     private final CharSequence mLabel;
 
     private OnClickListener mClickListener;
+    private SafeCloseable mOnDetachCleanup;
 
     private int mDragFlags;
 
@@ -216,15 +210,16 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
 
-        mOnDetachCleanup.executeAllAndClear();
         if ((mAppwidget != null)
                 && !mInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)
                 && mInfo.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED) {
             // If the widget is not completely restored, but has a valid ID, then listen of
             // updates from provider app for potential restore complete.
-            SafeCloseable updateCleanup = mWidgetHolder.addOnUpdateListener(
+            if (mOnDetachCleanup != null) {
+                mOnDetachCleanup.close();
+            }
+            mOnDetachCleanup = mWidgetHolder.addOnUpdateListener(
                     mInfo.appWidgetId, mAppwidget, this::checkIfRestored);
-            mOnDetachCleanup.add(updateCleanup::close);
             checkIfRestored();
         }
     }
@@ -232,7 +227,10 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mOnDetachCleanup.executeAllAndClear();
+        if (mOnDetachCleanup != null) {
+            mOnDetachCleanup.close();
+            mOnDetachCleanup = null;
+        }
     }
 
     /**
@@ -297,30 +295,43 @@
             mCenterDrawable.setCallback(null);
             mCenterDrawable = null;
         }
-        mDragFlags = FLAG_DRAW_ICON;
+        mDragFlags = 0;
+        if (info.bitmap.icon != null) {
+            mDragFlags = FLAG_DRAW_ICON;
 
-        // The view displays three modes,
-        //   1) App icon in the center
-        //   2) Preload icon in the center
-        //   3) App icon in the center with a setup icon on the top left corner.
-        if (mDisabledForSafeMode) {
-            FastBitmapDrawable disabledIcon = info.newIcon(getContext());
-            disabledIcon.setIsDisabled(true);
-            mCenterDrawable = disabledIcon;
-            mSettingIconDrawable = null;
-        } else if (isReadyForClickSetup()) {
-            mCenterDrawable = info.newIcon(getContext());
-            mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
-            updateSettingColor(info.bitmap.color);
+            Drawable widgetCategoryIcon = getWidgetCategoryIcon();
+            // The view displays three modes,
+            //   1) App icon in the center
+            //   2) Preload icon in the center
+            //   3) App icon in the center with a setup icon on the top left corner.
+            if (mDisabledForSafeMode) {
+                if (widgetCategoryIcon == null) {
+                    FastBitmapDrawable disabledIcon = info.newIcon(getContext());
+                    disabledIcon.setIsDisabled(true);
+                    mCenterDrawable = disabledIcon;
+                } else {
+                    widgetCategoryIcon.setColorFilter(getDisabledColorFilter());
+                    mCenterDrawable = widgetCategoryIcon;
+                }
+                mSettingIconDrawable = null;
+            } else if (isReadyForClickSetup()) {
+                mCenterDrawable = widgetCategoryIcon == null
+                        ? info.newIcon(getContext())
+                        : widgetCategoryIcon;
+                mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate();
+                updateSettingColor(info.bitmap.color);
 
-            mDragFlags |= FLAG_DRAW_SETTINGS | FLAG_DRAW_LABEL;
-        } else {
-            mCenterDrawable = newPendingIcon(getContext(), info);
-            mSettingIconDrawable = null;
-            applyState();
+                mDragFlags |= FLAG_DRAW_SETTINGS | FLAG_DRAW_LABEL;
+            } else {
+                mCenterDrawable = widgetCategoryIcon == null
+                        ? newPendingIcon(getContext(), info)
+                        : widgetCategoryIcon;
+                mSettingIconDrawable = null;
+                applyState();
+            }
+            mCenterDrawable.setCallback(this);
+            mDrawableSizeChanged = true;
         }
-        mCenterDrawable.setCallback(this);
-        mDrawableSizeChanged = true;
         invalidate();
     }
 
@@ -339,11 +350,6 @@
     }
 
     public void applyState() {
-        if (mCenterDrawable instanceof FastBitmapDrawable fb
-                && mInfo.pendingItemInfo != null
-                && !fb.isSameInfo(mInfo.pendingItemInfo.bitmap)) {
-            reapplyItemInfo(mInfo.pendingItemInfo);
-        }
         if (mCenterDrawable != null) {
             mCenterDrawable.setLevel(Math.max(mInfo.installProgress, 0));
         }
@@ -480,72 +486,16 @@
     }
 
     /**
-     * Creates a runnable runnable which tries to refresh the widget if it is restored
-     */
-    public void postProviderAvailabilityCheck() {
-        if (!mInfo.hasRestoreFlag(FLAG_PROVIDER_NOT_READY) && getAppWidgetInfo() == null) {
-            // If the info state suggests that the provider is ready, but there is no
-            // provider info attached on this pending view, recreate when the provider is available
-            DeferredWidgetRefresh restoreRunnable = new DeferredWidgetRefresh();
-            mOnDetachCleanup.add(restoreRunnable::cleanup);
-            mHandler.post(restoreRunnable::notifyWidgetProvidersChanged);
-        }
-    }
-
-    /**
-     * Used as a workaround to ensure that the AppWidgetService receives the
-     * PACKAGE_ADDED broadcast before updating widgets.
+     * Returns the widget category icon for {@link #mInfo}.
      *
-     * This class will periodically check for the availability of the WidgetProvider as a result
-     * of providerChanged callback from the host. When the provider is available or a timeout of
-     * 10-sec is reached, it reinflates the pending-widget which in-turn goes through the process
-     * of re-evaluating the pending state of the widget,
+     * <p>If {@link #mInfo}'s category is {@code PackageItemInfo#NO_CATEGORY} or unknown, returns
+     * {@code null}.
      */
-    private class DeferredWidgetRefresh implements Runnable, ProviderChangedListener {
-        private boolean mRefreshPending = true;
-
-        DeferredWidgetRefresh() {
-            mWidgetHolder.addProviderChangeListener(this);
-            // Force refresh after 10 seconds, if we don't get the provider changed event.
-            // This could happen when the provider is no longer available in the app.
-            Message msg = Message.obtain(getHandler(), this);
-            msg.obj = DeferredWidgetRefresh.class;
-            mHandler.sendMessageDelayed(msg, 10000);
+    @Nullable
+    private Drawable getWidgetCategoryIcon() {
+        if (mInfo.pendingItemInfo.widgetCategory == WidgetSections.NO_CATEGORY) {
+            return null;
         }
-
-        /**
-         * Reinflate the widget if it is still attached.
-         */
-        @Override
-        public void run() {
-            cleanup();
-            if (mRefreshPending) {
-                reInflate();
-                mRefreshPending = false;
-            }
-        }
-
-        @Override
-        public void notifyWidgetProvidersChanged() {
-            final AppWidgetProviderInfo widgetInfo;
-            WidgetManagerHelper widgetHelper = new WidgetManagerHelper(getContext());
-            if (mInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
-                widgetInfo = widgetHelper.findProvider(mInfo.providerName, mInfo.user);
-            } else {
-                widgetInfo = widgetHelper.getLauncherAppWidgetInfo(mInfo.appWidgetId,
-                        mInfo.getTargetComponent());
-            }
-            if (widgetInfo != null) {
-                run();
-            }
-        }
-
-        /**
-         * Removes any scheduled callbacks and change listeners, no-op if nothing is scheduled
-         */
-        public void cleanup() {
-            mWidgetHolder.removeProviderChangeListener(this);
-            mHandler.removeCallbacks(this);
-        }
+        return mInfo.pendingItemInfo.newIcon(getContext());
     }
 }
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index faf6b91..f51871b 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -27,9 +27,7 @@
 import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
 import static com.android.launcher3.Flags.FLAG_USE_NEW_ICON_FOR_ARCHIVED_APPS;
 import static com.android.launcher3.LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE;
-import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -41,8 +39,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
 import android.graphics.Typeface;
 import android.os.Build;
 import android.os.UserHandle;
@@ -61,17 +57,13 @@
 import com.android.launcher3.Flags;
 import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.graphics.PreloadIconDrawable;
-import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
-import com.android.launcher3.pm.PackageInstallInfo;
 import com.android.launcher3.search.StringMatcherUtility;
 import com.android.launcher3.util.ActivityContextWrapper;
 import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
-import com.android.launcher3.util.TestUtil;
 import com.android.launcher3.views.BaseDragLayer;
 
 import org.junit.After;
@@ -81,8 +73,6 @@
 import org.junit.runner.RunWith;
 import org.mockito.MockitoAnnotations;
 
-import java.util.concurrent.CountDownLatch;
-
 /**
  * Unit tests for testing modifyTitleToSupportMultiLine() in BubbleTextView.java
  * This class tests a couple of strings and uses the getMaxLines() to determine if the test passes.
@@ -495,40 +485,4 @@
 
         assertThat(mBubbleTextView.getIcon().hasBadge()).isEqualTo(true);
     }
-
-    @Test
-    public void applyingPendingIcon_preserves_last_icon() throws Exception {
-        mItemInfoWithIcon.bitmap =
-                BitmapInfo.fromBitmap(Bitmap.createBitmap(100, 100, Config.ARGB_8888));
-        mItemInfoWithIcon.setProgressLevel(30, PackageInstallInfo.STATUS_INSTALLING);
-
-        TestUtil.runOnExecutorSync(MAIN_EXECUTOR,
-                () -> mBubbleTextView.applyIconAndLabel(mItemInfoWithIcon));
-        assertThat(mBubbleTextView.getIcon()).isInstanceOf(PreloadIconDrawable.class);
-        assertThat(mBubbleTextView.getIcon().getLevel()).isEqualTo(30);
-        PreloadIconDrawable oldIcon = (PreloadIconDrawable) mBubbleTextView.getIcon();
-
-        // Same icon is used when progress changes
-        mItemInfoWithIcon.setProgressLevel(50, PackageInstallInfo.STATUS_INSTALLING);
-        TestUtil.runOnExecutorSync(MAIN_EXECUTOR,
-                () -> mBubbleTextView.applyIconAndLabel(mItemInfoWithIcon));
-        assertThat(mBubbleTextView.getIcon()).isSameInstanceAs(oldIcon);
-        assertThat(mBubbleTextView.getIcon().getLevel()).isEqualTo(50);
-
-        // Icon is replaced with a non pending icon when download finishes
-        mItemInfoWithIcon.setProgressLevel(100, PackageInstallInfo.STATUS_INSTALLED);
-
-        CountDownLatch animWait = new CountDownLatch(1);
-        TestUtil.runOnExecutorSync(MAIN_EXECUTOR, () -> {
-            mBubbleTextView.applyIconAndLabel(mItemInfoWithIcon);
-            assertThat(mBubbleTextView.getIcon()).isSameInstanceAs(oldIcon);
-            assertThat(oldIcon.getActiveAnimation()).isNotNull();
-            oldIcon.getActiveAnimation().addListener(forEndCallback(animWait::countDown));
-        });
-        animWait.await();
-
-        // Assert that the icon is replaced with a non-pending icon
-        assertThat(mBubbleTextView.getIcon()).isNotInstanceOf(PreloadIconDrawable.class);
-    }
-
 }
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherBindableItemsContainerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/LauncherBindableItemsContainerTest.kt
deleted file mode 100644
index 93be5f5..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/util/LauncherBindableItemsContainerTest.kt
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2025 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.util
-
-import android.content.ComponentName
-import android.content.pm.LauncherApps
-import android.graphics.Bitmap
-import android.graphics.Bitmap.Config.ARGB_8888
-import android.os.Process.myUserHandle
-import android.platform.uiautomatorhelpers.DeviceHelpers.context
-import android.view.View
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.launcher3.BubbleTextView
-import com.android.launcher3.graphics.PreloadIconDrawable
-import com.android.launcher3.icons.BitmapInfo
-import com.android.launcher3.icons.FastBitmapDrawable
-import com.android.launcher3.icons.PlaceHolderIconDrawable
-import com.android.launcher3.model.data.AppInfo
-import com.android.launcher3.model.data.AppInfo.makeLaunchIntent
-import com.android.launcher3.model.data.ItemInfo
-import com.android.launcher3.model.data.WorkspaceItemInfo
-import com.android.launcher3.pm.PackageInstallInfo
-import com.android.launcher3.util.Executors.MAIN_EXECUTOR
-import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator
-import com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY
-import com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY2
-import com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY3
-import com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class LauncherBindableItemsContainerTest {
-
-    private val icon1 by lazy { getLAI(TEST_ACTIVITY) }
-    private val icon2 by lazy { getLAI(TEST_ACTIVITY2) }
-    private val icon3 by lazy { getLAI(TEST_ACTIVITY3) }
-
-    private val container = TestContainer()
-
-    @Test
-    fun `icon bitmap is updated`() {
-        container.addIcon(icon1)
-        container.addIcon(icon2)
-        container.addIcon(icon3)
-
-        assertThat(container.getAppIcon(icon1).icon)
-            .isInstanceOf(PlaceHolderIconDrawable::class.java)
-        assertThat(container.getAppIcon(icon2).icon)
-            .isInstanceOf(PlaceHolderIconDrawable::class.java)
-        assertThat(container.getAppIcon(icon3).icon)
-            .isInstanceOf(PlaceHolderIconDrawable::class.java)
-
-        icon2.bitmap = BitmapInfo.fromBitmap(Bitmap.createBitmap(200, 200, ARGB_8888))
-        TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {
-            container.updateContainerItems(setOf(icon2), container)
-        }
-
-        assertThat(container.getAppIcon(icon1).icon)
-            .isInstanceOf(PlaceHolderIconDrawable::class.java)
-        assertThat(container.getAppIcon(icon3).icon)
-            .isInstanceOf(PlaceHolderIconDrawable::class.java)
-        assertThat(container.getAppIcon(icon2).icon)
-            .isNotInstanceOf(PlaceHolderIconDrawable::class.java)
-        assertThat(container.getAppIcon(icon2).icon).isInstanceOf(FastBitmapDrawable::class.java)
-    }
-
-    @Test
-    fun `icon download progress updated`() {
-        container.addIcon(icon1)
-        container.addIcon(icon2)
-        assertThat(container.getAppIcon(icon1).icon)
-            .isInstanceOf(PlaceHolderIconDrawable::class.java)
-        assertThat(container.getAppIcon(icon2).icon)
-            .isInstanceOf(PlaceHolderIconDrawable::class.java)
-
-        icon1.status = WorkspaceItemInfo.FLAG_RESTORED_ICON
-        icon1.bitmap = BitmapInfo.fromBitmap(Bitmap.createBitmap(200, 200, ARGB_8888))
-        icon1.setProgressLevel(30, PackageInstallInfo.STATUS_INSTALLING)
-        TestUtil.runOnExecutorSync(MAIN_EXECUTOR) {
-            container.updateContainerItems(setOf(icon1), container)
-        }
-
-        assertThat(container.getAppIcon(icon2).icon)
-            .isInstanceOf(PlaceHolderIconDrawable::class.java)
-        assertThat(container.getAppIcon(icon1).icon).isInstanceOf(PreloadIconDrawable::class.java)
-        val oldIcon = container.getAppIcon(icon1).icon as PreloadIconDrawable
-        assertThat(oldIcon.level).isEqualTo(30)
-    }
-
-    private fun getLAI(className: String): WorkspaceItemInfo =
-        AppInfo(
-                context,
-                context
-                    .getSystemService(LauncherApps::class.java)!!
-                    .resolveActivity(
-                        makeLaunchIntent(ComponentName(TEST_PACKAGE, className)),
-                        myUserHandle(),
-                    )!!,
-                myUserHandle(),
-            )
-            .makeWorkspaceItem(context)
-
-    class TestContainer : ActivityContextWrapper(context), LauncherBindableItemsContainer {
-
-        val items = mutableMapOf<ItemInfo, View>()
-
-        override fun mapOverItems(op: ItemOperator) {
-            items.forEach { (item, view) -> if (op.evaluate(item, view)) return@forEach }
-        }
-
-        fun addIcon(info: WorkspaceItemInfo) {
-            val btv = BubbleTextView(this)
-            btv.applyFromWorkspaceItem(info)
-            items[info] = btv
-        }
-
-        fun getAppIcon(info: WorkspaceItemInfo) = items[info] as BubbleTextView
-    }
-}