AppCompatDrawableManager.java revision 14f8f0dfae09445074dc0f7b5bbe5732d6922da7
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;
26469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v4.content.ContextCompat;
27469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v4.util.LruCache;
28469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.support.v7.appcompat.R;
29469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.util.Log;
30469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banesimport android.util.TypedValue;
31469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
32469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes/**
33469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes * @hide
34469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes */
35469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banespublic class TintManager {
36469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
37469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final String TAG = TintManager.class.getSimpleName();
38469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final boolean DEBUG = false;
39469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final PorterDuff.Mode DEFAULT_MODE = PorterDuff.Mode.SRC_IN;
40469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
41469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final ColorFilterLruCache COLOR_FILTER_CACHE = new ColorFilterLruCache(6);
42469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
43469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
44469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * Drawables which should be tinted with the value of {@code R.attr.colorControlNormal},
45469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * using the default mode.
46469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
47469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final int[] TINT_COLOR_CONTROL_NORMAL = {
48469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_ab_back_mtrl_am_alpha,
49469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_go_search_api_mtrl_alpha,
50469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_search_api_mtrl_alpha,
51469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_commit_search_api_mtrl_alpha,
52469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_clear_mtrl_alpha,
53469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_menu_share_mtrl_alpha,
54469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_menu_moreoverflow_mtrl_alpha,
55469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_ic_voice_search_api_mtrl_alpha,
56469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_textfield_search_default_mtrl_alpha,
57c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            R.drawable.abc_textfield_default_mtrl_alpha,
58c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            R.drawable.abc_list_divider_mtrl_alpha
59469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
60469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
61469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
62469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * Drawables which should be tinted with the value of {@code R.attr.colorControlActivated},
63469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * using the default mode.
64469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
65469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final int[] TINT_COLOR_CONTROL_ACTIVATED = {
66469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_textfield_activated_mtrl_alpha,
6714f8f0dfae09445074dc0f7b5bbe5732d6922da7Chris Banes            R.drawable.abc_textfield_search_activated_mtrl_alpha,
6814f8f0dfae09445074dc0f7b5bbe5732d6922da7Chris Banes            R.drawable.abc_cab_background_top_mtrl_alpha
69469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
70469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
71469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
72469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * Drawables which should be tinted with the value of {@code android.R.attr.colorBackground},
73469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * using the {@link android.graphics.PorterDuff.Mode#MULTIPLY} mode.
74469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
75469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final int[] TINT_COLOR_BACKGROUND_MULTIPLY = {
761073132946bb0a53a788949fe4c060f72051cd57Chris Banes            R.drawable.abc_popup_background_mtrl_mult,
771073132946bb0a53a788949fe4c060f72051cd57Chris Banes            R.drawable.abc_cab_background_internal_bg
78469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
79469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
80469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
81469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * Drawables which should be tinted using a state list containing values of
82469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * {@code R.attr.colorControlNormal} and {@code R.attr.colorControlActivated}
83469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
84469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final int[] TINT_COLOR_CONTROL_STATE_LIST = {
85469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_edit_text_material,
86469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_tab_indicator_material,
87469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_textfield_search_material,
88469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            R.drawable.abc_spinner_mtrl_am_alpha
89469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
90469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
91469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
92469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * Drawables which contain other drawables which should be tinted. The child drawable IDs
93469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * should be defined in one of the arrays above.
94469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
95469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static final int[] CONTAINERS_WITH_TINT_CHILDREN = {
961073132946bb0a53a788949fe4c060f72051cd57Chris Banes            R.drawable.abc_cab_background_top_material
97469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    };
98469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
99469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private final Context mContext;
100469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private final Resources mResources;
101469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private final TypedValue mTypedValue;
102469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
103469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private ColorStateList mDefaultColorStateList;
104469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
105469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    /**
106469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * A helper method to instantiate a {@link TintManager} and then call {@link #getDrawable(int)}.
107469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     * This method should not be used routinely.
108469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes     */
109469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    public static Drawable getDrawable(Context context, int resId) {
110469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        TintManager tintManager = new TintManager(context);
111469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        return tintManager.getDrawable(resId);
112469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
113469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
114469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    public TintManager(Context context) {
115469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        mContext = context;
116469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        mResources = new TintResources(context.getResources(), this);
117469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        mTypedValue = new TypedValue();
118469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
119469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
120469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    public Drawable getDrawable(int resId) {
121469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        Drawable drawable = ContextCompat.getDrawable(mContext, resId);
122469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
123469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        if (drawable != null) {
124469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (arrayContains(TINT_COLOR_CONTROL_STATE_LIST, resId)) {
125469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                drawable = new TintDrawableWrapper(drawable, getDefaultColorStateList());
126469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            } else if (arrayContains(CONTAINERS_WITH_TINT_CHILDREN, resId)) {
127469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                drawable = mResources.getDrawable(resId);
128469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            } else {
129469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                tintDrawable(resId, drawable);
130469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
131469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
132469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        return drawable;
133469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
134469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
135469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    void tintDrawable(int resId, Drawable drawable) {
136469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        PorterDuff.Mode tintMode = null;
137469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        boolean colorAttrSet = false;
138469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        int colorAttr = 0;
139469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
140469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        if (arrayContains(TINT_COLOR_CONTROL_NORMAL, resId)) {
141469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttr = R.attr.colorControlNormal;
142469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttrSet = true;
143469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        } else if (arrayContains(TINT_COLOR_CONTROL_ACTIVATED, resId)) {
144469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttr = R.attr.colorControlActivated;
145469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttrSet = true;
146469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        } else if (arrayContains(TINT_COLOR_BACKGROUND_MULTIPLY, resId)) {
147469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttr = android.R.attr.colorBackground;
148469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colorAttrSet = true;
149469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            tintMode = PorterDuff.Mode.MULTIPLY;
150469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
151469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
152f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        if (colorAttrSet) {
153469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (tintMode == null) {
154469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                tintMode = DEFAULT_MODE;
155469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
156f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            final int color = getThemeAttrColor(colorAttr);
157469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
158469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            // First, lets see if the cache already contains the color filter
159469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, tintMode);
160469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
161469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (filter == null) {
162469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                // Cache miss, so create a color filter and add it to the cache
163469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                filter = new PorterDuffColorFilter(color, tintMode);
164469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                COLOR_FILTER_CACHE.put(color, tintMode, filter);
165469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
166469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
167469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            // Finally set the color filter
168469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            drawable.setColorFilter(filter);
169469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
170469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (DEBUG) {
171469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                Log.d(TAG, "Tinted Drawable ID: " + mResources.getResourceName(resId) +
172469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                        " with color: #" + Integer.toHexString(color));
173469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
174469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
175469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
176469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
177469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static boolean arrayContains(int[] array, int value) {
178469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        for (int id : array) {
179469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            if (id == value) {
180469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes                return true;
181469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            }
182469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
183469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        return false;
184469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
185469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
186469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private ColorStateList getDefaultColorStateList() {
187469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        if (mDefaultColorStateList == null) {
188469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            /**
189469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes             * Generate the default color state list which uses the colorControl attributes.
190469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes             * Order is important here. The default enabled state needs to go at the bottom.
191469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes             */
192469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
193469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int colorControlNormal = getThemeAttrColor(R.attr.colorControlNormal);
194469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int colorControlActivated = getThemeAttrColor(R.attr.colorControlActivated);
195469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
196469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int[][] states = new int[7][];
197469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            final int[] colors = new int[7];
198469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            int i = 0;
199469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
200c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            // Disabled state
201c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { -android.R.attr.state_enabled };
202c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            colors[i] = getDisabledThemeAttrColor(R.attr.colorControlNormal);
203469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
204469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
205c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_focused };
206469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
207469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
208469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
209c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_activated };
210469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
211469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
212469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
213c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_pressed };
214469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
215469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
216469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
217c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_checked };
218469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            colors[i] = colorControlActivated;
219469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
220469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
221c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            states[i] = new int[] { android.R.attr.state_selected };
222c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            colors[i] = colorControlActivated;
223469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
224469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
225c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            // Default enabled state
226469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            states[i] = new int[0];
227c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes            colors[i] = colorControlNormal;
228469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            i++;
229469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
230469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            mDefaultColorStateList = new ColorStateList(states, colors);
231469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
232469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        return mDefaultColorStateList;
233469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
234469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
235469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    int getThemeAttrColor(int attr) {
236f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        if (mContext.getTheme().resolveAttribute(attr, mTypedValue, true)) {
237f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            if (mTypedValue.type >= TypedValue.TYPE_FIRST_INT
238f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes                    && mTypedValue.type <= TypedValue.TYPE_LAST_INT) {
239f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes                return mTypedValue.data;
240f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            } else if (mTypedValue.type == TypedValue.TYPE_STRING) {
241f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes                return mResources.getColor(mTypedValue.resourceId);
242f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes            }
243f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        }
244f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        return 0;
245469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
246469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
247c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes    int getDisabledThemeAttrColor(int attr) {
248f31fb9d2fd3b5b130f3f5ac121b033546d869231Chris Banes        final int color = getThemeAttrColor(attr);
249c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        final int originalAlpha = Color.alpha(color);
250c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes
251c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        // Now retrieve the disabledAlpha value from the theme
252c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        mContext.getTheme().resolveAttribute(android.R.attr.disabledAlpha, mTypedValue, true);
253c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        final float disabledAlpha = mTypedValue.getFloat();
254c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes
255c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        // Return the color, multiplying the original alpha by the disabled value
256c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes        return (color & 0x00ffffff) | (Math.round(originalAlpha * disabledAlpha) << 24);
257c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes    }
258c497221ee0e2e873f49653ff1a046df2e5276759Chris Banes
259469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    private static class ColorFilterLruCache extends LruCache<Integer, PorterDuffColorFilter> {
260469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
261469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        public ColorFilterLruCache(int maxSize) {
262469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            super(maxSize);
263469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
264469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
265469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        PorterDuffColorFilter get(int color, PorterDuff.Mode mode) {
266469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            return get(generateCacheKey(color, mode));
267469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
268469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
269469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        PorterDuffColorFilter put(int color, PorterDuff.Mode mode, PorterDuffColorFilter filter) {
270469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            return put(generateCacheKey(color, mode), filter);
271469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
272469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes
273469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        private static int generateCacheKey(int color, PorterDuff.Mode mode) {
274469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            int hashCode = 1;
275469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            hashCode = 31 * hashCode + color;
276469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            hashCode = 31 * hashCode + mode.hashCode();
277469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes            return hashCode;
278469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes        }
279469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes    }
280469286122bcbbecbdd0bef74fb50f9d8920e77b9Chris Banes}
281