17e82b99953680915596eaf0eb35927388e574ca8Chris Banes/* 27e82b99953680915596eaf0eb35927388e574ca8Chris Banes * Copyright (C) 2015 The Android Open Source Project 37e82b99953680915596eaf0eb35927388e574ca8Chris Banes * 47e82b99953680915596eaf0eb35927388e574ca8Chris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 57e82b99953680915596eaf0eb35927388e574ca8Chris Banes * you may not use this file except in compliance with the License. 67e82b99953680915596eaf0eb35927388e574ca8Chris Banes * You may obtain a copy of the License at 77e82b99953680915596eaf0eb35927388e574ca8Chris Banes * 87e82b99953680915596eaf0eb35927388e574ca8Chris Banes * http://www.apache.org/licenses/LICENSE-2.0 97e82b99953680915596eaf0eb35927388e574ca8Chris Banes * 107e82b99953680915596eaf0eb35927388e574ca8Chris Banes * Unless required by applicable law or agreed to in writing, software 117e82b99953680915596eaf0eb35927388e574ca8Chris Banes * distributed under the License is distributed on an "AS IS" BASIS, 127e82b99953680915596eaf0eb35927388e574ca8Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137e82b99953680915596eaf0eb35927388e574ca8Chris Banes * See the License for the specific language governing permissions and 147e82b99953680915596eaf0eb35927388e574ca8Chris Banes * limitations under the License. 157e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 167e82b99953680915596eaf0eb35927388e574ca8Chris Banes 177e82b99953680915596eaf0eb35927388e574ca8Chris Banespackage android.support.v4.graphics.drawable; 187e82b99953680915596eaf0eb35927388e574ca8Chris Banes 197e82b99953680915596eaf0eb35927388e574ca8Chris Banesimport android.content.res.ColorStateList; 209925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banesimport android.content.res.Resources; 217e82b99953680915596eaf0eb35927388e574ca8Chris Banesimport android.graphics.Canvas; 227e82b99953680915596eaf0eb35927388e574ca8Chris Banesimport android.graphics.ColorFilter; 237e82b99953680915596eaf0eb35927388e574ca8Chris Banesimport android.graphics.PorterDuff; 247e82b99953680915596eaf0eb35927388e574ca8Chris Banesimport android.graphics.Rect; 257e82b99953680915596eaf0eb35927388e574ca8Chris Banesimport android.graphics.Region; 267e82b99953680915596eaf0eb35927388e574ca8Chris Banesimport android.graphics.drawable.Drawable; 279925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banesimport android.support.annotation.NonNull; 289925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banesimport android.support.annotation.Nullable; 298f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viveretteimport android.support.annotation.RequiresApi; 307e82b99953680915596eaf0eb35927388e574ca8Chris Banes 317e82b99953680915596eaf0eb35927388e574ca8Chris Banes/** 3244ece5ceaaee232f9139ccbde40ac4a5e642bdeeChristophe Beyls * Drawable which delegates all calls to its wrapped {@link Drawable}. 338f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viverette * <p/> 347e82b99953680915596eaf0eb35927388e574ca8Chris Banes * Also allows backward compatible tinting via a color or {@link ColorStateList}. 357e82b99953680915596eaf0eb35927388e574ca8Chris Banes * This functionality is accessed via static methods in {@code DrawableCompat}. 367e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 378f886fe8c7e23fe6ccb8734167c960c2ed3429c3Alan Viverette 381bd3746e05e591865b430fd13dcc41ef10638fb2Aurimas Liutikas@RequiresApi(14) 39847790c44721520e4ec47f99f8af12d6caf713ffAurimas Liutikasclass DrawableWrapperApi14 extends Drawable 40be678137d44778590a6220ae0ef13649e83363a9Chris Banes implements Drawable.Callback, DrawableWrapper, TintAwareDrawable { 417e82b99953680915596eaf0eb35927388e574ca8Chris Banes 429925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN; 437e82b99953680915596eaf0eb35927388e574ca8Chris Banes 44c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes private int mCurrentColor; 45421affab4e0d1c631f759186f8b2975933c9b5a5Chris Banes private PorterDuff.Mode mCurrentMode; 46421affab4e0d1c631f759186f8b2975933c9b5a5Chris Banes private boolean mColorFilterSet; 477e82b99953680915596eaf0eb35927388e574ca8Chris Banes 489925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes DrawableWrapperState mState; 499925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes private boolean mMutated; 509925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 517e82b99953680915596eaf0eb35927388e574ca8Chris Banes Drawable mDrawable; 527e82b99953680915596eaf0eb35927388e574ca8Chris Banes 53847790c44721520e4ec47f99f8af12d6caf713ffAurimas Liutikas DrawableWrapperApi14(@NonNull DrawableWrapperState state, @Nullable Resources res) { 549925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState = state; 559925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes updateLocalState(res); 569925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 57c3b9589f61cbfda8c60344a47f8f87c0ded98554Chris Banes 589925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes /** 599925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * Creates a new wrapper around the specified drawable. 609925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * 619925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * @param dr the drawable to wrap 629925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes */ 63847790c44721520e4ec47f99f8af12d6caf713ffAurimas Liutikas DrawableWrapperApi14(@Nullable Drawable dr) { 64ffbf42aa3acb41b82cc6c1226c63c3649bedfe49Chris Banes mState = mutateConstantState(); 65c3b9589f61cbfda8c60344a47f8f87c0ded98554Chris Banes // Now set the drawable... 66c3b9589f61cbfda8c60344a47f8f87c0ded98554Chris Banes setWrappedDrawable(dr); 679925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 689925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 699925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes /** 709925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * Initializes local dynamic properties from state. This should be called 719925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * after significant state changes, e.g. from the One True Constructor and 729925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * after inflating or applying a theme. 739925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes */ 749925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes private void updateLocalState(@Nullable Resources res) { 759925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (mState != null && mState.mDrawableState != null) { 769925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes final Drawable dr = newDrawableFromState(mState.mDrawableState, res); 779925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes setWrappedDrawable(dr); 789925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 799925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 809925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 819925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes /** 829925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * Allows us to call ConstantState.newDrawable(*) is a API safe way 839925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes */ 849925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes protected Drawable newDrawableFromState(@NonNull Drawable.ConstantState state, 859925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Nullable Resources res) { 86f185f104c4786740765e549d535f9ba1052f96ccKirill Grouchnikov return state.newDrawable(res); 877e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 887e82b99953680915596eaf0eb35927388e574ca8Chris Banes 897e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 901bd3746e05e591865b430fd13dcc41ef10638fb2Aurimas Liutikas public void jumpToCurrentState() { 911bd3746e05e591865b430fd13dcc41ef10638fb2Aurimas Liutikas mDrawable.jumpToCurrentState(); 921bd3746e05e591865b430fd13dcc41ef10638fb2Aurimas Liutikas } 931bd3746e05e591865b430fd13dcc41ef10638fb2Aurimas Liutikas 941bd3746e05e591865b430fd13dcc41ef10638fb2Aurimas Liutikas @Override 957e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void draw(Canvas canvas) { 967e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.draw(canvas); 977e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 987e82b99953680915596eaf0eb35927388e574ca8Chris Banes 997e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1007e82b99953680915596eaf0eb35927388e574ca8Chris Banes protected void onBoundsChange(Rect bounds) { 101b1ba192200941f2a8c1eb2796c9fedc781bfe97fChris Banes if (mDrawable != null) { 102b1ba192200941f2a8c1eb2796c9fedc781bfe97fChris Banes mDrawable.setBounds(bounds); 103b1ba192200941f2a8c1eb2796c9fedc781bfe97fChris Banes } 1047e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1057e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1067e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1077e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void setChangingConfigurations(int configs) { 1087e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setChangingConfigurations(configs); 1097e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1107e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1117e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1127e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getChangingConfigurations() { 1139925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return super.getChangingConfigurations() 1149925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes | (mState != null ? mState.getChangingConfigurations() : 0) 1159925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes | mDrawable.getChangingConfigurations(); 1167e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1177e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1187e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1197e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void setDither(boolean dither) { 1207e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setDither(dither); 1217e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1227e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1237e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1247e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void setFilterBitmap(boolean filter) { 1257e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setFilterBitmap(filter); 1267e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1277e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1287e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1297e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void setAlpha(int alpha) { 1307e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setAlpha(alpha); 1317e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1327e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1337e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1347e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void setColorFilter(ColorFilter cf) { 1357e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setColorFilter(cf); 1367e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1377e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1387e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1397e82b99953680915596eaf0eb35927388e574ca8Chris Banes public boolean isStateful() { 140ffbf42aa3acb41b82cc6c1226c63c3649bedfe49Chris Banes final ColorStateList tintList = (isCompatTintEnabled() && mState != null) 141ffbf42aa3acb41b82cc6c1226c63c3649bedfe49Chris Banes ? mState.mTint 142ffbf42aa3acb41b82cc6c1226c63c3649bedfe49Chris Banes : null; 1437797b9f22c8c404309b778a0966266d2b1a84915Chris Banes return (tintList != null && tintList.isStateful()) || mDrawable.isStateful(); 1447e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1457e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1467e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1477e82b99953680915596eaf0eb35927388e574ca8Chris Banes public boolean setState(final int[] stateSet) { 1487e82b99953680915596eaf0eb35927388e574ca8Chris Banes boolean handled = mDrawable.setState(stateSet); 1497e82b99953680915596eaf0eb35927388e574ca8Chris Banes handled = updateTint(stateSet) || handled; 1507e82b99953680915596eaf0eb35927388e574ca8Chris Banes return handled; 1517e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1527e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1537e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1547e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int[] getState() { 1557e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getState(); 1567e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1577e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1587e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1597e82b99953680915596eaf0eb35927388e574ca8Chris Banes public Drawable getCurrent() { 1607e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getCurrent(); 1617e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1627e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1637e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1647e82b99953680915596eaf0eb35927388e574ca8Chris Banes public boolean setVisible(boolean visible, boolean restart) { 1657e82b99953680915596eaf0eb35927388e574ca8Chris Banes return super.setVisible(visible, restart) || mDrawable.setVisible(visible, restart); 1667e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1677e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1687e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1697e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getOpacity() { 1707e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getOpacity(); 1717e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1727e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1737e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1747e82b99953680915596eaf0eb35927388e574ca8Chris Banes public Region getTransparentRegion() { 1757e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getTransparentRegion(); 1767e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1777e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1787e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1797e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getIntrinsicWidth() { 1807e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getIntrinsicWidth(); 1817e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1827e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1837e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1847e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getIntrinsicHeight() { 1857e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getIntrinsicHeight(); 1867e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1877e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1887e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1897e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getMinimumWidth() { 1907e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getMinimumWidth(); 1917e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1927e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1937e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1947e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getMinimumHeight() { 1957e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getMinimumHeight(); 1967e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1977e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1987e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1997e82b99953680915596eaf0eb35927388e574ca8Chris Banes public boolean getPadding(Rect padding) { 2007e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getPadding(padding); 2017e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2027e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2037e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 2049925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Nullable 2059925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes public ConstantState getConstantState() { 2069925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (mState != null && mState.canConstantState()) { 2079925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState.mChangingConfigurations = getChangingConfigurations(); 2089925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return mState; 2099925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 2109925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return null; 2119925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 2129925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 2139925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Override 2147e82b99953680915596eaf0eb35927388e574ca8Chris Banes public Drawable mutate() { 2159925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (!mMutated && super.mutate() == this) { 2169925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState = mutateConstantState(); 2179925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (mDrawable != null) { 2189925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mDrawable.mutate(); 2199925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 2209925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (mState != null) { 2219925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState.mDrawableState = mDrawable != null ? mDrawable.getConstantState() : null; 2229925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 2239925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mMutated = true; 2247e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2257e82b99953680915596eaf0eb35927388e574ca8Chris Banes return this; 2267e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2277e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2287e82b99953680915596eaf0eb35927388e574ca8Chris Banes /** 2299925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * Mutates the constant state and returns the new state. 2309925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * <p> 2319925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * This method should never call the super implementation; it should always 2329925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * mutate and return its own constant state. 2339925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * 2349925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * @return the new state 2359925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes */ 2364da36b0dfa8436b197314094337fa3102fcca1bcChris Banes @NonNull 2379925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes DrawableWrapperState mutateConstantState() { 238f185f104c4786740765e549d535f9ba1052f96ccKirill Grouchnikov return new DrawableWrapperStateBase(mState, null); 2399925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 2409925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 2419925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes /** 2427e82b99953680915596eaf0eb35927388e574ca8Chris Banes * {@inheritDoc} 2437e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 244847790c44721520e4ec47f99f8af12d6caf713ffAurimas Liutikas @Override 2457e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void invalidateDrawable(Drawable who) { 2467e82b99953680915596eaf0eb35927388e574ca8Chris Banes invalidateSelf(); 2477e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2487e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2497e82b99953680915596eaf0eb35927388e574ca8Chris Banes /** 2507e82b99953680915596eaf0eb35927388e574ca8Chris Banes * {@inheritDoc} 2517e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 252847790c44721520e4ec47f99f8af12d6caf713ffAurimas Liutikas @Override 2537e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void scheduleDrawable(Drawable who, Runnable what, long when) { 2547e82b99953680915596eaf0eb35927388e574ca8Chris Banes scheduleSelf(what, when); 2557e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2567e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2577e82b99953680915596eaf0eb35927388e574ca8Chris Banes /** 2587e82b99953680915596eaf0eb35927388e574ca8Chris Banes * {@inheritDoc} 2597e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 260847790c44721520e4ec47f99f8af12d6caf713ffAurimas Liutikas @Override 2617e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void unscheduleDrawable(Drawable who, Runnable what) { 2627e82b99953680915596eaf0eb35927388e574ca8Chris Banes unscheduleSelf(what); 2637e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2647e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2657e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 2667e82b99953680915596eaf0eb35927388e574ca8Chris Banes protected boolean onLevelChange(int level) { 2677e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.setLevel(level); 2687e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2697e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2707e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 271be678137d44778590a6220ae0ef13649e83363a9Chris Banes public void setTint(int tint) { 272be678137d44778590a6220ae0ef13649e83363a9Chris Banes setTintList(ColorStateList.valueOf(tint)); 2737e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2747e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2757e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 276be678137d44778590a6220ae0ef13649e83363a9Chris Banes public void setTintList(ColorStateList tint) { 2779925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState.mTint = tint; 2789925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes updateTint(getState()); 2797e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2807e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2817e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 282be678137d44778590a6220ae0ef13649e83363a9Chris Banes public void setTintMode(PorterDuff.Mode tintMode) { 2839925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState.mTintMode = tintMode; 2849925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes updateTint(getState()); 2857e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2867e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2877e82b99953680915596eaf0eb35927388e574ca8Chris Banes private boolean updateTint(int[] state) { 2887797b9f22c8c404309b778a0966266d2b1a84915Chris Banes if (!isCompatTintEnabled()) { 2897797b9f22c8c404309b778a0966266d2b1a84915Chris Banes // If compat tinting is not enabled, fail fast 2907797b9f22c8c404309b778a0966266d2b1a84915Chris Banes return false; 2917797b9f22c8c404309b778a0966266d2b1a84915Chris Banes } 2927797b9f22c8c404309b778a0966266d2b1a84915Chris Banes 2939925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes final ColorStateList tintList = mState.mTint; 2949925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes final PorterDuff.Mode tintMode = mState.mTintMode; 2959925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 2969925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (tintList != null && tintMode != null) { 2979925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes final int color = tintList.getColorForState(state, tintList.getDefaultColor()); 2989925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (!mColorFilterSet || color != mCurrentColor || tintMode != mCurrentMode) { 2999925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes setColorFilter(color, tintMode); 3007e82b99953680915596eaf0eb35927388e574ca8Chris Banes mCurrentColor = color; 3019925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mCurrentMode = tintMode; 302421affab4e0d1c631f759186f8b2975933c9b5a5Chris Banes mColorFilterSet = true; 3037e82b99953680915596eaf0eb35927388e574ca8Chris Banes return true; 3047e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 305c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes } else { 306421affab4e0d1c631f759186f8b2975933c9b5a5Chris Banes mColorFilterSet = false; 307c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes clearColorFilter(); 3087e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 3097e82b99953680915596eaf0eb35927388e574ca8Chris Banes return false; 3107e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 3117e82b99953680915596eaf0eb35927388e574ca8Chris Banes 3127e82b99953680915596eaf0eb35927388e574ca8Chris Banes /** 3137e82b99953680915596eaf0eb35927388e574ca8Chris Banes * Returns the wrapped {@link Drawable} 3147e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 315e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 316c3b9589f61cbfda8c60344a47f8f87c0ded98554Chris Banes public final Drawable getWrappedDrawable() { 3177e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable; 3187e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 3197e82b99953680915596eaf0eb35927388e574ca8Chris Banes 3207e82b99953680915596eaf0eb35927388e574ca8Chris Banes /** 3217e82b99953680915596eaf0eb35927388e574ca8Chris Banes * Sets the current wrapped {@link Drawable} 3227e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 323e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 324c3b9589f61cbfda8c60344a47f8f87c0ded98554Chris Banes public final void setWrappedDrawable(Drawable dr) { 3257e82b99953680915596eaf0eb35927388e574ca8Chris Banes if (mDrawable != null) { 3267e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setCallback(null); 3277e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 3287e82b99953680915596eaf0eb35927388e574ca8Chris Banes 3299925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mDrawable = dr; 3309925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3319925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (dr != null) { 3329925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes dr.setCallback(this); 3339925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes // Only call setters for data that's stored in the base Drawable. 334d8ae10da39a28468fad19ed564799c52354a8d1fChris Banes setVisible(dr.isVisible(), true); 335d8ae10da39a28468fad19ed564799c52354a8d1fChris Banes setState(dr.getState()); 336d8ae10da39a28468fad19ed564799c52354a8d1fChris Banes setLevel(dr.getLevel()); 337d8ae10da39a28468fad19ed564799c52354a8d1fChris Banes setBounds(dr.getBounds()); 3389925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (mState != null) { 3399925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState.mDrawableState = dr.getConstantState(); 3409925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3417e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 342ac54e3ed316c378f9f339b88811613feb176e75dChris Banes 3437e82b99953680915596eaf0eb35927388e574ca8Chris Banes invalidateSelf(); 3447e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 3457797b9f22c8c404309b778a0966266d2b1a84915Chris Banes 3467797b9f22c8c404309b778a0966266d2b1a84915Chris Banes protected boolean isCompatTintEnabled() { 34764dbe1d454f1190b3cd8426d09b9119949a10709Kirill Grouchnikov // It's enabled by default on Gingerbread 3487797b9f22c8c404309b778a0966266d2b1a84915Chris Banes return true; 3497797b9f22c8c404309b778a0966266d2b1a84915Chris Banes } 3509925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 351847790c44721520e4ec47f99f8af12d6caf713ffAurimas Liutikas protected abstract static class DrawableWrapperState extends Drawable.ConstantState { 3529925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes int mChangingConfigurations; 3539925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes Drawable.ConstantState mDrawableState; 3549925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3559925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes ColorStateList mTint = null; 3569925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE; 3579925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3589925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes DrawableWrapperState(@Nullable DrawableWrapperState orig, @Nullable Resources res) { 3599925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (orig != null) { 3609925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mChangingConfigurations = orig.mChangingConfigurations; 3619925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mDrawableState = orig.mDrawableState; 3629925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mTint = orig.mTint; 3639925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mTintMode = orig.mTintMode; 3649925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3659925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3669925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3679925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Override 3689925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes public Drawable newDrawable() { 3699925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return newDrawable(null); 3709925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3719925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 372e2104f4b5c8e3ad63570306a25e61502dfe4c418Aurimas Liutikas @Override 3739925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes public abstract Drawable newDrawable(@Nullable Resources res); 3749925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3759925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Override 3769925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes public int getChangingConfigurations() { 3779925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return mChangingConfigurations 3789925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes | (mDrawableState != null ? mDrawableState.getChangingConfigurations() : 0); 3799925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3809925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3819925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes boolean canConstantState() { 3829925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return mDrawableState != null; 3839925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3849925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3859925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 386f185f104c4786740765e549d535f9ba1052f96ccKirill Grouchnikov private static class DrawableWrapperStateBase extends DrawableWrapperState { 387f185f104c4786740765e549d535f9ba1052f96ccKirill Grouchnikov DrawableWrapperStateBase( 3889925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Nullable DrawableWrapperState orig, @Nullable Resources res) { 3899925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes super(orig, res); 3909925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3919925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3929925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Override 3939925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes public Drawable newDrawable(@Nullable Resources res) { 394847790c44721520e4ec47f99f8af12d6caf713ffAurimas Liutikas return new DrawableWrapperApi14(this, res); 3959925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3969925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3977e82b99953680915596eaf0eb35927388e574ca8Chris Banes} 398