Revert^2 "Writing ApplicationInfoCache instead of multiple ApplicationInfos for nested RemoteViews"

This reverts commit 532a0a90b30a8045efdf1b0a84249a2352482607.

Reason for revert: Fixing original bug

Bug: 477278752
(cherry picked from commit 2137c24fb2d16addba712a6844a275dfd0349351)
Cherrypick-From: https://googleplex-android-review.googlesource.com/q/commit:890b9f6d59596bf68d2a38bdd62ba744cec68a96
Merged-In: I9caf4aedc7d2ba1697e06a5e46cd605bac07cad0
Change-Id: I9caf4aedc7d2ba1697e06a5e46cd605bac07cad0
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index c26d9f4..0b23c63 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -355,6 +355,11 @@
     public ApplicationInfo mApplication;
 
     /**
+     * Id referencing the ApplicationInfo in ApplicationInfoCache that hosts the remote views.
+     */
+    private int mApplicationId = -1;
+
+    /**
      * The resource ID of the layout file. (Added to the parcel)
      */
     @UnsupportedAppUsage
@@ -1050,39 +1055,64 @@
      * {@link ApplicationInfo} instance is used throughout the RemoteViews.
      */
     private static class ApplicationInfoCache {
-        private final Map<Pair<String, Integer>, ApplicationInfo> mPackageUserToApplicationInfo;
+        private final List<ApplicationInfo> mCachedApplicationInfos;
 
         ApplicationInfoCache() {
-            mPackageUserToApplicationInfo = new ArrayMap<>();
+            mCachedApplicationInfos = new ArrayList<>();
+        }
+
+        ApplicationInfoCache(Parcel parcel) {
+            mCachedApplicationInfos = parcel.createTypedArrayList(ApplicationInfo.CREATOR);
         }
 
         /**
-         * Adds the {@link ApplicationInfo} to the cache if it's not present. Returns either the
-         * provided {@code applicationInfo} or a previously added value with the same package name
-         * and uid.
+         * Adds the {@link ApplicationInfo} to the cache if it's not present. Returns an int Id
+         * which can be used to retrieve the {@link ApplicationInfo} from the cache.
          */
-        @Nullable
-        ApplicationInfo getOrPut(@Nullable ApplicationInfo applicationInfo) {
-            Pair<String, Integer> key = getPackageUserKey(applicationInfo);
-            if (key == null) return null;
-            return mPackageUserToApplicationInfo.computeIfAbsent(key, ignored -> applicationInfo);
+        int getOrPut(@Nullable ApplicationInfo applicationInfo) {
+            if (applicationInfo == null) return -1;
+            int id = findId(applicationInfo);
+            if (id != -1) return id;
+            mCachedApplicationInfos.add(applicationInfo);
+            return mCachedApplicationInfos.size() - 1;
+        }
+
+        int findId(@NonNull ApplicationInfo applicationInfo) {
+            if (applicationInfo == null) return -1;
+            for (int i = 0; i < mCachedApplicationInfos.size(); i++) {
+                ApplicationInfo cachedApplicationInfo = mCachedApplicationInfos.get(i);
+                if (Objects.equals(cachedApplicationInfo.packageName, applicationInfo.packageName)
+                        && cachedApplicationInfo.uid == applicationInfo.uid) {
+                    return i;
+                }
+            }
+            return -1;
         }
 
         /** Puts the {@link ApplicationInfo} in the cache, replacing any previously stored value. */
-        void put(@Nullable ApplicationInfo applicationInfo) {
-            Pair<String, Integer> key = getPackageUserKey(applicationInfo);
-            if (key == null) return;
-            mPackageUserToApplicationInfo.put(key, applicationInfo);
+        int updateAndGetId(@Nullable ApplicationInfo applicationInfo) {
+            if (applicationInfo == null) return -1;
+            int id = findId(applicationInfo);
+            if (id != -1) {
+                mCachedApplicationInfos.set(id, applicationInfo);
+                return id;
+            } else {
+                mCachedApplicationInfos.add(applicationInfo);
+                return mCachedApplicationInfos.size() - 1;
+            }
         }
 
         /**
          * Returns the currently stored {@link ApplicationInfo} from the cache matching
          * {@code  applicationInfo}, or null if there wasn't any.
          */
-        @Nullable ApplicationInfo get(@Nullable ApplicationInfo applicationInfo) {
-            Pair<String, Integer> key = getPackageUserKey(applicationInfo);
-            if (key == null) return null;
-            return mPackageUserToApplicationInfo.get(key);
+        @Nullable ApplicationInfo get(int id) {
+            return (id < 0 || id >= mCachedApplicationInfos.size())
+                    ? null : mCachedApplicationInfos.get(id);
+        }
+
+        void writeToParcel(Parcel dest, int flags) {
+            dest.writeTypedList(mCachedApplicationInfos, flags);
         }
     }
 
@@ -4018,7 +4048,7 @@
     protected RemoteViews(ApplicationInfo application, @LayoutRes int layoutId) {
         mApplication = application;
         mLayoutId = layoutId;
-        mApplicationInfoCache.put(application);
+        mApplicationId = mApplicationInfoCache.updateAndGetId(application);
     }
 
     private boolean hasMultipleLayouts() {
@@ -4068,6 +4098,7 @@
                     "Both RemoteViews must share the same package and user");
         }
         mApplication = portrait.mApplication;
+        mApplicationId = mApplicationInfoCache.updateAndGetId(mApplication);
         mLayoutId = portrait.mLayoutId;
         mViewId = portrait.mViewId;
         mLightBackgroundLayoutId = portrait.mLightBackgroundLayoutId;
@@ -4121,6 +4152,7 @@
 
         RemoteViews smallestView = findSmallestRemoteView();
         mApplication = smallestView.mApplication;
+        mApplicationId = mApplicationInfoCache.updateAndGetId(mApplication);
         mLayoutId = smallestView.mLayoutId;
         mViewId = smallestView.mViewId;
         mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId;
@@ -4206,6 +4238,7 @@
             mIsRoot = false;
         }
         mApplication = src.mApplication;
+        mApplicationId = mApplicationInfoCache.updateAndGetId(mApplication);
         mLayoutId = src.mLayoutId;
         mLightBackgroundLayoutId = src.mLightBackgroundLayoutId;
         mApplyFlags = src.mApplyFlags;
@@ -4282,13 +4315,15 @@
             mBitmapCache = new BitmapCache(parcel);
             // Store the class cookies such that they are available when we clone this RemoteView.
             mClassCookies = parcel.copyClassCookies();
+            mApplicationInfoCache = new ApplicationInfoCache(parcel);
             mCollectionCache = new RemoteCollectionCache(parcel);
         } else {
             configureAsChild(rootData);
         }
 
         if (mode == MODE_NORMAL) {
-            mApplication = parcel.readTypedObject(ApplicationInfo.CREATOR);
+            mApplicationId = parcel.readInt();
+            mApplication = mApplicationInfoCache.get(mApplicationId);
             mIdealSize = parcel.readInt() == 0 ? null : SizeF.CREATOR.createFromParcel(parcel);
             mLayoutId = parcel.readInt();
             mViewId = parcel.readInt();
@@ -4310,6 +4345,7 @@
             initializeSizedRemoteViews(remoteViews.iterator());
             RemoteViews smallestView = findSmallestRemoteView();
             mApplication = smallestView.mApplication;
+            mApplicationId = mApplicationInfoCache.updateAndGetId(mApplication);
             mLayoutId = smallestView.mLayoutId;
             mViewId = smallestView.mViewId;
             mLightBackgroundLayoutId = smallestView.mLightBackgroundLayoutId;
@@ -4319,6 +4355,7 @@
             mPortrait =
                     new RemoteViews(parcel, getHierarchyRootData(), mLandscape.mApplication, depth);
             mApplication = mPortrait.mApplication;
+            mApplicationId = mApplicationInfoCache.updateAndGetId(mApplication);
             mLayoutId = mPortrait.mLayoutId;
             mViewId = mPortrait.mViewId;
             mLightBackgroundLayoutId = mPortrait.mLightBackgroundLayoutId;
@@ -4462,7 +4499,8 @@
         // Before propagating down the tree, replace our application from the root application info
         // cache, to ensure the same instance is present throughout the hierarchy to allow for
         // squashing.
-        mApplication = mApplicationInfoCache.getOrPut(mApplication);
+        mApplicationId = mApplicationInfoCache.getOrPut(mApplication);
+        mApplication = mApplicationInfoCache.get(mApplicationId);
 
         HierarchyRootData rootData = getHierarchyRootData();
         if (hasSizedRemoteViews()) {
@@ -4489,7 +4527,8 @@
         if (!mIsRoot) return;
         mBitmapCache = new BitmapCache();
         mApplicationInfoCache = new ApplicationInfoCache();
-        mApplication = mApplicationInfoCache.getOrPut(mApplication);
+        mApplicationId = mApplicationInfoCache.getOrPut(mApplication);
+        mApplication = mApplicationInfoCache.get(mApplicationId);
         configureDescendantsAsChildren();
     }
 
@@ -6532,7 +6571,7 @@
 
     /** @hide */
     public void updateAppInfo(@NonNull ApplicationInfo info) {
-        ApplicationInfo existing = mApplicationInfoCache.get(info);
+        ApplicationInfo existing = mApplicationInfoCache.get(mApplicationInfoCache.findId(info));
         if (existing != null && !existing.sourceDir.equals(info.sourceDir)) {
             // Overlay paths are generated against a particular version of an application.
             // The overlays paths of a newly upgraded application are incompatible with the
@@ -6542,7 +6581,7 @@
 
         // If we can update to the new AppInfo, put it in the cache and propagate the change
         // throughout the hierarchy.
-        mApplicationInfoCache.put(info);
+        mApplicationInfoCache.updateAndGetId(info);
         configureDescendantsAsChildren();
     }
 
@@ -6809,9 +6848,10 @@
             // is shared by all children.
             if (mIsRoot) {
                 mBitmapCache.writeBitmapsToParcel(dest, flags);
+                mApplicationInfoCache.writeToParcel(dest, flags);
                 mCollectionCache.writeToParcel(dest, flags, intentsToIgnore);
             }
-            dest.writeTypedObject(mApplication, flags);
+            dest.writeInt(mApplicationId);
             if (mIsRoot || mIdealSize == null) {
                 dest.writeInt(0);
             } else {
@@ -6826,6 +6866,7 @@
             dest.writeInt(MODE_HAS_SIZED_REMOTEVIEWS);
             if (mIsRoot) {
                 mBitmapCache.writeBitmapsToParcel(dest, flags);
+                mApplicationInfoCache.writeToParcel(dest, flags);
                 mCollectionCache.writeToParcel(dest, flags, intentsToIgnore);
             }
             dest.writeInt(mSizedRemoteViews.size());
@@ -6838,6 +6879,7 @@
             // is shared by all children.
             if (mIsRoot) {
                 mBitmapCache.writeBitmapsToParcel(dest, flags);
+                mApplicationInfoCache.writeToParcel(dest, flags);
                 mCollectionCache.writeToParcel(dest, flags, intentsToIgnore);
             }
             mLandscape.writeToParcel(dest, flags);
@@ -7811,12 +7853,6 @@
         return viewId;
     }
 
-    @Nullable
-    private static Pair<String, Integer> getPackageUserKey(@Nullable ApplicationInfo info) {
-        if (info == null || info.packageName ==  null) return null;
-        return Pair.create(info.packageName, info.uid);
-    }
-
     private HierarchyRootData getHierarchyRootData() {
         return new HierarchyRootData(mBitmapCache, mCollectionCache,
                 mApplicationInfoCache, mClassCookies);