StateListDrawable.java revision 0af4b8b0c8b038bca9b4f60eb81f71e186f471ce
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 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.graphics.drawable;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParser;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
23079e23575024e103358c982152afb7a720ae1a8aDianne Hackbornimport java.util.Arrays;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.StateSet;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Lets you assign a number of graphic images to a single Drawable and swap out the visible item by a string
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ID value.
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p/>
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>It can be defined in an XML file with the <code>&lt;selector></code> element.
35dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * Each state Drawable is defined in a nested <code>&lt;item></code> element. For more
36dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * information, see the guide to <a
37dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#StateListDrawable_visible
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#StateListDrawable_variablePadding
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#StateListDrawable_constantSize
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_focused
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_window_focused
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_enabled
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_checkable
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_checked
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_selected
48079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn * @attr ref android.R.styleable#DrawableStates_state_activated
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_active
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_single
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_first
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_middle
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_last
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_pressed
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class StateListDrawable extends DrawableContainer {
57079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn    private static final boolean DEBUG = false;
58079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn    private static final String TAG = "StateListDrawable";
59079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn
60211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed    /**
61211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * To be proper, we should have a getter for dither (and alpha, etc.)
62211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * so that proxy classes like this can save/restore their delegates'
63211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * values, but we don't have getters. Since we do have setters
64211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * (e.g. setDither), which this proxy forwards on, we have to have some
65211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * default/initial setting.
66211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     *
67211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * The initial setting for dither is now true, since it almost always seems
68211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * to improve the quality at negligible cost.
69211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     */
70211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed    private static final boolean DEFAULT_DITHER = true;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final StateListState mStateListState;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mMutated;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public StateListDrawable() {
75c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        this(null, null);
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add a new image/string ID to the set of images.
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param stateSet - An array of resource Ids to associate with the image.
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                 Switch to this image by calling setState().
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param drawable -The image to show.
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addState(int[] stateSet, Drawable drawable) {
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (drawable != null) {
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateListState.addStateSet(stateSet, drawable);
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // in case the new state matches our current state...
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            onStateChange(getState());
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStateful() {
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean onStateChange(int[] stateSet) {
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int idx = mStateListState.indexOfStateSet(stateSet);
101079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn        if (DEBUG) android.util.Log.i(TAG, "onStateChange " + this + " states "
102079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                + Arrays.toString(stateSet) + " found " + idx);
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (idx < 0) {
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD);
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selectDrawable(idx)) {
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.onStateChange(stateSet);
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void inflate(Resources r, XmlPullParser parser,
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            AttributeSet attrs)
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws XmlPullParserException, IOException {
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TypedArray a = r.obtainAttributes(attrs,
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.StateListDrawable);
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.inflateWithAttributes(r, parser, a,
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.StateListDrawable_visible);
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStateListState.setVariablePadding(a.getBoolean(
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.StateListDrawable_variablePadding, false));
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStateListState.setConstantSize(a.getBoolean(
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                com.android.internal.R.styleable.StateListDrawable_constantSize, false));
127079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn        mStateListState.setEnterFadeDuration(a.getInt(
128079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                com.android.internal.R.styleable.StateListDrawable_enterFadeDuration, 0));
129079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn        mStateListState.setExitFadeDuration(a.getInt(
130079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                com.android.internal.R.styleable.StateListDrawable_exitFadeDuration, 0));
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
132211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed        setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither,
133211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed                               DEFAULT_DITHER));
1346afa16feb32d44c4977b3eb6007246a99f22fdbfJeff Sharkey
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a.recycle();
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int type;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int innerDepth = parser.getDepth() + 1;
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int depth;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && ((depth = parser.getDepth()) >= innerDepth
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || type != XmlPullParser.END_TAG)) {
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (type != XmlPullParser.START_TAG) {
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (depth > innerDepth || !parser.getName().equals("item")) {
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int drawableRes = 0;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int i;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int j = 0;
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int numAttrs = attrs.getAttributeCount();
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] states = new int[numAttrs];
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i = 0; i < numAttrs; i++) {
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int stateResId = attrs.getAttributeNameResource(i);
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (stateResId == 0) break;
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (stateResId == com.android.internal.R.attr.drawable) {
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    drawableRes = attrs.getAttributeResourceValue(i, 0);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    states[j++] = attrs.getAttributeBooleanValue(i, false)
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            ? stateResId
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            : -stateResId;
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            states = StateSet.trimStateSet(states, j);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Drawable dr;
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (drawableRes != 0) {
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dr = r.getDrawable(drawableRes);
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while ((type = parser.next()) == XmlPullParser.TEXT) {
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (type != XmlPullParser.START_TAG) {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    throw new XmlPullParserException(
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            parser.getPositionDescription()
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    + ": <item> tag requires a 'drawable' attribute or "
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    + "child tag defining a drawable");
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dr = Drawable.createFromXmlInner(r, parser, attrs);
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateListState.addStateSet(states, dr);
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onStateChange(getState());
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    StateListState getStateListState() {
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState;
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the number of states contained in this drawable.
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of states contained in this drawable.
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateSet(int)
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateDrawable(int)
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStateCount() {
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState.getChildCount();
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the state set at an index.
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index The index of the state set.
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The state set at the index.
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateCount()
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateDrawable(int)
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int[] getStateSet(int index) {
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState.mStateSets[index];
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the drawable at an index.
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index The index of the drawable.
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The drawable at the index.
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateCount()
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateSet(int)
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable getStateDrawable(int index) {
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState.getChildren()[index];
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the index of the drawable with the provided state set.
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param stateSet the state set to look up
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the index of the provided state set, or -1 if not found
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateDrawable(int)
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateSet(int)
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStateDrawableIndex(int[] stateSet) {
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState.indexOfStateSet(stateSet);
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable mutate() {
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mMutated && super.mutate() == this) {
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int[][] sets = mStateListState.mStateSets;
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int count = sets.length;
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateListState.mStateSets = new int[count][];
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < count; i++) {
2542b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                final int[] set = sets[i];
2552b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                if (set != null) {
2562b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                    mStateListState.mStateSets[i] = set.clone();
2572b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                }
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMutated = true;
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2640af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    @Override
2650af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    public void setLayoutDirection(int layoutDirection) {
2660af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        final int numStates = getStateCount();
2670af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        for (int i = 0; i < numStates; i++) {
2680af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            getStateDrawable(i).setLayoutDirection(layoutDirection);
2690af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        }
2700af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        super.setLayoutDirection(layoutDirection);
2710af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    }
2720af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final class StateListState extends DrawableContainerState {
274079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn        int[][] mStateSets;
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
276c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        StateListState(StateListState orig, StateListDrawable owner, Resources res) {
277c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            super(orig, owner, res);
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (orig != null) {
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mStateSets = orig.mStateSets;
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mStateSets = new int[getChildren().length][];
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int addStateSet(int[] stateSet, Drawable drawable) {
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int pos = addChild(drawable);
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateSets[pos] = stateSet;
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return pos;
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int indexOfStateSet(int[] stateSet) {
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int[][] stateSets = mStateSets;
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int N = getChildCount();
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < N; i++) {
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (StateSet.stateSetMatches(stateSets[i], stateSet)) {
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return i;
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Drawable newDrawable() {
305c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            return new StateListDrawable(this, null);
306c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
307c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
308c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        @Override
309c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        public Drawable newDrawable(Resources res) {
310c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            return new StateListDrawable(this, res);
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void growArray(int oldSize, int newSize) {
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.growArray(oldSize, newSize);
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int[][] newStateSets = new int[newSize][];
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(mStateSets, 0, newStateSets, 0, oldSize);
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateSets = newStateSets;
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
322c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    private StateListDrawable(StateListState state, Resources res) {
323c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        StateListState as = new StateListState(state, this, res);
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStateListState = as;
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setConstantState(as);
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onStateChange(getState());
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
330