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

Commit d6570d11 authored by Alan Viverette's avatar Alan Viverette
Browse files

Support theme attributes in StateListDrawable <item> element

Also adds support for specifying drawable as a color since getDrawable()
automatically wraps colors to ColorDrawable. Does not currently allow
themed item elements to be used in Zygote preload, but we can add that
at some point in the future.

BUG: 18208662
Change-Id: I4c9721ffd100da4b9db7743a46c914828b943dae
parent d69dacb0
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -4804,6 +4804,13 @@
        <attr name="autoMirrored"/>
    </declare-styleable>

    <!-- Represents a single state inside a StateListDrawable. -->
    <declare-styleable name="StateListDrawableItem">
        <!-- Reference to a drawable resource to use for the state. If not
             given, the drawable must be defined by the first child tag. -->
        <attr name="drawable" />
    </declare-styleable>

    <!-- Transition used to animate between states with keyframe IDs. -->
    <declare-styleable name="AnimatedStateListDrawableItem">
        <!-- Reference to a drawable resource to use for the frame.  If not
+31 −57
Original line number Diff line number Diff line
@@ -429,43 +429,31 @@ public class AnimatedStateListDrawable extends StateListDrawable {
    private int parseTransition(@NonNull Resources r, @NonNull XmlPullParser parser,
            @NonNull AttributeSet attrs, @Nullable Theme theme)
            throws XmlPullParserException, IOException {
        int drawableRes = 0;
        int fromId = 0;
        int toId = 0;
        boolean reversible = false;

        final int numAttrs = attrs.getAttributeCount();
        for (int i = 0; i < numAttrs; i++) {
            final int stateResId = attrs.getAttributeNameResource(i);
            switch (stateResId) {
                case 0:
                    break;
                case R.attr.fromId:
                    fromId = attrs.getAttributeResourceValue(i, 0);
                    break;
                case R.attr.toId:
                    toId = attrs.getAttributeResourceValue(i, 0);
                    break;
                case R.attr.drawable:
                    drawableRes = attrs.getAttributeResourceValue(i, 0);
                    break;
                case R.attr.reversible:
                    reversible = attrs.getAttributeBooleanValue(i, false);
                    break;
            }
        }

        final Drawable dr;
        if (drawableRes != 0) {
            dr = r.getDrawable(drawableRes, theme);
        } else {
        // This allows state list drawable item elements to be themed at
        // inflation time but does NOT make them work for Zygote preload.
        final TypedArray a = obtainAttributes(r, theme, attrs,
                R.styleable.AnimatedStateListDrawableTransition);
        final int fromId = a.getResourceId(
                R.styleable.AnimatedStateListDrawableTransition_fromId, 0);
        final int toId = a.getResourceId(
                R.styleable.AnimatedStateListDrawableTransition_toId, 0);
        final boolean reversible = a.getBoolean(
                R.styleable.AnimatedStateListDrawableTransition_reversible, false);
        Drawable dr = a.getDrawable(
                R.styleable.AnimatedStateListDrawableTransition_drawable);
        a.recycle();

        // Loading child elements modifies the state of the AttributeSet's
        // underlying parser, so it needs to happen after obtaining
        // attributes and extracting states.
        if (dr == null) {
            int type;
            while ((type = parser.next()) == XmlPullParser.TEXT) {
            }
            if (type != XmlPullParser.START_TAG) {
                throw new XmlPullParserException(
                        parser.getPositionDescription()
                                + ": <item> tag requires a 'drawable' attribute or "
                                + ": <transition> tag requires a 'drawable' attribute or "
                                + "child tag defining a drawable");
            }
            dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
@@ -477,34 +465,20 @@ public class AnimatedStateListDrawable extends StateListDrawable {
    private int parseItem(@NonNull Resources r, @NonNull XmlPullParser parser,
            @NonNull AttributeSet attrs, @Nullable Theme theme)
            throws XmlPullParserException, IOException {
        int drawableRes = 0;
        int keyframeId = 0;

        int j = 0;
        final int numAttrs = attrs.getAttributeCount();
        int[] states = new int[numAttrs];
        for (int i = 0; i < numAttrs; i++) {
            final int stateResId = attrs.getAttributeNameResource(i);
            switch (stateResId) {
                case 0:
                    break;
                case R.attr.id:
                    keyframeId = attrs.getAttributeResourceValue(i, 0);
                    break;
                case R.attr.drawable:
                    drawableRes = attrs.getAttributeResourceValue(i, 0);
                    break;
                default:
                    final boolean hasState = attrs.getAttributeBooleanValue(i, false);
                    states[j++] = hasState ? stateResId : -stateResId;
            }
        }
        states = StateSet.trimStateSet(states, j);

        final Drawable dr;
        if (drawableRes != 0) {
            dr = r.getDrawable(drawableRes, theme);
        } else {
        // This allows state list drawable item elements to be themed at
        // inflation time but does NOT make them work for Zygote preload.
        final TypedArray a = obtainAttributes(r, theme, attrs,
                R.styleable.AnimatedStateListDrawableItem);
        final int keyframeId = a.getResourceId(R.styleable.AnimatedStateListDrawableItem_id, 0);
        Drawable dr = a.getDrawable(R.styleable.AnimatedStateListDrawableItem_drawable);
        a.recycle();

        final int[] states = extractStateSet(attrs);

        // Loading child elements modifies the state of the AttributeSet's
        // underlying parser, so it needs to happen after obtaining
        // attributes and extracting states.
        if (dr == null) {
            int type;
            while ((type = parser.next()) == XmlPullParser.TEXT) {
            }
+42 −23
Original line number Diff line number Diff line
@@ -173,29 +173,19 @@ public class StateListDrawable extends DrawableContainer {
                continue;
            }

            int drawableRes = 0;
            // This allows state list drawable item elements to be themed at
            // inflation time but does NOT make them work for Zygote preload.
            final TypedArray a = obtainAttributes(r, theme, attrs,
                    R.styleable.StateListDrawableItem);
            Drawable dr = a.getDrawable(R.styleable.StateListDrawableItem_drawable);
            a.recycle();

            int i;
            int j = 0;
            final int numAttrs = attrs.getAttributeCount();
            int[] states = new int[numAttrs];
            for (i = 0; i < numAttrs; i++) {
                final int stateResId = attrs.getAttributeNameResource(i);
                if (stateResId == 0) break;
                if (stateResId == R.attr.drawable) {
                    drawableRes = attrs.getAttributeResourceValue(i, 0);
                } else {
                    states[j++] = attrs.getAttributeBooleanValue(i, false)
                            ? stateResId
                            : -stateResId;
                }
            }
            states = StateSet.trimStateSet(states, j);
            final int[] states = extractStateSet(attrs);

            final Drawable dr;
            if (drawableRes != 0) {
                dr = r.getDrawable(drawableRes, theme);
            } else {
            // Loading child elements modifies the state of the AttributeSet's
            // underlying parser, so it needs to happen after obtaining
            // attributes and extracting states.
            if (dr == null) {
                while ((type = parser.next()) == XmlPullParser.TEXT) {
                }
                if (type != XmlPullParser.START_TAG) {
@@ -211,6 +201,35 @@ public class StateListDrawable extends DrawableContainer {
        }
    }

    /**
     * Extracts state_ attributes from an attribute set.
     *
     * @param attrs The attribute set.
     * @return An array of state_ attributes.
     */
    int[] extractStateSet(AttributeSet attrs) {
        int j = 0;
        final int numAttrs = attrs.getAttributeCount();
        int[] states = new int[numAttrs];
        for (int i = 0; i < numAttrs; i++) {
            final int stateResId = attrs.getAttributeNameResource(i);
            switch (stateResId) {
                case 0:
                    break;
                case R.attr.drawable:
                case R.attr.id:
                    // Ignore attributes from StateListDrawableItem and
                    // AnimatedStateListDrawableItem.
                    continue;
                default:
                    states[j++] = attrs.getAttributeBooleanValue(i, false)
                            ? stateResId : -stateResId;
            }
        }
        states = StateSet.trimStateSet(states, j);
        return states;
    }

    StateListState getStateListState() {
        return mStateListState;
    }