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

Commit 52b999f0 authored by Alan Viverette's avatar Alan Viverette
Browse files

Implement APIs for obtaining, caching themed Drawables

When Drawables are inflated during preload (or otherwise without a theme)
they cache their themeable attributes in their constant state as an array
keyed on attribute index. Drawables inflated with a theme will simply
resolve theme attributes as part of normal inflation, and they will not
cache any themeable attributes.

Drawables obtained from Resources are pulled from theme-specific cache
when possible. If an unthemed Drawable exists in the preload cache, a
new constant state will be obtained for the Drawable and the theme will
be applied by resolving the cached themeable attributes and overwriting
their respective constant state properties. If no cached version exists,
a new Drawable is inflated against the desired theme.

Constant states from themed drawables may be cached if the applied theme
is "pure" and was loaded from a style resource without any subsequent
modifications.

This CL does not handle applying themes to several Drawable types, but it
fully supports BitmapDrawable, GradientDrawable, NinePatchDrawable,
ColorDrawable, and TouchFeedbackDrawable.

BUG: 12611005
Change-Id: I4e794fbb62f7a371715f4ebdf946ee5f9a5ad1c9
parent 852472d9
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -8125,6 +8125,7 @@ package android.content.res {
    method public void applyStyle(int, boolean);
    method public void dump(int, java.lang.String, java.lang.String);
    method public android.graphics.drawable.Drawable getDrawable(int) throws android.content.res.Resources.NotFoundException;
    method public android.content.res.Resources getResources();
    method public android.content.res.TypedArray obtainStyledAttributes(int[]);
    method public android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
    method public android.content.res.TypedArray obtainStyledAttributes(android.util.AttributeSet, int[], int, int);
@@ -8155,6 +8156,7 @@ package android.content.res {
    method public java.lang.String getString(int);
    method public java.lang.CharSequence getText(int);
    method public java.lang.CharSequence[] getTextArray(int);
    method public int getType(int);
    method public boolean getValue(int, android.util.TypedValue);
    method public boolean hasValue(int);
    method public int length();
@@ -10492,15 +10494,22 @@ package android.graphics.drawable {
  public abstract class Drawable {
    ctor public Drawable();
    method public void applyTheme(android.content.res.Resources.Theme);
    method public boolean canApplyTheme();
    method public void clearColorFilter();
    method public final void copyBounds(android.graphics.Rect);
    method public final android.graphics.Rect copyBounds();
    method public static android.graphics.drawable.Drawable createFromPath(java.lang.String);
    method public static android.graphics.drawable.Drawable createFromResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, java.lang.String);
    method public static android.graphics.drawable.Drawable createFromResourceStream(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, java.lang.String, android.graphics.BitmapFactory.Options);
    method public static android.graphics.drawable.Drawable createFromResourceStreamThemed(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, java.lang.String, android.content.res.Resources.Theme);
    method public static android.graphics.drawable.Drawable createFromResourceStreamThemed(android.content.res.Resources, android.util.TypedValue, java.io.InputStream, java.lang.String, android.graphics.BitmapFactory.Options, android.content.res.Resources.Theme);
    method public static android.graphics.drawable.Drawable createFromStream(java.io.InputStream, java.lang.String);
    method public static android.graphics.drawable.Drawable createFromStreamThemed(java.io.InputStream, java.lang.String, android.content.res.Resources.Theme);
    method public static android.graphics.drawable.Drawable createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
    method public static android.graphics.drawable.Drawable createFromXmlInner(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
    method public static android.graphics.drawable.Drawable createFromXmlInnerThemed(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
    method public static android.graphics.drawable.Drawable createFromXmlThemed(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
    method public abstract void draw(android.graphics.Canvas);
    method public int getAlpha();
    method public final android.graphics.Rect getBounds();
@@ -10520,6 +10529,7 @@ package android.graphics.drawable {
    method public int[] getState();
    method public android.graphics.Region getTransparentRegion();
    method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
    method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
    method public void invalidateSelf();
    method public boolean isAutoMirrored();
    method public boolean isStateful();
@@ -10555,9 +10565,11 @@ package android.graphics.drawable {
  public static abstract class Drawable.ConstantState {
    ctor public Drawable.ConstantState();
    method public boolean canApplyTheme();
    method public abstract int getChangingConfigurations();
    method public abstract android.graphics.drawable.Drawable newDrawable();
    method public android.graphics.drawable.Drawable newDrawable(android.content.res.Resources);
    method public android.graphics.drawable.Drawable newDrawable(android.content.res.Resources, android.content.res.Resources.Theme);
  }
  public class DrawableContainer extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+3 −0
Original line number Diff line number Diff line
@@ -722,6 +722,9 @@ public final class AssetManager {
    /*package*/ native static final boolean applyStyle(long theme,
            int defStyleAttr, int defStyleRes, long xmlParser,
            int[] inAttrs, int[] outValues, int[] outIndices);
    /*package*/ native static final boolean resolveAttrs(long theme,
            int defStyleAttr, int defStyleRes, int[] inValues,
            int[] inAttrs, int[] outValues, int[] outIndices);
    /*package*/ native final boolean retrieveAttributes(
            long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
    /*package*/ native final int getArraySize(int resource);
+311 −188

File changed.

Preview size limit exceeded, changes collapsed.

+118 −7
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pools.SynchronizedPool;
import android.util.TypedValue;

import com.android.internal.util.XmlUtils;
@@ -36,16 +37,40 @@ import java.util.Arrays;
 * the positions of the attributes given to obtainStyledAttributes.
 */
public class TypedArray {
    private final Resources mResources;
    private final DisplayMetrics mMetrics;
    private final AssetManager mAssets;
    private static final SynchronizedPool<TypedArray> mPool = new SynchronizedPool<TypedArray>(5);

    static TypedArray obtain(Resources res, int len) {
        final TypedArray attrs = mPool.acquire();
        if (attrs != null) {
            attrs.mLength = len;
            attrs.mResources = res;
            attrs.mMetrics = res.getDisplayMetrics();
            attrs.mAssets = res.getAssets();

            final int fullLen = len * AssetManager.STYLE_NUM_ENTRIES;
            if (attrs.mData.length >= fullLen) {
                return attrs;
            }

            attrs.mData = new int[fullLen];
            attrs.mIndices = new int[1 + len];
            return attrs;
        }

        return new TypedArray(res,
                new int[len*AssetManager.STYLE_NUM_ENTRIES],
                new int[1+len], len);
    }

    private Resources mResources;
    private DisplayMetrics mMetrics;
    private AssetManager mAssets;
    /*package*/ XmlBlock.Parser mXml;
    /*package*/ int[] mRsrcs;
    /*package*/ Resources.Theme mTheme;
    /*package*/ int[] mData;
    /*package*/ int[] mIndices;
    /*package*/ int mLength;
    /*package*/ TypedValue mValue = new TypedValue();
    /*package*/ Resources.Theme mTheme;

    /**
     * Return the number of values in this array.
@@ -579,6 +604,25 @@ public class TypedArray {
        return defValue;
    }

    /**
     * Retrieve the theme attribute resource identifier for the attribute at
     * <var>index</var>.
     *
     * @param index Index of attribute to retrieve.
     * @param defValue Value to return if the attribute is not defined or not a
     *            resource.
     * @return Theme attribute resource identifier, or defValue if not defined.
     * @hide
     */
    public int getThemeAttributeId(int index, int defValue) {
        index *= AssetManager.STYLE_NUM_ENTRIES;
        final int[] data = mData;
        if (data[index + AssetManager.STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
            return data[index + AssetManager.STYLE_DATA];
        }
        return defValue;
    }

    /**
     * Retrieve the Drawable for the attribute at <var>index</var>.  This
     * gets the resource ID of the selected attribute, and uses
@@ -646,6 +690,38 @@ public class TypedArray {
        return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
    }

    /**
     * Determines whether this TypedArray contains an attribute of the specified
     * type.
     *
     * @param type Type of data, e.g. {@link TypedValue#TYPE_ATTRIBUTE}
     * @return True if the TypedArray contains an attribute of the specified
     *         type.
     * @hide
     */
    public boolean hasType(int type) {
        final int[] data = mData;
        final int N = getIndexCount();
        for (int i = 0; i < N; i++) {
            final int index = getIndex(i) * AssetManager.STYLE_NUM_ENTRIES;
            if (data[index + AssetManager.STYLE_TYPE] == type) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns the type of attribute at the specified index.
     *
     * @param index Index of attribute whose type to retrieve.
     * @return Attribute type.
     */
    public int getType(int index) {
        index *= AssetManager.STYLE_NUM_ENTRIES;
        return mData[index + AssetManager.STYLE_TYPE];
    }

    /**
     * Determines whether there is an attribute at <var>index</var>.
     * 
@@ -690,11 +766,46 @@ public class TypedArray {
     * Give back a previously retrieved array, for later re-use.
     */
    public void recycle() {
        mResources.recycleCachedStyledAttributes(this);
        mResources = null;
        mMetrics = null;
        mAssets = null;

        // These may have been set by the client.
        mXml = null;
        mRsrcs = null;
        mTheme = null;

        synchronized (mPool) {
            mPool.release(this);
        }
    }

    /**
     * Extracts theme attributes from a typed array for later resolution using
     * {@link Theme#resolveAttributes(int[], int[], int, int)}.
     *
     * @param array An array to populate with theme attributes. If the array is
     *            null or not large enough, a new array will be returned.
     * @return an array of length {@link #getIndexCount()} populated with theme
     *         attributes, or null if there are no theme attributes in the
     *         typed array
     * @hide
     */
    public int[] extractThemeAttrs() {
        int[] attrs = null;

        final int N = getIndexCount();
        for (int i = 0; i < N; i++) {
            final int index = getIndex(i);
            final int attrId = getThemeAttributeId(index, 0);
            if (attrId != 0) {
                if (attrs == null) {
                    attrs = new int[N];
                }
                attrs[i] = attrId;
            }
        }

        return attrs;
    }

    private boolean getValueAt(int index, TypedValue outValue) {
+1 −1
Original line number Diff line number Diff line
@@ -664,7 +664,7 @@ public class ImageView extends View {
                InputStream stream = null;
                try {
                    stream = mContext.getContentResolver().openInputStream(mUri);
                    d = Drawable.createFromStream(stream, null);
                    d = Drawable.createFromStreamThemed(stream, null, mContext.getTheme());
                } catch (Exception e) {
                    Log.w("ImageView", "Unable to open content: " + mUri, e);
                } finally {
Loading