TintManager.java revision a5f106fbd09335ae504c39b1ee1e0caa3f1238e3
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,
10690075479814eb758d97b822606b448e1a521c298Chris Banes            R.drawable.abc_btn_default_mtrl_shape
107469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
108469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
109469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
110469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * Drawables which contain other drawables which should be tinted. The child drawable IDs
111469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * should be defined in one of the arrays above.
112469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
113469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final int[] CONTAINERS_WITH_TINT_CHILDREN = {
1141073132946bb0a53a788949fe4c060f72051cd57Chris Banes            R.drawable.abc_cab_background_top_material
115469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
116469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
117469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private final Context mContext;
118469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private final Resources mResources;
119469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private final TypedValue mTypedValue;
120469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
12190075479814eb758d97b822606b448e1a521c298Chris Banes    private final SparseArray<ColorStateList> mColorStateLists;
122469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private ColorStateList mDefaultColorStateList;
123469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
124469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
125469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * A helper method to instantiate a {@link TintManager} and then call {@link #getDrawable(int)}.
126469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * This method should not be used routinely.
127469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
128469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    public static Drawable getDrawable(Context context, int resId) {
129b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes        if (isInTintList(resId)) {
130b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes            return new TintManager(context).getDrawable(resId);
131b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes        } else {
132b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes            return ContextCompat.getDrawable(context, resId);
133b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes        }
134469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
135469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
136469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    public TintManager(Context context) {
13790075479814eb758d97b822606b448e1a521c298Chris Banes        mColorStateLists = new SparseArray<>();
138469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        mContext = context;
139469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        mResources = new TintResources(context.getResources(), this);
140469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        mTypedValue = new TypedValue();
141469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
142469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
143469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    public Drawable getDrawable(int resId) {
144469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        Drawable drawable = ContextCompat.getDrawable(mContext, resId);
145469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
146469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        if (drawable != null) {
147c7d6de1eb6692c627a02a4ed439a8a4b849ca66cChris Banes            drawable = drawable.mutate();
148c7d6de1eb6692c627a02a4ed439a8a4b849ca66cChris Banes
149469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (arrayContains(TINT_COLOR_CONTROL_STATE_LIST, resId)) {
150a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
151a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                ColorStateList colorStateList = getColorStateListForKnownDrawableId(resId);
152a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
153a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                PorterDuff.Mode tintMode = DEFAULT_MODE;
154a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                if (resId == R.drawable.abc_switch_thumb_material) {
155a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                    tintMode = PorterDuff.Mode.MULTIPLY;
156a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                }
157a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
158a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                if (colorStateList != null) {
159a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                    drawable = new TintDrawableWrapper(drawable, colorStateList, tintMode);
160a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                }
161469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            } else if (arrayContains(CONTAINERS_WITH_TINT_CHILDREN, resId)) {
162469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                drawable = mResources.getDrawable(resId);
163469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            } else {
164469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                tintDrawable(resId, drawable);
165469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
166469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
167469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        return drawable;
168469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
169469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
1700517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes    void tintDrawable(final int resId, final Drawable drawable) {
171469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        PorterDuff.Mode tintMode = null;
172469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        boolean colorAttrSet = false;
173469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        int colorAttr = 0;
1740517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes        int alpha = -1;
175469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
176469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        if (arrayContains(TINT_COLOR_CONTROL_NORMAL, resId)) {
177469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttr = R.attr.colorControlNormal;
178469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttrSet = true;
179469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        } else if (arrayContains(TINT_COLOR_CONTROL_ACTIVATED, resId)) {
180469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttr = R.attr.colorControlActivated;
181469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttrSet = true;
182469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        } else if (arrayContains(TINT_COLOR_BACKGROUND_MULTIPLY, resId)) {
183469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttr = android.R.attr.colorBackground;
184469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttrSet = true;
185469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            tintMode = PorterDuff.Mode.MULTIPLY;
1860517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes        } else if (resId == R.drawable.abc_list_divider_mtrl_alpha) {
1870517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes            colorAttr = android.R.attr.colorForeground;
1880517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes            colorAttrSet = true;
1890517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes            alpha = Math.round(0.16f * 255);
190469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
191469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
192f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        if (colorAttrSet) {
193469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (tintMode == null) {
194469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                tintMode = DEFAULT_MODE;
195469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
196f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            final int color = getThemeAttrColor(colorAttr);
197469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
198a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            tintDrawableUsingColorFilter(drawable, color, tintMode);
199469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
2000517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes            if (alpha != -1) {
2010517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes                drawable.setAlpha(alpha);
2020517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes            }
2030517b282bde8b9a0377dfe5bc4756405a196adb4Chris Banes
204469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (DEBUG) {
205469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                Log.d(TAG, "Tinted Drawable ID: " + mResources.getResourceName(resId) +
206469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                        " with color: #" + Integer.toHexString(color));
207469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
208469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
209469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
210469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
211469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static boolean arrayContains(int[] array, int value) {
212469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        for (int id : array) {
213469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (id == value) {
214469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                return true;
215469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
216469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
217469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        return false;
218469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
219469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
220b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes    private static boolean isInTintList(int drawableId) {
221b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes        return arrayContains(TINT_COLOR_BACKGROUND_MULTIPLY, drawableId) ||
222b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes                arrayContains(TINT_COLOR_CONTROL_NORMAL, drawableId) ||
223b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes                arrayContains(TINT_COLOR_CONTROL_ACTIVATED, drawableId) ||
224b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes                arrayContains(TINT_COLOR_CONTROL_STATE_LIST, drawableId) ||
225b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes                arrayContains(CONTAINERS_WITH_TINT_CHILDREN, drawableId);
226b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes    }
227b37a31664b07243ca9e86c8dac58b9be6a417e8cChris Banes
228a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    ColorStateList getColorStateList(int resId) {
229a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        return arrayContains(TINT_COLOR_CONTROL_STATE_LIST, resId)
230a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                ? getColorStateListForKnownDrawableId(resId)
231a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                : null;
232a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    }
233a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
234a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    private ColorStateList getColorStateListForKnownDrawableId(int resId) {
23590075479814eb758d97b822606b448e1a521c298Chris Banes        // Try the cache first
23690075479814eb758d97b822606b448e1a521c298Chris Banes        ColorStateList colorStateList = mColorStateLists.get(resId);
23790075479814eb758d97b822606b448e1a521c298Chris Banes
23890075479814eb758d97b822606b448e1a521c298Chris Banes        if (colorStateList == null) {
23990075479814eb758d97b822606b448e1a521c298Chris Banes            // ...if the cache did not contain a color state list, try and create
24090075479814eb758d97b822606b448e1a521c298Chris Banes            if (resId == R.drawable.abc_edit_text_material) {
24190075479814eb758d97b822606b448e1a521c298Chris Banes                colorStateList = createEditTextColorStateList();
24290075479814eb758d97b822606b448e1a521c298Chris Banes            } else if (resId == R.drawable.abc_switch_track_mtrl_alpha) {
24390075479814eb758d97b822606b448e1a521c298Chris Banes                colorStateList = createSwitchTrackColorStateList();
24490075479814eb758d97b822606b448e1a521c298Chris Banes            } else if (resId == R.drawable.abc_switch_thumb_material) {
24590075479814eb758d97b822606b448e1a521c298Chris Banes                colorStateList = createSwitchThumbColorStateList();
24690075479814eb758d97b822606b448e1a521c298Chris Banes            } else if (resId == R.drawable.abc_btn_default_mtrl_shape) {
24790075479814eb758d97b822606b448e1a521c298Chris Banes                colorStateList = createButtonColorStateList();
248cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes            } else if (resId == R.drawable.abc_spinner_mtrl_am_alpha
249cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes                    || resId == R.drawable.abc_spinner_textfield_background_material) {
250cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes                colorStateList = createSpinnerColorStateList();
25190075479814eb758d97b822606b448e1a521c298Chris Banes            } else {
25290075479814eb758d97b822606b448e1a521c298Chris Banes                // If we don't have an explicit color state list for this Drawable, use the default
25390075479814eb758d97b822606b448e1a521c298Chris Banes                colorStateList = getDefaultColorStateList();
25490075479814eb758d97b822606b448e1a521c298Chris Banes            }
255a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
25690075479814eb758d97b822606b448e1a521c298Chris Banes            // ..and add it to the cache
25790075479814eb758d97b822606b448e1a521c298Chris Banes            mColorStateLists.append(resId, colorStateList);
25890075479814eb758d97b822606b448e1a521c298Chris Banes        }
259a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        return colorStateList;
26090075479814eb758d97b822606b448e1a521c298Chris Banes    }
26190075479814eb758d97b822606b448e1a521c298Chris Banes
262469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private ColorStateList getDefaultColorStateList() {
263469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        if (mDefaultColorStateList == null) {
264469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            /**
265469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes             * Generate the default color state list which uses the colorControl attributes.
266469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes             * Order is important here. The default enabled state needs to go at the bottom.
267469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes             */
268469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
269469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int colorControlNormal = getThemeAttrColor(R.attr.colorControlNormal);
270469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int colorControlActivated = getThemeAttrColor(R.attr.colorControlActivated);
271469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
272469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int[][] states = new int[7][];
273469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int[] colors = new int[7];
274469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            int i = 0;
275469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
276c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            // Disabled state
277c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { -android.R.attr.state_enabled };
278c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            colors[i] = getDisabledThemeAttrColor(R.attr.colorControlNormal);
279469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
280469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
281c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_focused };
282469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
283469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
284469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
285c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_activated };
286469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
287469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
288469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
289c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_pressed };
290469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
291469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
292469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
293c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_checked };
294469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
295469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
296469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
297c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_selected };
298c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            colors[i] = colorControlActivated;
299469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
300469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
301c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            // Default enabled state
302469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            states[i] = new int[0];
303c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            colors[i] = colorControlNormal;
304469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
305469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
306469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            mDefaultColorStateList = new ColorStateList(states, colors);
307469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
308469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        return mDefaultColorStateList;
309469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
310469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
31190075479814eb758d97b822606b448e1a521c298Chris Banes    private ColorStateList createSwitchTrackColorStateList() {
31290075479814eb758d97b822606b448e1a521c298Chris Banes        final int[][] states = new int[3][];
31390075479814eb758d97b822606b448e1a521c298Chris Banes        final int[] colors = new int[3];
31490075479814eb758d97b822606b448e1a521c298Chris Banes        int i = 0;
315415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
31690075479814eb758d97b822606b448e1a521c298Chris Banes        // Disabled state
31790075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{-android.R.attr.state_enabled};
31890075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(android.R.attr.colorForeground, 0.1f);
31990075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
320415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
32190075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{android.R.attr.state_checked};
32290075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlActivated, 0.3f);
32390075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
324415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
32590075479814eb758d97b822606b448e1a521c298Chris Banes        // Default enabled state
32690075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[0];
32790075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(android.R.attr.colorForeground, 0.3f);
32890075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
329415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
33090075479814eb758d97b822606b448e1a521c298Chris Banes        return new ColorStateList(states, colors);
331415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes    }
332415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
33390075479814eb758d97b822606b448e1a521c298Chris Banes    private ColorStateList createSwitchThumbColorStateList() {
33490075479814eb758d97b822606b448e1a521c298Chris Banes        final int[][] states = new int[3][];
33590075479814eb758d97b822606b448e1a521c298Chris Banes        final int[] colors = new int[3];
33690075479814eb758d97b822606b448e1a521c298Chris Banes        int i = 0;
337415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
338414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        final ColorStateList thumbColor = getThemeAttrColorStateList(R.attr.colorSwitchThumbNormal);
339415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
340414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        if (thumbColor != null && thumbColor.isStateful()) {
341414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // If colorSwitchThumbNormal is a valid ColorStateList, extract the default and
342414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // disabled colors from it
343415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
344414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // Disabled state
345414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[]{-android.R.attr.state_enabled};
346414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = thumbColor.getColorForState(states[i], 0);
347414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
348414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
349414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[]{android.R.attr.state_checked};
350414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = getThemeAttrColor(R.attr.colorControlActivated);
351414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
352414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
353414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // Default enabled state
354414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[0];
355414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = thumbColor.getDefaultColor();
356414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
357414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        } else {
358414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // Else we'll use an approximation using the default disabled alpha
359414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
360414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // Disabled state
361414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[]{-android.R.attr.state_enabled};
362414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = getDisabledThemeAttrColor(R.attr.colorSwitchThumbNormal);
363414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
364414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
365414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[]{android.R.attr.state_checked};
366414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = getThemeAttrColor(R.attr.colorControlActivated);
367414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
368414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
369414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            // Default enabled state
370414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            states[i] = new int[0];
371414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            colors[i] = getThemeAttrColor(R.attr.colorSwitchThumbNormal);
372414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            i++;
373414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        }
374415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
37590075479814eb758d97b822606b448e1a521c298Chris Banes        return new ColorStateList(states, colors);
376415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes    }
377415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
37890075479814eb758d97b822606b448e1a521c298Chris Banes    private ColorStateList createEditTextColorStateList() {
37990075479814eb758d97b822606b448e1a521c298Chris Banes        final int[][] states = new int[3][];
38090075479814eb758d97b822606b448e1a521c298Chris Banes        final int[] colors = new int[3];
38190075479814eb758d97b822606b448e1a521c298Chris Banes        int i = 0;
382a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
38390075479814eb758d97b822606b448e1a521c298Chris Banes        // Disabled state
38490075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{-android.R.attr.state_enabled};
38590075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getDisabledThemeAttrColor(R.attr.colorControlNormal);
38690075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
387a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
38890075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{-android.R.attr.state_pressed, -android.R.attr.state_focused};
38990075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlNormal);
39090075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
391a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
39290075479814eb758d97b822606b448e1a521c298Chris Banes        // Default enabled state
39390075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[0];
39490075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlActivated);
39590075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
396a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
39790075479814eb758d97b822606b448e1a521c298Chris Banes        return new ColorStateList(states, colors);
39890075479814eb758d97b822606b448e1a521c298Chris Banes    }
399a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
40090075479814eb758d97b822606b448e1a521c298Chris Banes    private ColorStateList createButtonColorStateList() {
40190075479814eb758d97b822606b448e1a521c298Chris Banes        final int[][] states = new int[4][];
40290075479814eb758d97b822606b448e1a521c298Chris Banes        final int[] colors = new int[4];
40390075479814eb758d97b822606b448e1a521c298Chris Banes        int i = 0;
40490075479814eb758d97b822606b448e1a521c298Chris Banes
40590075479814eb758d97b822606b448e1a521c298Chris Banes        // Disabled state
40690075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{-android.R.attr.state_enabled};
40790075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getDisabledThemeAttrColor(R.attr.colorButtonNormal);
40890075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
40990075479814eb758d97b822606b448e1a521c298Chris Banes
41090075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{android.R.attr.state_pressed};
41190075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlHighlight);
41290075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
41390075479814eb758d97b822606b448e1a521c298Chris Banes
41490075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[]{android.R.attr.state_focused};
41590075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlHighlight);
41690075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
41790075479814eb758d97b822606b448e1a521c298Chris Banes
41890075479814eb758d97b822606b448e1a521c298Chris Banes        // Default enabled state
41990075479814eb758d97b822606b448e1a521c298Chris Banes        states[i] = new int[0];
42090075479814eb758d97b822606b448e1a521c298Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorButtonNormal);
42190075479814eb758d97b822606b448e1a521c298Chris Banes        i++;
42290075479814eb758d97b822606b448e1a521c298Chris Banes
42390075479814eb758d97b822606b448e1a521c298Chris Banes        return new ColorStateList(states, colors);
424a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes    }
425a9585dae398a69dd67797e7ca86f44ffcabd9e86Chris Banes
426cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes    private ColorStateList createSpinnerColorStateList() {
427cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        final int[][] states = new int[3][];
428cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        final int[] colors = new int[3];
429cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        int i = 0;
430cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes
431cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        // Disabled state
432cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        states[i] = new int[]{-android.R.attr.state_enabled};
433cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        colors[i] = getDisabledThemeAttrColor(R.attr.colorControlNormal);
434cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        i++;
435cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes
436cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        states[i] = new int[]{-android.R.attr.state_pressed, -android.R.attr.state_focused};
437cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlNormal);
438cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        i++;
439cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes
440cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        states[i] = new int[0];
441cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        colors[i] = getThemeAttrColor(R.attr.colorControlActivated);
442cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        i++;
443cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes
444cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes        return new ColorStateList(states, colors);
445cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes    }
446cdd1b1d70cefeb052c2b506738b396f2f982e519Chris Banes
44790075479814eb758d97b822606b448e1a521c298Chris Banes    private int getThemeAttrColor(int attr) {
448f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        if (mContext.getTheme().resolveAttribute(attr, mTypedValue, true)) {
449f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            if (mTypedValue.type >= TypedValue.TYPE_FIRST_INT
450f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes                    && mTypedValue.type <= TypedValue.TYPE_LAST_INT) {
451f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes                return mTypedValue.data;
452f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            } else if (mTypedValue.type == TypedValue.TYPE_STRING) {
453f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes                return mResources.getColor(mTypedValue.resourceId);
454f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            }
455f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        }
456f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        return 0;
457469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
458469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
459414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes    private ColorStateList getThemeAttrColorStateList(int attr) {
460414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        if (mContext.getTheme().resolveAttribute(attr, mTypedValue, true)) {
461414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            if (mTypedValue.type == TypedValue.TYPE_STRING) {
462414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes                return mResources.getColorStateList(mTypedValue.resourceId);
463414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes            }
464414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        }
465414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes        return null;
466414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes    }
467414f52397a88d52a783a31d4c098bc3bec632b8dChris Banes
46890075479814eb758d97b822606b448e1a521c298Chris Banes    private int getThemeAttrColor(int attr, float alpha) {
469f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        final int color = getThemeAttrColor(attr);
470c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        final int originalAlpha = Color.alpha(color);
471c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes
472415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes        // Return the color, multiplying the original alpha by the disabled value
473415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes        return (color & 0x00ffffff) | (Math.round(originalAlpha * alpha) << 24);
474415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes    }
475415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes
47690075479814eb758d97b822606b448e1a521c298Chris Banes    private int getDisabledThemeAttrColor(int attr) {
477c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        // Now retrieve the disabledAlpha value from the theme
478c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        mContext.getTheme().resolveAttribute(android.R.attr.disabledAlpha, mTypedValue, true);
479c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        final float disabledAlpha = mTypedValue.getFloat();
480c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes
481415f740df4981ef2f5fb462a50c7cf095cc21128Chris Banes        return getThemeAttrColor(attr, disabledAlpha);
482c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes    }
483c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes
484469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static class ColorFilterLruCache extends LruCache<Integer, PorterDuffColorFilter> {
485469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
486469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        public ColorFilterLruCache(int maxSize) {
487469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            super(maxSize);
488469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
489469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
490469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        PorterDuffColorFilter get(int color, PorterDuff.Mode mode) {
491469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            return get(generateCacheKey(color, mode));
492469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
493469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
494469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        PorterDuffColorFilter put(int color, PorterDuff.Mode mode, PorterDuffColorFilter filter) {
495469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            return put(generateCacheKey(color, mode), filter);
496469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
497469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
498469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        private static int generateCacheKey(int color, PorterDuff.Mode mode) {
499469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            int hashCode = 1;
500469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            hashCode = 31 * hashCode + color;
501469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            hashCode = 31 * hashCode + mode.hashCode();
502469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            return hashCode;
503469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
504469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
505a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
506a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    public static void tintViewBackground(View view, TintInfo tint) {
507a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        final Drawable background = view.getBackground();
508a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        if (tint.mTintList != null) {
509a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            tintDrawableUsingColorFilter(
510a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                    background,
511a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                    tint.mTintList.getColorForState(view.getDrawableState(),
512a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                            tint.mTintList.getDefaultColor()),
513a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes                    tint.mTintMode != null ? tint.mTintMode : DEFAULT_MODE);
514a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        } else {
515a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            background.clearColorFilter();
516a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        }
517a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    }
518a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
519a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    private static void tintDrawableUsingColorFilter(Drawable drawable, int color,
520a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            PorterDuff.Mode mode) {
521a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        // First, lets see if the cache already contains the color filter
522a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, mode);
523a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
524a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        if (filter == null) {
525a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            // Cache miss, so create a color filter and add it to the cache
526a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            filter = new PorterDuffColorFilter(color, mode);
527a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes            COLOR_FILTER_CACHE.put(color, mode, filter);
528a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        }
529a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes
530a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes        drawable.setColorFilter(filter);
531a5f106fbd09335ae504c39b1ee1e0caa3f1238e3Chris Banes    }
532469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes}
533