ColorDrawable.java revision a426445dfdab43886dd894f2ba8a1d55bfcbb278
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.graphics.drawable; 18 19import android.graphics.*; 20import android.graphics.PorterDuff.Mode; 21import android.content.res.ColorStateList; 22import android.content.res.Resources; 23import android.content.res.Resources.Theme; 24import android.content.res.TypedArray; 25import android.util.AttributeSet; 26import android.view.ViewDebug; 27 28import com.android.internal.R; 29 30import org.xmlpull.v1.XmlPullParser; 31import org.xmlpull.v1.XmlPullParserException; 32 33import java.io.IOException; 34 35/** 36 * A specialized Drawable that fills the Canvas with a specified color. 37 * Note that a ColorDrawable ignores the ColorFilter. 38 * 39 * <p>It can be defined in an XML file with the <code><color></code> element.</p> 40 * 41 * @attr ref android.R.styleable#ColorDrawable_color 42 */ 43public class ColorDrawable extends Drawable { 44 private final Paint mPaint = new Paint(); 45 46 @ViewDebug.ExportedProperty(deepExport = true, prefix = "state_") 47 private ColorState mColorState; 48 private PorterDuffColorFilter mTintFilter; 49 50 private boolean mMutated; 51 52 /** 53 * Creates a new black ColorDrawable. 54 */ 55 public ColorDrawable() { 56 mColorState = new ColorState(); 57 } 58 59 /** 60 * Creates a new ColorDrawable with the specified color. 61 * 62 * @param color The color to draw. 63 */ 64 public ColorDrawable(int color) { 65 mColorState = new ColorState(); 66 67 setColor(color); 68 } 69 70 @Override 71 public int getChangingConfigurations() { 72 return super.getChangingConfigurations() | mColorState.mChangingConfigurations; 73 } 74 75 /** 76 * A mutable BitmapDrawable still shares its Bitmap with any other Drawable 77 * that comes from the same resource. 78 * 79 * @return This drawable. 80 */ 81 @Override 82 public Drawable mutate() { 83 if (!mMutated && super.mutate() == this) { 84 mColorState = new ColorState(mColorState); 85 mMutated = true; 86 } 87 return this; 88 } 89 90 @Override 91 public void draw(Canvas canvas) { 92 final ColorFilter colorFilter = mPaint.getColorFilter(); 93 if ((mColorState.mUseColor >>> 24) != 0 || colorFilter != null || mTintFilter != null) { 94 if (colorFilter == null) { 95 mPaint.setColorFilter(mTintFilter); 96 } 97 98 mPaint.setColor(mColorState.mUseColor); 99 canvas.drawRect(getBounds(), mPaint); 100 101 // Restore original color filter. 102 mPaint.setColorFilter(colorFilter); 103 } 104 } 105 106 /** 107 * Gets the drawable's color value. 108 * 109 * @return int The color to draw. 110 */ 111 public int getColor() { 112 return mColorState.mUseColor; 113 } 114 115 /** 116 * Sets the drawable's color value. This action will clobber the results of 117 * prior calls to {@link #setAlpha(int)} on this object, which side-affected 118 * the underlying color. 119 * 120 * @param color The color to draw. 121 */ 122 public void setColor(int color) { 123 if (mColorState.mBaseColor != color || mColorState.mUseColor != color) { 124 mColorState.mBaseColor = mColorState.mUseColor = color; 125 invalidateSelf(); 126 } 127 } 128 129 /** 130 * Returns the alpha value of this drawable's color. 131 * 132 * @return A value between 0 and 255. 133 */ 134 @Override 135 public int getAlpha() { 136 return mColorState.mUseColor >>> 24; 137 } 138 139 /** 140 * Sets the color's alpha value. 141 * 142 * @param alpha The alpha value to set, between 0 and 255. 143 */ 144 @Override 145 public void setAlpha(int alpha) { 146 alpha += alpha >> 7; // make it 0..256 147 final int baseAlpha = mColorState.mBaseColor >>> 24; 148 final int useAlpha = baseAlpha * alpha >> 8; 149 final int useColor = (mColorState.mBaseColor << 8 >>> 8) | (useAlpha << 24); 150 if (mColorState.mUseColor != useColor) { 151 mColorState.mUseColor = useColor; 152 invalidateSelf(); 153 } 154 } 155 156 /** 157 * Sets the color filter applied to this color. 158 * <p> 159 * Only supported on version {@link android.os.Build.VERSION_CODES#L} and 160 * above. Calling this method has no effect on earlier versions. 161 * 162 * @see android.graphics.drawable.Drawable#setColorFilter(ColorFilter) 163 */ 164 @Override 165 public void setColorFilter(ColorFilter colorFilter) { 166 mPaint.setColorFilter(colorFilter); 167 } 168 169 @Override 170 public void setTintList(ColorStateList tint) { 171 mColorState.mTint = tint; 172 mTintFilter = updateTintFilter(mTintFilter, tint, mColorState.mTintMode); 173 invalidateSelf(); 174 } 175 176 @Override 177 public void setTintMode(Mode tintMode) { 178 mColorState.mTintMode = tintMode; 179 mTintFilter = updateTintFilter(mTintFilter, mColorState.mTint, tintMode); 180 invalidateSelf(); 181 } 182 183 @Override 184 protected boolean onStateChange(int[] stateSet) { 185 final ColorState state = mColorState; 186 if (state.mTint != null && state.mTintMode != null) { 187 mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); 188 return true; 189 } 190 return false; 191 } 192 193 @Override 194 public boolean isStateful() { 195 return mColorState.mTint != null && mColorState.mTint.isStateful(); 196 } 197 198 @Override 199 public int getOpacity() { 200 if (mTintFilter != null || mPaint.getColorFilter() != null) { 201 return PixelFormat.TRANSLUCENT; 202 } 203 204 switch (mColorState.mUseColor >>> 24) { 205 case 255: 206 return PixelFormat.OPAQUE; 207 case 0: 208 return PixelFormat.TRANSPARENT; 209 } 210 return PixelFormat.TRANSLUCENT; 211 } 212 213 @Override 214 public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) 215 throws XmlPullParserException, IOException { 216 super.inflate(r, parser, attrs, theme); 217 218 final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ColorDrawable); 219 updateStateFromTypedArray(a); 220 a.recycle(); 221 } 222 223 /** 224 * Updates the constant state from the values in the typed array. 225 */ 226 private void updateStateFromTypedArray(TypedArray a) { 227 final ColorState state = mColorState; 228 229 // Account for any configuration changes. 230 state.mChangingConfigurations |= a.getChangingConfigurations(); 231 232 // Extract the theme attributes, if any. 233 state.mThemeAttrs = a.extractThemeAttrs(); 234 235 state.mBaseColor = a.getColor(R.styleable.ColorDrawable_color, state.mBaseColor); 236 state.mUseColor = state.mBaseColor; 237 } 238 239 @Override 240 public void applyTheme(Theme t) { 241 super.applyTheme(t); 242 243 final ColorState state = mColorState; 244 if (state == null || state.mThemeAttrs == null) { 245 return; 246 } 247 248 final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ColorDrawable); 249 updateStateFromTypedArray(a); 250 a.recycle(); 251 } 252 253 @Override 254 public ConstantState getConstantState() { 255 return mColorState; 256 } 257 258 final static class ColorState extends ConstantState { 259 int[] mThemeAttrs; 260 int mBaseColor; // base color, independent of setAlpha() 261 @ViewDebug.ExportedProperty 262 int mUseColor; // basecolor modulated by setAlpha() 263 int mChangingConfigurations; 264 ColorStateList mTint; 265 Mode mTintMode; 266 267 ColorState() { 268 // Empty constructor. 269 } 270 271 ColorState(ColorState state) { 272 mThemeAttrs = state.mThemeAttrs; 273 mBaseColor = state.mBaseColor; 274 mUseColor = state.mUseColor; 275 mChangingConfigurations = state.mChangingConfigurations; 276 mTint = state.mTint; 277 mTintMode = state.mTintMode; 278 } 279 280 @Override 281 public boolean canApplyTheme() { 282 return mThemeAttrs != null; 283 } 284 285 @Override 286 public Drawable newDrawable() { 287 return new ColorDrawable(this, null, null); 288 } 289 290 @Override 291 public Drawable newDrawable(Resources res) { 292 return new ColorDrawable(this, res, null); 293 } 294 295 @Override 296 public Drawable newDrawable(Resources res, Theme theme) { 297 return new ColorDrawable(this, res, theme); 298 } 299 300 @Override 301 public int getChangingConfigurations() { 302 return mChangingConfigurations; 303 } 304 } 305 306 private ColorDrawable(ColorState state, Resources res, Theme theme) { 307 if (theme != null && state.canApplyTheme()) { 308 mColorState = new ColorState(state); 309 applyTheme(theme); 310 } else { 311 mColorState = state; 312 } 313 314 mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); 315 } 316} 317