StateListDrawable.java revision 39e33621a725bcdaa21a723866e53c6ea3356169
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
19ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viveretteimport com.android.internal.R;
20ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette
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 java.io.IOException;
25079e23575024e103358c982152afb7a720ae1a8aDianne Hackbornimport java.util.Arrays;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
2952b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viveretteimport android.content.res.Resources.Theme;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.StateSet;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The 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
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ID value.
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p/>
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>It can be defined in an XML file with the <code>&lt;selector></code> element.
38dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * Each state Drawable is defined in a nested <code>&lt;item></code> element. For more
39dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * information, see the guide to <a
40dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p>
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#StateListDrawable_visible
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#StateListDrawable_variablePadding
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#StateListDrawable_constantSize
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_focused
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_window_focused
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_enabled
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_checkable
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_checked
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_selected
51079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn * @attr ref android.R.styleable#DrawableStates_state_activated
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_active
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_single
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_first
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_middle
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_last
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_pressed
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class StateListDrawable extends DrawableContainer {
605e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    private static final String TAG = StateListDrawable.class.getSimpleName();
615e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
62079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn    private static final boolean DEBUG = false;
63079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn
64211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed    /**
65211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * To be proper, we should have a getter for dither (and alpha, etc.)
66211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * so that proxy classes like this can save/restore their delegates'
67211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * values, but we don't have getters. Since we do have setters
68211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * (e.g. setDither), which this proxy forwards on, we have to have some
69211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * default/initial setting.
70211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     *
71211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * The initial setting for dither is now true, since it almost always seems
72211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     * to improve the quality at negligible cost.
73211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed     */
74211db4a2874f1a2d0e7a8cb8d33e81fa08801763Mike Reed    private static final boolean DEFAULT_DITHER = true;
755e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
765e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    private StateListState mStateListState;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mMutated;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public StateListDrawable() {
80c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        this(null, null);
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Add a new image/string ID to the set of images.
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param stateSet - An array of resource Ids to associate with the image.
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *                 Switch to this image by calling setState().
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param drawable -The image to show.
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addState(int[] stateSet, Drawable drawable) {
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (drawable != null) {
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateListState.addStateSet(stateSet, drawable);
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // in case the new state matches our current state...
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            onStateChange(getState());
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStateful() {
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean onStateChange(int[] stateSet) {
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int idx = mStateListState.indexOfStateSet(stateSet);
106079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn        if (DEBUG) android.util.Log.i(TAG, "onStateChange " + this + " states "
107079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn                + Arrays.toString(stateSet) + " found " + idx);
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (idx < 0) {
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD);
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (selectDrawable(idx)) {
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.onStateChange(stateSet);
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
11852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws XmlPullParserException, IOException {
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12139e33621a725bcdaa21a723866e53c6ea3356169Alan Viverette        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.StateListDrawable);
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.inflateWithAttributes(r, parser, a,
124ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette                R.styleable.StateListDrawable_visible);
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStateListState.setVariablePadding(a.getBoolean(
127ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette                R.styleable.StateListDrawable_variablePadding, false));
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStateListState.setConstantSize(a.getBoolean(
129ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette                R.styleable.StateListDrawable_constantSize, false));
130079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn        mStateListState.setEnterFadeDuration(a.getInt(
131ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette                R.styleable.StateListDrawable_enterFadeDuration, 0));
132079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn        mStateListState.setExitFadeDuration(a.getInt(
133ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette                R.styleable.StateListDrawable_exitFadeDuration, 0));
1346afa16feb32d44c4977b3eb6007246a99f22fdbfJeff Sharkey
135ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette        setDither(a.getBoolean(R.styleable.StateListDrawable_dither, DEFAULT_DITHER));
136ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette        setAutoMirrored(a.getBoolean(R.styleable.StateListDrawable_autoMirrored, false));
1373f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        a.recycle();
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int innerDepth = parser.getDepth() + 1;
141ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette        int type;
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int depth;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && ((depth = parser.getDepth()) >= innerDepth
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || type != XmlPullParser.END_TAG)) {
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (type != XmlPullParser.START_TAG) {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (depth > innerDepth || !parser.getName().equals("item")) {
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int drawableRes = 0;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int i;
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int j = 0;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int numAttrs = attrs.getAttributeCount();
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] states = new int[numAttrs];
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i = 0; i < numAttrs; i++) {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int stateResId = attrs.getAttributeNameResource(i);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (stateResId == 0) break;
163ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette                if (stateResId == R.attr.drawable) {
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    drawableRes = attrs.getAttributeResourceValue(i, 0);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    states[j++] = attrs.getAttributeBooleanValue(i, false)
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            ? stateResId
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            : -stateResId;
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            states = StateSet.trimStateSet(states, j);
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
173ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette            final Drawable dr;
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (drawableRes != 0) {
175ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette                dr = r.getDrawable(drawableRes, theme);
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while ((type = parser.next()) == XmlPullParser.TEXT) {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (type != XmlPullParser.START_TAG) {
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    throw new XmlPullParserException(
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            parser.getPositionDescription()
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    + ": <item> tag requires a 'drawable' attribute or "
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    + "child tag defining a drawable");
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1856dbe51b50e82057af4d29882889444d22ac19c9cAlan Viverette                dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateListState.addStateSet(states, dr);
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onStateChange(getState());
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    StateListState getStateListState() {
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState;
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the number of states contained in this drawable.
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of states contained in this drawable.
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateSet(int)
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateDrawable(int)
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStateCount() {
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState.getChildCount();
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the state set at an index.
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index The index of the state set.
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The state set at the index.
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateCount()
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateDrawable(int)
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int[] getStateSet(int index) {
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState.mStateSets[index];
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the drawable at an index.
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index The index of the drawable.
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The drawable at the index.
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateCount()
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateSet(int)
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable getStateDrawable(int index) {
23372146433322588c1116ee06c27ac758ad09d869cAlan Viverette        return mStateListState.getChild(index);
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
235b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the index of the drawable with the provided state set.
238b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette     *
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param stateSet the state set to look up
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the index of the provided state set, or -1 if not found
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateDrawable(int)
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateSet(int)
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStateDrawableIndex(int[] stateSet) {
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState.indexOfStateSet(stateSet);
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
248b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable mutate() {
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mMutated && super.mutate() == this) {
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int[][] sets = mStateListState.mStateSets;
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int count = sets.length;
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateListState.mStateSets = new int[count][];
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < count; i++) {
2562b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                final int[] set = sets[i];
2572b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                if (set != null) {
2582b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                    mStateListState.mStateSets[i] = set.clone();
2592b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                }
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMutated = true;
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
266fc4947491f785600b8770112fa1d19ece06d42f9Dianne Hackborn    /** @hide */
2670af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    @Override
2680af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    public void setLayoutDirection(int layoutDirection) {
2690af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        super.setLayoutDirection(layoutDirection);
270f390f770ee570f1f4def41b165cb9492e381be40Alan Viverette
271f390f770ee570f1f4def41b165cb9492e381be40Alan Viverette        // Let the container handle setting its own layout direction. Otherwise,
272f390f770ee570f1f4def41b165cb9492e381be40Alan Viverette        // we're accessing potentially unused states.
273f390f770ee570f1f4def41b165cb9492e381be40Alan Viverette        mStateListState.setLayoutDirection(layoutDirection);
2740af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    }
2750af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio
2765e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    static class StateListState extends DrawableContainerState {
277079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn        int[][] mStateSets;
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
279c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        StateListState(StateListState orig, StateListDrawable owner, Resources res) {
280c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            super(orig, owner, res);
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (orig != null) {
28372146433322588c1116ee06c27ac758ad09d869cAlan Viverette                mStateSets = Arrays.copyOf(orig.mStateSets, orig.mStateSets.length);
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
28572146433322588c1116ee06c27ac758ad09d869cAlan Viverette                mStateSets = new int[getCapacity()][];
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int addStateSet(int[] stateSet, Drawable drawable) {
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int pos = addChild(drawable);
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateSets[pos] = stateSet;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return pos;
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2955e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        int indexOfStateSet(int[] stateSet) {
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int[][] stateSets = mStateSets;
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int N = getChildCount();
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < N; i++) {
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (StateSet.stateSetMatches(stateSets[i], stateSet)) {
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return i;
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Drawable newDrawable() {
308c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            return new StateListDrawable(this, null);
309c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
310c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
311c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        @Override
312c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        public Drawable newDrawable(Resources res) {
313c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            return new StateListDrawable(this, res);
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void growArray(int oldSize, int newSize) {
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.growArray(oldSize, newSize);
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int[][] newStateSets = new int[newSize][];
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(mStateSets, 0, newStateSets, 0, oldSize);
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateSets = newStateSets;
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3255e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    void setConstantState(StateListState state) {
3265e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        super.setConstantState(state);
3275e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
3285e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        mStateListState = state;
3295e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
3305e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
331c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    private StateListDrawable(StateListState state, Resources res) {
3325e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        final StateListState newState = new StateListState(state, this, res);
3335e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        setConstantState(newState);
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onStateChange(getState());
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3365e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette
3375e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    /**
3385e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     * This constructor exists so subclasses can avoid calling the default
3395e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     * constructor and setting up a StateListDrawable-specific constant state.
3405e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette     */
3415e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    StateListDrawable(StateListState state) {
3425e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        if (state != null) {
3435e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette            setConstantState(state);
3445e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette        }
3455e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette    }
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
348