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; 297e82b99953680915596eaf0eb35927388e574ca8Chris Banes 307e82b99953680915596eaf0eb35927388e574ca8Chris Banes/** 317e82b99953680915596eaf0eb35927388e574ca8Chris Banes * Drawable which delegates all calls to it's wrapped {@link android.graphics.drawable.Drawable}. 327e82b99953680915596eaf0eb35927388e574ca8Chris Banes * <p> 337e82b99953680915596eaf0eb35927388e574ca8Chris Banes * Also allows backward compatible tinting via a color or {@link ColorStateList}. 347e82b99953680915596eaf0eb35927388e574ca8Chris Banes * This functionality is accessed via static methods in {@code DrawableCompat}. 357e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 36be678137d44778590a6220ae0ef13649e83363a9Chris Banesclass DrawableWrapperDonut extends Drawable 37be678137d44778590a6220ae0ef13649e83363a9Chris Banes implements Drawable.Callback, DrawableWrapper, TintAwareDrawable { 387e82b99953680915596eaf0eb35927388e574ca8Chris Banes 399925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN; 407e82b99953680915596eaf0eb35927388e574ca8Chris Banes 41c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes private int mCurrentColor; 42421affab4e0d1c631f759186f8b2975933c9b5a5Chris Banes private PorterDuff.Mode mCurrentMode; 43421affab4e0d1c631f759186f8b2975933c9b5a5Chris Banes private boolean mColorFilterSet; 447e82b99953680915596eaf0eb35927388e574ca8Chris Banes 459925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes DrawableWrapperState mState; 469925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes private boolean mMutated; 479925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 487e82b99953680915596eaf0eb35927388e574ca8Chris Banes Drawable mDrawable; 497e82b99953680915596eaf0eb35927388e574ca8Chris Banes 509925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes DrawableWrapperDonut(@NonNull DrawableWrapperState state, @Nullable Resources res) { 519925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState = state; 529925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes updateLocalState(res); 539925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 54c3b9589f61cbfda8c60344a47f8f87c0ded98554Chris Banes 559925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes /** 569925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * Creates a new wrapper around the specified drawable. 579925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * 589925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * @param dr the drawable to wrap 599925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes */ 609925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes DrawableWrapperDonut(@Nullable Drawable dr) { 61ffbf42aa3acb41b82cc6c1226c63c3649bedfe49Chris Banes mState = mutateConstantState(); 62c3b9589f61cbfda8c60344a47f8f87c0ded98554Chris Banes // Now set the drawable... 63c3b9589f61cbfda8c60344a47f8f87c0ded98554Chris Banes setWrappedDrawable(dr); 649925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 659925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 669925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes /** 679925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * Initializes local dynamic properties from state. This should be called 689925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * after significant state changes, e.g. from the One True Constructor and 699925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * after inflating or applying a theme. 709925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes */ 719925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes private void updateLocalState(@Nullable Resources res) { 729925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (mState != null && mState.mDrawableState != null) { 739925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes final Drawable dr = newDrawableFromState(mState.mDrawableState, res); 749925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes setWrappedDrawable(dr); 759925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 769925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 779925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 789925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes /** 799925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * Allows us to call ConstantState.newDrawable(*) is a API safe way 809925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes */ 819925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes protected Drawable newDrawableFromState(@NonNull Drawable.ConstantState state, 829925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Nullable Resources res) { 839925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return state.newDrawable(); 847e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 857e82b99953680915596eaf0eb35927388e574ca8Chris Banes 867e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 877e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void draw(Canvas canvas) { 887e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.draw(canvas); 897e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 907e82b99953680915596eaf0eb35927388e574ca8Chris Banes 917e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 927e82b99953680915596eaf0eb35927388e574ca8Chris Banes protected void onBoundsChange(Rect bounds) { 93b1ba192200941f2a8c1eb2796c9fedc781bfe97fChris Banes if (mDrawable != null) { 94b1ba192200941f2a8c1eb2796c9fedc781bfe97fChris Banes mDrawable.setBounds(bounds); 95b1ba192200941f2a8c1eb2796c9fedc781bfe97fChris Banes } 967e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 977e82b99953680915596eaf0eb35927388e574ca8Chris Banes 987e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 997e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void setChangingConfigurations(int configs) { 1007e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setChangingConfigurations(configs); 1017e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1027e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1037e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1047e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getChangingConfigurations() { 1059925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return super.getChangingConfigurations() 1069925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes | (mState != null ? mState.getChangingConfigurations() : 0) 1079925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes | mDrawable.getChangingConfigurations(); 1087e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1097e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1107e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1117e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void setDither(boolean dither) { 1127e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setDither(dither); 1137e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1147e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1157e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1167e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void setFilterBitmap(boolean filter) { 1177e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setFilterBitmap(filter); 1187e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1197e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1207e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1217e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void setAlpha(int alpha) { 1227e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setAlpha(alpha); 1237e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1247e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1257e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1267e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void setColorFilter(ColorFilter cf) { 1277e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setColorFilter(cf); 1287e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1297e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1307e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1317e82b99953680915596eaf0eb35927388e574ca8Chris Banes public boolean isStateful() { 132ffbf42aa3acb41b82cc6c1226c63c3649bedfe49Chris Banes final ColorStateList tintList = (isCompatTintEnabled() && mState != null) 133ffbf42aa3acb41b82cc6c1226c63c3649bedfe49Chris Banes ? mState.mTint 134ffbf42aa3acb41b82cc6c1226c63c3649bedfe49Chris Banes : null; 1357797b9f22c8c404309b778a0966266d2b1a84915Chris Banes return (tintList != null && tintList.isStateful()) || mDrawable.isStateful(); 1367e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1377e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1387e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1397e82b99953680915596eaf0eb35927388e574ca8Chris Banes public boolean setState(final int[] stateSet) { 1407e82b99953680915596eaf0eb35927388e574ca8Chris Banes boolean handled = mDrawable.setState(stateSet); 1417e82b99953680915596eaf0eb35927388e574ca8Chris Banes handled = updateTint(stateSet) || handled; 1427e82b99953680915596eaf0eb35927388e574ca8Chris Banes return handled; 1437e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1447e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1457e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1467e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int[] getState() { 1477e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getState(); 1487e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1497e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1507e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1517e82b99953680915596eaf0eb35927388e574ca8Chris Banes public Drawable getCurrent() { 1527e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getCurrent(); 1537e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1547e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1557e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1567e82b99953680915596eaf0eb35927388e574ca8Chris Banes public boolean setVisible(boolean visible, boolean restart) { 1577e82b99953680915596eaf0eb35927388e574ca8Chris Banes return super.setVisible(visible, restart) || mDrawable.setVisible(visible, restart); 1587e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1597e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1607e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1617e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getOpacity() { 1627e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getOpacity(); 1637e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1647e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1657e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1667e82b99953680915596eaf0eb35927388e574ca8Chris Banes public Region getTransparentRegion() { 1677e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getTransparentRegion(); 1687e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1697e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1707e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1717e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getIntrinsicWidth() { 1727e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getIntrinsicWidth(); 1737e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1747e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1757e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1767e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getIntrinsicHeight() { 1777e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getIntrinsicHeight(); 1787e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1797e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1807e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1817e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getMinimumWidth() { 1827e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getMinimumWidth(); 1837e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1847e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1857e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1867e82b99953680915596eaf0eb35927388e574ca8Chris Banes public int getMinimumHeight() { 1877e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getMinimumHeight(); 1887e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1897e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1907e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1917e82b99953680915596eaf0eb35927388e574ca8Chris Banes public boolean getPadding(Rect padding) { 1927e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.getPadding(padding); 1937e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 1947e82b99953680915596eaf0eb35927388e574ca8Chris Banes 1957e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 1969925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Nullable 1979925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes public ConstantState getConstantState() { 1989925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (mState != null && mState.canConstantState()) { 1999925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState.mChangingConfigurations = getChangingConfigurations(); 2009925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return mState; 2019925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 2029925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return null; 2039925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 2049925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 2059925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Override 2067e82b99953680915596eaf0eb35927388e574ca8Chris Banes public Drawable mutate() { 2079925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (!mMutated && super.mutate() == this) { 2089925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState = mutateConstantState(); 2099925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (mDrawable != null) { 2109925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mDrawable.mutate(); 2119925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 2129925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (mState != null) { 2139925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState.mDrawableState = mDrawable != null ? mDrawable.getConstantState() : null; 2149925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 2159925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mMutated = true; 2167e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2177e82b99953680915596eaf0eb35927388e574ca8Chris Banes return this; 2187e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2197e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2207e82b99953680915596eaf0eb35927388e574ca8Chris Banes /** 2219925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * Mutates the constant state and returns the new state. 2229925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * <p> 2239925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * This method should never call the super implementation; it should always 2249925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * mutate and return its own constant state. 2259925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * 2269925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes * @return the new state 2279925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes */ 2284da36b0dfa8436b197314094337fa3102fcca1bcChris Banes @NonNull 2299925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes DrawableWrapperState mutateConstantState() { 2309925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return new DrawableWrapperStateDonut(mState, null); 2319925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 2329925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 2339925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes /** 2347e82b99953680915596eaf0eb35927388e574ca8Chris Banes * {@inheritDoc} 2357e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 2367e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void invalidateDrawable(Drawable who) { 2377e82b99953680915596eaf0eb35927388e574ca8Chris Banes invalidateSelf(); 2387e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2397e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2407e82b99953680915596eaf0eb35927388e574ca8Chris Banes /** 2417e82b99953680915596eaf0eb35927388e574ca8Chris Banes * {@inheritDoc} 2427e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 2437e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void scheduleDrawable(Drawable who, Runnable what, long when) { 2447e82b99953680915596eaf0eb35927388e574ca8Chris Banes scheduleSelf(what, when); 2457e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2467e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2477e82b99953680915596eaf0eb35927388e574ca8Chris Banes /** 2487e82b99953680915596eaf0eb35927388e574ca8Chris Banes * {@inheritDoc} 2497e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 2507e82b99953680915596eaf0eb35927388e574ca8Chris Banes public void unscheduleDrawable(Drawable who, Runnable what) { 2517e82b99953680915596eaf0eb35927388e574ca8Chris Banes unscheduleSelf(what); 2527e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2537e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2547e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 2557e82b99953680915596eaf0eb35927388e574ca8Chris Banes protected boolean onLevelChange(int level) { 2567e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable.setLevel(level); 2577e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2587e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2597e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 260be678137d44778590a6220ae0ef13649e83363a9Chris Banes public void setTint(int tint) { 261be678137d44778590a6220ae0ef13649e83363a9Chris Banes setTintList(ColorStateList.valueOf(tint)); 2627e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2637e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2647e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 265be678137d44778590a6220ae0ef13649e83363a9Chris Banes public void setTintList(ColorStateList tint) { 2669925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState.mTint = tint; 2679925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes updateTint(getState()); 2687e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2697e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2707e82b99953680915596eaf0eb35927388e574ca8Chris Banes @Override 271be678137d44778590a6220ae0ef13649e83363a9Chris Banes public void setTintMode(PorterDuff.Mode tintMode) { 2729925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState.mTintMode = tintMode; 2739925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes updateTint(getState()); 2747e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2757e82b99953680915596eaf0eb35927388e574ca8Chris Banes 2767e82b99953680915596eaf0eb35927388e574ca8Chris Banes private boolean updateTint(int[] state) { 2777797b9f22c8c404309b778a0966266d2b1a84915Chris Banes if (!isCompatTintEnabled()) { 2787797b9f22c8c404309b778a0966266d2b1a84915Chris Banes // If compat tinting is not enabled, fail fast 2797797b9f22c8c404309b778a0966266d2b1a84915Chris Banes return false; 2807797b9f22c8c404309b778a0966266d2b1a84915Chris Banes } 2817797b9f22c8c404309b778a0966266d2b1a84915Chris Banes 2829925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes final ColorStateList tintList = mState.mTint; 2839925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes final PorterDuff.Mode tintMode = mState.mTintMode; 2849925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 2859925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (tintList != null && tintMode != null) { 2869925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes final int color = tintList.getColorForState(state, tintList.getDefaultColor()); 2879925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (!mColorFilterSet || color != mCurrentColor || tintMode != mCurrentMode) { 2889925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes setColorFilter(color, tintMode); 2897e82b99953680915596eaf0eb35927388e574ca8Chris Banes mCurrentColor = color; 2909925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mCurrentMode = tintMode; 291421affab4e0d1c631f759186f8b2975933c9b5a5Chris Banes mColorFilterSet = true; 2927e82b99953680915596eaf0eb35927388e574ca8Chris Banes return true; 2937e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 294c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes } else { 295421affab4e0d1c631f759186f8b2975933c9b5a5Chris Banes mColorFilterSet = false; 296c88bcc13910d9d1a0ddd077e7cb96f3d95bde76cChris Banes clearColorFilter(); 2977e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 2987e82b99953680915596eaf0eb35927388e574ca8Chris Banes return false; 2997e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 3007e82b99953680915596eaf0eb35927388e574ca8Chris Banes 3017e82b99953680915596eaf0eb35927388e574ca8Chris Banes /** 3027e82b99953680915596eaf0eb35927388e574ca8Chris Banes * Returns the wrapped {@link Drawable} 3037e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 304c3b9589f61cbfda8c60344a47f8f87c0ded98554Chris Banes public final Drawable getWrappedDrawable() { 3057e82b99953680915596eaf0eb35927388e574ca8Chris Banes return mDrawable; 3067e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 3077e82b99953680915596eaf0eb35927388e574ca8Chris Banes 3087e82b99953680915596eaf0eb35927388e574ca8Chris Banes /** 3097e82b99953680915596eaf0eb35927388e574ca8Chris Banes * Sets the current wrapped {@link Drawable} 3107e82b99953680915596eaf0eb35927388e574ca8Chris Banes */ 311c3b9589f61cbfda8c60344a47f8f87c0ded98554Chris Banes public final void setWrappedDrawable(Drawable dr) { 3127e82b99953680915596eaf0eb35927388e574ca8Chris Banes if (mDrawable != null) { 3137e82b99953680915596eaf0eb35927388e574ca8Chris Banes mDrawable.setCallback(null); 3147e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 3157e82b99953680915596eaf0eb35927388e574ca8Chris Banes 3169925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mDrawable = dr; 3179925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3189925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (dr != null) { 3199925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes dr.setCallback(this); 3209925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes // Only call setters for data that's stored in the base Drawable. 3219925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes dr.setVisible(isVisible(), true); 3229925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes dr.setState(getState()); 3239925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes dr.setLevel(getLevel()); 3249925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes dr.setBounds(getBounds()); 3259925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (mState != null) { 3269925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mState.mDrawableState = dr.getConstantState(); 3279925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3287e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 329ac54e3ed316c378f9f339b88811613feb176e75dChris Banes 3307e82b99953680915596eaf0eb35927388e574ca8Chris Banes invalidateSelf(); 3317e82b99953680915596eaf0eb35927388e574ca8Chris Banes } 3327797b9f22c8c404309b778a0966266d2b1a84915Chris Banes 3337797b9f22c8c404309b778a0966266d2b1a84915Chris Banes protected boolean isCompatTintEnabled() { 3347797b9f22c8c404309b778a0966266d2b1a84915Chris Banes // It's enabled by default on Donut 3357797b9f22c8c404309b778a0966266d2b1a84915Chris Banes return true; 3367797b9f22c8c404309b778a0966266d2b1a84915Chris Banes } 3379925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3389925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes protected static abstract class DrawableWrapperState extends Drawable.ConstantState { 3399925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes int mChangingConfigurations; 3409925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes Drawable.ConstantState mDrawableState; 3419925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3429925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes ColorStateList mTint = null; 3439925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE; 3449925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3459925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes DrawableWrapperState(@Nullable DrawableWrapperState orig, @Nullable Resources res) { 3469925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes if (orig != null) { 3479925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mChangingConfigurations = orig.mChangingConfigurations; 3489925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mDrawableState = orig.mDrawableState; 3499925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mTint = orig.mTint; 3509925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes mTintMode = orig.mTintMode; 3519925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3529925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3539925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3549925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Override 3559925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes public Drawable newDrawable() { 3569925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return newDrawable(null); 3579925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3589925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3599925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes public abstract Drawable newDrawable(@Nullable Resources res); 3609925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3619925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Override 3629925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes public int getChangingConfigurations() { 3639925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return mChangingConfigurations 3649925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes | (mDrawableState != null ? mDrawableState.getChangingConfigurations() : 0); 3659925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3669925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3679925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes boolean canConstantState() { 3689925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return mDrawableState != null; 3699925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3709925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3719925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3729925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes private static class DrawableWrapperStateDonut extends DrawableWrapperState { 3739925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes DrawableWrapperStateDonut( 3749925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Nullable DrawableWrapperState orig, @Nullable Resources res) { 3759925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes super(orig, res); 3769925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3779925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes 3789925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes @Override 3799925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes public Drawable newDrawable(@Nullable Resources res) { 3809925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes return new DrawableWrapperDonut(this, res); 3819925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3829925d4a53e0dbaacf07901fb48907fe1aff9bbbdChris Banes } 3837e82b99953680915596eaf0eb35927388e574ca8Chris Banes} 384