Version-2: Prioritize the session-provided icon & label for archived apps during unarchival in the iconCache.

* Also ensures that apps are sorted based on their actual name, so that
  they don't jump around when "Pending.." switches to "Downloading.."
* In case of faillure during unarchival, icons shown are reverted to that of PM supplied ones.

New UI: http://recall/-/gMbThhDGagWFqnJTbQCqSz/fPuzxUuU7cGXCNdygMkXAB

Test: atest CacheDataUpdatedTaskTest.java and locally verified.
Bug: 319495216
Flag: ACONFIG com.android.launcher3.enable_support_for_archiving TRUNKFOOD
Change-Id: I6410482706af900e273fdc6f7cf0b0692442364c
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index d124746..99fca62 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -441,17 +441,35 @@
             @Override
             public void execute(@NonNull final LauncherAppState app,
                     @NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
+                IconCache iconCache = app.getIconCache();
                 final IntSet removedIds = new IntSet();
+                HashSet<WorkspaceItemInfo> archivedItemsToCacheRefresh = new HashSet<>();
+                HashSet<String> archivedPackagesToCacheRefresh = new HashSet<>();
                 synchronized (dataModel) {
                     for (ItemInfo info : dataModel.itemsIdMap) {
                         if (info instanceof WorkspaceItemInfo
                                 && ((WorkspaceItemInfo) info).hasPromiseIconUi()
                                 && user.equals(info.user)
-                                && info.getIntent() != null
-                                && TextUtils.equals(packageName, info.getIntent().getPackage())) {
-                            removedIds.add(info.id);
+                                && info.getIntent() != null) {
+                            if (TextUtils.equals(packageName, info.getIntent().getPackage())) {
+                                removedIds.add(info.id);
+                            }
+                            if (((WorkspaceItemInfo) info).isArchived()) {
+                                WorkspaceItemInfo workspaceItem = (WorkspaceItemInfo) info;
+                                // Remove package cache icon for archived app in case of a session
+                                // failure.
+                                mApp.getIconCache().removeIconsForPkg(packageName, user);
+                                // Refresh icons on the workspace for archived apps.
+                                iconCache.getTitleAndIcon(workspaceItem,
+                                        workspaceItem.usingLowResIcon());
+                                archivedPackagesToCacheRefresh.add(packageName);
+                                archivedItemsToCacheRefresh.add(workspaceItem);
+                            }
                         }
                     }
+                    if (!archivedPackagesToCacheRefresh.isEmpty()) {
+                        apps.updateIconsAndLabels(archivedPackagesToCacheRefresh, user);
+                    }
                 }
 
                 if (!removedIds.isEmpty()) {
@@ -459,6 +477,10 @@
                             ItemInfoMatcher.ofItemIds(removedIds),
                             "removed because install session failed");
                 }
+                if (!archivedItemsToCacheRefresh.isEmpty()) {
+                    bindUpdatedWorkspaceItems(archivedItemsToCacheRefresh.stream().toList());
+                    bindApplicationsIfNeeded();
+                }
             }
         });
     }
diff --git a/src/com/android/launcher3/allapps/AppInfoComparator.java b/src/com/android/launcher3/allapps/AppInfoComparator.java
index 311a40e..a0867db 100644
--- a/src/com/android/launcher3/allapps/AppInfoComparator.java
+++ b/src/com/android/launcher3/allapps/AppInfoComparator.java
@@ -43,9 +43,7 @@
     @Override
     public int compare(AppInfo a, AppInfo b) {
         // Order by the title in the current locale
-        int result = mLabelComparator.compare(
-                a.title == null ? "" : a.title.toString(),
-                b.title == null ? "" : b.title.toString());
+        int result = mLabelComparator.compare(getSortingTitle(a), getSortingTitle(b));
         if (result != 0) {
             return result;
         }
@@ -64,4 +62,14 @@
             return aUserSerial.compareTo(bUserSerial);
         }
     }
+
+    private String getSortingTitle(AppInfo info) {
+        if (info.appTitle != null) {
+            return info.appTitle.toString();
+        }
+        if (info.title != null) {
+            return info.title.toString();
+        }
+        return "";
+    }
 }
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 2f7f51e..d8fa90a 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -219,7 +219,19 @@
         CacheEntry entry = cacheLocked(application.componentName,
                 application.user, () -> null, mLauncherActivityInfoCachingLogic,
                 false, application.usingLowResIcon());
-        if (entry.bitmap != null && !isDefaultIcon(entry.bitmap, application.user)) {
+        if (entry.bitmap == null || isDefaultIcon(entry.bitmap, application.user)) {
+            return;
+        }
+
+        boolean preferPackageIcon = application.isArchived();
+        if (preferPackageIcon) {
+            String packageName = application.getTargetPackage();
+            CacheEntry packageEntry =
+                    cacheLocked(new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
+                            application.user, () -> null, mLauncherActivityInfoCachingLogic,
+                            false, application.usingLowResIcon());
+            applyPackageEntry(packageEntry, application, entry);
+        } else {
             applyCacheEntry(entry, application);
         }
     }
@@ -227,10 +239,14 @@
     /**
      * Fill in {@param info} with the icon and label for {@param activityInfo}
      */
+    @SuppressWarnings("NewApi")
     public synchronized void getTitleAndIcon(ItemInfoWithIcon info,
             LauncherActivityInfo activityInfo, boolean useLowResIcon) {
+        boolean isAppArchived = Utilities.enableSupportForArchiving() && activityInfo != null
+                && activityInfo.getActivityInfo().isArchived;
         // If we already have activity info, no need to use package icon
-        getTitleAndIcon(info, () -> activityInfo, false, useLowResIcon);
+        getTitleAndIcon(info, () -> activityInfo, isAppArchived, useLowResIcon,
+                isAppArchived);
     }
 
     /**
@@ -309,7 +325,7 @@
         } else {
             Intent intent = info.getIntent();
             getTitleAndIcon(info, () -> mLauncherApps.resolveActivity(intent, info.user),
-                    true, useLowResIcon);
+                    true, useLowResIcon, info.isArchived());
         }
     }
 
@@ -334,6 +350,28 @@
     }
 
     /**
+     * Fill in {@param mWorkspaceItemInfo} with the icon and label for {@param info}
+     */
+    public synchronized void getTitleAndIcon(
+            @NonNull ItemInfoWithIcon infoInOut,
+            @NonNull Supplier<LauncherActivityInfo> activityInfoProvider,
+            boolean usePkgIcon, boolean useLowResIcon, boolean preferPackageEntry) {
+        CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), infoInOut.user,
+                activityInfoProvider, mLauncherActivityInfoCachingLogic, usePkgIcon,
+                useLowResIcon);
+        if (preferPackageEntry) {
+            String packageName = infoInOut.getTargetPackage();
+            CacheEntry packageEntry = cacheLocked(
+                    new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
+                    infoInOut.user, activityInfoProvider, mLauncherActivityInfoCachingLogic,
+                    usePkgIcon, useLowResIcon);
+            applyPackageEntry(packageEntry, infoInOut, entry);
+        } else {
+            applyCacheEntry(entry, infoInOut);
+        }
+    }
+
+    /**
      * Creates an sql cursor for a query of a set of ItemInfoWithIcon icons and titles.
      *
      * @param iconRequestInfos List of IconRequestInfos representing titles and icons to query.
@@ -551,6 +589,19 @@
         }
     }
 
+    protected void applyPackageEntry(@NonNull final CacheEntry packageEntry,
+            @NonNull final ItemInfoWithIcon info, @NonNull final CacheEntry fallbackEntry) {
+        info.title = Utilities.trim(packageEntry.title);
+        info.appTitle = Utilities.trim(fallbackEntry.title);
+        info.contentDescription = packageEntry.contentDescription;
+        info.bitmap = packageEntry.bitmap;
+        if (packageEntry.bitmap == null) {
+            // TODO: entry.bitmap can never be null, so this should not happen at all.
+            Log.wtf(TAG, "Cannot find bitmap from the cache, default icon was loaded.");
+            info.bitmap = getDefaultIcon(info.user);
+        }
+    }
+
     public Drawable getFullResIcon(LauncherActivityInfo info) {
         return mIconProvider.getIcon(info, mIconDpi);
     }
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 86393a0..55849c2 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -160,6 +160,13 @@
     public CharSequence title;
 
     /**
+     * Optionally set: The appTitle might e.g. be different if {@code title} is used to
+     * display progress (e.g. Downloading..).
+     */
+    @Nullable
+    public CharSequence appTitle;
+
+    /**
      * Content description of the item.
      */
     @Nullable