TintManager.java revision fa91294114db5cfa43910d4d921fd06449192420
1469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes/* 2469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Copyright (C) 2014 The Android Open Source Project 3469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * 4469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Licensed under the Apache License, Version 2.0 (the "License"); 5469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * you may not use this file except in compliance with the License. 6469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * You may obtain a copy of the License at 7469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * 8469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * http://www.apache.org/licenses/LICENSE-2.0 9469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * 10469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Unless required by applicable law or agreed to in writing, software 11469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * distributed under the License is distributed on an "AS IS" BASIS, 12469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * See the License for the specific language governing permissions and 14469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * limitations under the License. 15469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 16469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 17469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banespackage android.support.v7.internal.widget; 18469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 19469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.content.Context; 20469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.content.res.ColorStateList; 21469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.graphics.PorterDuff; 22469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.graphics.PorterDuffColorFilter; 23469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.graphics.drawable.Drawable; 24cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banesimport android.graphics.drawable.LayerDrawable; 25fd1eb27a3700de31507de34fd1bcc51830fe876cChris Banesimport android.os.Build; 26469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v4.content.ContextCompat; 277e82b99953680915596eaf0eb35927388e574ca8Chris Banesimport android.support.v4.graphics.drawable.DrawableCompat; 28469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v4.util.LruCache; 29469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v7.appcompat.R; 30469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.util.Log; 3190075479814eb758d97b822606b448e1a521c298Chris Banesimport android.util.SparseArray; 32a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banesimport android.view.View; 33469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 34cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banesimport java.lang.ref.WeakReference; 35cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banesimport java.util.WeakHashMap; 36cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 372aeb0f4237bca35d7f650c3145354416306d4f7bChris Banesimport static android.support.v7.internal.widget.ThemeUtils.getDisabledThemeAttrColor; 382aeb0f4237bca35d7f650c3145354416306d4f7bChris Banesimport static android.support.v7.internal.widget.ThemeUtils.getThemeAttrColor; 392aeb0f4237bca35d7f650c3145354416306d4f7bChris Banesimport static android.support.v7.internal.widget.ThemeUtils.getThemeAttrColorStateList; 402aeb0f4237bca35d7f650c3145354416306d4f7bChris Banes 41469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes/** 42469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * @hide 43469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 44a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banespublic final class TintManager { 45469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 462cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banes public static final boolean SHOULD_BE_USED = Build.VERSION.SDK_INT < 21; 47fd1eb27a3700de31507de34fd1bcc51830fe876cChris Banes 48cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final String TAG = "TintManager"; 49469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static final boolean DEBUG = false; 50cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final PorterDuff.Mode DEFAULT_MODE = PorterDuff.Mode.SRC_IN; 51415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 52cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final WeakHashMap<Context, TintManager> INSTANCE_CACHE = new WeakHashMap<>(); 53469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static final ColorFilterLruCache COLOR_FILTER_CACHE = new ColorFilterLruCache(6); 54469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 55469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 56469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Drawables which should be tinted with the value of {@code R.attr.colorControlNormal}, 57cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * using the default mode using a raw color filter. 58cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes */ 59cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final int[] COLORFILTER_TINT_COLOR_CONTROL_NORMAL = { 60cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes R.drawable.abc_textfield_search_default_mtrl_alpha, 61cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes R.drawable.abc_textfield_default_mtrl_alpha, 62cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes R.drawable.abc_ab_share_pack_mtrl_alpha 63cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes }; 64cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 65cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes /** 66cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * Drawables which should be tinted with the value of {@code R.attr.colorControlNormal}, using 67cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * {@link DrawableCompat}'s tinting functionality. 68469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 69469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static final int[] TINT_COLOR_CONTROL_NORMAL = { 70469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_ab_back_mtrl_am_alpha, 71469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_go_search_api_mtrl_alpha, 72469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_search_api_mtrl_alpha, 73469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_commit_search_api_mtrl_alpha, 74469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_clear_mtrl_alpha, 75469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_menu_share_mtrl_alpha, 76b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes R.drawable.abc_ic_menu_copy_mtrl_am_alpha, 77b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes R.drawable.abc_ic_menu_cut_mtrl_alpha, 78b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes R.drawable.abc_ic_menu_selectall_mtrl_alpha, 79b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes R.drawable.abc_ic_menu_paste_mtrl_am_alpha, 80469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_menu_moreoverflow_mtrl_alpha, 81cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes R.drawable.abc_ic_voice_search_api_mtrl_alpha 82469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes }; 83469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 84469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 85469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Drawables which should be tinted with the value of {@code R.attr.colorControlActivated}, 86cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * using a color filter. 87469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 88cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final int[] COLORFILTER_COLOR_CONTROL_ACTIVATED = { 89469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_textfield_activated_mtrl_alpha, 9014f8f0dfae09445074dc0f7b5bbe5732d6922da7Chris Banes R.drawable.abc_textfield_search_activated_mtrl_alpha, 91911642499da7d796aa1e7c19178c3552a590f48bChris Banes R.drawable.abc_cab_background_top_mtrl_alpha, 92911642499da7d796aa1e7c19178c3552a590f48bChris Banes R.drawable.abc_text_cursor_mtrl_alpha 93469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes }; 94469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 95469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 96469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Drawables which should be tinted with the value of {@code android.R.attr.colorBackground}, 97cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * using the {@link android.graphics.PorterDuff.Mode#MULTIPLY} mode and a color filter. 98469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 99cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final int[] COLORFILTER_COLOR_BACKGROUND_MULTIPLY = { 1001073132946bb0a53a788949fe4c060f72051cd57Chris Banes R.drawable.abc_popup_background_mtrl_mult, 10157c6de90985a63358129b99b9f0cd4d6afe887d6Chris Banes R.drawable.abc_cab_background_internal_bg, 10257c6de90985a63358129b99b9f0cd4d6afe887d6Chris Banes R.drawable.abc_menu_hardkey_panel_mtrl_mult 103469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes }; 104469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 105469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 106469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Drawables which should be tinted using a state list containing values of 107469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * {@code R.attr.colorControlNormal} and {@code R.attr.colorControlActivated} 108469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 109469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static final int[] TINT_COLOR_CONTROL_STATE_LIST = { 110469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_edit_text_material, 111469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_tab_indicator_material, 112469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_textfield_search_material, 113415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.drawable.abc_spinner_mtrl_am_alpha, 114415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.drawable.abc_btn_check_material, 115f67cc46fd515df18c4b70dce9e5dcdd4e3245cd8Chris Banes R.drawable.abc_btn_radio_material, 116a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes R.drawable.abc_spinner_textfield_background_material, 11790075479814eb758d97b822606b448e1a521c298Chris Banes R.drawable.abc_ratingbar_full_material, 11890075479814eb758d97b822606b448e1a521c298Chris Banes R.drawable.abc_switch_track_mtrl_alpha, 11990075479814eb758d97b822606b448e1a521c298Chris Banes R.drawable.abc_switch_thumb_material, 12016e8d4dd91083260223c007c797e46bc8f631055Chris Banes R.drawable.abc_btn_default_mtrl_shape, 12116e8d4dd91083260223c007c797e46bc8f631055Chris Banes R.drawable.abc_btn_borderless_material 122469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes }; 123469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 124cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private final WeakReference<Context> mContextRef; 125cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private SparseArray<ColorStateList> mTintLists; 126469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private ColorStateList mDefaultColorStateList; 127469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 128469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 129cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * A helper method to get a {@link TintManager} and then call {@link #getDrawable(int)}. 130469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * This method should not be used routinely. 131469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 132469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes public static Drawable getDrawable(Context context, int resId) { 133b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes if (isInTintList(resId)) { 134cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return TintManager.get(context).getDrawable(resId); 135b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes } else { 136b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes return ContextCompat.getDrawable(context, resId); 137b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes } 138469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 139469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 140cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes /** 141cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * Get a {@link android.support.v7.internal.widget.TintManager} instance. 142cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes */ 143cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes public static TintManager get(Context context) { 144cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes TintManager tm = INSTANCE_CACHE.get(context); 145cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (tm == null) { 146cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tm = new TintManager(context); 147cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes INSTANCE_CACHE.put(context, tm); 148cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } 149cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return tm; 150911642499da7d796aa1e7c19178c3552a590f48bChris Banes } 151911642499da7d796aa1e7c19178c3552a590f48bChris Banes 152cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private TintManager(Context context) { 153cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes mContextRef = new WeakReference<>(context); 154469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 155469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 156469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes public Drawable getDrawable(int resId) { 157cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final Context context = mContextRef.get(); 158cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (context == null) return null; 159cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 160cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes Drawable drawable = ContextCompat.getDrawable(context, resId); 161469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 162469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes if (drawable != null) { 163fa91294114db5cfa43910d4d921fd06449192420Chris Banes if (Build.VERSION.SDK_INT >= 8) { 164fa91294114db5cfa43910d4d921fd06449192420Chris Banes // Mutate can cause NPEs on 2.1 165fa91294114db5cfa43910d4d921fd06449192420Chris Banes drawable = drawable.mutate(); 166fa91294114db5cfa43910d4d921fd06449192420Chris Banes } 167c7d6de1eb6692c627a02a4ed439a8a4b849ca66cChris Banes 168cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final ColorStateList tintList = getTintList(resId); 169cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (tintList != null) { 170cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // First wrap the Drawable and set the tint list 171cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes drawable = DrawableCompat.wrap(drawable); 172cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes DrawableCompat.setTintList(drawable, tintList); 173a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 174cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // If there is a blending mode specified for the drawable, use it 175cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final PorterDuff.Mode tintMode = getTintMode(resId); 176cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (tintMode != null) { 1777e82b99953680915596eaf0eb35927388e574ca8Chris Banes DrawableCompat.setTintMode(drawable, tintMode); 178a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 179cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } else if (resId == R.drawable.abc_cab_background_top_material) { 180cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return new LayerDrawable(new Drawable[] { 181cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes getDrawable(R.drawable.abc_cab_background_internal_bg), 182cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes getDrawable(R.drawable.abc_cab_background_top_mtrl_alpha) 183cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes }); 184469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } else { 185cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tintDrawableUsingColorFilter(resId, drawable); 186469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 187469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 188469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return drawable; 189469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 190469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 1912cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banes public final void tintDrawableUsingColorFilter(final int resId, Drawable drawable) { 192cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final Context context = mContextRef.get(); 193cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (context == null) return; 194cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 195469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes PorterDuff.Mode tintMode = null; 196469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes boolean colorAttrSet = false; 197469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes int colorAttr = 0; 1980517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes int alpha = -1; 199469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 200cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (arrayContains(COLORFILTER_TINT_COLOR_CONTROL_NORMAL, resId)) { 201469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttr = R.attr.colorControlNormal; 202469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttrSet = true; 203cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } else if (arrayContains(COLORFILTER_COLOR_CONTROL_ACTIVATED, resId)) { 204469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttr = R.attr.colorControlActivated; 205469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttrSet = true; 206cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } else if (arrayContains(COLORFILTER_COLOR_BACKGROUND_MULTIPLY, resId)) { 207469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttr = android.R.attr.colorBackground; 208469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttrSet = true; 209469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes tintMode = PorterDuff.Mode.MULTIPLY; 2100517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes } else if (resId == R.drawable.abc_list_divider_mtrl_alpha) { 2110517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes colorAttr = android.R.attr.colorForeground; 2120517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes colorAttrSet = true; 2130517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes alpha = Math.round(0.16f * 255); 214469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 215469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 216f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes if (colorAttrSet) { 217cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final int color = getThemeAttrColor(context, colorAttr); 218cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes setPorterDuffColorFilter(drawable, color, tintMode); 219469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 2200517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes if (alpha != -1) { 2210517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes drawable.setAlpha(alpha); 2220517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes } 2230517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes 224469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes if (DEBUG) { 225cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes Log.d(TAG, "Tinted Drawable: " + context.getResources().getResourceName(resId) + 226469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes " with color: #" + Integer.toHexString(color)); 227469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 228469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 229469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 230469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 231469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static boolean arrayContains(int[] array, int value) { 232469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes for (int id : array) { 233469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes if (id == value) { 234469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return true; 235469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 236469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 237469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return false; 238469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 239469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 240b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes private static boolean isInTintList(int drawableId) { 241cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return arrayContains(TINT_COLOR_CONTROL_NORMAL, drawableId) || 242cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes arrayContains(COLORFILTER_TINT_COLOR_CONTROL_NORMAL, drawableId) || 243cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes arrayContains(COLORFILTER_COLOR_CONTROL_ACTIVATED, drawableId) || 244b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes arrayContains(TINT_COLOR_CONTROL_STATE_LIST, drawableId) || 245cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes arrayContains(COLORFILTER_COLOR_BACKGROUND_MULTIPLY, drawableId) || 246cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes drawableId == R.drawable.abc_cab_background_top_material; 247b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes } 248b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes 249cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final PorterDuff.Mode getTintMode(final int resId) { 250cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes PorterDuff.Mode mode = null; 251cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 252cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (resId == R.drawable.abc_switch_thumb_material) { 253cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes mode = PorterDuff.Mode.MULTIPLY; 254cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } 255cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 256cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return mode; 257a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 258a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 2592cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banes public final ColorStateList getTintList(int resId) { 260cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final Context context = mContextRef.get(); 261cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (context == null) return null; 26290075479814eb758d97b822606b448e1a521c298Chris Banes 263cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // Try the cache first (if it exists) 264cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes ColorStateList tint = mTintLists != null ? mTintLists.get(resId) : null; 265cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 266cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (tint == null) { 267cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // ...if the cache did not contain a color state list, try and create one 26890075479814eb758d97b822606b448e1a521c298Chris Banes if (resId == R.drawable.abc_edit_text_material) { 269cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = createEditTextColorStateList(context); 27090075479814eb758d97b822606b448e1a521c298Chris Banes } else if (resId == R.drawable.abc_switch_track_mtrl_alpha) { 271cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = createSwitchTrackColorStateList(context); 27290075479814eb758d97b822606b448e1a521c298Chris Banes } else if (resId == R.drawable.abc_switch_thumb_material) { 273cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = createSwitchThumbColorStateList(context); 27416e8d4dd91083260223c007c797e46bc8f631055Chris Banes } else if (resId == R.drawable.abc_btn_default_mtrl_shape 27516e8d4dd91083260223c007c797e46bc8f631055Chris Banes || resId == R.drawable.abc_btn_borderless_material) { 276cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = createButtonColorStateList(context); 277cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes } else if (resId == R.drawable.abc_spinner_mtrl_am_alpha 278cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes || resId == R.drawable.abc_spinner_textfield_background_material) { 279cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = createSpinnerColorStateList(context); 280cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } else if (arrayContains(TINT_COLOR_CONTROL_NORMAL, resId)) { 281cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = getThemeAttrColorStateList(context, R.attr.colorControlNormal); 282cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } else if (arrayContains(TINT_COLOR_CONTROL_STATE_LIST, resId)) { 283cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = getDefaultColorStateList(context); 28490075479814eb758d97b822606b448e1a521c298Chris Banes } 285a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 286cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (tint != null) { 287cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (mTintLists == null) { 288cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // If our tint list cache hasn't been set up yet, create it 289cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes mTintLists = new SparseArray<>(); 290cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } 291cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // Add any newly created ColorStateList to the cache 292cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes mTintLists.append(resId, tint); 293cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } 29490075479814eb758d97b822606b448e1a521c298Chris Banes } 295cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return tint; 29690075479814eb758d97b822606b448e1a521c298Chris Banes } 29790075479814eb758d97b822606b448e1a521c298Chris Banes 298cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private ColorStateList getDefaultColorStateList(Context context) { 299469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes if (mDefaultColorStateList == null) { 300469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 301469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Generate the default color state list which uses the colorControl attributes. 302469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Order is important here. The default enabled state needs to go at the bottom. 303469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 304469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 305cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final int colorControlNormal = getThemeAttrColor(context, R.attr.colorControlNormal); 306cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final int colorControlActivated = getThemeAttrColor(context, 3072aeb0f4237bca35d7f650c3145354416306d4f7bChris Banes R.attr.colorControlActivated); 308469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 309469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes final int[][] states = new int[7][]; 310469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes final int[] colors = new int[7]; 311469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes int i = 0; 312469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 313c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes // Disabled state 314c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes states[i] = new int[] { -android.R.attr.state_enabled }; 315cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlNormal); 316469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 317469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 318c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes states[i] = new int[] { android.R.attr.state_focused }; 319469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colors[i] = colorControlActivated; 320469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 321469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 322c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes states[i] = new int[] { android.R.attr.state_activated }; 323469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colors[i] = colorControlActivated; 324469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 325469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 326c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes states[i] = new int[] { android.R.attr.state_pressed }; 327469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colors[i] = colorControlActivated; 328469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 329469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 330c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes states[i] = new int[] { android.R.attr.state_checked }; 331469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colors[i] = colorControlActivated; 332469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 333469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 334c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes states[i] = new int[] { android.R.attr.state_selected }; 335c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes colors[i] = colorControlActivated; 336469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 337469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 338c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes // Default enabled state 339469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes states[i] = new int[0]; 340c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes colors[i] = colorControlNormal; 341469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 342469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 343469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes mDefaultColorStateList = new ColorStateList(states, colors); 344469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 345469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return mDefaultColorStateList; 346469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 347469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 348cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private ColorStateList createSwitchTrackColorStateList(Context context) { 34990075479814eb758d97b822606b448e1a521c298Chris Banes final int[][] states = new int[3][]; 35090075479814eb758d97b822606b448e1a521c298Chris Banes final int[] colors = new int[3]; 35190075479814eb758d97b822606b448e1a521c298Chris Banes int i = 0; 352415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 35390075479814eb758d97b822606b448e1a521c298Chris Banes // Disabled state 35490075479814eb758d97b822606b448e1a521c298Chris Banes states[i] = new int[]{-android.R.attr.state_enabled}; 355cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, android.R.attr.colorForeground, 0.1f); 35690075479814eb758d97b822606b448e1a521c298Chris Banes i++; 357415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 35890075479814eb758d97b822606b448e1a521c298Chris Banes states[i] = new int[]{android.R.attr.state_checked}; 359cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated, 0.3f); 36090075479814eb758d97b822606b448e1a521c298Chris Banes i++; 361415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 36290075479814eb758d97b822606b448e1a521c298Chris Banes // Default enabled state 36390075479814eb758d97b822606b448e1a521c298Chris Banes states[i] = new int[0]; 364cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, android.R.attr.colorForeground, 0.3f); 36590075479814eb758d97b822606b448e1a521c298Chris Banes i++; 366415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 36790075479814eb758d97b822606b448e1a521c298Chris Banes return new ColorStateList(states, colors); 368415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 369415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 370cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private ColorStateList createSwitchThumbColorStateList(Context context) { 37190075479814eb758d97b822606b448e1a521c298Chris Banes final int[][] states = new int[3][]; 37290075479814eb758d97b822606b448e1a521c298Chris Banes final int[] colors = new int[3]; 37390075479814eb758d97b822606b448e1a521c298Chris Banes int i = 0; 374415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 375cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final ColorStateList thumbColor = getThemeAttrColorStateList(context, 3762aeb0f4237bca35d7f650c3145354416306d4f7bChris Banes R.attr.colorSwitchThumbNormal); 377415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 378414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbColor != null && thumbColor.isStateful()) { 379414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // If colorSwitchThumbNormal is a valid ColorStateList, extract the default and 380414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // disabled colors from it 381415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 382414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // Disabled state 383414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes states[i] = new int[]{-android.R.attr.state_enabled}; 384414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes colors[i] = thumbColor.getColorForState(states[i], 0); 385414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 386414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 387414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes states[i] = new int[]{android.R.attr.state_checked}; 388cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated); 389414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 390414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 391414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // Default enabled state 392414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes states[i] = new int[0]; 393414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes colors[i] = thumbColor.getDefaultColor(); 394414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 395414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } else { 396414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // Else we'll use an approximation using the default disabled alpha 397414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 398414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // Disabled state 399414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes states[i] = new int[]{-android.R.attr.state_enabled}; 400cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getDisabledThemeAttrColor(context, R.attr.colorSwitchThumbNormal); 401414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 402414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 403414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes states[i] = new int[]{android.R.attr.state_checked}; 404cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated); 405414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 406414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 407414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // Default enabled state 408414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes states[i] = new int[0]; 409cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorSwitchThumbNormal); 410414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 411414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 412415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 41390075479814eb758d97b822606b448e1a521c298Chris Banes return new ColorStateList(states, colors); 414415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 415415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 416cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private ColorStateList createEditTextColorStateList(Context context) { 41790075479814eb758d97b822606b448e1a521c298Chris Banes final int[][] states = new int[3][]; 41890075479814eb758d97b822606b448e1a521c298Chris Banes final int[] colors = new int[3]; 41990075479814eb758d97b822606b448e1a521c298Chris Banes int i = 0; 420a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 42190075479814eb758d97b822606b448e1a521c298Chris Banes // Disabled state 42290075479814eb758d97b822606b448e1a521c298Chris Banes states[i] = new int[]{-android.R.attr.state_enabled}; 423cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlNormal); 42490075479814eb758d97b822606b448e1a521c298Chris Banes i++; 425a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 42690075479814eb758d97b822606b448e1a521c298Chris Banes states[i] = new int[]{-android.R.attr.state_pressed, -android.R.attr.state_focused}; 427cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlNormal); 42890075479814eb758d97b822606b448e1a521c298Chris Banes i++; 429a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 43090075479814eb758d97b822606b448e1a521c298Chris Banes // Default enabled state 43190075479814eb758d97b822606b448e1a521c298Chris Banes states[i] = new int[0]; 432cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated); 43390075479814eb758d97b822606b448e1a521c298Chris Banes i++; 434a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 43590075479814eb758d97b822606b448e1a521c298Chris Banes return new ColorStateList(states, colors); 43690075479814eb758d97b822606b448e1a521c298Chris Banes } 437a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 438cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private ColorStateList createButtonColorStateList(Context context) { 43990075479814eb758d97b822606b448e1a521c298Chris Banes final int[][] states = new int[4][]; 44090075479814eb758d97b822606b448e1a521c298Chris Banes final int[] colors = new int[4]; 44190075479814eb758d97b822606b448e1a521c298Chris Banes int i = 0; 44290075479814eb758d97b822606b448e1a521c298Chris Banes 44390075479814eb758d97b822606b448e1a521c298Chris Banes // Disabled state 44490075479814eb758d97b822606b448e1a521c298Chris Banes states[i] = new int[]{-android.R.attr.state_enabled}; 445cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getDisabledThemeAttrColor(context, R.attr.colorButtonNormal); 44690075479814eb758d97b822606b448e1a521c298Chris Banes i++; 44790075479814eb758d97b822606b448e1a521c298Chris Banes 44890075479814eb758d97b822606b448e1a521c298Chris Banes states[i] = new int[]{android.R.attr.state_pressed}; 449cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlHighlight); 45090075479814eb758d97b822606b448e1a521c298Chris Banes i++; 45190075479814eb758d97b822606b448e1a521c298Chris Banes 45290075479814eb758d97b822606b448e1a521c298Chris Banes states[i] = new int[]{android.R.attr.state_focused}; 453cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlHighlight); 45490075479814eb758d97b822606b448e1a521c298Chris Banes i++; 45590075479814eb758d97b822606b448e1a521c298Chris Banes 45690075479814eb758d97b822606b448e1a521c298Chris Banes // Default enabled state 45790075479814eb758d97b822606b448e1a521c298Chris Banes states[i] = new int[0]; 458cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorButtonNormal); 45990075479814eb758d97b822606b448e1a521c298Chris Banes i++; 46090075479814eb758d97b822606b448e1a521c298Chris Banes 46190075479814eb758d97b822606b448e1a521c298Chris Banes return new ColorStateList(states, colors); 462a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes } 463a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 464cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private ColorStateList createSpinnerColorStateList(Context context) { 465cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes final int[][] states = new int[3][]; 466cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes final int[] colors = new int[3]; 467cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes int i = 0; 468cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes 469cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes // Disabled state 470cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes states[i] = new int[]{-android.R.attr.state_enabled}; 471cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlNormal); 472cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes i++; 473cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes 474cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes states[i] = new int[]{-android.R.attr.state_pressed, -android.R.attr.state_focused}; 475cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlNormal); 476cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes i++; 477cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes 478cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes states[i] = new int[0]; 479cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated); 480cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes i++; 481cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes 482cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes return new ColorStateList(states, colors); 483cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes } 484cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes 485469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static class ColorFilterLruCache extends LruCache<Integer, PorterDuffColorFilter> { 486469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 487469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes public ColorFilterLruCache(int maxSize) { 488469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes super(maxSize); 489469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 490469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 491469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes PorterDuffColorFilter get(int color, PorterDuff.Mode mode) { 492469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return get(generateCacheKey(color, mode)); 493469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 494469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 495469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes PorterDuffColorFilter put(int color, PorterDuff.Mode mode, PorterDuffColorFilter filter) { 496469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return put(generateCacheKey(color, mode), filter); 497469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 498469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 499469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static int generateCacheKey(int color, PorterDuff.Mode mode) { 500469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes int hashCode = 1; 501469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes hashCode = 31 * hashCode + color; 502469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes hashCode = 31 * hashCode + mode.hashCode(); 503469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return hashCode; 504469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 505469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 506a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 507a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes public static void tintViewBackground(View view, TintInfo tint) { 508a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes final Drawable background = view.getBackground(); 5092cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banes if (tint.mHasTintList) { 510cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes setPorterDuffColorFilter( 511a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes background, 512a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes tint.mTintList.getColorForState(view.getDrawableState(), 513a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes tint.mTintList.getDefaultColor()), 5142cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banes tint.mHasTintMode ? tint.mTintMode : null); 515a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } else { 516a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes background.clearColorFilter(); 517a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 518a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 519a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 520cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static void setPorterDuffColorFilter(Drawable d, int color, PorterDuff.Mode mode) { 521cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (mode == null) { 522cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // If we don't have a blending mode specified, use our default 523cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes mode = DEFAULT_MODE; 524cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } 525cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 526a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes // First, lets see if the cache already contains the color filter 527a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode); 528a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 529a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes if (filter == null) { 530a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes // Cache miss, so create a color filter and add it to the cache 531a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes filter = new PorterDuffColorFilter(color, mode); 532a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes COLOR_FILTER_CACHE.put(color, mode, filter); 533a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 534a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 535cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes d.setColorFilter(filter); 536a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 537469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes} 538