Loading core/java/android/animation/AnimatorInflater.java +2 −2 Original line number Diff line number Diff line Loading @@ -108,7 +108,7 @@ public class AnimatorInflater { float pathErrorScale) throws NotFoundException { final ConfigurationBoundResourceCache<Animator> animatorCache = resources .getAnimatorCache(); Animator animator = animatorCache.get(id, theme); Animator animator = animatorCache.getInstance(id, theme); if (animator != null) { if (DBG_ANIMATOR_INFLATER) { Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id)); Loading Loading @@ -157,7 +157,7 @@ public class AnimatorInflater { final ConfigurationBoundResourceCache<StateListAnimator> cache = resources .getStateListAnimatorCache(); final Theme theme = context.getTheme(); StateListAnimator animator = cache.get(id, theme); StateListAnimator animator = cache.getInstance(id, theme); if (animator != null) { return animator; } Loading core/java/android/app/ActivityThread.java +8 −2 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDebug; import android.database.sqlite.SQLiteDebug.DbStats; Loading Loading @@ -4186,9 +4187,14 @@ public final class ActivityThread { if (!mConfiguration.isOtherSeqNewer(config) && compat == null) { return; } configDiff = mConfiguration.diff(config); mConfiguration.updateFrom(config); configDiff = mConfiguration.updateFrom(config); config = applyCompatConfiguration(mCurDefaultDisplayDpi); final Theme systemTheme = getSystemContext().getTheme(); if ((systemTheme.getChangingConfigurations() & configDiff) != 0) { systemTheme.rebase(); } } ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config); Loading core/java/android/content/res/AssetManager.java +1 −0 Original line number Diff line number Diff line Loading @@ -785,6 +785,7 @@ public final class AssetManager implements AutoCloseable { private native final void deleteTheme(long theme); /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force); /*package*/ native static final void copyTheme(long dest, long source); /*package*/ native static final void clearTheme(long theme); /*package*/ native static final int loadThemeAttributeValue(long theme, int ident, TypedValue outValue, boolean resolve); Loading core/java/android/content/res/ConfigurationBoundResourceCache.java +33 −113 Original line number Diff line number Diff line Loading @@ -13,126 +13,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.res; import android.util.ArrayMap; import android.util.LongSparseArray; import java.lang.ref.WeakReference; package android.content.res; /** * A Cache class which can be used to cache resource objects that are easy to clone but more * expensive to inflate. * @hide * * @hide For internal use only. */ public class ConfigurationBoundResourceCache<T> { private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState<T>>>> mCache = new ArrayMap<String, LongSparseArray<WeakReference<ConstantState<T>>>>(); final Resources mResources; public class ConfigurationBoundResourceCache<T> extends ThemedResourceCache<ConstantState<T>> { private final Resources mResources; /** * Creates a Resource cache for the given Resources instance. * Creates a cache for the given Resources instance. * * @param resources The Resource which can be used when creating new instances. * @param resources the resources to use when creating new instances */ public ConfigurationBoundResourceCache(Resources resources) { mResources = resources; } /** * Adds a new item to the cache. * * @param key A custom key that uniquely identifies the resource. * @param theme The Theme instance where this resource was loaded. * @param constantState The constant state that can create new instances of the resource. * If the resource is cached, creates and returns a new instance of it. * * @param key a key that uniquely identifies the drawable resource * @param theme the theme where the resource will be used * @return a new instance of the resource, or {@code null} if not in * the cache */ public void put(long key, Resources.Theme theme, ConstantState<T> constantState) { if (constantState == null) { return; } final String themeKey = theme == null ? "" : theme.getKey(); LongSparseArray<WeakReference<ConstantState<T>>> themedCache; synchronized (this) { themedCache = mCache.get(themeKey); if (themedCache == null) { themedCache = new LongSparseArray<WeakReference<ConstantState<T>>>(1); mCache.put(themeKey, themedCache); } themedCache.put(key, new WeakReference<ConstantState<T>>(constantState)); } } /** * If the resource is cached, creates a new instance of it and returns. * * @param key The long key which can be used to uniquely identify the resource. * @param theme The The Theme instance where we want to load this resource. * * @return If this resources was loaded before, returns a new instance of it. Otherwise, returns * null. */ public T get(long key, Resources.Theme theme) { final String themeKey = theme != null ? theme.getKey() : ""; final LongSparseArray<WeakReference<ConstantState<T>>> themedCache; final WeakReference<ConstantState<T>> wr; synchronized (this) { themedCache = mCache.get(themeKey); if (themedCache == null) { return null; } wr = themedCache.get(key); } if (wr == null) { return null; } final ConstantState entry = wr.get(); public T getInstance(long key, Resources.Theme theme) { final ConstantState<T> entry = get(key, theme); if (entry != null) { return (T) entry.newInstance(mResources, theme); } else { // our entry has been purged synchronized (this) { // there is a potential race condition here where this entry may be put in // another thread. But we prefer it to minimize lock duration themedCache.delete(key); } } return null; return entry.newInstance(mResources, theme); } /** * Users of ConfigurationBoundResourceCache must call this method whenever a configuration * change happens. On this callback, the cache invalidates all resources that are not valid * anymore. * * @param configChanges The configuration changes */ public void onConfigurationChange(final int configChanges) { synchronized (this) { final int size = mCache.size(); for (int i = size - 1; i >= 0; i--) { final LongSparseArray<WeakReference<ConstantState<T>>> themeCache = mCache.valueAt(i); onConfigurationChangeInt(themeCache, configChanges); if (themeCache.size() == 0) { mCache.removeAt(i); } } } return null; } private void onConfigurationChangeInt( final LongSparseArray<WeakReference<ConstantState<T>>> themeCache, final int configChanges) { final int size = themeCache.size(); for (int i = size - 1; i >= 0; i--) { final WeakReference<ConstantState<T>> wr = themeCache.valueAt(i); final ConstantState<T> constantState = wr.get(); if (constantState == null || Configuration.needNewResources( configChanges, constantState.getChangingConfigurations())) { themeCache.removeAt(i); } @Override public boolean shouldInvalidateEntry(ConstantState<T> entry, int configChanges) { return Configuration.needNewResources(configChanges, entry.getChangingConfigurations()); } } } core/java/android/content/res/DrawableCache.java 0 → 100644 +57 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.res; import android.graphics.drawable.Drawable; /** * Class which can be used to cache Drawable resources against a theme. */ class DrawableCache extends ThemedResourceCache<Drawable.ConstantState> { private final Resources mResources; /** * Creates a cache for the given Resources instance. * * @param resources the resources to use when creating new instances */ public DrawableCache(Resources resources) { mResources = resources; } /** * If the resource is cached, creates and returns a new instance of it. * * @param key a key that uniquely identifies the drawable resource * @param theme the theme where the resource will be used * @return a new instance of the resource, or {@code null} if not in * the cache */ public Drawable getInstance(long key, Resources.Theme theme) { final Drawable.ConstantState entry = get(key, theme); if (entry != null) { return entry.newDrawable(mResources, theme); } return null; } @Override public boolean shouldInvalidateEntry(Drawable.ConstantState entry, int configChanges) { return false; } } Loading
core/java/android/animation/AnimatorInflater.java +2 −2 Original line number Diff line number Diff line Loading @@ -108,7 +108,7 @@ public class AnimatorInflater { float pathErrorScale) throws NotFoundException { final ConfigurationBoundResourceCache<Animator> animatorCache = resources .getAnimatorCache(); Animator animator = animatorCache.get(id, theme); Animator animator = animatorCache.getInstance(id, theme); if (animator != null) { if (DBG_ANIMATOR_INFLATER) { Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id)); Loading Loading @@ -157,7 +157,7 @@ public class AnimatorInflater { final ConfigurationBoundResourceCache<StateListAnimator> cache = resources .getStateListAnimatorCache(); final Theme theme = context.getTheme(); StateListAnimator animator = cache.get(id, theme); StateListAnimator animator = cache.getInstance(id, theme); if (animator != null) { return animator; } Loading
core/java/android/app/ActivityThread.java +8 −2 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.content.res.AssetManager; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDebug; import android.database.sqlite.SQLiteDebug.DbStats; Loading Loading @@ -4186,9 +4187,14 @@ public final class ActivityThread { if (!mConfiguration.isOtherSeqNewer(config) && compat == null) { return; } configDiff = mConfiguration.diff(config); mConfiguration.updateFrom(config); configDiff = mConfiguration.updateFrom(config); config = applyCompatConfiguration(mCurDefaultDisplayDpi); final Theme systemTheme = getSystemContext().getTheme(); if ((systemTheme.getChangingConfigurations() & configDiff) != 0) { systemTheme.rebase(); } } ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config); Loading
core/java/android/content/res/AssetManager.java +1 −0 Original line number Diff line number Diff line Loading @@ -785,6 +785,7 @@ public final class AssetManager implements AutoCloseable { private native final void deleteTheme(long theme); /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force); /*package*/ native static final void copyTheme(long dest, long source); /*package*/ native static final void clearTheme(long theme); /*package*/ native static final int loadThemeAttributeValue(long theme, int ident, TypedValue outValue, boolean resolve); Loading
core/java/android/content/res/ConfigurationBoundResourceCache.java +33 −113 Original line number Diff line number Diff line Loading @@ -13,126 +13,46 @@ * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.res; import android.util.ArrayMap; import android.util.LongSparseArray; import java.lang.ref.WeakReference; package android.content.res; /** * A Cache class which can be used to cache resource objects that are easy to clone but more * expensive to inflate. * @hide * * @hide For internal use only. */ public class ConfigurationBoundResourceCache<T> { private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState<T>>>> mCache = new ArrayMap<String, LongSparseArray<WeakReference<ConstantState<T>>>>(); final Resources mResources; public class ConfigurationBoundResourceCache<T> extends ThemedResourceCache<ConstantState<T>> { private final Resources mResources; /** * Creates a Resource cache for the given Resources instance. * Creates a cache for the given Resources instance. * * @param resources The Resource which can be used when creating new instances. * @param resources the resources to use when creating new instances */ public ConfigurationBoundResourceCache(Resources resources) { mResources = resources; } /** * Adds a new item to the cache. * * @param key A custom key that uniquely identifies the resource. * @param theme The Theme instance where this resource was loaded. * @param constantState The constant state that can create new instances of the resource. * If the resource is cached, creates and returns a new instance of it. * * @param key a key that uniquely identifies the drawable resource * @param theme the theme where the resource will be used * @return a new instance of the resource, or {@code null} if not in * the cache */ public void put(long key, Resources.Theme theme, ConstantState<T> constantState) { if (constantState == null) { return; } final String themeKey = theme == null ? "" : theme.getKey(); LongSparseArray<WeakReference<ConstantState<T>>> themedCache; synchronized (this) { themedCache = mCache.get(themeKey); if (themedCache == null) { themedCache = new LongSparseArray<WeakReference<ConstantState<T>>>(1); mCache.put(themeKey, themedCache); } themedCache.put(key, new WeakReference<ConstantState<T>>(constantState)); } } /** * If the resource is cached, creates a new instance of it and returns. * * @param key The long key which can be used to uniquely identify the resource. * @param theme The The Theme instance where we want to load this resource. * * @return If this resources was loaded before, returns a new instance of it. Otherwise, returns * null. */ public T get(long key, Resources.Theme theme) { final String themeKey = theme != null ? theme.getKey() : ""; final LongSparseArray<WeakReference<ConstantState<T>>> themedCache; final WeakReference<ConstantState<T>> wr; synchronized (this) { themedCache = mCache.get(themeKey); if (themedCache == null) { return null; } wr = themedCache.get(key); } if (wr == null) { return null; } final ConstantState entry = wr.get(); public T getInstance(long key, Resources.Theme theme) { final ConstantState<T> entry = get(key, theme); if (entry != null) { return (T) entry.newInstance(mResources, theme); } else { // our entry has been purged synchronized (this) { // there is a potential race condition here where this entry may be put in // another thread. But we prefer it to minimize lock duration themedCache.delete(key); } } return null; return entry.newInstance(mResources, theme); } /** * Users of ConfigurationBoundResourceCache must call this method whenever a configuration * change happens. On this callback, the cache invalidates all resources that are not valid * anymore. * * @param configChanges The configuration changes */ public void onConfigurationChange(final int configChanges) { synchronized (this) { final int size = mCache.size(); for (int i = size - 1; i >= 0; i--) { final LongSparseArray<WeakReference<ConstantState<T>>> themeCache = mCache.valueAt(i); onConfigurationChangeInt(themeCache, configChanges); if (themeCache.size() == 0) { mCache.removeAt(i); } } } return null; } private void onConfigurationChangeInt( final LongSparseArray<WeakReference<ConstantState<T>>> themeCache, final int configChanges) { final int size = themeCache.size(); for (int i = size - 1; i >= 0; i--) { final WeakReference<ConstantState<T>> wr = themeCache.valueAt(i); final ConstantState<T> constantState = wr.get(); if (constantState == null || Configuration.needNewResources( configChanges, constantState.getChangingConfigurations())) { themeCache.removeAt(i); } @Override public boolean shouldInvalidateEntry(ConstantState<T> entry, int configChanges) { return Configuration.needNewResources(configChanges, entry.getChangingConfigurations()); } } }
core/java/android/content/res/DrawableCache.java 0 → 100644 +57 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.content.res; import android.graphics.drawable.Drawable; /** * Class which can be used to cache Drawable resources against a theme. */ class DrawableCache extends ThemedResourceCache<Drawable.ConstantState> { private final Resources mResources; /** * Creates a cache for the given Resources instance. * * @param resources the resources to use when creating new instances */ public DrawableCache(Resources resources) { mResources = resources; } /** * If the resource is cached, creates and returns a new instance of it. * * @param key a key that uniquely identifies the drawable resource * @param theme the theme where the resource will be used * @return a new instance of the resource, or {@code null} if not in * the cache */ public Drawable getInstance(long key, Resources.Theme theme) { final Drawable.ConstantState entry = get(key, theme); if (entry != null) { return entry.newDrawable(mResources, theme); } return null; } @Override public boolean shouldInvalidateEntry(Drawable.ConstantState entry, int configChanges) { return false; } }