OSDN Git Service

Support theme attributes in StateListDrawable <item> element
authorAlan Viverette <alanv@google.com>
Thu, 6 Nov 2014 21:50:22 +0000 (13:50 -0800)
committerAlan Viverette <alanv@google.com>
Thu, 6 Nov 2014 21:50:22 +0000 (13:50 -0800)
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

core/res/res/values/attrs.xml
graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
graphics/java/android/graphics/drawable/StateListDrawable.java

index 67ba27d..e63fc55 100644 (file)
         <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
index 5a3a617..84555c6 100644 (file)
@@ -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;
-            }
-        }
+        // 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();
 
-        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) {
             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);
+        // 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 Drawable dr;
-        if (drawableRes != 0) {
-            dr = r.getDrawable(drawableRes, theme);
-        } else {
+        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) {
             }
index 963943b..e7a8233 100644 (file)
@@ -173,29 +173,19 @@ public class StateListDrawable extends DrawableContainer {
                 continue;
             }
 
-            int drawableRes = 0;
-
-            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 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.StateListDrawableItem);
+            Drawable dr = a.getDrawable(R.styleable.StateListDrawableItem_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) {
                 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;
     }