TintManager.java revision 16e8d4dd91083260223c007c797e46bc8f631055
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.content.res.Resources;
22469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.graphics.Color;
23469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.graphics.PorterDuff;
24469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.graphics.PorterDuffColorFilter;
25469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.graphics.drawable.Drawable;
26fd1eb27a3700de31507de34fd1bcc51830fe876cChris Banesimport android.os.Build;
27469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v4.content.ContextCompat;
28469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v4.util.LruCache;
29469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v7.appcompat.R;
30469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.util.Log;
3190075479814eb758d97b822606b448e1a521c298Chris Banesimport android.util.SparseArray;
32469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.util.TypedValue;
33a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banesimport android.view.View;
34469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
35469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes/**
36469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * @hide
37469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */
38a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banespublic final class TintManager {
39469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
40fd1eb27a3700de31507de34fd1bcc51830fe876cChris Banes    static final boolean SHOULD_BE_USED = Build.VERSION.SDK_INT < 21;
41fd1eb27a3700de31507de34fd1bcc51830fe876cChris Banes
42469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final String TAG = TintManager.class.getSimpleName();
43469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final boolean DEBUG = false;
44415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
45415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes    static final PorterDuff.Mode DEFAULT_MODE = PorterDuff.Mode.SRC_IN;
46469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
47469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final ColorFilterLruCache COLOR_FILTER_CACHE = new ColorFilterLruCache(6);
48469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
49469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
50469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * Drawables which should be tinted with the value of {@code R.attr.colorControlNormal},
51469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * using the default mode.
52469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
53469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final int[] TINT_COLOR_CONTROL_NORMAL = {
54469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_ab_back_mtrl_am_alpha,
55469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_go_search_api_mtrl_alpha,
56469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_search_api_mtrl_alpha,
57469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_commit_search_api_mtrl_alpha,
58469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_clear_mtrl_alpha,
59469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_menu_share_mtrl_alpha,
60b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes            R.drawable.abc_ic_menu_copy_mtrl_am_alpha,
61b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes            R.drawable.abc_ic_menu_cut_mtrl_alpha,
62b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes            R.drawable.abc_ic_menu_selectall_mtrl_alpha,
63b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes            R.drawable.abc_ic_menu_paste_mtrl_am_alpha,
64469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_menu_moreoverflow_mtrl_alpha,
65469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_voice_search_api_mtrl_alpha,
66469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_textfield_search_default_mtrl_alpha,
67b645de790756e27bbe92d133216b7ac79cca7679Chris Banes            R.drawable.abc_textfield_default_mtrl_alpha,
68b645de790756e27bbe92d133216b7ac79cca7679Chris Banes            R.drawable.abc_ab_share_pack_mtrl_alpha
69469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
70469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
71469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
72469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * Drawables which should be tinted with the value of {@code R.attr.colorControlActivated},
73469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * using the default mode.
74469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
75469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final int[] TINT_COLOR_CONTROL_ACTIVATED = {
76469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_textfield_activated_mtrl_alpha,
7714f8f0dfae09445074dc0f7b5bbe5732d6922da7Chris Banes            R.drawable.abc_textfield_search_activated_mtrl_alpha,
7814f8f0dfae09445074dc0f7b5bbe5732d6922da7Chris Banes            R.drawable.abc_cab_background_top_mtrl_alpha
79469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
80469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
81469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
82469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * Drawables which should be tinted with the value of {@code android.R.attr.colorBackground},
83469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * using the {@link android.graphics.PorterDuff.Mode#MULTIPLY} mode.
84469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
85469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final int[] TINT_COLOR_BACKGROUND_MULTIPLY = {
861073132946bb0a53a788949fe4c060f72051cd57Chris Banes            R.drawable.abc_popup_background_mtrl_mult,
8757c6de90985a63358129b99b9f0cd4d6afe887d6Chris Banes            R.drawable.abc_cab_background_internal_bg,
8857c6de90985a63358129b99b9f0cd4d6afe887d6Chris Banes            R.drawable.abc_menu_hardkey_panel_mtrl_mult
89469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
90469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
91469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
92469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * Drawables which should be tinted using a state list containing values of
93469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * {@code R.attr.colorControlNormal} and {@code R.attr.colorControlActivated}
94469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
95469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final int[] TINT_COLOR_CONTROL_STATE_LIST = {
96469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_edit_text_material,
97469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_tab_indicator_material,
98469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_textfield_search_material,
99415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes            R.drawable.abc_spinner_mtrl_am_alpha,
100415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes            R.drawable.abc_btn_check_material,
101f67cc46fd515df18c4b70dce9e5dcdd4e3245cd8Chris Banes            R.drawable.abc_btn_radio_material,
102a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes            R.drawable.abc_spinner_textfield_background_material,
10390075479814eb758d97b822606b448e1a521c298Chris Banes            R.drawable.abc_ratingbar_full_material,
10490075479814eb758d97b822606b448e1a521c298Chris Banes            R.drawable.abc_switch_track_mtrl_alpha,
10590075479814eb758d97b822606b448e1a521c298Chris Banes            R.drawable.abc_switch_thumb_material,
10616e8d4dd91083260223c007c797e46bc8f631055Chris Banes            R.drawable.abc_btn_default_mtrl_shape,
10716e8d4dd91083260223c007c797e46bc8f631055Chris Banes            R.drawable.abc_btn_borderless_material
108469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
109469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
110469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
111469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * Drawables which contain other drawables which should be tinted. The child drawable IDs
112469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * should be defined in one of the arrays above.
113469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
114469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final int[] CONTAINERS_WITH_TINT_CHILDREN = {
1151073132946bb0a53a788949fe4c060f72051cd57Chris Banes            R.drawable.abc_cab_background_top_material
116469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
117469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
118469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private final Context mContext;
119469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private final Resources mResources;
120469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private final TypedValue mTypedValue;
121469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
12290075479814eb758d97b822606b448e1a521c298Chris Banes    private final SparseArray<ColorStateList> mColorStateLists;
123469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private ColorStateList mDefaultColorStateList;
124469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
125469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
126469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * A helper method to instantiate a {@link TintManager} and then call {@link #getDrawable(int)}.
127469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * This method should not be used routinely.
128469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
129469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    public static Drawable getDrawable(Context context, int resId) {
130b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes        if (isInTintList(resId)) {
131b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes            return new TintManager(context).getDrawable(resId);
132b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes        } else {
133b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes            return ContextCompat.getDrawable(context, resId);
134b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes        }
135469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
136469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
137469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    public TintManager(Context context) {
13890075479814eb758d97b822606b448e1a521c298Chris Banes        mColorStateLists = new SparseArray<>();
139469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        mContext = context;
140469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        mResources = new TintResources(context.getResources(), this);
141469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        mTypedValue = new TypedValue();
142469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
143469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
144469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    public Drawable getDrawable(int resId) {
145469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        Drawable drawable = ContextCompat.getDrawable(mContext, resId);
146469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
147469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        if (drawable != null) {
148c7d6de1eb6692c627a02a4ed439a8a4b849ca66cChris Banes            drawable = drawable.mutate();
149c7d6de1eb6692c627a02a4ed439a8a4b849ca66cChris Banes
150469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (arrayContains(TINT_COLOR_CONTROL_STATE_LIST, resId)) {
151a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
152a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                ColorStateList colorStateList = getColorStateListForKnownDrawableId(resId);
153a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
154a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                PorterDuff.Mode tintMode = DEFAULT_MODE;
155a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                if (resId == R.drawable.abc_switch_thumb_material) {
156a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                    tintMode = PorterDuff.Mode.MULTIPLY;
157a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                }
158a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
159a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                if (colorStateList != null) {
160a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                    drawable = new TintDrawableWrapper(drawable, colorStateList, tintMode);
161a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                }
162469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            } else if (arrayContains(CONTAINERS_WITH_TINT_CHILDREN, resId)) {
163469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                drawable = mResources.getDrawable(resId);
164469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            } else {
165469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                tintDrawable(resId, drawable);
166469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
167469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
168469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        return drawable;
169469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
170469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
1710517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes    void tintDrawable(final int resId, final Drawable drawable) {
172469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        PorterDuff.Mode tintMode = null;
173469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        boolean colorAttrSet = false;
174469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        int colorAttr = 0;
1750517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes        int alpha = -1;
176469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
177469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        if (arrayContains(TINT_COLOR_CONTROL_NORMAL, resId)) {
178469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttr = R.attr.colorControlNormal;
179469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttrSet = true;
180469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        } else if (arrayContains(TINT_COLOR_CONTROL_ACTIVATED, resId)) {
181469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttr = R.attr.colorControlActivated;
182469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttrSet = true;
183469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        } else if (arrayContains(TINT_COLOR_BACKGROUND_MULTIPLY, resId)) {
184469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttr = android.R.attr.colorBackground;
185469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttrSet = true;
186469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            tintMode = PorterDuff.Mode.MULTIPLY;
1870517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes        } else if (resId == R.drawable.abc_list_divider_mtrl_alpha) {
1880517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes            colorAttr = android.R.attr.colorForeground;
1890517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes            colorAttrSet = true;
1900517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes            alpha = Math.round(0.16f * 255);
191469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
192469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
193f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        if (colorAttrSet) {
194469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (tintMode == null) {
195469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                tintMode = DEFAULT_MODE;
196469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
197f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            final int color = getThemeAttrColor(colorAttr);
198469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
199a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            tintDrawableUsingColorFilter(drawable, color, tintMode);
200469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
2010517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes            if (alpha != -1) {
2020517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes                drawable.setAlpha(alpha);
2030517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes            }
2040517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes
205469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (DEBUG) {
206469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                Log.d(TAG, "Tinted Drawable ID: " + mResources.getResourceName(resId) +
207469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                        " with color: #" + Integer.toHexString(color));
208469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
209469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
210469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
211469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
212469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static boolean arrayContains(int[] array, int value) {
213469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        for (int id : array) {
214469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (id == value) {
215469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                return true;
216469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
217469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
218469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        return false;
219469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
220469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
221b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes    private static boolean isInTintList(int drawableId) {
222b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes        return arrayContains(TINT_COLOR_BACKGROUND_MULTIPLY, drawableId) ||
223b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes                arrayContains(TINT_COLOR_CONTROL_NORMAL, drawableId) ||
224b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes                arrayContains(TINT_COLOR_CONTROL_ACTIVATED, drawableId) ||
225b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes                arrayContains(TINT_COLOR_CONTROL_STATE_LIST, drawableId) ||
226b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes                arrayContains(CONTAINERS_WITH_TINT_CHILDREN, drawableId);
227b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes    }
228b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes
229a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    ColorStateList getColorStateList(int resId) {
230a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        return arrayContains(TINT_COLOR_CONTROL_STATE_LIST, resId)
231a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                ? getColorStateListForKnownDrawableId(resId)
232a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                : null;
233a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    }
234a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
235a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    private ColorStateList getColorStateListForKnownDrawableId(int resId) {
23690075479814eb758d97b822606b448e1a521c298Chris Banes        // Try the cache first
23790075479814eb758d97b822606b448e1a521c298Chris Banes        ColorStateList colorStateList = mColorStateLists.get(resId);
23890075479814eb758d97b822606b448e1a521c298Chris Banes
23990075479814eb758d97b822606b448e1a521c298Chris Banes        if (colorStateList == null) {
24090075479814eb758d97b822606b448e1a521c298Chris Banes            // ...if the cache did not contain a color state list, try and create
24190075479814eb758d97b822606b448e1a521c298Chris Banes            if (resId == R.drawable.abc_edit_text_material) {
24290075479814eb758d97b822606b448e1a521c298Chris Banes                colorStateList = createEditTextColorStateList();
24390075479814eb758d97b822606b448e1a521c298Chris Banes            } else if (resId == R.drawable.abc_switch_track_mtrl_alpha) {
24490075479814eb758d97b822606b448e1a521c298Chris Banes                colorStateList = createSwitchTrackColorStateList();
24590075479814eb758d97b822606b448e1a521c298Chris Banes            } else if (resId == R.drawable.abc_switch_thumb_material) {
24690075479814eb758d97b822606b448e1a521c298Chris Banes                colorStateList = createSwitchThumbColorStateList();
24716e8d4dd91083260223c007c797e46bc8f631055Chris Banes            } else if (resId == R.drawable.abc_btn_default_mtrl_shape
24816e8d4dd91083260223c007c797e46bc8f631055Chris Banes                    || resId == R.drawable.abc_btn_borderless_material) {
24990075479814eb758d97b822606b448e1a521c298Chris Banes                colorStateList = createButtonColorStateList();
250cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes            } else if (resId == R.drawable.abc_spinner_mtrl_am_alpha
251cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes                    || resId == R.drawable.abc_spinner_textfield_background_material) {
252cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes                colorStateList = createSpinnerColorStateList();
25390075479814eb758d97b822606b448e1a521c298Chris Banes            } else {
25490075479814eb758d97b822606b448e1a521c298Chris Banes                // If we don't have an explicit color state list for this Drawable, use the default
25590075479814eb758d97b822606b448e1a521c298Chris Banes                colorStateList = getDefaultColorStateList();
25690075479814eb758d97b822606b448e1a521c298Chris Banes            }
257a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
25890075479814eb758d97b822606b448e1a521c298Chris Banes            // ..and add it to the cache
25990075479814eb758d97b822606b448e1a521c298Chris Banes            mColorStateLists.append(resId, colorStateList);
26090075479814eb758d97b822606b448e1a521c298Chris Banes        }
261a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        return colorStateList;
26290075479814eb758d97b822606b448e1a521c298Chris Banes    }
26390075479814eb758d97b822606b448e1a521c298Chris Banes
264469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private ColorStateList getDefaultColorStateList() {
265469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        if (mDefaultColorStateList == null) {
266469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            /**
267469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes             * Generate the default color state list which uses the colorControl attributes.
268469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes             * Order is important here. The default enabled state needs to go at the bottom.
269469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes             */
270469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
271469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int colorControlNormal = getThemeAttrColor(R.attr.colorControlNormal);
272469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int colorControlActivated = getThemeAttrColor(R.attr.colorControlActivated);
273469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
274469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int[][] states = new int[7][];
275469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int[] colors = new int[7];
276469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            int i = 0;
277469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
278c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            // Disabled state
279c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { -android.R.attr.state_enabled };
280c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            colors[i] = getDisabledThemeAttrColor(R.attr.colorControlNormal);
281469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
282469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
283c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_focused };
284469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
285469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
286469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
287c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_activated };
288469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
289469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
290469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
291c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_pressed };
292469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
293469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
294469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
295c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_checked };
296469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
297469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
298469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
299c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_selected };
300c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            colors[i] = colorControlActivated;
301469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
302469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
303c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            // Default enabled state
304469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            states[i] = new int[0];
305c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            colors[i] = colorControlNormal;
306469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
307469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
308469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            mDefaultColorStateList = new ColorStateList(states, colors);
309469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
310469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        return mDefaultColorStateList;
311469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
312469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
31390075479814eb758d97b822606b448e1a521c298Chris Banes    private ColorStateList createSwitchTrackColorStateList() {
31490075479814eb758d97b822606b448e1a521c298Chris Banes        final int[][] states = new int[3][];
31590075479814eb758d97b822606b448e1a521c298Chris Banes        final int[] colors = new int[3];
31690075479814eb758d97b822606b448e1a521c298Chris Banes        int i = 0;
317415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
31890075479814eb758d97b822606b448e1a521c298Chris Banes        // Disabled state
31990075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{-android.R.attr.state_enabled};
32090075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(android.R.attr.colorForeground, 0.1f);
32190075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
322415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
32390075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{android.R.attr.state_checked};
32490075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlActivated, 0.3f);
32590075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
326415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
32790075479814eb758d97b822606b448e1a521c298Chris Banes        // Default enabled state
32890075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[0];
32990075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(android.R.attr.colorForeground, 0.3f);
33090075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
331415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
33290075479814eb758d97b822606b448e1a521c298Chris Banes        return new ColorStateList(states, colors);
333415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes    }
334415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
33590075479814eb758d97b822606b448e1a521c298Chris Banes    private ColorStateList createSwitchThumbColorStateList() {
33690075479814eb758d97b822606b448e1a521c298Chris Banes        final int[][] states = new int[3][];
33790075479814eb758d97b822606b448e1a521c298Chris Banes        final int[] colors = new int[3];
33890075479814eb758d97b822606b448e1a521c298Chris Banes        int i = 0;
339415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
340414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        final ColorStateList thumbColor = getThemeAttrColorStateList(R.attr.colorSwitchThumbNormal);
341415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
342414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        if (thumbColor != null && thumbColor.isStateful()) {
343414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // If colorSwitchThumbNormal is a valid ColorStateList, extract the default and
344414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // disabled colors from it
345415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
346414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // Disabled state
347414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[]{-android.R.attr.state_enabled};
348414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = thumbColor.getColorForState(states[i], 0);
349414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
350414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
351414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[]{android.R.attr.state_checked};
352414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = getThemeAttrColor(R.attr.colorControlActivated);
353414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
354414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
355414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // Default enabled state
356414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[0];
357414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = thumbColor.getDefaultColor();
358414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
359414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        } else {
360414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // Else we'll use an approximation using the default disabled alpha
361414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
362414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // Disabled state
363414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[]{-android.R.attr.state_enabled};
364414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = getDisabledThemeAttrColor(R.attr.colorSwitchThumbNormal);
365414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
366414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
367414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[]{android.R.attr.state_checked};
368414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = getThemeAttrColor(R.attr.colorControlActivated);
369414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
370414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
371414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // Default enabled state
372414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[0];
373414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = getThemeAttrColor(R.attr.colorSwitchThumbNormal);
374414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
375414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        }
376415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
37790075479814eb758d97b822606b448e1a521c298Chris Banes        return new ColorStateList(states, colors);
378415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes    }
379415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
38090075479814eb758d97b822606b448e1a521c298Chris Banes    private ColorStateList createEditTextColorStateList() {
38190075479814eb758d97b822606b448e1a521c298Chris Banes        final int[][] states = new int[3][];
38290075479814eb758d97b822606b448e1a521c298Chris Banes        final int[] colors = new int[3];
38390075479814eb758d97b822606b448e1a521c298Chris Banes        int i = 0;
384a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
38590075479814eb758d97b822606b448e1a521c298Chris Banes        // Disabled state
38690075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{-android.R.attr.state_enabled};
38790075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getDisabledThemeAttrColor(R.attr.colorControlNormal);
38890075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
389a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
39090075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{-android.R.attr.state_pressed, -android.R.attr.state_focused};
39190075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlNormal);
39290075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
393a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
39490075479814eb758d97b822606b448e1a521c298Chris Banes        // Default enabled state
39590075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[0];
39690075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlActivated);
39790075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
398a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
39990075479814eb758d97b822606b448e1a521c298Chris Banes        return new ColorStateList(states, colors);
40090075479814eb758d97b822606b448e1a521c298Chris Banes    }
401a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
40290075479814eb758d97b822606b448e1a521c298Chris Banes    private ColorStateList createButtonColorStateList() {
40390075479814eb758d97b822606b448e1a521c298Chris Banes        final int[][] states = new int[4][];
40490075479814eb758d97b822606b448e1a521c298Chris Banes        final int[] colors = new int[4];
40590075479814eb758d97b822606b448e1a521c298Chris Banes        int i = 0;
40690075479814eb758d97b822606b448e1a521c298Chris Banes
40790075479814eb758d97b822606b448e1a521c298Chris Banes        // Disabled state
40890075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{-android.R.attr.state_enabled};
40990075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getDisabledThemeAttrColor(R.attr.colorButtonNormal);
41090075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
41190075479814eb758d97b822606b448e1a521c298Chris Banes
41290075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{android.R.attr.state_pressed};
41390075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlHighlight);
41490075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
41590075479814eb758d97b822606b448e1a521c298Chris Banes
41690075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{android.R.attr.state_focused};
41790075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlHighlight);
41890075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
41990075479814eb758d97b822606b448e1a521c298Chris Banes
42090075479814eb758d97b822606b448e1a521c298Chris Banes        // Default enabled state
42190075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[0];
42290075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorButtonNormal);
42390075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
42490075479814eb758d97b822606b448e1a521c298Chris Banes
42590075479814eb758d97b822606b448e1a521c298Chris Banes        return new ColorStateList(states, colors);
426a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes    }
427a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
428cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes    private ColorStateList createSpinnerColorStateList() {
429cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        final int[][] states = new int[3][];
430cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        final int[] colors = new int[3];
431cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        int i = 0;
432cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes
433cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        // Disabled state
434cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        states[i] = new int[]{-android.R.attr.state_enabled};
435cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        colors[i] = getDisabledThemeAttrColor(R.attr.colorControlNormal);
436cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        i++;
437cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes
438cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        states[i] = new int[]{-android.R.attr.state_pressed, -android.R.attr.state_focused};
439cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlNormal);
440cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        i++;
441cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes
442cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        states[i] = new int[0];
443cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlActivated);
444cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        i++;
445cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes
446cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        return new ColorStateList(states, colors);
447cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes    }
448cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes
44990075479814eb758d97b822606b448e1a521c298Chris Banes    private int getThemeAttrColor(int attr) {
450f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        if (mContext.getTheme().resolveAttribute(attr, mTypedValue, true)) {
451f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            if (mTypedValue.type >= TypedValue.TYPE_FIRST_INT
452f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes                    && mTypedValue.type <= TypedValue.TYPE_LAST_INT) {
453f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes                return mTypedValue.data;
454f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            } else if (mTypedValue.type == TypedValue.TYPE_STRING) {
455f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes                return mResources.getColor(mTypedValue.resourceId);
456f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            }
457f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        }
458f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        return 0;
459469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
460469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
461414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes    private ColorStateList getThemeAttrColorStateList(int attr) {
462414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        if (mContext.getTheme().resolveAttribute(attr, mTypedValue, true)) {
463414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            if (mTypedValue.type == TypedValue.TYPE_STRING) {
464414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes                return mResources.getColorStateList(mTypedValue.resourceId);
465414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            }
466414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        }
467414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        return null;
468414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes    }
469414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
47090075479814eb758d97b822606b448e1a521c298Chris Banes    private int getThemeAttrColor(int attr, float alpha) {
471f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        final int color = getThemeAttrColor(attr);
472c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        final int originalAlpha = Color.alpha(color);
473c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes
474415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes        // Return the color, multiplying the original alpha by the disabled value
475415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes        return (color & 0x00ffffff) | (Math.round(originalAlpha * alpha) << 24);
476415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes    }
477415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
47890075479814eb758d97b822606b448e1a521c298Chris Banes    private int getDisabledThemeAttrColor(int attr) {
479c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        // Now retrieve the disabledAlpha value from the theme
480c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        mContext.getTheme().resolveAttribute(android.R.attr.disabledAlpha, mTypedValue, true);
481c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        final float disabledAlpha = mTypedValue.getFloat();
482c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes
483415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes        return getThemeAttrColor(attr, disabledAlpha);
484c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes    }
485c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes
486469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static class ColorFilterLruCache extends LruCache<Integer, PorterDuffColorFilter> {
487469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
488469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        public ColorFilterLruCache(int maxSize) {
489469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            super(maxSize);
490469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
491469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
492469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        PorterDuffColorFilter get(int color, PorterDuff.Mode mode) {
493469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            return get(generateCacheKey(color, mode));
494469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
495469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
496469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        PorterDuffColorFilter put(int color, PorterDuff.Mode mode, PorterDuffColorFilter filter) {
497469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            return put(generateCacheKey(color, mode), filter);
498469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
499469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
500469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        private static int generateCacheKey(int color, PorterDuff.Mode mode) {
501469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            int hashCode = 1;
502469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            hashCode = 31 * hashCode + color;
503469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            hashCode = 31 * hashCode + mode.hashCode();
504469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            return hashCode;
505469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
506469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
507a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
508a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    public static void tintViewBackground(View view, TintInfo tint) {
509a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        final Drawable background = view.getBackground();
510a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        if (tint.mTintList != null) {
511a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            tintDrawableUsingColorFilter(
512a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                    background,
513a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                    tint.mTintList.getColorForState(view.getDrawableState(),
514a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                            tint.mTintList.getDefaultColor()),
515a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                    tint.mTintMode != null ? tint.mTintMode : DEFAULT_MODE);
516a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        } else {
517a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            background.clearColorFilter();
518a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        }
519a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    }
520a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
521a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    private static void tintDrawableUsingColorFilter(Drawable drawable, int color,
522a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            PorterDuff.Mode mode) {
523a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        // First, lets see if the cache already contains the color filter
524a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode);
525a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
526a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        if (filter == null) {
527a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            // Cache miss, so create a color filter and add it to the cache
528a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            filter = new PorterDuffColorFilter(color, mode);
529a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            COLOR_FILTER_CACHE.put(color, mode, filter);
530a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        }
531a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
532a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        drawable.setColorFilter(filter);
533a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    }
534469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes}
535