Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32948407 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Calculate maximum bitmap cache size when constructing collection items" into main

parents 38fe0959 234e3954
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -523,6 +523,8 @@ public class AppWidgetManager {
    private final IAppWidgetService mService;
    private final DisplayMetrics mDisplayMetrics;

    private int mMaxBitmapMemory = 0;

    private boolean mHasPostedLegacyLists = false;

    /**
@@ -548,6 +550,12 @@ public class AppWidgetManager {
        if (mService == null) {
            return;
        }
        // Allowing some buffer when estimating the maximum bitmap cache size
        try {
            mMaxBitmapMemory = (int) (mService.getMaxBitmapMemory() * 0.9);
        } catch (Exception e) {
            Log.e(TAG, "Error setting the maximum bitmap memory", e);
        }
        BackgroundThread.getExecutor().execute(() -> {
            try {
                mService.notifyProviderInheritance(getInstalledProvidersForPackage(mPackageName,
@@ -576,7 +584,7 @@ public class AppWidgetManager {
            final RemoteViews viewsCopy = new RemoteViews(original);
            Runnable updateWidgetWithTask = () -> {
                try {
                    viewsCopy.collectAllIntents().get();
                    viewsCopy.collectAllIntents(mMaxBitmapMemory).get();
                    action.acceptOrThrow(viewsCopy);
                } catch (Exception e) {
                    Log.e(TAG, failureMsg, e);
+66 −9
Original line number Diff line number Diff line
@@ -140,10 +140,12 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -1236,8 +1238,8 @@ public class RemoteViews implements Parcelable, Filter {
    /**
     * @hide
     */
    public CompletableFuture<Void> collectAllIntents() {
        return mCollectionCache.collectAllIntentsNoComplete(this);
    public CompletableFuture<Void> collectAllIntents(int bitmapSizeLimit) {
        return mCollectionCache.collectAllIntentsNoComplete(this, bitmapSizeLimit);
    }

    private class RemoteCollectionCache {
@@ -1286,7 +1288,7 @@ public class RemoteViews implements Parcelable, Filter {
        }

        public @NonNull CompletableFuture<Void> collectAllIntentsNoComplete(
                @NonNull RemoteViews inViews) {
                @NonNull RemoteViews inViews, int bitmapSizeLimit) {
            SparseArray<Intent> idToIntentMapping = new SparseArray<>();
            // Collect the number of uinque Intent (which is equal to the number of new connections
            // to make) for size allocation and exclude certain collections from being written to
@@ -1314,7 +1316,11 @@ public class RemoteViews implements Parcelable, Filter {
                    ? 0
                    : remainingSize / numOfIntents;

            return connectAllUniqueIntents(individualSize, idToIntentMapping);
            int individualBitmapSizeLimit = (bitmapSizeLimit - getBitmapMemoryUsedByActions())
                    / numOfIntents;

            return connectAllUniqueIntents(individualSize, individualBitmapSizeLimit,
                    idToIntentMapping);
        }

        private void collectAllIntentsInternal(@NonNull RemoteViews inViews,
@@ -1380,13 +1386,13 @@ public class RemoteViews implements Parcelable, Filter {
        }

        private @NonNull CompletableFuture<Void> connectAllUniqueIntents(int individualSize,
                @NonNull SparseArray<Intent> idToIntentMapping) {
                int individualBitmapSize, @NonNull SparseArray<Intent> idToIntentMapping) {
            List<CompletableFuture<Void>> intentFutureList = new ArrayList<>();
            for (int i = 0; i < idToIntentMapping.size(); i++) {
                String currentIntentUri = mIdToUriMapping.get(idToIntentMapping.keyAt(i));
                Intent currentIntent = idToIntentMapping.valueAt(i);
                intentFutureList.add(getItemsFutureFromIntentWithTimeout(currentIntent,
                        individualSize)
                        individualSize, individualBitmapSize)
                        .thenAccept(items -> {
                            items.setHierarchyRootData(getHierarchyRootData());
                            mUriToCollectionMapping.put(currentIntentUri, items);
@@ -1397,7 +1403,7 @@ public class RemoteViews implements Parcelable, Filter {
        }

        private static CompletableFuture<RemoteCollectionItems> getItemsFutureFromIntentWithTimeout(
                Intent intent, int individualSize) {
                Intent intent, int individualSize, int individualBitmapSize) {
            if (intent == null) {
                Log.e(LOG_TAG, "Null intent received when generating adapter future");
                return CompletableFuture.completedFuture(new RemoteCollectionItems
@@ -1415,7 +1421,8 @@ public class RemoteViews implements Parcelable, Filter {
                            RemoteCollectionItems items;
                            try {
                                items = IRemoteViewsFactory.Stub.asInterface(iBinder)
                                        .getRemoteCollectionItems(individualSize);
                                        .getRemoteCollectionItems(individualSize,
                                                individualBitmapSize);
                            } catch (RemoteException re) {
                                items = new RemoteCollectionItems.Builder().build();
                                Log.e(LOG_TAG, "Error getting collection items from the"
@@ -2007,7 +2014,14 @@ public class RemoteViews implements Parcelable, Filter {
        }
    }

    private static class BitmapCache {
    /**
     * @hide
     */
    @NonNull BitmapCache getBitmapCache() {
        return mBitmapCache;
    }

    static class BitmapCache {
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
        ArrayList<Bitmap> mBitmaps;
        SparseIntArray mBitmapHashes;
@@ -2029,6 +2043,11 @@ public class RemoteViews implements Parcelable, Filter {
            }
        }

        BitmapCache(BitmapCache other) {
            mBitmaps = new ArrayList<>(other.mBitmaps);
            mBitmapHashes = other.mBitmapHashes.clone();
        }

        public int getBitmapId(Bitmap b) {
            if (b == null) {
                return -1;
@@ -2071,6 +2090,12 @@ public class RemoteViews implements Parcelable, Filter {
            }
            return mBitmapMemory;
        }

        public void mergeWithCache(BitmapCache other) {
            for (int i = 0; i < other.mBitmaps.size(); i++) {
                getBitmapId(other.mBitmaps.get(i));
            }
        }
    }

    private class BitmapReflectionAction extends Action {
@@ -7343,6 +7368,38 @@ public class RemoteViews implements Parcelable, Filter {
        return true;
    }

    private int getBitmapMemoryUsedByActions() {
        Set<Integer> bitmapIdSet = getBitmapIdsUsedByActions(new HashSet<>());
        int result = 0;
        for (int bitmapId: bitmapIdSet) {
            result += mBitmapCache.getBitmapForId(bitmapId).getAllocationByteCount();
        }

        return result;
    }

    private Set<Integer> getBitmapIdsUsedByActions(@NonNull Set<Integer> intSet) {
        if (hasSizedRemoteViews()) {
            for (RemoteViews views: mSizedRemoteViews) {
                views.getBitmapIdsUsedByActions(intSet);
            }
        } else if (hasLandscapeAndPortraitLayouts()) {
            mLandscape.getBitmapIdsUsedByActions(intSet);
            mPortrait.getBitmapIdsUsedByActions(intSet);
        } else if (mActions != null) {
            for (Action action: mActions) {
                if (action instanceof ViewGroupActionAdd vgaa
                        && vgaa.mNestedViews != null) {
                    vgaa.mNestedViews.getBitmapIdsUsedByActions(intSet);
                } else if (action instanceof BitmapReflectionAction bitmapAction) {
                    intSet.add(bitmapAction.mBitmapId);
                }
            }
        }

        return intSet;
    }

    /** Representation of a fixed list of items to be displayed in a RemoteViews collection. */
    public static final class RemoteCollectionItems implements Parcelable {
        private final long[] mIds;
+15 −3
Original line number Diff line number Diff line
@@ -128,7 +128,8 @@ public abstract class RemoteViewsService extends Service {
        /**
         * @hide
         */
        default RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize) {
        default RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize,
                int capBitmapSize) {
            RemoteViews.RemoteCollectionItems items = new RemoteViews.RemoteCollectionItems
                    .Builder().build();
            Parcel capSizeTestParcel = Parcel.obtain();
@@ -138,6 +139,7 @@ public abstract class RemoteViewsService extends Service {
            try {
                RemoteViews.RemoteCollectionItems.Builder itemsBuilder =
                        new RemoteViews.RemoteCollectionItems.Builder();
                RemoteViews.BitmapCache testBitmapCache = null;
                onDataSetChanged();

                itemsBuilder.setHasStableIds(hasStableIds());
@@ -150,6 +152,15 @@ public abstract class RemoteViewsService extends Service {
                    if (capSizeTestParcel.dataSize() > capSize) {
                        break;
                    }
                    if (testBitmapCache == null) {
                        testBitmapCache = new RemoteViews.BitmapCache(currentView.getBitmapCache());
                    } else {
                        testBitmapCache.mergeWithCache(currentView.getBitmapCache());
                    }
                    if (testBitmapCache.getBitmapMemory() >= capBitmapSize) {
                        break;
                    }

                    itemsBuilder.addItem(currentItemId, currentView);
                }

@@ -266,11 +277,12 @@ public abstract class RemoteViewsService extends Service {
        }

        @Override
        public RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize) {
        public RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize,
                int capBitmapSize) {
            RemoteViews.RemoteCollectionItems items = new RemoteViews.RemoteCollectionItems
                    .Builder().build();
            try {
                items = mFactory.getRemoteCollectionItems(capSize);
                items = mFactory.getRemoteCollectionItems(capSize, capBitmapSize);
            } catch (Exception ex) {
                Thread t = Thread.currentThread();
                Thread.getDefaultUncaughtExceptionHandler().uncaughtException(t, ex);
+1 −0
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ interface IAppWidgetService {
    boolean bindRemoteViewsService(String callingPackage, int appWidgetId, in Intent intent,
            IApplicationThread caller, IBinder token, IServiceConnection connection, long flags);
    void notifyProviderInheritance(in ComponentName[] componentNames);
    int getMaxBitmapMemory();

    @UnsupportedAppUsage
    int[] getAppWidgetIds(in ComponentName providerComponent);
+1 −1
Original line number Diff line number Diff line
@@ -39,6 +39,6 @@ interface IRemoteViewsFactory {
    boolean hasStableIds();
    @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
    boolean isCreated();
    RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize);
    RemoteViews.RemoteCollectionItems getRemoteCollectionItems(int capSize, int capBitmapSize);
}
Loading