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

Commit 47289587 authored by Jeremy Meyer's avatar Jeremy Meyer Committed by Automerger Merge Worker
Browse files

Merge "Track generations in resource caches" into udc-dev am: a2f3279d

parents cbe91b60 a2f3279d
Loading
Loading
Loading
Loading
+13 −10
Original line number Diff line number Diff line
@@ -111,19 +111,20 @@ public class AnimatorInflater {
            float pathErrorScale) throws NotFoundException {
        final ConfigurationBoundResourceCache<Animator> animatorCache = resources
                .getAnimatorCache();
        Animator animator = animatorCache.getInstance(id, resources, theme);
        if (animator != null) {
        ConfigurationBoundResourceCache.Entry<Animator> animatorEntry =
                animatorCache.getInstance(id, resources, theme);
        if (animatorEntry.hasValue()) {
            if (DBG_ANIMATOR_INFLATER) {
                Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
            }
            return animator;
            return animatorEntry.getValue();
        } else if (DBG_ANIMATOR_INFLATER) {
            Log.d(TAG, "cache miss for animator " + resources.getResourceName(id));
        }
        XmlResourceParser parser = null;
        try {
            parser = resources.getAnimation(id);
            animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
            Animator animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale);
            if (animator != null) {
                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
                final ConstantState<Animator> constantState = animator.createConstantState();
@@ -131,7 +132,7 @@ public class AnimatorInflater {
                    if (DBG_ANIMATOR_INFLATER) {
                        Log.d(TAG, "caching animator for res " + resources.getResourceName(id));
                    }
                    animatorCache.put(id, theme, constantState);
                    animatorCache.put(id, theme, constantState, animatorEntry.getGeneration());
                    // create a new animator so that cached version is never used by the user
                    animator = constantState.newInstance(resources, theme);
                }
@@ -160,20 +161,22 @@ public class AnimatorInflater {
        final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
                .getStateListAnimatorCache();
        final Theme theme = context.getTheme();
        StateListAnimator animator = cache.getInstance(id, resources, theme);
        if (animator != null) {
            return animator;
        ConfigurationBoundResourceCache.Entry<StateListAnimator> animatorEntry =
                cache.getInstance(id, resources, theme);
        if (animatorEntry.hasValue()) {
            return animatorEntry.getValue();
        }
        XmlResourceParser parser = null;
        try {
            parser = resources.getAnimation(id);
            animator = createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
            StateListAnimator animator =
                    createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
            if (animator != null) {
                animator.appendChangingConfigurations(getChangingConfigs(resources, id));
                final ConstantState<StateListAnimator> constantState = animator
                        .createConstantState();
                if (constantState != null) {
                    cache.put(id, theme, constantState);
                    cache.put(id, theme, constantState, animatorEntry.getGeneration());
                    // return a clone so that the animator in constant state is never used.
                    animator = constantState.newInstance(resources, theme);
                }
+6 −6
Original line number Diff line number Diff line
@@ -37,16 +37,16 @@ public class ConfigurationBoundResourceCache<T> extends ThemedResourceCache<Cons
     * @param key a key that uniquely identifies the drawable resource
     * @param resources a Resources object from which to create new instances.
     * @param theme the theme where the resource will be used
     * @return a new instance of the resource, or {@code null} if not in
     * @return an Entry wrapping a new instance of the resource, or {@code null} if not in
     *         the cache
     */
    public T getInstance(long key, Resources resources, Resources.Theme theme) {
        final ConstantState<T> entry = get(key, theme);
        if (entry != null) {
            return entry.newInstance(resources, theme);
    public Entry<T> getInstance(long key, Resources resources, Resources.Theme theme) {
        final Entry<ConstantState<T>> e = get(key, theme);
        if (e.hasValue()) {
            return new Entry<>(e.getValue().newInstance(resources, theme), e.getGeneration());
        }

        return null;
        return new Entry<>(null, e.getGeneration());
    }

    @Override
+21 −3
Original line number Diff line number Diff line
@@ -40,14 +40,32 @@ class DrawableCache extends ThemedResourceCache<Drawable.ConstantState> {
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public Drawable getInstance(long key, Resources resources, Resources.Theme theme) {
        final Drawable.ConstantState entry = get(key, theme);
        if (entry != null) {
            return entry.newDrawable(resources, theme);
        final Entry<Drawable.ConstantState> entry = get(key, theme);
        if (entry.getValue() != null) {
            return entry.getValue().newDrawable(resources, theme);
        }

        return null;
    }

    /**
     * If the resource is cached, creates and returns a new instance of it.
     *
     * @param key a key that uniquely identifies the drawable resource
     * @param resources a Resources object from which to create new instances.
     * @param theme the theme where the resource will be used
     * @return an Entry wrapping a a new instance of the resource, or {@code null} if not in
     *         the cache
     */
    public Entry<Drawable> getDrawable(long key, Resources resources, Resources.Theme theme) {
        final Entry<Drawable.ConstantState> e = get(key, theme);
        if (e.hasValue()) {
            return new Entry<>(e.getValue().newDrawable(resources, theme), e.getGeneration());
        }

        return new Entry<>(null, e.getGeneration());
    }

    @Override
    public boolean shouldInvalidateEntry(Drawable.ConstantState entry, int configChanges) {
        return Configuration.needNewResources(configChanges, entry.getChangingConfigurations());
+21 −11
Original line number Diff line number Diff line
@@ -650,15 +650,21 @@ public class ResourcesImpl {
                key = (((long) value.assetCookie) << 32) | value.data;
            }

            int cacheGeneration;
            // First, check whether we have a cached version of this drawable
            // that was inflated against the specified theme. Skip the cache if
            // we're currently preloading or we're not using the cache.
            if (!mPreloading && useCache) {
                final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
                if (cachedDrawable != null) {
                    cachedDrawable.setChangingConfigurations(value.changingConfigurations);
                    return cachedDrawable;
                }
                final ThemedResourceCache.Entry<Drawable> cachedDrawable =
                        caches.getDrawable(key, wrapper, theme);
                if (cachedDrawable.hasValue()) {
                    cachedDrawable.getValue().setChangingConfigurations(
                            value.changingConfigurations);
                    return cachedDrawable.getValue();
                }
                cacheGeneration = cachedDrawable.getGeneration();
            } else {
                cacheGeneration = ThemedResourceCache.UNDEFINED_GENERATION;
            }

            // Next, check preloaded drawables. Preloaded drawables may contain
@@ -702,7 +708,8 @@ public class ResourcesImpl {
            if (dr != null) {
                dr.setChangingConfigurations(value.changingConfigurations);
                if (useCache) {
                    cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
                    cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr,
                            cacheGeneration);
                    if (needsNewDrawableAfterCache) {
                        Drawable.ConstantState state = dr.getConstantState();
                        if (state != null) {
@@ -733,7 +740,7 @@ public class ResourcesImpl {
    }

    private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
            Resources.Theme theme, boolean usesTheme, long key, Drawable dr) {
            Resources.Theme theme, boolean usesTheme, long key, Drawable dr, int cacheGeneration) {
        final Drawable.ConstantState cs = dr.getConstantState();
        if (cs == null) {
            return;
@@ -761,7 +768,7 @@ public class ResourcesImpl {
            }
        } else {
            synchronized (mAccessLock) {
                caches.put(key, theme, cs, usesTheme);
                caches.put(key, theme, cs, cacheGeneration, usesTheme);
            }
        }
    }
@@ -1002,14 +1009,16 @@ public class ResourcesImpl {
            TypedValue value, int id) {
        final long key = (((long) value.assetCookie) << 32) | value.data;
        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
        ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
        if (complexColor != null) {
            return complexColor;
        ThemedResourceCache.Entry<ComplexColor> complexColorEntry =
                cache.getInstance(key, wrapper, theme);
        if (complexColorEntry.hasValue()) {
            return complexColorEntry.getValue();
        }

        final android.content.res.ConstantState<ComplexColor> factory =
                sPreloadedComplexColors.get(key);

        ComplexColor complexColor = null;
        if (factory != null) {
            complexColor = factory.newInstance(wrapper, theme);
        }
@@ -1026,7 +1035,8 @@ public class ResourcesImpl {
                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
                }
            } else {
                cache.put(key, theme, complexColor.getConstantState());
                cache.put(key, theme, complexColor.getConstantState(),
                        complexColorEntry.getGeneration());
            }
        }
        return complexColor;
+39 −8
Original line number Diff line number Diff line
@@ -33,11 +33,37 @@ import java.lang.ref.WeakReference;
 * @param <T> type of data to cache
 */
abstract class ThemedResourceCache<T> {
    public static final int UNDEFINED_GENERATION = -1;
    @UnsupportedAppUsage
    private ArrayMap<ThemeKey, LongSparseArray<WeakReference<T>>> mThemedEntries;
    private LongSparseArray<WeakReference<T>> mUnthemedEntries;
    private LongSparseArray<WeakReference<T>> mNullThemedEntries;

    private int mGeneration;

    public static class Entry<S> {
        private S mValue;
        private int mGeneration;


        public S getValue() {
            return mValue;
        }

        public boolean hasValue() {
            return mValue != null;
        }

        public int getGeneration() {
            return mGeneration;
        }

        Entry(S value, int generation) {
            this.mValue = value;
            this.mGeneration = generation;
        }
    }

    /**
     * Adds a new theme-dependent entry to the cache.
     *
@@ -45,9 +71,10 @@ abstract class ThemedResourceCache<T> {
     * @param theme the theme against which this entry was inflated, or
     *              {@code null} if the entry has no theme applied
     * @param entry the entry to cache
     * @param generation The generation of the cache to compare against before storing
     */
    public void put(long key, @Nullable Theme theme, @NonNull T entry) {
        put(key, theme, entry, true);
    public void put(long key, @Nullable Theme theme, @NonNull T entry, int generation) {
        put(key, theme, entry, generation, true);
    }

    /**
@@ -57,10 +84,12 @@ abstract class ThemedResourceCache<T> {
     * @param theme the theme against which this entry was inflated, or
     *              {@code null} if the entry has no theme applied
     * @param entry the entry to cache
     * @param generation The generation of the cache to compare against before storing
     * @param usesTheme {@code true} if the entry is affected theme changes,
     *                  {@code false} otherwise
     */
    public void put(long key, @Nullable Theme theme, @NonNull T entry, boolean usesTheme) {
    public void put(long key, @Nullable Theme theme, @NonNull T entry, int generation,
            boolean usesTheme) {
        if (entry == null) {
            return;
        }
@@ -72,7 +101,8 @@ abstract class ThemedResourceCache<T> {
            } else {
                entries = getThemedLocked(theme, true);
            }
            if (entries != null) {
            if (entries != null
                    && ((generation == mGeneration) || (generation == UNDEFINED_GENERATION)))  {
                entries.put(key, new WeakReference<>(entry));
            }
        }
@@ -86,7 +116,7 @@ abstract class ThemedResourceCache<T> {
     * @return a cached entry, or {@code null} if not in the cache
     */
    @Nullable
    public T get(long key, @Nullable Theme theme) {
    public Entry get(long key, @Nullable Theme theme) {
        // The themed (includes null-themed) and unthemed caches are mutually
        // exclusive, so we'll give priority to whichever one we think we'll
        // hit first. Since most of the framework drawables are themed, that's
@@ -96,7 +126,7 @@ abstract class ThemedResourceCache<T> {
            if (themedEntries != null) {
                final WeakReference<T> themedEntry = themedEntries.get(key);
                if (themedEntry != null) {
                    return themedEntry.get();
                    return new Entry(themedEntry.get(), mGeneration);
                }
            }

@@ -104,12 +134,12 @@ abstract class ThemedResourceCache<T> {
            if (unthemedEntries != null) {
                final WeakReference<T> unthemedEntry = unthemedEntries.get(key);
                if (unthemedEntry != null) {
                    return unthemedEntry.get();
                    return new Entry(unthemedEntry.get(), mGeneration);
                }
            }
        }

        return null;
        return new Entry(null, mGeneration);
    }

    /**
@@ -121,6 +151,7 @@ abstract class ThemedResourceCache<T> {
    @UnsupportedAppUsage
    public void onConfigurationChange(@Config int configChanges) {
        prune(configChanges);
        mGeneration++;
    }

    /**
Loading