1091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes/* 2091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * Copyright (C) 2015 The Android Open Source Project 3091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * 4091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 5091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * you may not use this file except in compliance with the License. 6091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * You may obtain a copy of the License at 7091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * 8091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * http://www.apache.org/licenses/LICENSE-2.0 9091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * 10091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * Unless required by applicable law or agreed to in writing, software 11091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * distributed under the License is distributed on an "AS IS" BASIS, 12091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * See the License for the specific language governing permissions and 14091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes * limitations under the License. 15091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes */ 16091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 17091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banespackage android.support.v7.widget; 18091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 19091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.content.res.ColorStateList; 20091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.graphics.PorterDuff; 21091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.graphics.drawable.Drawable; 22483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banesimport android.os.Build; 23483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banesimport android.support.annotation.NonNull; 24091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.v4.view.ViewCompat; 25091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.support.v7.appcompat.R; 26091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.util.AttributeSet; 27091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesimport android.view.View; 28091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 29091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banesclass AppCompatBackgroundHelper { 30091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 31091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes private final View mView; 327e4e8b664820f773bc96e37ee1d2bbf500d64e69Chris Banes private final AppCompatDrawableManager mDrawableManager; 33091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 34c3fa0c344f27c192cf69c5f608d5dc7073a4dfb8Chris Banes private int mBackgroundResId = -1; 35c3fa0c344f27c192cf69c5f608d5dc7073a4dfb8Chris Banes 36f39fda5f5a43ca50ea942da561cbe4eb9a93be8aChris Banes private TintInfo mInternalBackgroundTint; 37f39fda5f5a43ca50ea942da561cbe4eb9a93be8aChris Banes private TintInfo mBackgroundTint; 38f39fda5f5a43ca50ea942da561cbe4eb9a93be8aChris Banes private TintInfo mTmpInfo; 39091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 404c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes AppCompatBackgroundHelper(View view) { 41091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mView = view; 424c99f0e29b0926d8e5de44b7e3980d47f052f04cChris Banes mDrawableManager = AppCompatDrawableManager.get(); 43091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 44091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 45091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void loadFromAttributes(AttributeSet attrs, int defStyleAttr) { 469d5f84f33353a42e837c6b465412d1a6f2fc6eaaChris Banes TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), attrs, 47091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes R.styleable.ViewBackgroundHelper, defStyleAttr, 0); 48091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes try { 49091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (a.hasValue(R.styleable.ViewBackgroundHelper_android_background)) { 50c3fa0c344f27c192cf69c5f608d5dc7073a4dfb8Chris Banes mBackgroundResId = a.getResourceId( 51c3fa0c344f27c192cf69c5f608d5dc7073a4dfb8Chris Banes R.styleable.ViewBackgroundHelper_android_background, -1); 52c3fa0c344f27c192cf69c5f608d5dc7073a4dfb8Chris Banes ColorStateList tint = mDrawableManager 53c3fa0c344f27c192cf69c5f608d5dc7073a4dfb8Chris Banes .getTintList(mView.getContext(), mBackgroundResId); 54091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (tint != null) { 55091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes setInternalBackgroundTint(tint); 56091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 57091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 58091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (a.hasValue(R.styleable.ViewBackgroundHelper_backgroundTint)) { 59091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes ViewCompat.setBackgroundTintList(mView, 60091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes a.getColorStateList(R.styleable.ViewBackgroundHelper_backgroundTint)); 61091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 62091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (a.hasValue(R.styleable.ViewBackgroundHelper_backgroundTintMode)) { 63091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes ViewCompat.setBackgroundTintMode(mView, 64091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes DrawableUtils.parseTintMode( 65091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes a.getInt(R.styleable.ViewBackgroundHelper_backgroundTintMode, -1), 66091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes null)); 67091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 68091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } finally { 69091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes a.recycle(); 70091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 71091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 72091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 73091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void onSetBackgroundResource(int resId) { 74c3fa0c344f27c192cf69c5f608d5dc7073a4dfb8Chris Banes mBackgroundResId = resId; 75091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes // Update the default background tint 767e4e8b664820f773bc96e37ee1d2bbf500d64e69Chris Banes setInternalBackgroundTint(mDrawableManager != null 777e4e8b664820f773bc96e37ee1d2bbf500d64e69Chris Banes ? mDrawableManager.getTintList(mView.getContext(), resId) 787e4e8b664820f773bc96e37ee1d2bbf500d64e69Chris Banes : null); 79f39fda5f5a43ca50ea942da561cbe4eb9a93be8aChris Banes applySupportBackgroundTint(); 80091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 81091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 82091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void onSetBackgroundDrawable(Drawable background) { 83c3fa0c344f27c192cf69c5f608d5dc7073a4dfb8Chris Banes mBackgroundResId = -1; 84091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes // We don't know that this drawable is, so we need to clear the default background tint 85091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes setInternalBackgroundTint(null); 86f39fda5f5a43ca50ea942da561cbe4eb9a93be8aChris Banes applySupportBackgroundTint(); 87091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 88091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 89091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void setSupportBackgroundTintList(ColorStateList tint) { 90091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (mBackgroundTint == null) { 91f39fda5f5a43ca50ea942da561cbe4eb9a93be8aChris Banes mBackgroundTint = new TintInfo(); 92091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 93f39fda5f5a43ca50ea942da561cbe4eb9a93be8aChris Banes mBackgroundTint.mTintList = tint; 94091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mBackgroundTint.mHasTintList = true; 95f39fda5f5a43ca50ea942da561cbe4eb9a93be8aChris Banes applySupportBackgroundTint(); 96091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 97091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 98091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes ColorStateList getSupportBackgroundTintList() { 99091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 100091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 101091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 102091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void setSupportBackgroundTintMode(PorterDuff.Mode tintMode) { 103091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (mBackgroundTint == null) { 104f39fda5f5a43ca50ea942da561cbe4eb9a93be8aChris Banes mBackgroundTint = new TintInfo(); 105091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 106091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mBackgroundTint.mTintMode = tintMode; 107091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mBackgroundTint.mHasTintMode = true; 108091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 109091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes applySupportBackgroundTint(); 110091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 111091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 112091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes PorterDuff.Mode getSupportBackgroundTintMode() { 113091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes return mBackgroundTint != null ? mBackgroundTint.mTintMode : null; 114091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 115091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 116091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void applySupportBackgroundTint() { 117f7b73431b366b76bcf58536b7b1086489e4683b2Chris Banes final Drawable background = mView.getBackground(); 118f7b73431b366b76bcf58536b7b1086489e4683b2Chris Banes if (background != null) { 1191cd642752286e1fba44d8ec87e9793f116a22240Chris Banes if (shouldApplyFrameworkTintUsingColorFilter() 1201cd642752286e1fba44d8ec87e9793f116a22240Chris Banes && applyFrameworkTintUsingColorFilter(background)) { 1211cd642752286e1fba44d8ec87e9793f116a22240Chris Banes // This needs to be called before the internal tints below so it takes 122779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes // effect on any widgets using the compat tint on API 21 (EditText) 123779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes return; 124779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes } 125779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes 126091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (mBackgroundTint != null) { 127779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes AppCompatDrawableManager.tintDrawable(background, mBackgroundTint, 128779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes mView.getDrawableState()); 129091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } else if (mInternalBackgroundTint != null) { 1307e4e8b664820f773bc96e37ee1d2bbf500d64e69Chris Banes AppCompatDrawableManager.tintDrawable(background, mInternalBackgroundTint, 131f7b73431b366b76bcf58536b7b1086489e4683b2Chris Banes mView.getDrawableState()); 132091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 133091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 134091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 135091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes 136091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes void setInternalBackgroundTint(ColorStateList tint) { 137091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (tint != null) { 138091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes if (mInternalBackgroundTint == null) { 139f39fda5f5a43ca50ea942da561cbe4eb9a93be8aChris Banes mInternalBackgroundTint = new TintInfo(); 140091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 141091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mInternalBackgroundTint.mTintList = tint; 142091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mInternalBackgroundTint.mHasTintList = true; 143091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } else { 144091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes mInternalBackgroundTint = null; 145091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 146091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes applySupportBackgroundTint(); 147091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes } 148483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes 1491cd642752286e1fba44d8ec87e9793f116a22240Chris Banes private boolean shouldApplyFrameworkTintUsingColorFilter() { 1501cd642752286e1fba44d8ec87e9793f116a22240Chris Banes final int sdk = Build.VERSION.SDK_INT; 15129def828b59307ae6bfec1e5da8c44b7e651ddcfKirill Grouchnikov if (sdk > 21) { 15229def828b59307ae6bfec1e5da8c44b7e651ddcfKirill Grouchnikov // On API 22+, if we're using an internal compat background tint, we're also 15329def828b59307ae6bfec1e5da8c44b7e651ddcfKirill Grouchnikov // responsible for applying any custom tint set via the framework impl 15429def828b59307ae6bfec1e5da8c44b7e651ddcfKirill Grouchnikov return mInternalBackgroundTint != null; 1551cd642752286e1fba44d8ec87e9793f116a22240Chris Banes } else if (sdk == 21) { 1561cd642752286e1fba44d8ec87e9793f116a22240Chris Banes // GradientDrawable doesn't implement setTintList on API 21, and since there is 1571cd642752286e1fba44d8ec87e9793f116a22240Chris Banes // no nice way to unwrap DrawableContainers we have to blanket apply this 1581cd642752286e1fba44d8ec87e9793f116a22240Chris Banes // on API 21 1591cd642752286e1fba44d8ec87e9793f116a22240Chris Banes return true; 1601cd642752286e1fba44d8ec87e9793f116a22240Chris Banes } else { 16129def828b59307ae6bfec1e5da8c44b7e651ddcfKirill Grouchnikov // API 19 and below doesn't have framework tint 16229def828b59307ae6bfec1e5da8c44b7e651ddcfKirill Grouchnikov return false; 1631cd642752286e1fba44d8ec87e9793f116a22240Chris Banes } 1641cd642752286e1fba44d8ec87e9793f116a22240Chris Banes } 1651cd642752286e1fba44d8ec87e9793f116a22240Chris Banes 166779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes /** 167779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes * Applies the framework background tint to a view, but using the compat method (ColorFilter) 168779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes * 169779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes * @return true if a tint was applied 170779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes */ 171779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes private boolean applyFrameworkTintUsingColorFilter(@NonNull Drawable background) { 172483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes if (mTmpInfo == null) { 173f39fda5f5a43ca50ea942da561cbe4eb9a93be8aChris Banes mTmpInfo = new TintInfo(); 174483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes } 175483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes final TintInfo info = mTmpInfo; 176483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes info.clear(); 177483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes 178483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes final ColorStateList tintList = ViewCompat.getBackgroundTintList(mView); 179483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes if (tintList != null) { 180483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes info.mHasTintList = true; 181483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes info.mTintList = tintList; 182483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes } 183483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes final PorterDuff.Mode mode = ViewCompat.getBackgroundTintMode(mView); 184483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes if (mode != null) { 185483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes info.mHasTintMode = true; 186483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes info.mTintMode = mode; 187483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes } 188483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes 189483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes if (info.mHasTintList || info.mHasTintMode) { 190483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes AppCompatDrawableManager.tintDrawable(background, info, mView.getDrawableState()); 191779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes return true; 192483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes } 193779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes 194779bf4e0187ccc8601fbe9d37a5c0079a534733fChris Banes return false; 195483ee34ae7ef0cac94d60cbe32a945dae4cb2b21Chris Banes } 196091b0f935e68ce9bfecc2422e60eada33fa3b09cChris Banes} 197