/* * 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.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.
* 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(); } @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. */ 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. */ private void updateLocalState(Resources r) { mTintFilter = updateTintFilter(mTintFilter, mColorState.mTint, mColorState.mTintMode); } }