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; 2139cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banesimport android.graphics.Color; 22469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.graphics.PorterDuff; 23469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.graphics.PorterDuffColorFilter; 24469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.graphics.drawable.Drawable; 25cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banesimport android.graphics.drawable.LayerDrawable; 26fd1eb27a3700de31507de34fd1bcc51830fe876cChris Banesimport android.os.Build; 27469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v4.content.ContextCompat; 28eb0d0c030a15e93f456cc1403fffb909c0ae4e66Chris Banesimport android.support.v4.graphics.ColorUtils; 297e82b99953680915596eaf0eb35927388e574ca8Chris Banesimport android.support.v4.graphics.drawable.DrawableCompat; 30469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v4.util.LruCache; 31469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v7.appcompat.R; 32469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.util.Log; 3390075479814eb758d97b822606b448e1a521c298Chris Banesimport android.util.SparseArray; 34a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banesimport android.view.View; 35469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 36cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banesimport java.lang.ref.WeakReference; 37cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banesimport java.util.WeakHashMap; 38cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 392aeb0f4237bca35d7f650c3145354416306d4f7bChris Banesimport static android.support.v7.internal.widget.ThemeUtils.getDisabledThemeAttrColor; 402aeb0f4237bca35d7f650c3145354416306d4f7bChris Banesimport static android.support.v7.internal.widget.ThemeUtils.getThemeAttrColor; 412aeb0f4237bca35d7f650c3145354416306d4f7bChris Banesimport static android.support.v7.internal.widget.ThemeUtils.getThemeAttrColorStateList; 422aeb0f4237bca35d7f650c3145354416306d4f7bChris Banes 43469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes/** 44469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * @hide 45469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 46a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banespublic final class TintManager { 47469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 482cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banes public static final boolean SHOULD_BE_USED = Build.VERSION.SDK_INT < 21; 49fd1eb27a3700de31507de34fd1bcc51830fe876cChris Banes 50cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final String TAG = "TintManager"; 51469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static final boolean DEBUG = false; 52cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final PorterDuff.Mode DEFAULT_MODE = PorterDuff.Mode.SRC_IN; 53415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 54cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final WeakHashMap<Context, TintManager> INSTANCE_CACHE = new WeakHashMap<>(); 55469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static final ColorFilterLruCache COLOR_FILTER_CACHE = new ColorFilterLruCache(6); 56469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 57469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 58469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Drawables which should be tinted with the value of {@code R.attr.colorControlNormal}, 59cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * using the default mode using a raw color filter. 60cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes */ 61cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final int[] COLORFILTER_TINT_COLOR_CONTROL_NORMAL = { 62cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes R.drawable.abc_textfield_search_default_mtrl_alpha, 63cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes R.drawable.abc_textfield_default_mtrl_alpha, 64cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes R.drawable.abc_ab_share_pack_mtrl_alpha 65cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes }; 66cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 67cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes /** 68cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * Drawables which should be tinted with the value of {@code R.attr.colorControlNormal}, using 69cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * {@link DrawableCompat}'s tinting functionality. 70469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 71469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static final int[] TINT_COLOR_CONTROL_NORMAL = { 72469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_ab_back_mtrl_am_alpha, 73469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_go_search_api_mtrl_alpha, 74469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_search_api_mtrl_alpha, 75469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_commit_search_api_mtrl_alpha, 76469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_clear_mtrl_alpha, 77469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_menu_share_mtrl_alpha, 78b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes R.drawable.abc_ic_menu_copy_mtrl_am_alpha, 79b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes R.drawable.abc_ic_menu_cut_mtrl_alpha, 80b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes R.drawable.abc_ic_menu_selectall_mtrl_alpha, 81b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes R.drawable.abc_ic_menu_paste_mtrl_am_alpha, 82469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_ic_menu_moreoverflow_mtrl_alpha, 83cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes R.drawable.abc_ic_voice_search_api_mtrl_alpha 84469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes }; 85469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 86469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 87469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Drawables which should be tinted with the value of {@code R.attr.colorControlActivated}, 88cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * using a color filter. 89469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 90cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final int[] COLORFILTER_COLOR_CONTROL_ACTIVATED = { 91469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_textfield_activated_mtrl_alpha, 9214f8f0dfae09445074dc0f7b5bbe5732d6922da7Chris Banes R.drawable.abc_textfield_search_activated_mtrl_alpha, 93911642499da7d796aa1e7c19178c3552a590f48bChris Banes R.drawable.abc_cab_background_top_mtrl_alpha, 94f65da421a61773f1ce03550230dcd6f58cee54e9Chris Banes R.drawable.abc_text_cursor_material 95469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes }; 96469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 97469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 98469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Drawables which should be tinted with the value of {@code android.R.attr.colorBackground}, 99cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * using the {@link android.graphics.PorterDuff.Mode#MULTIPLY} mode and a color filter. 100469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 101cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private static final int[] COLORFILTER_COLOR_BACKGROUND_MULTIPLY = { 1021073132946bb0a53a788949fe4c060f72051cd57Chris Banes R.drawable.abc_popup_background_mtrl_mult, 10357c6de90985a63358129b99b9f0cd4d6afe887d6Chris Banes R.drawable.abc_cab_background_internal_bg, 10457c6de90985a63358129b99b9f0cd4d6afe887d6Chris Banes R.drawable.abc_menu_hardkey_panel_mtrl_mult 105469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes }; 106469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 107469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 108469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Drawables which should be tinted using a state list containing values of 109469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * {@code R.attr.colorControlNormal} and {@code R.attr.colorControlActivated} 110469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 111469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static final int[] TINT_COLOR_CONTROL_STATE_LIST = { 112469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_edit_text_material, 113469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_tab_indicator_material, 114469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes R.drawable.abc_textfield_search_material, 115415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes R.drawable.abc_spinner_mtrl_am_alpha, 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 1241752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes /** 1251752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes * Drawables which should be tinted using a state list containing values of 1261752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes * {@code R.attr.colorControlNormal} and {@code R.attr.colorControlActivated} for the checked 1271752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes * state. 1281752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes */ 1291752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes private static final int[] TINT_CHECKABLE_BUTTON_LIST = { 1301752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes R.drawable.abc_btn_check_material, 1311752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes R.drawable.abc_btn_radio_material 1321752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes }; 1331752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes 134cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private final WeakReference<Context> mContextRef; 135cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private SparseArray<ColorStateList> mTintLists; 136469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private ColorStateList mDefaultColorStateList; 137469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 138469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 139cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * A helper method to get a {@link TintManager} and then call {@link #getDrawable(int)}. 140469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * This method should not be used routinely. 141469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 142469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes public static Drawable getDrawable(Context context, int resId) { 143b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes if (isInTintList(resId)) { 144cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return TintManager.get(context).getDrawable(resId); 145b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes } else { 146b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes return ContextCompat.getDrawable(context, resId); 147b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes } 148469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 149469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 150cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes /** 151cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes * Get a {@link android.support.v7.internal.widget.TintManager} instance. 152cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes */ 153cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes public static TintManager get(Context context) { 154cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes TintManager tm = INSTANCE_CACHE.get(context); 155cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (tm == null) { 156cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tm = new TintManager(context); 157cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes INSTANCE_CACHE.put(context, tm); 158cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } 159cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return tm; 160911642499da7d796aa1e7c19178c3552a590f48bChris Banes } 161911642499da7d796aa1e7c19178c3552a590f48bChris Banes 162cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private TintManager(Context context) { 163cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes mContextRef = new WeakReference<>(context); 164469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 165469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 166469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes public Drawable getDrawable(int resId) { 1674ab820f4155444d20b37e105873775dd71907eefChris Banes return getDrawable(resId, false); 1684ab820f4155444d20b37e105873775dd71907eefChris Banes } 1694ab820f4155444d20b37e105873775dd71907eefChris Banes 1704ab820f4155444d20b37e105873775dd71907eefChris Banes public Drawable getDrawable(int resId, boolean failIfNotKnown) { 171cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final Context context = mContextRef.get(); 172cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (context == null) return null; 173cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 174cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes Drawable drawable = ContextCompat.getDrawable(context, resId); 175469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 176469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes if (drawable != null) { 177fa91294114db5cfa43910d4d921fd06449192420Chris Banes if (Build.VERSION.SDK_INT >= 8) { 178fa91294114db5cfa43910d4d921fd06449192420Chris Banes // Mutate can cause NPEs on 2.1 179fa91294114db5cfa43910d4d921fd06449192420Chris Banes drawable = drawable.mutate(); 180fa91294114db5cfa43910d4d921fd06449192420Chris Banes } 181c7d6de1eb6692c627a02a4ed439a8a4b849ca66cChris Banes 182cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final ColorStateList tintList = getTintList(resId); 183cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (tintList != null) { 184cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // First wrap the Drawable and set the tint list 185cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes drawable = DrawableCompat.wrap(drawable); 186cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes DrawableCompat.setTintList(drawable, tintList); 187a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 188cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // If there is a blending mode specified for the drawable, use it 189cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final PorterDuff.Mode tintMode = getTintMode(resId); 190cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (tintMode != null) { 1917e82b99953680915596eaf0eb35927388e574ca8Chris Banes DrawableCompat.setTintMode(drawable, tintMode); 192a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 193cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } else if (resId == R.drawable.abc_cab_background_top_material) { 194cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return new LayerDrawable(new Drawable[] { 195cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes getDrawable(R.drawable.abc_cab_background_internal_bg), 196cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes getDrawable(R.drawable.abc_cab_background_top_mtrl_alpha) 197cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes }); 198469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } else { 1994ab820f4155444d20b37e105873775dd71907eefChris Banes final boolean usedColorFilter = tintDrawableUsingColorFilter(resId, drawable); 2004ab820f4155444d20b37e105873775dd71907eefChris Banes if (!usedColorFilter && failIfNotKnown) { 2014ab820f4155444d20b37e105873775dd71907eefChris Banes // If we didn't tint using a ColorFilter, and we're set to fail if we don't 2024ab820f4155444d20b37e105873775dd71907eefChris Banes // know the id, return null 2034ab820f4155444d20b37e105873775dd71907eefChris Banes drawable = null; 2044ab820f4155444d20b37e105873775dd71907eefChris Banes } 205469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 206469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 207469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return drawable; 208469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 209469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 2104ab820f4155444d20b37e105873775dd71907eefChris Banes public final boolean tintDrawableUsingColorFilter(final int resId, Drawable drawable) { 211cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final Context context = mContextRef.get(); 2124ab820f4155444d20b37e105873775dd71907eefChris Banes if (context == null) return false; 213cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 21439cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes PorterDuff.Mode tintMode = DEFAULT_MODE; 215469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes boolean colorAttrSet = false; 216469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes int colorAttr = 0; 2170517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes int alpha = -1; 218469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 219cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (arrayContains(COLORFILTER_TINT_COLOR_CONTROL_NORMAL, resId)) { 220469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttr = R.attr.colorControlNormal; 221469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttrSet = true; 222cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } else if (arrayContains(COLORFILTER_COLOR_CONTROL_ACTIVATED, resId)) { 223469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttr = R.attr.colorControlActivated; 224469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttrSet = true; 225cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } else if (arrayContains(COLORFILTER_COLOR_BACKGROUND_MULTIPLY, resId)) { 226469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttr = android.R.attr.colorBackground; 227469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colorAttrSet = true; 228469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes tintMode = PorterDuff.Mode.MULTIPLY; 2290517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes } else if (resId == R.drawable.abc_list_divider_mtrl_alpha) { 2300517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes colorAttr = android.R.attr.colorForeground; 2310517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes colorAttrSet = true; 2320517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes alpha = Math.round(0.16f * 255); 233469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 234469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 235f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes if (colorAttrSet) { 236cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final int color = getThemeAttrColor(context, colorAttr); 23739cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes drawable.setColorFilter(getPorterDuffColorFilter(color, tintMode)); 238469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 2390517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes if (alpha != -1) { 2400517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes drawable.setAlpha(alpha); 2410517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes } 2420517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes 243469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes if (DEBUG) { 244cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes Log.d(TAG, "Tinted Drawable: " + context.getResources().getResourceName(resId) + 245469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes " with color: #" + Integer.toHexString(color)); 246469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 2474ab820f4155444d20b37e105873775dd71907eefChris Banes return true; 248469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 2494ab820f4155444d20b37e105873775dd71907eefChris Banes return false; 250469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 251469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 252469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static boolean arrayContains(int[] array, int value) { 253469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes for (int id : array) { 254469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes if (id == value) { 255469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return true; 256469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 257469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 258469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return false; 259469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 260469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 261b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes private static boolean isInTintList(int drawableId) { 262cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return arrayContains(TINT_COLOR_CONTROL_NORMAL, drawableId) || 263cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes arrayContains(COLORFILTER_TINT_COLOR_CONTROL_NORMAL, drawableId) || 264cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes arrayContains(COLORFILTER_COLOR_CONTROL_ACTIVATED, drawableId) || 265b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes arrayContains(TINT_COLOR_CONTROL_STATE_LIST, drawableId) || 266cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes arrayContains(COLORFILTER_COLOR_BACKGROUND_MULTIPLY, drawableId) || 2671752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes arrayContains(TINT_CHECKABLE_BUTTON_LIST, drawableId) || 268cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes drawableId == R.drawable.abc_cab_background_top_material; 269b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes } 270b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes 271cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final PorterDuff.Mode getTintMode(final int resId) { 272cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes PorterDuff.Mode mode = null; 273cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 274cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (resId == R.drawable.abc_switch_thumb_material) { 275cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes mode = PorterDuff.Mode.MULTIPLY; 276cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } 277cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 278cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return mode; 279a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 280a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 2812cccf609662389d6a23dbc0711d5fb2e826e8c63Chris Banes public final ColorStateList getTintList(int resId) { 282cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final Context context = mContextRef.get(); 283cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (context == null) return null; 28490075479814eb758d97b822606b448e1a521c298Chris Banes 285cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // Try the cache first (if it exists) 286cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes ColorStateList tint = mTintLists != null ? mTintLists.get(resId) : null; 287cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 288cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (tint == null) { 289cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // ...if the cache did not contain a color state list, try and create one 29090075479814eb758d97b822606b448e1a521c298Chris Banes if (resId == R.drawable.abc_edit_text_material) { 291cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = createEditTextColorStateList(context); 29290075479814eb758d97b822606b448e1a521c298Chris Banes } else if (resId == R.drawable.abc_switch_track_mtrl_alpha) { 293cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = createSwitchTrackColorStateList(context); 29490075479814eb758d97b822606b448e1a521c298Chris Banes } else if (resId == R.drawable.abc_switch_thumb_material) { 295cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = createSwitchThumbColorStateList(context); 29616e8d4dd91083260223c007c797e46bc8f631055Chris Banes } else if (resId == R.drawable.abc_btn_default_mtrl_shape 29716e8d4dd91083260223c007c797e46bc8f631055Chris Banes || resId == R.drawable.abc_btn_borderless_material) { 298b1131c6dfc9affe5751523f235878055cb699960Chris Banes tint = createDefaultButtonColorStateList(context); 299b1131c6dfc9affe5751523f235878055cb699960Chris Banes } else if (resId == R.drawable.abc_btn_colored_material) { 300b1131c6dfc9affe5751523f235878055cb699960Chris Banes tint = createColoredButtonColorStateList(context); 301cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes } else if (resId == R.drawable.abc_spinner_mtrl_am_alpha 302cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes || resId == R.drawable.abc_spinner_textfield_background_material) { 303cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = createSpinnerColorStateList(context); 304cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } else if (arrayContains(TINT_COLOR_CONTROL_NORMAL, resId)) { 305cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = getThemeAttrColorStateList(context, R.attr.colorControlNormal); 306cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } else if (arrayContains(TINT_COLOR_CONTROL_STATE_LIST, resId)) { 307cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes tint = getDefaultColorStateList(context); 3081752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes } else if (arrayContains(TINT_CHECKABLE_BUTTON_LIST, resId)) { 3091752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes tint = createCheckableButtonColorStateList(context); 31090075479814eb758d97b822606b448e1a521c298Chris Banes } 311a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 312cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (tint != null) { 313cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes if (mTintLists == null) { 314cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // If our tint list cache hasn't been set up yet, create it 315cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes mTintLists = new SparseArray<>(); 316cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } 317cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes // Add any newly created ColorStateList to the cache 318cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes mTintLists.append(resId, tint); 319cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } 32090075479814eb758d97b822606b448e1a521c298Chris Banes } 321cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes return tint; 32290075479814eb758d97b822606b448e1a521c298Chris Banes } 32390075479814eb758d97b822606b448e1a521c298Chris Banes 324cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private ColorStateList getDefaultColorStateList(Context context) { 325469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes if (mDefaultColorStateList == null) { 326469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes /** 327469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Generate the default color state list which uses the colorControl attributes. 328469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * Order is important here. The default enabled state needs to go at the bottom. 329469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */ 330469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 331cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final int colorControlNormal = getThemeAttrColor(context, R.attr.colorControlNormal); 332cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final int colorControlActivated = getThemeAttrColor(context, 3332aeb0f4237bca35d7f650c3145354416306d4f7bChris Banes R.attr.colorControlActivated); 334469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 335469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes final int[][] states = new int[7][]; 336469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes final int[] colors = new int[7]; 337469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes int i = 0; 338469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 339c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes // Disabled state 340bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.DISABLED_STATE_SET; 341cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlNormal); 342469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 343469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 344bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.FOCUSED_STATE_SET; 345469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colors[i] = colorControlActivated; 346469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 347469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 348bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.ACTIVATED_STATE_SET; 349469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colors[i] = colorControlActivated; 350469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 351469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 352bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.PRESSED_STATE_SET; 353469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colors[i] = colorControlActivated; 354469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 355469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 356bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.CHECKED_STATE_SET; 357469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes colors[i] = colorControlActivated; 358469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 359469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 360bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.SELECTED_STATE_SET; 361c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes colors[i] = colorControlActivated; 362469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 363469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 364c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes // Default enabled state 365bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.EMPTY_STATE_SET; 366c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes colors[i] = colorControlNormal; 367469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes i++; 368469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 369469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes mDefaultColorStateList = new ColorStateList(states, colors); 370469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 371469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return mDefaultColorStateList; 372469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 373469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 3741752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes private ColorStateList createCheckableButtonColorStateList(Context context) { 3751752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes final int[][] states = new int[3][]; 3761752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes final int[] colors = new int[3]; 3771752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes int i = 0; 3781752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes 3791752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes // Disabled state 3801752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes states[i] = ThemeUtils.DISABLED_STATE_SET; 3811752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlNormal); 3821752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes i++; 3831752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes 3841752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes states[i] = ThemeUtils.CHECKED_STATE_SET; 3851752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated); 3861752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes i++; 3871752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes 3881752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes // Default enabled state 3891752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes states[i] = ThemeUtils.EMPTY_STATE_SET; 3901752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlNormal); 3911752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes i++; 3921752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes 3931752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes return new ColorStateList(states, colors); 3941752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes } 3951752dfd10e8242d6e017b3828c7d6e94f044691cChris Banes 396cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private ColorStateList createSwitchTrackColorStateList(Context context) { 39790075479814eb758d97b822606b448e1a521c298Chris Banes final int[][] states = new int[3][]; 39890075479814eb758d97b822606b448e1a521c298Chris Banes final int[] colors = new int[3]; 39990075479814eb758d97b822606b448e1a521c298Chris Banes int i = 0; 400415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 40190075479814eb758d97b822606b448e1a521c298Chris Banes // Disabled state 402bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.DISABLED_STATE_SET; 403cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, android.R.attr.colorForeground, 0.1f); 40490075479814eb758d97b822606b448e1a521c298Chris Banes i++; 405415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 406bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.CHECKED_STATE_SET; 407cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated, 0.3f); 40890075479814eb758d97b822606b448e1a521c298Chris Banes i++; 409415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 41090075479814eb758d97b822606b448e1a521c298Chris Banes // Default enabled state 411bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.EMPTY_STATE_SET; 412cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, android.R.attr.colorForeground, 0.3f); 41390075479814eb758d97b822606b448e1a521c298Chris Banes i++; 414415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 41590075479814eb758d97b822606b448e1a521c298Chris Banes return new ColorStateList(states, colors); 416415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 417415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 418cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private ColorStateList createSwitchThumbColorStateList(Context context) { 41990075479814eb758d97b822606b448e1a521c298Chris Banes final int[][] states = new int[3][]; 42090075479814eb758d97b822606b448e1a521c298Chris Banes final int[] colors = new int[3]; 42190075479814eb758d97b822606b448e1a521c298Chris Banes int i = 0; 422415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 423cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes final ColorStateList thumbColor = getThemeAttrColorStateList(context, 4242aeb0f4237bca35d7f650c3145354416306d4f7bChris Banes R.attr.colorSwitchThumbNormal); 425415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 426414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes if (thumbColor != null && thumbColor.isStateful()) { 427414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // If colorSwitchThumbNormal is a valid ColorStateList, extract the default and 428414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // disabled colors from it 429415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 430414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // Disabled state 431bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.DISABLED_STATE_SET; 432414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes colors[i] = thumbColor.getColorForState(states[i], 0); 433414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 434414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 435bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.CHECKED_STATE_SET; 436cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated); 437414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 438414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 439414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // Default enabled state 440bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.EMPTY_STATE_SET; 441414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes colors[i] = thumbColor.getDefaultColor(); 442414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 443414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } else { 444414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // Else we'll use an approximation using the default disabled alpha 445414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 446414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // Disabled state 447bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.DISABLED_STATE_SET; 448cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getDisabledThemeAttrColor(context, R.attr.colorSwitchThumbNormal); 449414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 450414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 451bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.CHECKED_STATE_SET; 452cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated); 453414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 454414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes 455414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes // Default enabled state 456bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.EMPTY_STATE_SET; 457cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorSwitchThumbNormal); 458414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes i++; 459414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes } 460415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 46190075479814eb758d97b822606b448e1a521c298Chris Banes return new ColorStateList(states, colors); 462415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes } 463415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes 464cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private ColorStateList createEditTextColorStateList(Context context) { 46590075479814eb758d97b822606b448e1a521c298Chris Banes final int[][] states = new int[3][]; 46690075479814eb758d97b822606b448e1a521c298Chris Banes final int[] colors = new int[3]; 46790075479814eb758d97b822606b448e1a521c298Chris Banes int i = 0; 468a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 46990075479814eb758d97b822606b448e1a521c298Chris Banes // Disabled state 470bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.DISABLED_STATE_SET; 471cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlNormal); 47290075479814eb758d97b822606b448e1a521c298Chris Banes i++; 473a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 474bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.NOT_PRESSED_OR_FOCUSED_STATE_SET; 475cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlNormal); 47690075479814eb758d97b822606b448e1a521c298Chris Banes i++; 477a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 47890075479814eb758d97b822606b448e1a521c298Chris Banes // Default enabled state 479bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.EMPTY_STATE_SET; 480cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated); 48190075479814eb758d97b822606b448e1a521c298Chris Banes i++; 482a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 48390075479814eb758d97b822606b448e1a521c298Chris Banes return new ColorStateList(states, colors); 48490075479814eb758d97b822606b448e1a521c298Chris Banes } 485a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 486b1131c6dfc9affe5751523f235878055cb699960Chris Banes private ColorStateList createDefaultButtonColorStateList(Context context) { 487b1131c6dfc9affe5751523f235878055cb699960Chris Banes return createButtonColorStateList(context, R.attr.colorButtonNormal); 488b1131c6dfc9affe5751523f235878055cb699960Chris Banes } 489b1131c6dfc9affe5751523f235878055cb699960Chris Banes 490b1131c6dfc9affe5751523f235878055cb699960Chris Banes private ColorStateList createColoredButtonColorStateList(Context context) { 491b1131c6dfc9affe5751523f235878055cb699960Chris Banes return createButtonColorStateList(context, R.attr.colorAccent); 492b1131c6dfc9affe5751523f235878055cb699960Chris Banes } 493b1131c6dfc9affe5751523f235878055cb699960Chris Banes 494b1131c6dfc9affe5751523f235878055cb699960Chris Banes private ColorStateList createButtonColorStateList(Context context, int baseColorAttr) { 49590075479814eb758d97b822606b448e1a521c298Chris Banes final int[][] states = new int[4][]; 49690075479814eb758d97b822606b448e1a521c298Chris Banes final int[] colors = new int[4]; 49790075479814eb758d97b822606b448e1a521c298Chris Banes int i = 0; 49890075479814eb758d97b822606b448e1a521c298Chris Banes 499b1131c6dfc9affe5751523f235878055cb699960Chris Banes final int baseColor = getThemeAttrColor(context, baseColorAttr); 500eb0d0c030a15e93f456cc1403fffb909c0ae4e66Chris Banes final int colorControlHighlight = getThemeAttrColor(context, R.attr.colorControlHighlight); 501eb0d0c030a15e93f456cc1403fffb909c0ae4e66Chris Banes 50290075479814eb758d97b822606b448e1a521c298Chris Banes // Disabled state 503bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.DISABLED_STATE_SET; 504cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getDisabledThemeAttrColor(context, R.attr.colorButtonNormal); 50590075479814eb758d97b822606b448e1a521c298Chris Banes i++; 50690075479814eb758d97b822606b448e1a521c298Chris Banes 507bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.PRESSED_STATE_SET; 508b1131c6dfc9affe5751523f235878055cb699960Chris Banes colors[i] = ColorUtils.compositeColors(colorControlHighlight, baseColor); 50990075479814eb758d97b822606b448e1a521c298Chris Banes i++; 51090075479814eb758d97b822606b448e1a521c298Chris Banes 511bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.FOCUSED_STATE_SET; 512b1131c6dfc9affe5751523f235878055cb699960Chris Banes colors[i] = ColorUtils.compositeColors(colorControlHighlight, baseColor); 51390075479814eb758d97b822606b448e1a521c298Chris Banes i++; 51490075479814eb758d97b822606b448e1a521c298Chris Banes 51590075479814eb758d97b822606b448e1a521c298Chris Banes // Default enabled state 516bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.EMPTY_STATE_SET; 517b1131c6dfc9affe5751523f235878055cb699960Chris Banes colors[i] = baseColor; 51890075479814eb758d97b822606b448e1a521c298Chris Banes i++; 51990075479814eb758d97b822606b448e1a521c298Chris Banes 52090075479814eb758d97b822606b448e1a521c298Chris Banes return new ColorStateList(states, colors); 521a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes } 522a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes 523cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes private ColorStateList createSpinnerColorStateList(Context context) { 524cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes final int[][] states = new int[3][]; 525cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes final int[] colors = new int[3]; 526cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes int i = 0; 527cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes 528cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes // Disabled state 529bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.DISABLED_STATE_SET; 530cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getDisabledThemeAttrColor(context, R.attr.colorControlNormal); 531cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes i++; 532cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes 533bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.NOT_PRESSED_OR_FOCUSED_STATE_SET; 534cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlNormal); 535cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes i++; 536cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes 537bb1a62b3eed874aa47ea4763ac972902c77e988fChris Banes states[i] = ThemeUtils.EMPTY_STATE_SET; 538cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes colors[i] = getThemeAttrColor(context, R.attr.colorControlActivated); 539cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes i++; 540cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes 541cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes return new ColorStateList(states, colors); 542cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes } 543cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes 544469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static class ColorFilterLruCache extends LruCache<Integer, PorterDuffColorFilter> { 545469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 546469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes public ColorFilterLruCache(int maxSize) { 547469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes super(maxSize); 548469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 549469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 550469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes PorterDuffColorFilter get(int color, PorterDuff.Mode mode) { 551469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return get(generateCacheKey(color, mode)); 552469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 553469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 554469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes PorterDuffColorFilter put(int color, PorterDuff.Mode mode, PorterDuffColorFilter filter) { 555469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return put(generateCacheKey(color, mode), filter); 556469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 557469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes 558469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes private static int generateCacheKey(int color, PorterDuff.Mode mode) { 559469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes int hashCode = 1; 560469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes hashCode = 31 * hashCode + color; 561469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes hashCode = 31 * hashCode + mode.hashCode(); 562469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes return hashCode; 563469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 564469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes } 565a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 566a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes public static void tintViewBackground(View view, TintInfo tint) { 567a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes final Drawable background = view.getBackground(); 56839cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes if (tint.mHasTintList || tint.mHasTintMode) { 56939cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes background.setColorFilter(createTintFilter( 57039cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes tint.mHasTintList ? tint.mTintList : null, 57139cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes tint.mHasTintMode ? tint.mTintMode : DEFAULT_MODE, 57239cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes view.getDrawableState())); 573a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } else { 574a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes background.clearColorFilter(); 575a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 576eb0d0c030a15e93f456cc1403fffb909c0ae4e66Chris Banes 577eb0d0c030a15e93f456cc1403fffb909c0ae4e66Chris Banes if (Build.VERSION.SDK_INT <= 10) { 578eb0d0c030a15e93f456cc1403fffb909c0ae4e66Chris Banes // On Gingerbread, GradientDrawable does not invalidate itself when it's ColorFilter 579eb0d0c030a15e93f456cc1403fffb909c0ae4e66Chris Banes // has changed, so we need to force an invalidation 580eb0d0c030a15e93f456cc1403fffb909c0ae4e66Chris Banes view.invalidate(); 581eb0d0c030a15e93f456cc1403fffb909c0ae4e66Chris Banes } 582a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 583a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 58439cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes private static PorterDuffColorFilter createTintFilter(ColorStateList tint, 58539cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes PorterDuff.Mode tintMode, final int[] state) { 58639cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes if (tint == null || tintMode == null) { 58739cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes return null; 588cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes } 58939cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes final int color = tint.getColorForState(state, Color.TRANSPARENT); 59039cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes return getPorterDuffColorFilter(color, tintMode); 59139cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes } 592cd6e77607caba0b3b26163791a361938afb8b9c5Chris Banes 59339cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes private static PorterDuffColorFilter getPorterDuffColorFilter(int color, PorterDuff.Mode mode) { 594a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes // First, lets see if the cache already contains the color filter 595a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode); 596a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 597a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes if (filter == null) { 598a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes // Cache miss, so create a color filter and add it to the cache 599a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes filter = new PorterDuffColorFilter(color, mode); 600a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes COLOR_FILTER_CACHE.put(color, mode, filter); 601a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 602a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes 60339cb4c1c59fa156ed28bc8835ef05eeb356ad13cChris Banes return filter; 604a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes } 605469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes} 606