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;
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;
public ColorDrawable() {
mColorState = new ColorState();
}
public ColorDrawable(@ColorInt int color) {
mColorState = new ColorState();
setColor(color);
}
@Override
public @Config int getChangingConfigurations() {
return super.getChangingConfigurations() | mColorState.getChangingConfigurations();
}
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
mColorState = new ColorState(mColorState);
mMutated = true;
}
return this;
}
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);
mPaint.setColorFilter(colorFilter);
}
}
@ColorInt
public int getColor() {
return mColorState.mUseColor;
}
public void setColor(@ColorInt int color) {
if (mColorState.mBaseColor != color || mColorState.mUseColor != color) {
mColorState.mBaseColor = mColorState.mUseColor = color;
invalidateSelf();
}
}
@Override
public int getAlpha() {
return mColorState.mUseColor >>> 24;
}
@Override
public void setAlpha(int alpha) {
alpha += alpha >> 7;
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();
}
}
@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();
}
@Override
public boolean hasFocusStateSpecified() {
return mColorState.mTint != null && mColorState.mTint.hasFocusStateSpecified();
}
@Override
public void setXfermode(@Nullable Xfermode mode) {
mPaint.setXfermode(mode);
invalidateSelf();
}
@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);
}
private void updateStateFromTypedArray(TypedArray a) {
final ColorState state = mColorState;
state.mChangingConfigurations |= a.getChangingConfigurations();
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;
@ViewDebug.ExportedProperty
int mUseColor;
@Config int mChangingConfigurations;
ColorStateList mTint = null;
Mode mTintMode = DEFAULT_TINT_MODE;
ColorState() {
}
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);
}
private void updateLocalState(Resources r) {
mTintFilter = updateTintFilter(mTintFilter, mColorState.mTint, mColorState.mTintMode);
}
}