/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.graphics.drawable;

import android.annotation.ColorInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.content.pm.ActivityInfo.Config;
import android.graphics.*;
import android.graphics.PorterDuff.Mode;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.ViewDebug;

import com.android.internal.R;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;

A specialized Drawable that fills the Canvas with a specified color. Note that a ColorDrawable ignores the ColorFilter.

It can be defined in an XML file with the <color> element.

@attrref android.R.styleable#ColorDrawable_color
/** * A specialized Drawable that fills the Canvas with a specified color. * Note that a ColorDrawable ignores the ColorFilter. * * <p>It can be defined in an XML file with the <code>&lt;color></code> element.</p> * * @attr ref android.R.styleable#ColorDrawable_color */
public class ColorDrawable extends Drawable { private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @ViewDebug.ExportedProperty(deepExport = true, prefix = "state_") private ColorState mColorState; private PorterDuffColorFilter mTintFilter; private boolean mMutated;
Creates a new black ColorDrawable.
/** * Creates a new black ColorDrawable. */
public ColorDrawable() { mColorState = new ColorState(); }
Creates a new ColorDrawable with the specified color.
Params:
  • color – The color to draw.
/** * Creates a new ColorDrawable with the specified color. * * @param color The color to draw. */
public ColorDrawable(@ColorInt int color) { mColorState = new ColorState(); setColor(color); } @Override public @Config int getChangingConfigurations() { return super.getChangingConfigurations() | mColorState.getChangingConfigurations(); }
A mutable BitmapDrawable still shares its Bitmap with any other Drawable that comes from the same resource.
Returns:This drawable.
/** * A mutable BitmapDrawable still shares its Bitmap with any other Drawable * that comes from the same resource. * * @return This drawable. */
@Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { mColorState = new ColorState(mColorState); mMutated = true; } return this; }
@hide
/** * @hide */
public void clearMutated() { super.clearMutated(); mMutated = false; } @Override public void draw(Canvas canvas) { final ColorFilter colorFilter = mPaint.getColorFilter(); if ((mColorState.mUseColor >>> 24) != 0 || colorFilter != null || mTintFilter != null) { if (colorFilter == null) { mPaint.setColorFilter(mTintFilter); } mPaint.setColor(mColorState.mUseColor); canvas.drawRect(getBounds(), mPaint); // Restore original color filter. mPaint.setColorFilter(colorFilter); } }
Gets the drawable's color value.
Returns:int The color to draw.
/** * Gets the drawable's color value. * * @return int The color to draw. */
@ColorInt public int getColor() { return mColorState.mUseColor; }
Sets the drawable's color value. This action will clobber the results of prior calls to setAlpha(int) on this object, which side-affected the underlying color.
Params:
  • color – The color to draw.
/** * Sets the drawable's color value. This action will clobber the results of * prior calls to {@link #setAlpha(int)} on this object, which side-affected * the underlying color. * * @param color The color to draw. */
public void setColor(@ColorInt int color) { if (mColorState.mBaseColor != color || mColorState.mUseColor != color) { mColorState.mBaseColor = mColorState.mUseColor = color; invalidateSelf(); } }
Returns the alpha value of this drawable's color.
Returns:A value between 0 and 255.
/** * Returns the alpha value of this drawable's color. * * @return A value between 0 and 255. */
@Override public int getAlpha() { return mColorState.mUseColor >>> 24; }
Sets the color's alpha value.
Params:
  • alpha – The alpha value to set, between 0 and 255.
/** * Sets the color's alpha value. * * @param alpha The alpha value to set, between 0 and 255. */
@Override public void setAlpha(int alpha) { alpha += alpha >> 7; // make it 0..256 final int baseAlpha = mColorState.mBaseColor >>> 24; final int useAlpha = baseAlpha * alpha >> 8; final int useColor = (mColorState.mBaseColor << 8 >>> 8) | (useAlpha << 24); if (mColorState.mUseColor != useColor) { mColorState.mUseColor = useColor; invalidateSelf(); } }
Sets the color filter applied to this color.

Only supported on version VERSION_CODES.LOLLIPOP and above. Calling this method has no effect on earlier versions.

See Also:
/** * Sets the color filter applied to this color. * <p> * Only supported on version {@link android.os.Build.VERSION_CODES#LOLLIPOP} and * above. Calling this method has no effect on earlier versions. * * @see android.graphics.drawable.Drawable#setColorFilter(ColorFilter) */
@Override public void setColorFilter(ColorFilter colorFilter) { mPaint.setColorFilter(colorFilter); } @Override public void setTintList(ColorStateList tint) { mColorState.mTint = tint; mTintFilter = updateTintFilter(mTintFilter, tint, mColorState.mTintMode); invalidateSelf(); } @Override public void setTintMode(Mode tintMode) { mColorState.mTintMode = tintMode; mTintFilter = updateTintFilter(mTintFilter, mColorState.mTint, tintMode); invalidateSelf(); } @Override protected boolean onStateChange(int[] stateSet) { final ColorState state = mColorState; if (state.mTint != null && state.mTintMode != null) { mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); return true; } return false; } @Override public boolean isStateful() { return mColorState.mTint != null && mColorState.mTint.isStateful(); }
@hide
/** @hide */
@Override public boolean hasFocusStateSpecified() { return mColorState.mTint != null && mColorState.mTint.hasFocusStateSpecified(); }
Params:
  • mode – new transfer mode
@hide
/** * @hide * @param mode new transfer mode */
@Override public void setXfermode(@Nullable Xfermode mode) { mPaint.setXfermode(mode); invalidateSelf(); }
@hide
Returns:current transfer mode
/** * @hide * @return current transfer mode */
@TestApi public Xfermode getXfermode() { return mPaint.getXfermode(); } @Override public int getOpacity() { if (mTintFilter != null || mPaint.getColorFilter() != null) { return PixelFormat.TRANSLUCENT; } switch (mColorState.mUseColor >>> 24) { case 255: return PixelFormat.OPAQUE; case 0: return PixelFormat.TRANSPARENT; } return PixelFormat.TRANSLUCENT; } @Override public void getOutline(@NonNull Outline outline) { outline.setRect(getBounds()); outline.setAlpha(getAlpha() / 255.0f); } @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { super.inflate(r, parser, attrs, theme); final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ColorDrawable); updateStateFromTypedArray(a); a.recycle(); updateLocalState(r); }
Updates the constant state from the values in the typed array.
/** * Updates the constant state from the values in the typed array. */
private void updateStateFromTypedArray(TypedArray a) { final ColorState state = mColorState; // Account for any configuration changes. state.mChangingConfigurations |= a.getChangingConfigurations(); // Extract the theme attributes, if any. state.mThemeAttrs = a.extractThemeAttrs(); state.mBaseColor = a.getColor(R.styleable.ColorDrawable_color, state.mBaseColor); state.mUseColor = state.mBaseColor; } @Override public boolean canApplyTheme() { return mColorState.canApplyTheme() || super.canApplyTheme(); } @Override public void applyTheme(Theme t) { super.applyTheme(t); final ColorState state = mColorState; if (state == null) { return; } if (state.mThemeAttrs != null) { final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ColorDrawable); updateStateFromTypedArray(a); a.recycle(); } if (state.mTint != null && state.mTint.canApplyTheme()) { state.mTint = state.mTint.obtainForTheme(t); } updateLocalState(t.getResources()); } @Override public ConstantState getConstantState() { return mColorState; } final static class ColorState extends ConstantState { int[] mThemeAttrs; int mBaseColor; // base color, independent of setAlpha() @ViewDebug.ExportedProperty int mUseColor; // basecolor modulated by setAlpha() @Config int mChangingConfigurations; ColorStateList mTint = null; Mode mTintMode = DEFAULT_TINT_MODE; ColorState() { // Empty constructor. } ColorState(ColorState state) { mThemeAttrs = state.mThemeAttrs; mBaseColor = state.mBaseColor; mUseColor = state.mUseColor; mChangingConfigurations = state.mChangingConfigurations; mTint = state.mTint; mTintMode = state.mTintMode; } @Override public boolean canApplyTheme() { return mThemeAttrs != null || (mTint != null && mTint.canApplyTheme()); } @Override public Drawable newDrawable() { return new ColorDrawable(this, null); } @Override public Drawable newDrawable(Resources res) { return new ColorDrawable(this, res); } @Override public @Config int getChangingConfigurations() { return mChangingConfigurations | (mTint != null ? mTint.getChangingConfigurations() : 0); } } private ColorDrawable(ColorState state, Resources res) { mColorState = state; updateLocalState(res); }
Initializes local dynamic properties from state. This should be called after significant state changes, e.g. from the One True Constructor and after inflating or applying a theme.
/** * Initializes local dynamic properties from state. This should be called * after significant state changes, e.g. from the One True Constructor and * after inflating or applying a theme. */
private void updateLocalState(Resources r) { mTintFilter = updateTintFilter(mTintFilter, mColorState.mTint, mColorState.mTintMode); } }