Adding support for easily extending Launcher DragAndDrop support

Bug: 232165524
Test: Verified locally
Change-Id: I3b4f37bc9914de55330662edd678e6fdd0eafece
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 6302739..490a134 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -53,6 +53,7 @@
 
 import com.android.launcher3.accessibility.BaseAccessibilityDelegate;
 import com.android.launcher3.dot.DotInfo;
+import com.android.launcher3.dragndrop.DragOptions.PreDragCondition;
 import com.android.launcher3.dragndrop.DraggableView;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.graphics.IconShape;
@@ -65,12 +66,11 @@
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
-import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.model.data.SearchActionItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.util.SafeCloseable;
+import com.android.launcher3.util.ShortcutUtil;
 import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.BubbleTextHolder;
 import com.android.launcher3.views.IconLabelDotView;
 
 import java.text.NumberFormat;
@@ -174,7 +174,6 @@
     private HandlerRunnable mIconLoadRequest;
 
     private boolean mEnableIconUpdateAnimation = false;
-    private BubbleTextHolder mBubbleTextHolder;
 
     public BubbleTextView(Context context) {
         this(context, null, 0);
@@ -361,15 +360,8 @@
         setDownloadStateContentDescription(info, info.getProgressLevel());
     }
 
-    private void setItemInfo(ItemInfoWithIcon itemInfo) {
+    protected void setItemInfo(ItemInfoWithIcon itemInfo) {
         setTag(itemInfo);
-        if (mBubbleTextHolder != null) {
-            mBubbleTextHolder.onItemInfoUpdated(itemInfo);
-        }
-    }
-
-    public void setBubbleTextHolder(BubbleTextHolder bubbleTextHolder) {
-        mBubbleTextHolder = bubbleTextHolder;
     }
 
     @UiThread
@@ -917,10 +909,8 @@
             } else if (info instanceof WorkspaceItemInfo) {
                 applyFromWorkspaceItem((WorkspaceItemInfo) info);
                 mActivity.invalidateParent(info);
-            } else if (info instanceof PackageItemInfo) {
-                applyFromItemInfoWithIcon((PackageItemInfo) info);
-            } else if (info instanceof SearchActionItemInfo) {
-                applyFromItemInfoWithIcon((SearchActionItemInfo) info);
+            } else if (info != null) {
+                applyFromItemInfoWithIcon(info);
             }
 
             mDisableRelayout = false;
@@ -1058,4 +1048,19 @@
         args.put("count", notificationCount);
         return icuCountFormat.format(args);
     }
+
+    /**
+     * Starts a long press action and returns the corresponding pre-drag condition
+     */
+    public PreDragCondition startLongPressAction() {
+        PopupContainerWithArrow popup = PopupContainerWithArrow.showForIcon(this);
+        return popup != null ? popup.createPreDragCondition(true) : null;
+    }
+
+    /**
+     * Returns true if the view can show long-press popup
+     */
+    public boolean canShowLongPressPopup() {
+        return getTag() instanceof ItemInfo && ShortcutUtil.supportsShortcuts((ItemInfo) getTag());
+    }
 }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index fb028b9..6c091f0 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -85,14 +85,12 @@
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
-import com.android.launcher3.model.data.AppInfo;
 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.SearchActionItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemFactory;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pageindicators.PageIndicator;
-import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.states.StateAnimationConfig;
@@ -1680,11 +1678,7 @@
         }
 
         if (child instanceof BubbleTextView && !dragOptions.isAccessibleDrag) {
-            PopupContainerWithArrow<Launcher> popupContainer = PopupContainerWithArrow
-                    .showForIcon((BubbleTextView) child);
-            if (popupContainer != null) {
-                dragOptions.preDragCondition = popupContainer.createPreDragCondition(true);
-            }
+            dragOptions.preDragCondition = ((BubbleTextView) child).startLongPressAction();
         }
 
         final DragView dv;
@@ -2777,9 +2771,9 @@
                 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
                 case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
                 case LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION:
-                    if (info instanceof AppInfo) {
+                    if (info instanceof WorkspaceItemFactory) {
                         // Came from all apps -- make a copy
-                        info = ((AppInfo) info).makeWorkspaceItem();
+                        info = ((WorkspaceItemFactory) info).makeWorkspaceItem(mLauncher);
                         d.dragInfo = info;
                     }
                     if (info instanceof WorkspaceItemInfo
@@ -2788,11 +2782,6 @@
                         info = new WorkspaceItemInfo((WorkspaceItemInfo) info);
                         d.dragInfo = info;
                     }
-                    if (info instanceof SearchActionItemInfo) {
-                        info = ((SearchActionItemInfo) info).createWorkspaceItem(
-                                mLauncher.getModel());
-                        d.dragInfo = info;
-                    }
                     view = mLauncher.createShortcut(cellLayout, (WorkspaceItemInfo) info);
                     break;
                 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
diff --git a/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
index 14b2431..19d0421 100644
--- a/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
@@ -23,6 +23,7 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
 
+import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DropTarget;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.dragndrop.DragController;
@@ -31,9 +32,9 @@
 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.Thunk;
 import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.BubbleTextHolder;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -72,7 +73,7 @@
             getSupportedActions(host, item, actions);
             actions.forEach(la -> info.addAction(la.accessibilityAction));
 
-            if (!itemSupportsLongClick(host, item)) {
+            if (!itemSupportsLongClick(host)) {
                 info.setLongClickable(false);
                 info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
             }
@@ -84,8 +85,15 @@
      */
     protected abstract void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out);
 
-    private boolean itemSupportsLongClick(View host, ItemInfo info) {
-        return PopupContainerWithArrow.canShow(host, info);
+    private boolean itemSupportsLongClick(View host) {
+        if (host instanceof BubbleTextView) {
+            return ((BubbleTextView) host).canShowLongPressPopup();
+        } else if (host instanceof BubbleTextHolder) {
+            BubbleTextHolder holder = (BubbleTextHolder) host;
+            return holder.getBubbleText() != null && holder.getBubbleText().canShowLongPressPopup();
+        } else {
+            return false;
+        }
     }
 
     protected boolean itemSupportsAccessibleDrag(ItemInfo item) {
@@ -113,7 +121,6 @@
     @Thunk
     protected void announceConfirmation(String confirmation) {
         mContext.getDragLayer().announceForAccessibility(confirmation);
-
     }
 
     public boolean isInAccessibleDrag() {
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 12eb837..44d57d7 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -24,13 +24,14 @@
 import com.android.launcher3.R;
 import com.android.launcher3.Workspace;
 import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.DragOptions.PreDragCondition;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.keyboard.KeyboardDragAndDropView;
-import com.android.launcher3.model.data.AppInfo;
 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.WorkspaceItemFactory;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.notification.NotificationListener;
 import com.android.launcher3.popup.ArrowPopup;
@@ -40,6 +41,7 @@
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.ShortcutUtil;
 import com.android.launcher3.util.Thunk;
+import com.android.launcher3.views.BubbleTextHolder;
 import com.android.launcher3.views.OptionsPopupView;
 import com.android.launcher3.views.OptionsPopupView.OptionItem;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -118,7 +120,7 @@
             }
         }
 
-        if ((item instanceof AppInfo) || (item instanceof WorkspaceItemInfo)
+        if ((item instanceof WorkspaceItemFactory) || (item instanceof WorkspaceItemInfo)
                 || (item instanceof PendingAddItemInfo)) {
             out.add(mActions.get(ADD_TO_WORKSPACE));
         }
@@ -143,13 +145,18 @@
     protected boolean performAction(final View host, final ItemInfo item, int action,
             boolean fromKeyboard) {
         if (action == ACTION_LONG_CLICK) {
-            if (PopupContainerWithArrow.canShow(host, item)) {
-                // Long press should be consumed for workspace items, and it should invoke the
-                // Shortcuts / Notifications / Actions pop-up menu, and not start a drag as the
-                // standard long press path does.
-                PopupContainerWithArrow.showForIcon((BubbleTextView) host);
-                return true;
+            PreDragCondition dragCondition = null;
+            // Long press should be consumed for workspace items, and it should invoke the
+            // Shortcuts / Notifications / Actions pop-up menu, and not start a drag as the
+            // standard long press path does.
+            if (host instanceof BubbleTextView) {
+                dragCondition = ((BubbleTextView) host).startLongPressAction();
+            } else if (host instanceof BubbleTextHolder) {
+                BubbleTextHolder holder = (BubbleTextHolder) host;
+                dragCondition = holder.getBubbleText() == null ? null
+                        : holder.getBubbleText().startLongPressAction();
             }
+            return dragCondition != null;
         } else if (action == MOVE) {
             return beginAccessibleDrag(host, item, fromKeyboard);
         } else if (action == ADD_TO_WORKSPACE) {
@@ -166,7 +173,10 @@
             popup.setOnCloseCallback(host::requestFocus);
             return true;
         } else if (action == DEEP_SHORTCUTS || action == SHORTCUTS_AND_NOTIFICATIONS) {
-            return PopupContainerWithArrow.showForIcon((BubbleTextView) host) != null;
+            BubbleTextView btv = host instanceof BubbleTextView ? (BubbleTextView) host
+                    : (host instanceof BubbleTextHolder
+                            ? ((BubbleTextHolder) host).getBubbleText() : null);
+            return btv != null && PopupContainerWithArrow.showForIcon(btv) != null;
         } else {
             for (ButtonDropTarget dropTarget : mContext.getDropTargetBar().getDropTargets()) {
                 if (dropTarget.supportsAccessibilityDrop(item, host)
@@ -367,8 +377,8 @@
             return false;
         }
         mContext.getStateManager().goToState(NORMAL, true, forSuccessCallback(() -> {
-            if (item instanceof AppInfo) {
-                WorkspaceItemInfo info = ((AppInfo) item).makeWorkspaceItem();
+            if (item instanceof WorkspaceItemFactory) {
+                WorkspaceItemInfo info = ((WorkspaceItemFactory) item).makeWorkspaceItem(mContext);
                 mContext.getModelWriter().addItemToDatabase(info,
                         LauncherSettings.Favorites.CONTAINER_DESKTOP,
                         screenId, coordinates[0], coordinates[1]);
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 8916519..512fa1c 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -88,10 +88,10 @@
 import com.android.launcher3.logger.LauncherAtom.ToState;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
-import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.FolderInfo.FolderListener;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemFactory;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pageindicators.PageIndicatorDots;
 import com.android.launcher3.util.Executors;
@@ -1283,9 +1283,9 @@
             final WorkspaceItemInfo si;
             if (pasiSi != null) {
                 si = pasiSi;
-            } else if (d.dragInfo instanceof AppInfo) {
+            } else if (d.dragInfo instanceof WorkspaceItemFactory) {
                 // Came from all apps -- make a copy.
-                si = ((AppInfo) d.dragInfo).makeWorkspaceItem();
+                si = ((WorkspaceItemFactory) d.dragInfo).makeWorkspaceItem(launcher);
             } else {
                 // WorkspaceItemInfo
                 si = (WorkspaceItemInfo) d.dragInfo;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 5fe2435..4b436d3 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -68,11 +68,11 @@
 import com.android.launcher3.logger.LauncherAtom.ToState;
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.FolderInfo.FolderListener;
 import com.android.launcher3.model.data.FolderInfo.LabelState;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemFactory;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.util.Executors;
@@ -284,7 +284,7 @@
         mBackground.animateToAccept(cl, lp.cellX, lp.cellY);
         mOpenAlarm.setOnAlarmListener(mOnOpenListener);
         if (SPRING_LOADING_ENABLED &&
-                ((dragInfo instanceof AppInfo)
+                ((dragInfo instanceof WorkspaceItemFactory)
                         || (dragInfo instanceof WorkspaceItemInfo)
                         || (dragInfo instanceof PendingAddShortcutInfo))) {
             mOpenAlarm.setAlarm(ON_OPEN_DELAY);
@@ -486,9 +486,9 @@
 
     public void onDrop(DragObject d, boolean itemReturnedOnFailedDrop) {
         WorkspaceItemInfo item;
-        if (d.dragInfo instanceof AppInfo) {
+        if (d.dragInfo instanceof WorkspaceItemFactory) {
             // Came from all apps -- make a copy
-            item = ((AppInfo) d.dragInfo).makeWorkspaceItem();
+            item = ((WorkspaceItemFactory) d.dragInfo).makeWorkspaceItem(getContext());
         } else if (d.dragSource instanceof BaseItemDragListener){
             // Came from a different window -- make a copy
             item = new WorkspaceItemInfo((WorkspaceItemInfo) d.dragInfo);
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index ca91296..31ef2e5 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -32,6 +32,7 @@
 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.WorkspaceItemFactory;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.pm.InstallSessionHelper;
 import com.android.launcher3.pm.PackageInstallInfo;
@@ -107,8 +108,8 @@
                 }
 
                 if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
-                    if (item instanceof AppInfo) {
-                        item = ((AppInfo) item).makeWorkspaceItem();
+                    if (item instanceof WorkspaceItemFactory) {
+                        item = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
                     }
                 }
                 if (item != null) {
@@ -130,8 +131,8 @@
                 if (item instanceof WorkspaceItemInfo || item instanceof FolderInfo ||
                         item instanceof LauncherAppWidgetInfo) {
                     itemInfo = item;
-                } else if (item instanceof AppInfo) {
-                    itemInfo = ((AppInfo) item).makeWorkspaceItem();
+                } else if (item instanceof WorkspaceItemFactory) {
+                    itemInfo = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
                 } else {
                     throw new RuntimeException("Unexpected info type");
                 }
@@ -180,7 +181,7 @@
                         // App was installed while launcher was in the background,
                         // or app was already installed for another user.
                         itemInfo = new AppInfo(app.getContext(), activities.get(0), item.user)
-                                .makeWorkspaceItem();
+                                .makeWorkspaceItem(app.getContext());
 
                         if (shortcutExists(dataModel, itemInfo.getIntent(), itemInfo.user)) {
                             // We need this additional check here since we treat all auto added
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index 7f70bad..5b2bcf5 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -35,7 +35,6 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.pm.PackageInstallInfo;
-import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.PackageManagerHelper;
 
 import java.util.Comparator;
@@ -43,7 +42,7 @@
 /**
  * Represents an app in AllAppsView.
  */
-public class AppInfo extends ItemInfoWithIcon {
+public class AppInfo extends ItemInfoWithIcon implements WorkspaceItemFactory {
 
     public static final AppInfo[] EMPTY_ARRAY = new AppInfo[0];
     public static final Comparator<AppInfo> COMPONENT_KEY_COMPARATOR = (a, b) -> {
@@ -121,7 +120,8 @@
         return super.dumpProperties() + " componentName=" + componentName;
     }
 
-    public WorkspaceItemInfo makeWorkspaceItem() {
+    @Override
+    public WorkspaceItemInfo makeWorkspaceItem(Context context) {
         WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(this);
 
         if ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) {
@@ -139,10 +139,6 @@
         return workspaceItemInfo;
     }
 
-    public ComponentKey toComponentKey() {
-        return new ComponentKey(componentName, user);
-    }
-
     public static Intent makeLaunchIntent(LauncherActivityInfo info) {
         return makeLaunchIntent(info.getComponentName());
     }
diff --git a/src/com/android/launcher3/model/data/SearchActionItemInfo.java b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
index cc22601..e879313 100644
--- a/src/com/android/launcher3/model/data/SearchActionItemInfo.java
+++ b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
@@ -18,6 +18,7 @@
 import static com.android.launcher3.LauncherSettings.Favorites.EXTENDED_CONTAINERS;
 
 import android.app.PendingIntent;
+import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Icon;
 import android.os.Process;
@@ -26,18 +27,14 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherModel;
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.logger.LauncherAtom.ItemInfo;
 import com.android.launcher3.logger.LauncherAtom.SearchActionItem;
-import com.android.launcher3.model.AllAppsList;
-import com.android.launcher3.model.BaseModelUpdateTask;
-import com.android.launcher3.model.BgDataModel;
 
 /**
  * Represents a SearchAction with in launcher
  */
-public class SearchActionItemInfo extends ItemInfoWithIcon {
+public class SearchActionItemInfo extends ItemInfoWithIcon implements WorkspaceItemFactory {
 
     public static final int FLAG_SHOULD_START = 1 << 1;
     public static final int FLAG_SHOULD_START_FOR_RESULT = FLAG_SHOULD_START | 1 << 2;
@@ -158,7 +155,8 @@
     /**
      * Creates a {@link WorkspaceItemInfo} coorsponding to search action to be stored in launcher db
      */
-    public WorkspaceItemInfo createWorkspaceItem(LauncherModel model) {
+    @Override
+    public WorkspaceItemInfo makeWorkspaceItem(Context context) {
         WorkspaceItemInfo info = new WorkspaceItemInfo();
         info.title = title;
         info.bitmap = bitmap;
@@ -167,18 +165,12 @@
         if (hasFlags(FLAG_SHOULD_START_FOR_RESULT)) {
             info.options |= WorkspaceItemInfo.FLAG_START_FOR_RESULT;
         }
-
-        model.enqueueModelUpdateTask(new BaseModelUpdateTask() {
-            @Override
-            public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
-
-                model.updateAndBindWorkspaceItem(() -> {
-                    PackageItemInfo pkgInfo = new PackageItemInfo(getIntentPackageName(), user);
-                    app.getIconCache().getTitleAndIconForApp(pkgInfo, false);
-                    info.bitmap = info.bitmap.withBadgeInfo(pkgInfo.bitmap);
-                    return info;
-                });
-            }
+        LauncherAppState app = LauncherAppState.getInstance(context);
+        app.getModel().updateAndBindWorkspaceItem(() -> {
+            PackageItemInfo pkgInfo = new PackageItemInfo(getIntentPackageName(), user);
+            app.getIconCache().getTitleAndIconForApp(pkgInfo, false);
+            info.bitmap = info.bitmap.withBadgeInfo(pkgInfo.bitmap);
+            return info;
         });
         return info;
     }
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemFactory.java b/src/com/android/launcher3/model/data/WorkspaceItemFactory.java
new file mode 100644
index 0000000..47b9c6e
--- /dev/null
+++ b/src/com/android/launcher3/model/data/WorkspaceItemFactory.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 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.model.data;
+
+import android.content.Context;
+
+/**
+ * Interface to objects capable of generating workspace item
+ */
+public interface WorkspaceItemFactory {
+
+    /**
+     * Called to create a pinnable item info
+     */
+    WorkspaceItemInfo makeWorkspaceItem(Context context);
+}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 484b879..49d97d2 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -187,7 +187,10 @@
 
     /**
      * Returns true if we can show the container.
+     *
+     * @deprecated Left here since some dependent projects are using this method
      */
+    @Deprecated
     public static boolean canShow(View icon, ItemInfo item) {
         return icon instanceof BubbleTextView && ShortcutUtil.supportsShortcuts(item);
     }
@@ -204,7 +207,7 @@
             return null;
         }
         ItemInfo item = (ItemInfo) icon.getTag();
-        if (!canShow(icon, item)) {
+        if (!ShortcutUtil.supportsShortcuts(item)) {
             return null;
         }
 
@@ -538,7 +541,7 @@
     public static void dismissInvalidPopup(BaseDraggingActivity activity) {
         PopupContainerWithArrow popup = getOpen(activity);
         if (popup != null && (!popup.mOriginalIcon.isAttachedToWindow()
-                || !canShow(popup.mOriginalIcon, (ItemInfo) popup.mOriginalIcon.getTag()))) {
+                || !ShortcutUtil.supportsShortcuts((ItemInfo) popup.mOriginalIcon.getTag()))) {
             popup.animateClose();
         }
     }
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index cd00f15..c4d2bc4 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -100,8 +100,7 @@
                 onClickFolderIcon(v);
             }
         } else if (tag instanceof AppInfo) {
-            startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher
-            );
+            startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
         } else if (tag instanceof LauncherAppWidgetInfo) {
             if (v instanceof PendingAppWidgetHostView) {
                 onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index f876dd9..6bae745 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -37,6 +37,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.TestProtocol;
+import com.android.launcher3.views.BubbleTextHolder;
 
 /**
  * Class to handle long-clicks on workspace items and start drag as a result.
@@ -79,9 +80,12 @@
         launcher.getWorkspace().startDrag(longClickCellInfo, dragOptions);
     }
 
-    private static boolean onAllAppsItemLongClick(View v) {
+    private static boolean onAllAppsItemLongClick(View view) {
         TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onAllAppsItemLongClick");
-        v.cancelLongPress();
+        view.cancelLongPress();
+        View v = (view instanceof BubbleTextHolder)
+                ? ((BubbleTextHolder) view).getBubbleText()
+                : view;
         Launcher launcher = Launcher.getLauncher(v.getContext());
         if (!canStartDrag(launcher)) return false;
         // When we have exited all apps or are in transition, disregard long clicks
diff --git a/src/com/android/launcher3/views/BubbleTextHolder.java b/src/com/android/launcher3/views/BubbleTextHolder.java
index 76c465c..84f8049 100644
--- a/src/com/android/launcher3/views/BubbleTextHolder.java
+++ b/src/com/android/launcher3/views/BubbleTextHolder.java
@@ -16,8 +16,6 @@
 package com.android.launcher3.views;
 
 import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
 
 /**
  * Views that contain {@link BubbleTextView} should implement this interface.
@@ -25,14 +23,6 @@
 public interface BubbleTextHolder extends IconLabelDotView {
     BubbleTextView getBubbleText();
 
-    /**
-     * Called when new {@link ItemInfo} is set to {@link BubbleTextView}
-     *
-     * @param itemInfo the new itemInfo
-     */
-    default void onItemInfoUpdated(ItemInfoWithIcon itemInfo) {
-    }
-
     @Override
     default void setIconVisible(boolean visible) {
         getBubbleText().setIconVisible(visible);