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);