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
1353f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio        setAutoMirrored(a.getBoolean(
1363f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio                com.android.internal.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        int type;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int innerDepth = parser.getDepth() + 1;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int depth;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                && ((depth = parser.getDepth()) >= innerDepth
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                || type != XmlPullParser.END_TAG)) {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (type != XmlPullParser.START_TAG) {
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (depth > innerDepth || !parser.getName().equals("item")) {
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int drawableRes = 0;
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int i;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int j = 0;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int numAttrs = attrs.getAttributeCount();
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] states = new int[numAttrs];
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (i = 0; i < numAttrs; i++) {
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int stateResId = attrs.getAttributeNameResource(i);
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (stateResId == 0) break;
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (stateResId == com.android.internal.R.attr.drawable) {
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    drawableRes = attrs.getAttributeResourceValue(i, 0);
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    states[j++] = attrs.getAttributeBooleanValue(i, false)
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            ? stateResId
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            : -stateResId;
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            states = StateSet.trimStateSet(states, j);
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Drawable dr;
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (drawableRes != 0) {
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dr = r.getDrawable(drawableRes);
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                while ((type = parser.next()) == XmlPullParser.TEXT) {
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (type != XmlPullParser.START_TAG) {
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    throw new XmlPullParserException(
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            parser.getPositionDescription()
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    + ": <item> tag requires a 'drawable' attribute or "
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    + "child tag defining a drawable");
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dr = Drawable.createFromXmlInner(r, parser, attrs);
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateListState.addStateSet(states, dr);
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onStateChange(getState());
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    StateListState getStateListState() {
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState;
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the number of states contained in this drawable.
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The number of states contained in this drawable.
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateSet(int)
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateDrawable(int)
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStateCount() {
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState.getChildCount();
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the state set at an index.
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index The index of the state set.
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The state set at the index.
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateCount()
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateDrawable(int)
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int[] getStateSet(int index) {
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState.mStateSets[index];
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the drawable at an index.
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index The index of the drawable.
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The drawable at the index.
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateCount()
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateSet(int)
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable getStateDrawable(int index) {
23472146433322588c1116ee06c27ac758ad09d869cAlan Viverette        return mStateListState.getChild(index);
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the index of the drawable with the provided state set.
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param stateSet the state set to look up
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the index of the provided state set, or -1 if not found
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @hide pending API council
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateDrawable(int)
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #getStateSet(int)
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStateDrawableIndex(int[] stateSet) {
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mStateListState.indexOfStateSet(stateSet);
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable mutate() {
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mMutated && super.mutate() == this) {
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int[][] sets = mStateListState.mStateSets;
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int count = sets.length;
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateListState.mStateSets = new int[count][];
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < count; i++) {
2572b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                final int[] set = sets[i];
2582b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                if (set != null) {
2592b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                    mStateListState.mStateSets[i] = set.clone();
2602b95c2413838c2e2b127ebab8fb4fead7d52e460Jeff Sharkey                }
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMutated = true;
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
267fc4947491f785600b8770112fa1d19ece06d42f9Dianne Hackborn    /** @hide */
2680af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    @Override
2690af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    public void setLayoutDirection(int layoutDirection) {
2700af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio        super.setLayoutDirection(layoutDirection);
271f390f770ee570f1f4def41b165cb9492e381be40Alan Viverette
272f390f770ee570f1f4def41b165cb9492e381be40Alan Viverette        // Let the container handle setting its own layout direction. Otherwise,
273f390f770ee570f1f4def41b165cb9492e381be40Alan Viverette        // we're accessing potentially unused states.
274f390f770ee570f1f4def41b165cb9492e381be40Alan Viverette        mStateListState.setLayoutDirection(layoutDirection);
2750af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio    }
2760af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final class StateListState extends DrawableContainerState {
278079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn        int[][] mStateSets;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
280c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        StateListState(StateListState orig, StateListDrawable owner, Resources res) {
281c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            super(orig, owner, res);
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (orig != null) {
28472146433322588c1116ee06c27ac758ad09d869cAlan Viverette                mStateSets = Arrays.copyOf(orig.mStateSets, orig.mStateSets.length);
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
28672146433322588c1116ee06c27ac758ad09d869cAlan Viverette                mStateSets = new int[getCapacity()][];
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int addStateSet(int[] stateSet, Drawable drawable) {
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int pos = addChild(drawable);
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateSets[pos] = stateSet;
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return pos;
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int indexOfStateSet(int[] stateSet) {
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int[][] stateSets = mStateSets;
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int N = getChildCount();
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < N; i++) {
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (StateSet.stateSetMatches(stateSets[i], stateSet)) {
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return i;
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return -1;
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Drawable newDrawable() {
309c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            return new StateListDrawable(this, null);
310c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        }
311c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn
312c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        @Override
313c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        public Drawable newDrawable(Resources res) {
314c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn            return new StateListDrawable(this, res);
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void growArray(int oldSize, int newSize) {
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super.growArray(oldSize, newSize);
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int[][] newStateSets = new int[newSize][];
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            System.arraycopy(mStateSets, 0, newStateSets, 0, oldSize);
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStateSets = newStateSets;
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
326c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn    private StateListDrawable(StateListState state, Resources res) {
327c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn        StateListState as = new StateListState(state, this, res);
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mStateListState = as;
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setConstantState(as);
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onStateChange(getState());
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
334