Simplifying InstallShortcutReceiver

> Removing support for legacy shortcuts (with embedded icon)
> Unifying pattern for storing the data in prefs

Change-Id: Ife250807c7ce5337969d25444ee23c751bc2a487
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index be6adc7..d2b05c5 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -16,6 +16,13 @@
 
 package com.android.launcher3;
 
+import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
+
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID;
+import static com.android.launcher3.model.data.AppInfo.makeLaunchIntent;
 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
 
 import android.appwidget.AppWidgetManager;
@@ -24,37 +31,25 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
 import android.content.pm.ShortcutInfo;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Parcelable;
 import android.os.Process;
 import android.os.UserHandle;
-import android.text.TextUtils;
-import android.util.Base64;
 import android.util.Log;
 import android.util.Pair;
 
 import androidx.annotation.Nullable;
 import androidx.annotation.WorkerThread;
 
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.GraphicsUtils;
-import com.android.launcher3.icons.LauncherIcons;
-import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.LauncherSettings.Favorites;
 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;
 import com.android.launcher3.shortcuts.ShortcutRequest;
-import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.Preconditions;
-import com.android.launcher3.util.Thunk;
 
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -81,17 +76,6 @@
     private static final String TAG = "InstallShortcutReceiver";
     private static final boolean DBG = false;
 
-    private static final String LAUNCH_INTENT_KEY = "intent.launch";
-    private static final String NAME_KEY = "name";
-    private static final String ICON_KEY = "icon";
-    private static final String ICON_RESOURCE_NAME_KEY = "iconResource";
-    private static final String ICON_RESOURCE_PACKAGE_NAME_KEY = "iconResourcePackage";
-
-    private static final String APP_SHORTCUT_TYPE_KEY = "isAppShortcut";
-    private static final String DEEPSHORTCUT_TYPE_KEY = "isDeepShortcut";
-    private static final String APP_WIDGET_TYPE_KEY = "isAppWidget";
-    private static final String USER_HANDLE_KEY = "userHandle";
-
     // The set of shortcuts that are pending install
     private static final String APPS_PENDING_INSTALL = "apps_to_install";
 
@@ -100,7 +84,7 @@
 
     @WorkerThread
     private static void addToQueue(Context context, PendingInstallShortcutInfo info) {
-        String encoded = info.encodeToString();
+        String encoded = info.encodeToString(context);
         SharedPreferences prefs = Utilities.getPrefs(context);
         Set<String> strings = prefs.getStringSet(APPS_PENDING_INSTALL, null);
         strings = (strings != null) ? new HashSet<>(strings) : new HashSet<>(1);
@@ -123,25 +107,14 @@
             return;
         }
 
-        LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
         for (String encoded : strings) {
             PendingInstallShortcutInfo info = decode(encoded, context);
             if (info == null) {
                 continue;
             }
 
-            String pkg = getIntentPackage(info.launchIntent);
-            if (!TextUtils.isEmpty(pkg)
-                    && !launcherApps.isPackageEnabled(pkg, info.user)
-                    && !info.isActivity) {
-                if (DBG) {
-                    Log.d(TAG, "Ignoring shortcut for absent package: " + info.launchIntent);
-                }
-                continue;
-            }
-
             // Generate a shortcut info to add into the model
-            installQueue.add(info.getItemInfo());
+            installQueue.add(info.getItemInfo(context));
         }
         prefs.edit().remove(APPS_PENDING_INSTALL).apply();
         if (!installQueue.isEmpty()) {
@@ -172,8 +145,8 @@
             String encoded = newStringsIter.next();
             try {
                 Decoder decoder = new Decoder(encoded, context);
-                if (packageNames.contains(getIntentPackage(decoder.launcherIntent)) &&
-                        user.equals(decoder.user)) {
+                if (packageNames.contains(getIntentPackage(decoder.intent))
+                        && user.equals(decoder.user)) {
                     newStringsIter.remove();
                 }
             } catch (JSONException | URISyntaxException e) {
@@ -184,57 +157,17 @@
         sp.edit().putStringSet(APPS_PENDING_INSTALL, newStrings).apply();
     }
 
-    /**
-     * @return true is the extra is either null or is of type {@param type}
-     */
-    private static boolean isValidExtraType(Intent intent, String key, Class type) {
-        Object extra = intent.getParcelableExtra(key);
-        return extra == null || type.isInstance(extra);
-    }
-
-    /**
-     * Verifies the intent and creates a {@link PendingInstallShortcutInfo}
-     */
-    private static PendingInstallShortcutInfo createPendingInfo(Context context, Intent data) {
-        if (!isValidExtraType(data, Intent.EXTRA_SHORTCUT_INTENT, Intent.class) ||
-                !(isValidExtraType(data, Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
-                        Intent.ShortcutIconResource.class)) ||
-                !(isValidExtraType(data, Intent.EXTRA_SHORTCUT_ICON, Bitmap.class))) {
-
-            if (DBG) Log.e(TAG, "Invalid install shortcut intent");
-            return null;
-        }
-
-        PendingInstallShortcutInfo info = new PendingInstallShortcutInfo(
-                data, Process.myUserHandle(), context);
-        if (info.launchIntent == null || info.label == null) {
-            if (DBG) Log.e(TAG, "Invalid install shortcut intent");
-            return null;
-        }
-
-        return convertToLauncherActivityIfPossible(info);
-    }
-
-    public static WorkspaceItemInfo fromShortcutIntent(Context context, Intent data) {
-        PendingInstallShortcutInfo info = createPendingInfo(context, data);
-        return info == null ? null : (WorkspaceItemInfo) info.getItemInfo().first;
-    }
-
     public static void queueShortcut(ShortcutInfo info, Context context) {
-        queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context);
+        queuePendingShortcutInfo(new PendingInstallShortcutInfo(info), context);
     }
 
     public static void queueWidget(AppWidgetProviderInfo info, int widgetId, Context context) {
-        queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, widgetId, context), context);
+        queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, widgetId), context);
     }
 
-    public static void queueApplication(LauncherActivityInfo info, Context context) {
-        queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, context), context);
-    }
-
-    public static void queueApplication(Intent data, UserHandle user, Context context) {
-        queuePendingShortcutInfo(new PendingInstallShortcutInfo(data, context, user),
-                context);
+    public static void queueApplication(
+            String packageName, UserHandle userHandle, Context context) {
+        queuePendingShortcutInfo(new PendingInstallShortcutInfo(packageName, userHandle), context);
     }
 
     public static HashSet<ShortcutKey> getPendingShortcuts(Context context) {
@@ -248,8 +181,8 @@
         for (String encoded : strings) {
             try {
                 Decoder decoder = new Decoder(encoded, context);
-                if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
-                    result.add(ShortcutKey.fromIntent(decoder.launcherIntent, decoder.user));
+                if (decoder.optInt(Favorites.ITEM_TYPE, -1) == ITEM_TYPE_DEEP_SHORTCUT) {
+                    result.add(ShortcutKey.fromIntent(decoder.intent, decoder.user));
                 }
             } catch (JSONException | URISyntaxException e) {
                 Log.d(TAG, "Exception reading shortcut to add: " + e);
@@ -279,224 +212,111 @@
         MODEL_EXECUTOR.post(() -> flushQueueInBackground(context));
     }
 
-    /**
-     * Ensures that we have a valid, non-null name.  If the provided name is null, we will return
-     * the application name instead.
-     */
-    @Thunk static CharSequence ensureValidName(Context context, Intent intent, CharSequence name) {
-        if (name == null) {
-            try {
-                PackageManager pm = context.getPackageManager();
-                ActivityInfo info = pm.getActivityInfo(intent.getComponent(), 0);
-                name = info.loadLabel(pm);
-            } catch (PackageManager.NameNotFoundException nnfe) {
-                return "";
-            }
-        }
-        return name;
-    }
 
-    private static class PendingInstallShortcutInfo {
+    private static class PendingInstallShortcutInfo extends ItemInfo {
 
-        final boolean isActivity;
-        @Nullable final ShortcutInfo shortcutInfo;
-        @Nullable final AppWidgetProviderInfo providerInfo;
+        final Intent intent;
 
-        @Nullable final Intent data;
-        final Context mContext;
-        final Intent launchIntent;
-        final String label;
-        final UserHandle user;
+        @Nullable ShortcutInfo shortcutInfo;
+        @Nullable AppWidgetProviderInfo providerInfo;
 
         /**
-         * Initializes a PendingInstallShortcutInfo received from a different app.
+         * Initializes a PendingInstallShortcutInfo to represent a pending launcher target.
          */
-        public PendingInstallShortcutInfo(Intent data, UserHandle user, Context context) {
-            isActivity = false;
-            shortcutInfo = null;
-            providerInfo = null;
-
-            this.data = data;
-            this.user = user;
-            mContext = context;
-
-            launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
-            label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+        public PendingInstallShortcutInfo(String packageName, UserHandle userHandle) {
+            itemType = Favorites.ITEM_TYPE_APPLICATION;
+            intent = new Intent().setPackage(packageName);
+            user = userHandle;
         }
 
         /**
-         * Initializes a PendingInstallShortcutInfo to represent a launcher target.
+         * Initializes a PendingInstallShortcutInfo to represent a deep shortcut.
          */
-        public PendingInstallShortcutInfo(LauncherActivityInfo info, Context context) {
-            isActivity = true;
-            shortcutInfo = null;
-            providerInfo = null;
-
-            String packageName = info.getComponentName().getPackageName();
-            data = new Intent();
-            data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent().setComponent(
-                    new ComponentName(packageName, "")).setPackage(packageName));
-            data.putExtra(Intent.EXTRA_SHORTCUT_NAME, info.getLabel());
-
-            user = info.getUser();
-            mContext = context;
-
-            launchIntent = AppInfo.makeLaunchIntent(info);
-            label = info.getLabel().toString();
-        }
-
-        /**
-         * Initializes a PendingInstallShortcutInfo to represent a launcher target.
-         */
-        public PendingInstallShortcutInfo(Intent data, Context context, UserHandle user) {
-            isActivity = true;
-            shortcutInfo = null;
-            providerInfo = null;
-
-            this.data = data;
-            this.user = user;
-            mContext = context;
-
-            launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
-            label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
-        }
-
-        /**
-         * Initializes a PendingInstallShortcutInfo to represent a launcher target.
-         */
-        public PendingInstallShortcutInfo(ShortcutInfo info, Context context) {
-            isActivity = false;
-            shortcutInfo = info;
-            providerInfo = null;
-
-            data = null;
-            mContext = context;
+        public PendingInstallShortcutInfo(ShortcutInfo info) {
+            itemType = Favorites.ITEM_TYPE_DEEP_SHORTCUT;
+            intent = ShortcutKey.makeIntent(info);
             user = info.getUserHandle();
 
-            launchIntent = ShortcutKey.makeIntent(info);
-            label = info.getShortLabel().toString();
+            shortcutInfo = info;
         }
 
         /**
-         * Initializes a PendingInstallShortcutInfo to represent a launcher target.
+         * Initializes a PendingInstallShortcutInfo to represent an app widget.
          */
-        public PendingInstallShortcutInfo(
-                AppWidgetProviderInfo info, int widgetId, Context context) {
-            isActivity = false;
-            shortcutInfo = null;
-            providerInfo = info;
-
-            data = null;
-            mContext = context;
+        public PendingInstallShortcutInfo(AppWidgetProviderInfo info, int widgetId) {
+            itemType = Favorites.ITEM_TYPE_APPWIDGET;
+            intent = new Intent()
+                    .setComponent(info.provider)
+                    .putExtra(EXTRA_APPWIDGET_ID, widgetId);
             user = info.getProfile();
 
-            launchIntent = new Intent().setComponent(info.provider)
-                    .putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
-            label = info.label;
+            providerInfo = info;
         }
 
-        public String encodeToString() {
+        public String encodeToString(Context context) {
             try {
-                if (shortcutInfo != null) {
-                    // If it a launcher target, we only need component name, and user to
-                    // recreate this.
-                    return new JSONStringer()
-                            .object()
-                            .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
-                            .key(DEEPSHORTCUT_TYPE_KEY).value(true)
-                            .key(USER_HANDLE_KEY).value(UserCache.INSTANCE.get(mContext)
-                                    .getSerialNumberForUser(user))
-                            .endObject().toString();
-                } else if (providerInfo != null) {
-                    // If it a launcher target, we only need component name, and user to
-                    // recreate this.
-                    return new JSONStringer()
-                            .object()
-                            .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
-                            .key(APP_WIDGET_TYPE_KEY).value(true)
-                            .key(USER_HANDLE_KEY).value(UserCache.INSTANCE.get(mContext)
-                                    .getSerialNumberForUser(user))
-                            .endObject().toString();
-                }
-
-                if (launchIntent.getAction() == null) {
-                    launchIntent.setAction(Intent.ACTION_VIEW);
-                } else if (launchIntent.getAction().equals(Intent.ACTION_MAIN) &&
-                        launchIntent.getCategories() != null &&
-                        launchIntent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {
-                    launchIntent.addFlags(
-                            Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-                }
-
-                // This name is only used for comparisons and notifications, so fall back to activity
-                // name if not supplied
-                String name = ensureValidName(mContext, launchIntent, label).toString();
-                Bitmap icon = data == null ? null
-                        : data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
-                Intent.ShortcutIconResource iconResource = data == null ? null
-                    : data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
-
-                // Only encode the parameters which are supported by the API.
-                JSONStringer json = new JSONStringer()
-                    .object()
-                    .key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
-                    .key(NAME_KEY).value(name)
-                    .key(USER_HANDLE_KEY).value(
-                            UserCache.INSTANCE.get(mContext).getSerialNumberForUser(user))
-                    .key(APP_SHORTCUT_TYPE_KEY).value(isActivity);
-                if (icon != null) {
-                    byte[] iconByteArray = GraphicsUtils.flattenBitmap(icon);
-                    if (iconByteArray != null) {
-                        json = json.key(ICON_KEY).value(
-                                Base64.encodeToString(
-                                        iconByteArray, 0, iconByteArray.length, Base64.DEFAULT));
-                    }
-                }
-                if (iconResource != null) {
-                    json = json.key(ICON_RESOURCE_NAME_KEY).value(iconResource.resourceName);
-                    json = json.key(ICON_RESOURCE_PACKAGE_NAME_KEY)
-                            .value(iconResource.packageName);
-                }
-                return json.endObject().toString();
+                return new JSONStringer()
+                        .object()
+                        .key(Favorites.ITEM_TYPE).value(itemType)
+                        .key(Favorites.INTENT).value(intent.toUri(0))
+                        .key(PROFILE_ID).value(
+                                UserCache.INSTANCE.get(context).getSerialNumberForUser(user))
+                        .endObject().toString();
             } catch (JSONException e) {
                 Log.d(TAG, "Exception when adding shortcut: " + e);
                 return null;
             }
         }
 
-        public Pair<ItemInfo, Object> getItemInfo() {
-            if (isActivity) {
-                WorkspaceItemInfo si = createWorkspaceItemInfo(data, user,
-                        LauncherAppState.getInstance(mContext));
-                si.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
-                si.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON;
-                return Pair.create(si, null);
-            } else if (shortcutInfo != null) {
-                WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(shortcutInfo, mContext);
-                LauncherAppState.getInstance(mContext).getIconCache().getShortcutIcon(
-                        itemInfo, shortcutInfo);
-                return Pair.create(itemInfo, shortcutInfo);
-            } else if (providerInfo != null) {
-                LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo
-                        .fromProviderInfo(mContext, providerInfo);
-                LauncherAppWidgetInfo widgetInfo = new LauncherAppWidgetInfo(
-                        launchIntent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0),
-                        info.provider);
-                InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
-                widgetInfo.minSpanX = info.minSpanX;
-                widgetInfo.minSpanY = info.minSpanY;
-                widgetInfo.spanX = Math.min(info.spanX, idp.numColumns);
-                widgetInfo.spanY = Math.min(info.spanY, idp.numRows);
-                return Pair.create(widgetInfo, providerInfo);
-            } else {
-                WorkspaceItemInfo itemInfo =
-                        createWorkspaceItemInfo(data, user, LauncherAppState.getInstance(mContext));
-                return Pair.create(itemInfo, null);
-            }
-        }
+        public Pair<ItemInfo, Object> getItemInfo(Context context) {
+            switch (itemType) {
+                case ITEM_TYPE_APPLICATION: {
+                    String packageName = intent.getPackage();
+                    List<LauncherActivityInfo> laiList =
+                            context.getSystemService(LauncherApps.class)
+                                    .getActivityList(packageName, user);
 
-        public boolean isLauncherActivity() {
-            return isActivity;
+                    final WorkspaceItemInfo si = new WorkspaceItemInfo();
+                    si.user = user;
+                    si.itemType = ITEM_TYPE_APPLICATION;
+
+                    LauncherActivityInfo lai;
+                    boolean usePackageIcon = laiList.isEmpty();
+                    if (usePackageIcon) {
+                        lai = null;
+                        si.intent = makeLaunchIntent(new ComponentName(packageName, ""))
+                                .setPackage(packageName);
+                        si.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON;
+                    } else {
+                        lai = laiList.get(0);
+                        si.intent = makeLaunchIntent(lai);
+                    }
+                    LauncherAppState.getInstance(context).getIconCache()
+                            .getTitleAndIcon(si, () -> lai, usePackageIcon, false);
+                    return Pair.create(si, null);
+                }
+                case ITEM_TYPE_DEEP_SHORTCUT: {
+                    WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(shortcutInfo, context);
+                    LauncherAppState.getInstance(context).getIconCache()
+                            .getShortcutIcon(itemInfo, shortcutInfo);
+                    return Pair.create(itemInfo, shortcutInfo);
+                }
+                case ITEM_TYPE_APPWIDGET: {
+                    LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo
+                            .fromProviderInfo(context, providerInfo);
+                    LauncherAppWidgetInfo widgetInfo = new LauncherAppWidgetInfo(
+                            intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0),
+                            info.provider);
+                    InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
+                    widgetInfo.minSpanX = info.minSpanX;
+                    widgetInfo.minSpanY = info.minSpanY;
+                    widgetInfo.spanX = Math.min(info.spanX, idp.numColumns);
+                    widgetInfo.spanY = Math.min(info.spanY, idp.numRows);
+                    widgetInfo.user = user;
+                    return Pair.create(widgetInfo, providerInfo);
+                }
+            }
+            return null;
         }
     }
 
@@ -508,56 +328,32 @@
     private static PendingInstallShortcutInfo decode(String encoded, Context context) {
         try {
             Decoder decoder = new Decoder(encoded, context);
-            if (decoder.optBoolean(APP_SHORTCUT_TYPE_KEY)) {
-                LauncherActivityInfo info = context.getSystemService(LauncherApps.class)
-                        .resolveActivity(decoder.launcherIntent, decoder.user);
-                if (info != null) {
-                    return new PendingInstallShortcutInfo(info, context);
+            switch (decoder.optInt(Favorites.ITEM_TYPE, -1)) {
+                case Favorites.ITEM_TYPE_APPLICATION:
+                    return new PendingInstallShortcutInfo(
+                            decoder.intent.getPackage(), decoder.user);
+                case Favorites.ITEM_TYPE_DEEP_SHORTCUT: {
+                    List<ShortcutInfo> si = ShortcutKey.fromIntent(decoder.intent, decoder.user)
+                            .buildRequest(context)
+                            .query(ShortcutRequest.ALL);
+                    if (si.isEmpty()) {
+                        return null;
+                    } else {
+                        return new PendingInstallShortcutInfo(si.get(0));
+                    }
                 }
-            } else if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
-                List<ShortcutInfo> si = ShortcutKey.fromIntent(decoder.launcherIntent, decoder.user)
-                        .buildRequest(context)
-                        .query(ShortcutRequest.ALL);
-                if (si.isEmpty()) {
-                    return null;
-                } else {
-                    return new PendingInstallShortcutInfo(si.get(0), context);
+                case Favorites.ITEM_TYPE_APPWIDGET: {
+                    int widgetId = decoder.intent.getIntExtra(EXTRA_APPWIDGET_ID, 0);
+                    AppWidgetProviderInfo info =
+                            AppWidgetManager.getInstance(context).getAppWidgetInfo(widgetId);
+                    if (info == null || !info.provider.equals(decoder.intent.getComponent())
+                            || !info.getProfile().equals(decoder.user)) {
+                        return null;
+                    }
+                    return new PendingInstallShortcutInfo(info, widgetId);
                 }
-            } else if (decoder.optBoolean(APP_WIDGET_TYPE_KEY)) {
-                int widgetId = decoder.launcherIntent
-                        .getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0);
-                AppWidgetProviderInfo info = AppWidgetManager.getInstance(context)
-                        .getAppWidgetInfo(widgetId);
-                if (info == null || !info.provider.equals(decoder.launcherIntent.getComponent()) ||
-                        !info.getProfile().equals(decoder.user)) {
-                    return null;
-                }
-                return new PendingInstallShortcutInfo(info, widgetId, context);
-            }
-
-            Intent data = new Intent();
-            data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, decoder.launcherIntent);
-            data.putExtra(Intent.EXTRA_SHORTCUT_NAME, decoder.getString(NAME_KEY));
-
-            String iconBase64 = decoder.optString(ICON_KEY);
-            String iconResourceName = decoder.optString(ICON_RESOURCE_NAME_KEY);
-            String iconResourcePackageName = decoder.optString(ICON_RESOURCE_PACKAGE_NAME_KEY);
-            if (iconBase64 != null && !iconBase64.isEmpty()) {
-                byte[] iconArray = Base64.decode(iconBase64, Base64.DEFAULT);
-                Bitmap b = BitmapFactory.decodeByteArray(iconArray, 0, iconArray.length);
-                data.putExtra(Intent.EXTRA_SHORTCUT_ICON, b);
-            } else if (iconResourceName != null && !iconResourceName.isEmpty()) {
-                Intent.ShortcutIconResource iconResource =
-                    new Intent.ShortcutIconResource();
-                iconResource.resourceName = iconResourceName;
-                iconResource.packageName = iconResourcePackageName;
-                data.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource);
-            }
-
-            if (decoder.optBoolean(APP_SHORTCUT_TYPE_KEY)) {
-                return new PendingInstallShortcutInfo(data, context, decoder.user);
-            } else {
-                return new PendingInstallShortcutInfo(data, decoder.user, context);
+                default:
+                    Log.e(TAG, "Unknown item type");
             }
         } catch (JSONException | URISyntaxException e) {
             Log.d(TAG, "Exception reading shortcut to add: " + e);
@@ -566,88 +362,18 @@
     }
 
     private static class Decoder extends JSONObject {
-        public final Intent launcherIntent;
+        public final Intent intent;
         public final UserHandle user;
 
         private Decoder(String encoded, Context context) throws JSONException, URISyntaxException {
             super(encoded);
-            launcherIntent = Intent.parseUri(getString(LAUNCH_INTENT_KEY), 0);
-            user = has(USER_HANDLE_KEY) ? UserCache.INSTANCE.get(context)
-                    .getUserForSerialNumber(getLong(USER_HANDLE_KEY))
+            intent = Intent.parseUri(getString(Favorites.INTENT), 0);
+            user = has(PROFILE_ID)
+                    ? UserCache.INSTANCE.get(context).getUserForSerialNumber(getLong(PROFILE_ID))
                     : Process.myUserHandle();
-            if (user == null) {
-                throw new JSONException("Invalid user");
+            if (user == null || intent == null) {
+                throw new JSONException("Invalid data");
             }
         }
     }
-
-    /**
-     * Tries to create a new PendingInstallShortcutInfo which represents the same target,
-     * but is an app target and not a shortcut.
-     * @return the newly created info or the original one.
-     */
-    private static PendingInstallShortcutInfo convertToLauncherActivityIfPossible(
-            PendingInstallShortcutInfo original) {
-        if (original.isLauncherActivity()) {
-            // Already an activity target
-            return original;
-        }
-        if (!PackageManagerHelper.isLauncherAppTarget(original.launchIntent)) {
-            return original;
-        }
-
-        LauncherActivityInfo info = original.mContext.getSystemService(LauncherApps.class)
-                .resolveActivity(original.launchIntent, original.user);
-        if (info == null) {
-            return original;
-        }
-        // Ignore any conflicts in the label name, as that can change based on locale.
-        return new PendingInstallShortcutInfo(info, original.mContext);
-    }
-
-    private static WorkspaceItemInfo createWorkspaceItemInfo(Intent data, UserHandle user,
-            LauncherAppState app) {
-        if (data == null) {
-            Log.e(TAG, "Can't construct WorkspaceItemInfo with null data");
-            return null;
-        }
-
-        Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
-        String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
-        Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
-
-        if (intent == null) {
-            // If the intent is null, return null as we can't construct a valid WorkspaceItemInfo
-            Log.e(TAG, "Can't construct WorkspaceItemInfo with null intent");
-            return null;
-        }
-
-        final WorkspaceItemInfo info = new WorkspaceItemInfo();
-        info.user = user;
-
-        BitmapInfo iconInfo = null;
-        LauncherIcons li = LauncherIcons.obtain(app.getContext());
-        if (bitmap instanceof Bitmap) {
-            iconInfo = li.createIconBitmap((Bitmap) bitmap);
-        } else {
-            Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
-            if (extra instanceof Intent.ShortcutIconResource) {
-                info.iconResource = (Intent.ShortcutIconResource) extra;
-                iconInfo = li.createIconBitmap(info.iconResource);
-            }
-        }
-        li.recycle();
-
-        if (iconInfo == null) {
-            iconInfo = app.getIconCache().getDefaultIcon(info.user);
-        }
-        info.bitmap = iconInfo;
-
-        info.title = Utilities.trim(name);
-        info.contentDescription = app.getContext().getPackageManager()
-                .getUserBadgedLabel(info.title, info.user);
-        info.intent = intent;
-        return info;
-    }
-
 }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index e723408..3f64df3 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -120,6 +120,7 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.logging.UserEventDispatcher;
 import com.android.launcher3.model.BgDataModel.Callbacks;
+import com.android.launcher3.model.ModelUtils;
 import com.android.launcher3.model.ModelWriter;
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.FolderInfo;
@@ -1202,7 +1203,7 @@
         if (info == null) {
             // Legacy shortcuts are only supported for primary profile.
             info = Process.myUserHandle().equals(args.user)
-                    ? InstallShortcutReceiver.fromShortcutIntent(this, data) : null;
+                    ? ModelUtils.fromLegacyShortcutIntent(this, data) : null;
 
             if (info == null) {
                 Log.e(TAG, "Unable to parse a valid custom shortcut result");
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index a8d6490..e48ffb9 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -19,8 +19,6 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.LauncherActivityInfo;
-import android.content.pm.LauncherApps;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageManager;
@@ -29,8 +27,6 @@
 
 import com.android.launcher3.pm.InstallSessionHelper;
 
-import java.util.List;
-
 /**
  * BroadcastReceiver to handle session commit intent.
  */
@@ -63,18 +59,7 @@
             return;
         }
 
-        queueAppIconAddition(context, info.getAppPackageName(), user);
-    }
-
-    public static void queueAppIconAddition(Context context, String packageName, UserHandle user) {
-        List<LauncherActivityInfo> activities = context.getSystemService(LauncherApps.class)
-                .getActivityList(packageName, user);
-        if (activities.isEmpty()) {
-            // no activity found
-            return;
-        }
-
-        InstallShortcutReceiver.queueApplication(activities.get(0), context);
+        InstallShortcutReceiver.queueApplication(info.getAppPackageName(), user, context);
     }
 
     public static boolean isEnabled(Context context) {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 068d0bc..dea2a8d 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -25,6 +25,7 @@
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
@@ -639,6 +640,14 @@
         }
     }
 
+    /**
+     * @return true is the extra is either null or is of type {@param type}
+     */
+    public static boolean isValidExtraType(Intent intent, String key, Class type) {
+        Object extra = intent.getParcelableExtra(key);
+        return extra == null || type.isInstance(extra);
+    }
+
     public static float squaredHypot(float x, float y) {
         return x * x + y * y;
     }
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index ff0f773..444c2da 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -260,14 +260,6 @@
     }
 
     /**
-     * Fill in info with the icon and label for deep shortcut.
-     */
-    public synchronized CacheEntry getDeepShortcutTitleAndIcon(ShortcutInfo info) {
-        return cacheLocked(ShortcutKey.fromInfo(info).componentName, info.getUserHandle(),
-                () -> info, mShortcutCachingLogic, false, false);
-    }
-
-    /**
      * Fill in {@param info} with the icon and label. If the
      * corresponding activity is not found, it reverts to the package icon.
      */
@@ -295,7 +287,7 @@
     /**
      * Fill in {@param mWorkspaceItemInfo} with the icon and label for {@param info}
      */
-    private synchronized void getTitleAndIcon(
+    public synchronized void getTitleAndIcon(
             @NonNull ItemInfoWithIcon infoInOut,
             @NonNull Supplier<LauncherActivityInfo> activityInfoProvider,
             boolean usePkgIcon, boolean useLowResIcon) {
diff --git a/src/com/android/launcher3/model/ModelUtils.java b/src/com/android/launcher3/model/ModelUtils.java
index 4efeba5..a8cc9ad 100644
--- a/src/com/android/launcher3/model/ModelUtils.java
+++ b/src/com/android/launcher3/model/ModelUtils.java
@@ -15,10 +15,22 @@
  */
 package com.android.launcher3.model;
 
+import static com.android.launcher3.Utilities.isValidExtraType;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.os.Process;
+import android.util.Log;
+
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.IntSet;
 
@@ -33,6 +45,8 @@
  */
 public class ModelUtils {
 
+    private static final String TAG = "ModelUtils";
+
     /**
      * Filters the set of items who are directly or indirectly (via another container) on the
      * specified screen.
@@ -125,4 +139,52 @@
         IntStream.range(0, len).filter(i -> !seen.contains(i)).forEach(result::add);
         return result;
     }
+
+
+    /**
+     * Creates a workspace item info for the legacy shortcut intent
+     */
+    @SuppressWarnings("deprecation")
+    public static WorkspaceItemInfo fromLegacyShortcutIntent(Context context, Intent data) {
+        if (!isValidExtraType(data, Intent.EXTRA_SHORTCUT_INTENT, Intent.class)
+                || !(isValidExtraType(data, Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
+                        Intent.ShortcutIconResource.class))
+                || !(isValidExtraType(data, Intent.EXTRA_SHORTCUT_ICON, Bitmap.class))) {
+
+            Log.e(TAG, "Invalid install shortcut intent");
+            return null;
+        }
+
+        Intent launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+        String label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+        if (launchIntent == null || label == null) {
+            Log.e(TAG, "Invalid install shortcut intent");
+            return null;
+        }
+
+        final WorkspaceItemInfo info = new WorkspaceItemInfo();
+        info.user = Process.myUserHandle();
+
+        BitmapInfo iconInfo = null;
+        try (LauncherIcons li = LauncherIcons.obtain(context)) {
+            Bitmap bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
+            if (bitmap != null) {
+                iconInfo = li.createIconBitmap(bitmap);
+            } else {
+                info.iconResource = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
+                if (info.iconResource != null) {
+                    iconInfo = li.createIconBitmap(info.iconResource);
+                }
+            }
+        }
+
+        if (iconInfo == null) {
+            Log.e(TAG, "Invalid icon by the app");
+            return null;
+        }
+        info.bitmap = iconInfo;
+        info.contentDescription = info.title = Utilities.trim(label);
+        info.intent = launchIntent;
+        return info;
+    }
 }
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index ce4644f..d546013 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -18,9 +18,7 @@
 
 import static com.android.launcher3.Utilities.getPrefs;
 
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageInstaller;
@@ -215,20 +213,8 @@
                 && !mPromiseIconIds.contains(sessionInfo.getSessionId())
                 && new PackageManagerHelper(mAppContext).getApplicationInfo(
                         sessionInfo.getAppPackageName(), getUserHandle(sessionInfo), 0) == null) {
-
-            String packageName = sessionInfo.getAppPackageName();
-            if (mAppContext.getSystemService(LauncherApps.class)
-                    .getActivityList(packageName, getUserHandle(sessionInfo)).isEmpty()) {
-                // Ensure application isn't already installed.
-                Intent data = new Intent();
-                data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent().setComponent(
-                        new ComponentName(packageName, "")).setPackage(packageName));
-                data.putExtra(Intent.EXTRA_SHORTCUT_NAME, sessionInfo.getAppLabel());
-                data.putExtra(Intent.EXTRA_SHORTCUT_ICON, sessionInfo.getAppIcon());
-
-                InstallShortcutReceiver.queueApplication(data, getUserHandle(sessionInfo),
-                        mAppContext);
-            }
+            InstallShortcutReceiver.queueApplication(
+                    sessionInfo.getAppPackageName(), getUserHandle(sessionInfo), mAppContext);
 
             mPromiseIconIds.add(sessionInfo.getSessionId());
             updatePromiseIconPrefs();