FileDocCategorySizeDatePackage
TintManager.javaAPI DocAndroid 5.1 API15346Thu Mar 12 22:22:56 GMT 2015android.support.v7.internal.widget

TintManager

public class TintManager extends Object
hide

Fields Summary
private static final String
TAG
private static final boolean
DEBUG
static final PorterDuff.Mode
DEFAULT_MODE
private static final ColorFilterLruCache
COLOR_FILTER_CACHE
private static final int[]
TINT_COLOR_CONTROL_NORMAL
Drawables which should be tinted with the value of {@code R.attr.colorControlNormal}, using the default mode.
private static final int[]
TINT_COLOR_CONTROL_ACTIVATED
Drawables which should be tinted with the value of {@code R.attr.colorControlActivated}, using the default mode.
private static final int[]
TINT_COLOR_BACKGROUND_MULTIPLY
Drawables which should be tinted with the value of {@code android.R.attr.colorBackground}, using the {@link android.graphics.PorterDuff.Mode#MULTIPLY} mode.
private static final int[]
TINT_COLOR_CONTROL_STATE_LIST
Drawables which should be tinted using a state list containing values of {@code R.attr.colorControlNormal} and {@code R.attr.colorControlActivated}
private static final int[]
CONTAINERS_WITH_TINT_CHILDREN
Drawables which contain other drawables which should be tinted. The child drawable IDs should be defined in one of the arrays above.
private final android.content.Context
mContext
private final android.content.res.Resources
mResources
private final android.util.TypedValue
mTypedValue
private android.content.res.ColorStateList
mDefaultColorStateList
private android.content.res.ColorStateList
mSwitchThumbStateList
private android.content.res.ColorStateList
mSwitchTrackStateList
private android.content.res.ColorStateList
mButtonStateList
Constructors Summary
public TintManager(android.content.Context context)

        mContext = context;
        mResources = new TintResources(context.getResources(), this);
        mTypedValue = new TypedValue();
    
Methods Summary
private static booleanarrayContains(int[] array, int value)

        for (int id : array) {
            if (id == value) {
                return true;
            }
        }
        return false;
    
private android.content.res.ColorStateListgetButtonColorStateList()

        if (mButtonStateList == null) {
            final int[][] states = new int[4][];
            final int[] colors = new int[4];
            int i = 0;

            // Disabled state
            states[i] = new int[] { -android.R.attr.state_enabled };
            colors[i] = getDisabledThemeAttrColor(R.attr.colorButtonNormal);
            i++;

            states[i] = new int[] { android.R.attr.state_pressed };
            colors[i] = getThemeAttrColor(R.attr.colorControlHighlight);
            i++;

            states[i] = new int[] { android.R.attr.state_focused };
            colors[i] = getThemeAttrColor(R.attr.colorControlHighlight);
            i++;

            // Default enabled state
            states[i] = new int[0];
            colors[i] = getThemeAttrColor(R.attr.colorButtonNormal);
            i++;

            mButtonStateList = new ColorStateList(states, colors);
        }
        return mButtonStateList;
    
private android.content.res.ColorStateListgetDefaultColorStateList()

        if (mDefaultColorStateList == null) {
            /**
             * Generate the default color state list which uses the colorControl attributes.
             * Order is important here. The default enabled state needs to go at the bottom.
             */

            final int colorControlNormal = getThemeAttrColor(R.attr.colorControlNormal);
            final int colorControlActivated = getThemeAttrColor(R.attr.colorControlActivated);

            final int[][] states = new int[7][];
            final int[] colors = new int[7];
            int i = 0;

            // Disabled state
            states[i] = new int[] { -android.R.attr.state_enabled };
            colors[i] = getDisabledThemeAttrColor(R.attr.colorControlNormal);
            i++;

            states[i] = new int[] { android.R.attr.state_focused };
            colors[i] = colorControlActivated;
            i++;

            states[i] = new int[] { android.R.attr.state_activated };
            colors[i] = colorControlActivated;
            i++;

            states[i] = new int[] { android.R.attr.state_pressed };
            colors[i] = colorControlActivated;
            i++;

            states[i] = new int[] { android.R.attr.state_checked };
            colors[i] = colorControlActivated;
            i++;

            states[i] = new int[] { android.R.attr.state_selected };
            colors[i] = colorControlActivated;
            i++;

            // Default enabled state
            states[i] = new int[0];
            colors[i] = colorControlNormal;
            i++;

            mDefaultColorStateList = new ColorStateList(states, colors);
        }
        return mDefaultColorStateList;
    
intgetDisabledThemeAttrColor(int attr)

        // Now retrieve the disabledAlpha value from the theme
        mContext.getTheme().resolveAttribute(android.R.attr.disabledAlpha, mTypedValue, true);
        final float disabledAlpha = mTypedValue.getFloat();

        return getThemeAttrColor(attr, disabledAlpha);
    
public static android.graphics.drawable.DrawablegetDrawable(android.content.Context context, int resId)
A helper method to instantiate a {@link TintManager} and then call {@link #getDrawable(int)}. This method should not be used routinely.


                             
           
        if (isInTintList(resId)) {
            return new TintManager(context).getDrawable(resId);
        } else {
            return ContextCompat.getDrawable(context, resId);
        }
    
public android.graphics.drawable.DrawablegetDrawable(int resId)

        Drawable drawable = ContextCompat.getDrawable(mContext, resId);

        if (drawable != null) {
            drawable = drawable.mutate();

            if (arrayContains(TINT_COLOR_CONTROL_STATE_LIST, resId)) {
                drawable = new TintDrawableWrapper(drawable, getDefaultColorStateList());
            } else if (resId == R.drawable.abc_switch_track_mtrl_alpha) {
                drawable = new TintDrawableWrapper(drawable, getSwitchTrackColorStateList());
            } else if (resId == R.drawable.abc_switch_thumb_material) {
                drawable = new TintDrawableWrapper(drawable, getSwitchThumbColorStateList(),
                        PorterDuff.Mode.MULTIPLY);
            } else if (resId == R.drawable.abc_btn_default_mtrl_shape) {
                drawable = new TintDrawableWrapper(drawable, getButtonColorStateList());
            } else if (arrayContains(CONTAINERS_WITH_TINT_CHILDREN, resId)) {
                drawable = mResources.getDrawable(resId);
            } else {
                tintDrawable(resId, drawable);
            }
        }
        return drawable;
    
private android.content.res.ColorStateListgetSwitchThumbColorStateList()

        if (mSwitchThumbStateList == null) {
            final int[][] states = new int[3][];
            final int[] colors = new int[3];
            int i = 0;

            // Disabled state
            states[i] = new int[] { -android.R.attr.state_enabled };
            colors[i] = getDisabledThemeAttrColor(R.attr.colorSwitchThumbNormal);
            i++;

            states[i] = new int[] { android.R.attr.state_checked };
            colors[i] = getThemeAttrColor(R.attr.colorControlActivated);
            i++;

            // Default enabled state
            states[i] = new int[0];
            colors[i] = getThemeAttrColor(R.attr.colorSwitchThumbNormal);
            i++;

            mSwitchThumbStateList = new ColorStateList(states, colors);
        }
        return mSwitchThumbStateList;
    
private android.content.res.ColorStateListgetSwitchTrackColorStateList()

        if (mSwitchTrackStateList == null) {
            final int[][] states = new int[3][];
            final int[] colors = new int[3];
            int i = 0;

            // Disabled state
            states[i] = new int[] { -android.R.attr.state_enabled };
            colors[i] = getThemeAttrColor(android.R.attr.colorForeground, 0.1f);
            i++;

            states[i] = new int[] { android.R.attr.state_checked };
            colors[i] = getThemeAttrColor(R.attr.colorControlActivated, 0.3f);
            i++;

            // Default enabled state
            states[i] = new int[0];
            colors[i] = getThemeAttrColor(android.R.attr.colorForeground, 0.3f);
            i++;

            mSwitchTrackStateList = new ColorStateList(states, colors);
        }
        return mSwitchTrackStateList;
    
intgetThemeAttrColor(int attr)

        if (mContext.getTheme().resolveAttribute(attr, mTypedValue, true)) {
            if (mTypedValue.type >= TypedValue.TYPE_FIRST_INT
                    && mTypedValue.type <= TypedValue.TYPE_LAST_INT) {
                return mTypedValue.data;
            } else if (mTypedValue.type == TypedValue.TYPE_STRING) {
                return mResources.getColor(mTypedValue.resourceId);
            }
        }
        return 0;
    
intgetThemeAttrColor(int attr, float alpha)

        final int color = getThemeAttrColor(attr);
        final int originalAlpha = Color.alpha(color);

        // Return the color, multiplying the original alpha by the disabled value
        return (color & 0x00ffffff) | (Math.round(originalAlpha * alpha) << 24);
    
private static booleanisInTintList(int drawableId)

        return arrayContains(TINT_COLOR_BACKGROUND_MULTIPLY, drawableId) ||
                arrayContains(TINT_COLOR_CONTROL_NORMAL, drawableId) ||
                arrayContains(TINT_COLOR_CONTROL_ACTIVATED, drawableId) ||
                arrayContains(TINT_COLOR_CONTROL_STATE_LIST, drawableId) ||
                arrayContains(CONTAINERS_WITH_TINT_CHILDREN, drawableId);
    
voidtintDrawable(int resId, android.graphics.drawable.Drawable drawable)

        PorterDuff.Mode tintMode = null;
        boolean colorAttrSet = false;
        int colorAttr = 0;
        int alpha = -1;

        if (arrayContains(TINT_COLOR_CONTROL_NORMAL, resId)) {
            colorAttr = R.attr.colorControlNormal;
            colorAttrSet = true;
        } else if (arrayContains(TINT_COLOR_CONTROL_ACTIVATED, resId)) {
            colorAttr = R.attr.colorControlActivated;
            colorAttrSet = true;
        } else if (arrayContains(TINT_COLOR_BACKGROUND_MULTIPLY, resId)) {
            colorAttr = android.R.attr.colorBackground;
            colorAttrSet = true;
            tintMode = PorterDuff.Mode.MULTIPLY;
        } else if (resId == R.drawable.abc_list_divider_mtrl_alpha) {
            colorAttr = android.R.attr.colorForeground;
            colorAttrSet = true;
            alpha = Math.round(0.16f * 255);
        }

        if (colorAttrSet) {
            if (tintMode == null) {
                tintMode = DEFAULT_MODE;
            }
            final int color = getThemeAttrColor(colorAttr);

            // First, lets see if the cache already contains the color filter
            PorterDuffColorFilter filter = COLOR_FILTER_CACHE.get(color, tintMode);

            if (filter == null) {
                // Cache miss, so create a color filter and add it to the cache
                filter = new PorterDuffColorFilter(color, tintMode);
                COLOR_FILTER_CACHE.put(color, tintMode, filter);
            }

            // Finally set the color filter
            drawable.setColorFilter(filter);

            if (alpha != -1) {
                drawable.setAlpha(alpha);
            }

            if (DEBUG) {
                Log.d(TAG, "Tinted Drawable ID: " + mResources.getResourceName(resId) +
                        " with color: #" + Integer.toHexString(color));
            }
        }