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