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 278dcd533786df8d824f1e040230ee9e7e5b083998Alan Viveretteimport android.annotation.NonNull; 288dcd533786df8d824f1e040230ee9e7e5b083998Alan Viveretteimport android.annotation.Nullable; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray; 3152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viveretteimport android.content.res.Resources.Theme; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.StateSet; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The 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 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ID value. 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p/> 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>It can be defined in an XML file with the <code><selector></code> element. 40dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * Each state Drawable is defined in a nested <code><item></code> element. For more 41dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * information, see the guide to <a 42dfe5c204403bc56c29bb36410574eab8b1950417Scott Main * href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#StateListDrawable_visible 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#StateListDrawable_variablePadding 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#StateListDrawable_constantSize 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_focused 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_window_focused 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_enabled 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_checkable 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_checked 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_selected 53079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn * @attr ref android.R.styleable#DrawableStates_state_activated 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_active 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_single 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_first 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_middle 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_last 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#DrawableStates_state_pressed 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class StateListDrawable extends DrawableContainer { 6206ff2af68aa1041eeb26778e994e0fe196bf8b1eAlan Viverette private static final String TAG = "StateListDrawable"; 635e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette 64079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn private static final boolean DEBUG = false; 65079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn 665e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette private StateListState mStateListState; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mMutated; 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public StateListDrawable() { 70c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn this(null, null); 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Add a new image/string ID to the set of images. 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param stateSet - An array of resource Ids to associate with the image. 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Switch to this image by calling setState(). 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param drawable -The image to show. 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void addState(int[] stateSet, Drawable drawable) { 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (drawable != null) { 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStateListState.addStateSet(stateSet, drawable); 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // in case the new state matches our current state... 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onStateChange(getState()); 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isStateful() { 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected boolean onStateChange(int[] stateSet) { 9506ff2af68aa1041eeb26778e994e0fe196bf8b1eAlan Viverette final boolean changed = super.onStateChange(stateSet); 9606ff2af68aa1041eeb26778e994e0fe196bf8b1eAlan Viverette 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int idx = mStateListState.indexOfStateSet(stateSet); 98079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn if (DEBUG) android.util.Log.i(TAG, "onStateChange " + this + " states " 99079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn + Arrays.toString(stateSet) + " found " + idx); 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (idx < 0) { 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD); 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10306ff2af68aa1041eeb26778e994e0fe196bf8b1eAlan Viverette 10406ff2af68aa1041eeb26778e994e0fe196bf8b1eAlan Viverette return selectDrawable(idx) || changed; 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 10852b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws XmlPullParserException, IOException { 11039e33621a725bcdaa21a723866e53c6ea3356169Alan Viverette final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.StateListDrawable); 111d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette super.inflateWithAttributes(r, parser, a, R.styleable.StateListDrawable_visible); 112d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette updateStateFromTypedArray(a); 113d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette a.recycle(); 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 115d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette inflateChildElements(r, parser, attrs, theme); 1166afa16feb32d44c4977b3eb6007246a99f22fdbfJeff Sharkey 117d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette onStateChange(getState()); 118d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette } 1193f5a90b2fbba2a83a8a2c5babd5d466a5e0ad2aaFabrice Di Meglio 120d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette /** 121d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette * Updates the constant state from the values in the typed array. 122d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette */ 123d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette private void updateStateFromTypedArray(TypedArray a) { 124d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette final StateListState state = mStateListState; 125d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette 126d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette // Account for any configuration changes. 127d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette state.mChangingConfigurations |= a.getChangingConfigurations(); 128d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette 129d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette // Extract the theme attributes, if any. 130d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette state.mThemeAttrs = a.extractThemeAttrs(); 131d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette 132d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette state.mVariablePadding = a.getBoolean( 133d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette R.styleable.StateListDrawable_variablePadding, state.mVariablePadding); 134d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette state.mConstantSize = a.getBoolean( 135d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette R.styleable.StateListDrawable_constantSize, state.mConstantSize); 136d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette state.mEnterFadeDuration = a.getInt( 137d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette R.styleable.StateListDrawable_enterFadeDuration, state.mEnterFadeDuration); 138d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette state.mExitFadeDuration = a.getInt( 139d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette R.styleable.StateListDrawable_exitFadeDuration, state.mExitFadeDuration); 140d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette state.mDither = a.getBoolean( 141d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette R.styleable.StateListDrawable_dither, state.mDither); 142d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette state.mAutoMirrored = a.getBoolean( 143d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette R.styleable.StateListDrawable_autoMirrored, state.mAutoMirrored); 144d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette } 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 146d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette /** 147d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette * Inflates child elements from XML. 148d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette */ 149d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs, 150d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette Theme theme) throws XmlPullParserException, IOException { 151d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette final StateListState state = mStateListState; 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int innerDepth = parser.getDepth() + 1; 153ad55abdc748f2cba6955e9e60cf7964dc027f2b5Alan Viverette int type; 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int depth; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project && ((depth = parser.getDepth()) >= innerDepth 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || type != XmlPullParser.END_TAG)) { 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (type != XmlPullParser.START_TAG) { 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (depth > innerDepth || !parser.getName().equals("item")) { 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 166d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette // This allows state list drawable item elements to be themed at 167d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette // inflation time but does NOT make them work for Zygote preload. 168d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette final TypedArray a = obtainAttributes(r, theme, attrs, 169d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette R.styleable.StateListDrawableItem); 170d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette Drawable dr = a.getDrawable(R.styleable.StateListDrawableItem_drawable); 171d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette a.recycle(); 172d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette 173d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette final int[] states = extractStateSet(attrs); 174d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette 175d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette // Loading child elements modifies the state of the AttributeSet's 176d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette // underlying parser, so it needs to happen after obtaining 177d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette // attributes and extracting states. 178d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette if (dr == null) { 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while ((type = parser.next()) == XmlPullParser.TEXT) { 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (type != XmlPullParser.START_TAG) { 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new XmlPullParserException( 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parser.getPositionDescription() 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + ": <item> tag requires a 'drawable' attribute or " 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "child tag defining a drawable"); 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1876dbe51b50e82057af4d29882889444d22ac19c9cAlan Viverette dr = Drawable.createFromXmlInner(r, parser, attrs, theme); 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 190d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette state.addStateSet(states, dr); 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 194d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette /** 195d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette * Extracts state_ attributes from an attribute set. 196d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette * 197d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette * @param attrs The attribute set. 198d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette * @return An array of state_ attributes. 199d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette */ 200d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette int[] extractStateSet(AttributeSet attrs) { 201d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette int j = 0; 202d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette final int numAttrs = attrs.getAttributeCount(); 203d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette int[] states = new int[numAttrs]; 204d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette for (int i = 0; i < numAttrs; i++) { 205d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette final int stateResId = attrs.getAttributeNameResource(i); 206d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette switch (stateResId) { 207d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette case 0: 208d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette break; 209d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette case R.attr.drawable: 210d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette case R.attr.id: 211d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette // Ignore attributes from StateListDrawableItem and 212d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette // AnimatedStateListDrawableItem. 213d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette continue; 214d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette default: 215d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette states[j++] = attrs.getAttributeBooleanValue(i, false) 216d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette ? stateResId : -stateResId; 217d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette } 218d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette } 219d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette states = StateSet.trimStateSet(states, j); 220d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette return states; 221d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette } 222d6570d11e4d1e43c2cfe1d10e27a7786c4283169Alan Viverette 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project StateListState getStateListState() { 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mStateListState; 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the number of states contained in this drawable. 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The number of states contained in this drawable. 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide pending API council 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getStateSet(int) 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getStateDrawable(int) 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getStateCount() { 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mStateListState.getChildCount(); 2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the state set at an index. 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param index The index of the state set. 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The state set at the index. 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide pending API council 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getStateCount() 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getStateDrawable(int) 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int[] getStateSet(int index) { 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mStateListState.mStateSets[index]; 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the drawable at an index. 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param index The index of the drawable. 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The drawable at the index. 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide pending API council 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getStateCount() 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getStateSet(int) 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Drawable getStateDrawable(int index) { 26272146433322588c1116ee06c27ac758ad09d869cAlan Viverette return mStateListState.getChild(index); 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 264b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Gets the index of the drawable with the provided state set. 267b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette * 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param stateSet the state set to look up 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return the index of the provided state set, or -1 if not found 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide pending API council 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getStateDrawable(int) 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #getStateSet(int) 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getStateDrawableIndex(int[] stateSet) { 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mStateListState.indexOfStateSet(stateSet); 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 277b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Drawable mutate() { 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mMutated && super.mutate() == this) { 2818dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette mStateListState.mutate(); 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMutated = true; 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return this; 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2878dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette @Override 2888dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette StateListState cloneConstantState() { 2898dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette return new StateListState(mStateListState, this, null); 2908dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette } 2918dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette 292727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette /** 293727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette * @hide 294727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette */ 295727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette public void clearMutated() { 296727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette super.clearMutated(); 297727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette mMutated = false; 298727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette } 299727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette 3005e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette static class StateListState extends DrawableContainerState { 301d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette int[] mThemeAttrs; 302079e23575024e103358c982152afb7a720ae1a8aDianne Hackborn int[][] mStateSets; 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 304c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn StateListState(StateListState orig, StateListDrawable owner, Resources res) { 305c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn super(orig, owner, res); 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (orig != null) { 3088dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette // Perform a shallow copy and rely on mutate() to deep-copy. 309d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette mThemeAttrs = orig.mThemeAttrs; 3108dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette mStateSets = orig.mStateSets; 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 312d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette mThemeAttrs = null; 31372146433322588c1116ee06c27ac758ad09d869cAlan Viverette mStateSets = new int[getCapacity()][]; 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 31706ff2af68aa1041eeb26778e994e0fe196bf8b1eAlan Viverette void mutate() { 3188dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette mThemeAttrs = mThemeAttrs != null ? mThemeAttrs.clone() : null; 3198dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette 3208dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette final int[][] stateSets = new int[mStateSets.length][]; 3218dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette for (int i = mStateSets.length - 1; i >= 0; i--) { 3228dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette stateSets[i] = mStateSets[i] != null ? mStateSets[i].clone() : null; 3238dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette } 32406ff2af68aa1041eeb26778e994e0fe196bf8b1eAlan Viverette mStateSets = stateSets; 3258dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette } 3268dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int addStateSet(int[] stateSet, Drawable drawable) { 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int pos = addChild(drawable); 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStateSets[pos] = stateSet; 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return pos; 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3335e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette int indexOfStateSet(int[] stateSet) { 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int[][] stateSets = mStateSets; 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int N = getChildCount(); 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < N; i++) { 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (StateSet.stateSetMatches(stateSets[i], stateSet)) { 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return i; 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return -1; 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Drawable newDrawable() { 346c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn return new StateListDrawable(this, null); 347c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn } 348c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn 349c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn @Override 350c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn public Drawable newDrawable(Resources res) { 351c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn return new StateListDrawable(this, res); 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 355d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette public boolean canApplyTheme() { 356d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette return mThemeAttrs != null || super.canApplyTheme(); 357d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette } 358d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette 359d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette @Override 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void growArray(int oldSize, int newSize) { 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.growArray(oldSize, newSize); 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int[][] newStateSets = new int[newSize][]; 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.arraycopy(mStateSets, 0, newStateSets, 0, oldSize); 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStateSets = newStateSets; 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 36817cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette @Override 36917cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette public void applyTheme(Theme theme) { 37017cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette super.applyTheme(theme); 37117cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette 37217cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette onStateChange(getState()); 37317cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette } 37417cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette 3758dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette protected void setConstantState(@NonNull DrawableContainerState state) { 3765e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette super.setConstantState(state); 3775e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette 3788dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette if (state instanceof StateListState) { 3798dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette mStateListState = (StateListState) state; 3808dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette } 3815e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette } 3825e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette 383c2974809373697147cbe5754835cc871fb93aef1Dianne Hackborn private StateListDrawable(StateListState state, Resources res) { 3848dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette // Every state list drawable has its own constant state. 3855e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette final StateListState newState = new StateListState(state, this, res); 3865e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette setConstantState(newState); 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onStateChange(getState()); 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3895e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette 3905e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette /** 3915e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * This constructor exists so subclasses can avoid calling the default 3925e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette * constructor and setting up a StateListDrawable-specific constant state. 3935e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette */ 3948dcd533786df8d824f1e040230ee9e7e5b083998Alan Viverette StateListDrawable(@Nullable StateListState state) { 3955e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette if (state != null) { 3965e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette setConstantState(state); 3975e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette } 3985e92c95d847a68178cf6099c801f82dcb7e4fa47Alan Viverette } 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 401