19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.content.res;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.util.ArrayUtils;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParser;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseArray;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.StateSet;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Xml;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.lang.ref.WeakReference;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Lets you map {@link android.view.View} state sets to colors.
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link android.content.res.ColorStateList}s are created from XML resource files defined in the
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * "color" subdirectory directory of an application's resource directory.  The XML file contains
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a single "selector" element with a number of "item" elements inside.  For example:
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <pre>
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * &lt;selector xmlns:android="http://schemas.android.com/apk/res/android"&gt;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *   &lt;item android:state_focused="true" android:color="@color/testcolor1"/&gt;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *   &lt;item android:state_pressed="true" android:state_enabled="false" android:color="@color/testcolor2" /&gt;
4779dc8ccddd846816d4e0e55405ad0dbefa5b0ff6Romain Guy *   &lt;item android:state_enabled="false" android:color="@color/testcolor3" /&gt;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *   &lt;item android:color="@color/testcolor5"/&gt;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * &lt;/selector&gt;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </pre>
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This defines a set of state spec / color pairs where each state spec specifies a set of
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * states that a view must either be in or not be in and the color specifies the color associated
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with that spec.  The list of state specs will be processed in order of the items in the XML file.
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * An item with no state spec is considered to match any set of states and is generally useful as
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * a final item to be used as a default.  Note that if you have such an item before any other items
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in the list then any subsequent items will end up being ignored.
588dd87ad9440bc63bc312b06f292adcd2642b1c41Scott Main * <p>For more information, see the guide to <a
598dd87ad9440bc63bc312b06f292adcd2642b1c41Scott Main * href="{@docRoot}guide/topics/resources/color-list-resource.html">Color State
608dd87ad9440bc63bc312b06f292adcd2642b1c41Scott Main * List Resource</a>.</p>
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class ColorStateList implements Parcelable {
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int[][] mStateSpecs; // must be parallel to mColors
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int[] mColors;      // must be parallel to mStateSpecs
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mDefaultColor = 0xffff0000;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int[][] EMPTY = new int[][] { new int[0] };
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final SparseArray<WeakReference<ColorStateList>> sCache =
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            new SparseArray<WeakReference<ColorStateList>>();
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ColorStateList() { }
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a ColorStateList that returns the specified mapping from
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * states to colors.
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ColorStateList(int[][] states, int[] colors) {
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStateSpecs = states;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mColors = colors;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (states.length > 0) {
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDefaultColor = colors[0];
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < states.length; i++) {
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (states[i].length == 0) {
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mDefaultColor = colors[i];
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates or retrieves a ColorStateList that always returns a single color.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static ColorStateList valueOf(int color) {
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // TODO: should we collect these eventually?
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (sCache) {
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            WeakReference<ColorStateList> ref = sCache.get(color);
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ColorStateList csl = ref != null ? ref.get() : null;
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (csl != null) {
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return csl;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            csl = new ColorStateList(EMPTY, new int[] { color });
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sCache.put(color, new WeakReference<ColorStateList>(csl));
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return csl;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Create a ColorStateList from an XML document, given a set of {@link Resources}.
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static ColorStateList createFromXml(Resources r, XmlPullParser parser)
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws XmlPullParserException, IOException {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AttributeSet attrs = Xml.asAttributeSet(parser);
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int type;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while ((type=parser.next()) != XmlPullParser.START_TAG
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                   && type != XmlPullParser.END_DOCUMENT) {
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (type != XmlPullParser.START_TAG) {
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new XmlPullParserException("No start tag found");
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return createFromXmlInner(r, parser, attrs);
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Create from inside an XML document.  Called on a parser positioned at
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * a tag in an XML document, tries to create a ColorStateList from that tag.
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns null if the tag is not a valid ColorStateList.
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static ColorStateList createFromXmlInner(Resources r, XmlPullParser parser,
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            AttributeSet attrs) throws XmlPullParserException, IOException {
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ColorStateList colorStateList;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final String name = parser.getName();
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (name.equals("selector")) {
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            colorStateList = new ColorStateList();
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new XmlPullParserException(
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                parser.getPositionDescription() + ": invalid drawable tag " + name);
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        colorStateList.inflate(r, parser, attrs);
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return colorStateList;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a new ColorStateList that has the same states and
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * colors as this one but where each color has the specified alpha value
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (0-255).
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ColorStateList withAlpha(int alpha) {
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] colors = new int[mColors.length];
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = colors.length;
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < len; i++) {
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            colors[i] = (mColors[i] & 0xFFFFFF) | (alpha << 24);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return new ColorStateList(mStateSpecs, colors);
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Fill in this object based on the contents of an XML "selector" element.
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        throws XmlPullParserException, IOException {
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int type;
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int innerDepth = parser.getDepth()+1;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int depth;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int listAllocated = 20;
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int listSize = 0;
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[] colorList = new int[listAllocated];
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int[][] stateSpecList = new int[listAllocated][];
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               && ((depth=parser.getDepth()) >= innerDepth
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                   || type != XmlPullParser.END_TAG)) {
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (type != XmlPullParser.START_TAG) {
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (depth > innerDepth || !parser.getName().equals("item")) {
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int colorRes = 0;
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int color = 0xffff0000;
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean haveColor = false;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int i;
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int j = 0;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int numAttrs = attrs.getAttributeCount();
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] stateSpec = new int[numAttrs];
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i = 0; i < numAttrs; i++) {
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int stateResId = attrs.getAttributeNameResource(i);
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (stateResId == 0) break;
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (stateResId == com.android.internal.R.attr.color) {
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    colorRes = attrs.getAttributeResourceValue(i, 0);
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (colorRes == 0) {
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        color = attrs.getAttributeIntValue(i, color);
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        haveColor = true;
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    stateSpec[j++] = attrs.getAttributeBooleanValue(i, false)
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                  ? stateResId
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                  : -stateResId;
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            stateSpec = StateSet.trimStateSet(stateSpec, j);
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (colorRes != 0) {
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                color = r.getColor(colorRes);
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (!haveColor) {
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new XmlPullParserException(
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        parser.getPositionDescription()
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + ": <item> tag requires a 'android:color' attribute.");
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (listSize == 0 || stateSpec.length == 0) {
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDefaultColor = color;
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (listSize + 1 >= listAllocated) {
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                listAllocated = ArrayUtils.idealIntArraySize(listSize + 1);
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int[] ncolor = new int[listAllocated];
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.arraycopy(colorList, 0, ncolor, 0, listSize);
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int[][] nstate = new int[listAllocated][];
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.arraycopy(stateSpecList, 0, nstate, 0, listSize);
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                colorList = ncolor;
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                stateSpecList = nstate;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            colorList[listSize] = color;
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            stateSpecList[listSize] = stateSpec;
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            listSize++;
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mColors = new int[listSize];
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStateSpecs = new int[listSize][];
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        System.arraycopy(colorList, 0, mColors, 0, listSize);
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        System.arraycopy(stateSpecList, 0, mStateSpecs, 0, listSize);
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStateful() {
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateSpecs.length > 1;
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the color associated with the given set of {@link android.view.View} states.
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param stateSet an array of {@link android.view.View} states
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param defaultColor the color to return if there's not state spec in this
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link ColorStateList} that matches the stateSet.
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the color associated with that set of states in this {@link ColorStateList}.
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getColorForState(int[] stateSet, int defaultColor) {
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int setLength = mStateSpecs.length;
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < setLength; i++) {
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] stateSpec = mStateSpecs[i];
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (StateSet.stateSetMatches(stateSpec, stateSet)) {
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mColors[i];
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return defaultColor;
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Return the default color in this {@link ColorStateList}.
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the default color in this {@link ColorStateList}.
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getDefaultColor() {
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mDefaultColor;
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String toString() {
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return "ColorStateList{" +
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               "mStateSpecs=" + Arrays.deepToString(mStateSpecs) +
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               "mColors=" + Arrays.toString(mColors) +
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               "mDefaultColor=" + mDefaultColor + '}';
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int describeContents() {
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return 0;
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void writeToParcel(Parcel dest, int flags) {
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = mStateSpecs.length;
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dest.writeInt(N);
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i=0; i<N; i++) {
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.writeIntArray(mStateSpecs[i]);
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        dest.writeIntArray(mColors);
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final Parcelable.Creator<ColorStateList> CREATOR =
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            new Parcelable.Creator<ColorStateList>() {
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ColorStateList[] newArray(int size) {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new ColorStateList[size];
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ColorStateList createFromParcel(Parcel source) {
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int N = source.readInt();
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[][] stateSpecs = new int[N][];
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=0; i<N; i++) {
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                stateSpecs[i] = source.createIntArray();
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] colors = source.createIntArray();
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new ColorStateList(stateSpecs, colors);
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
329