ColorDrawable.java revision 13d965485e5ca1355071eb0f04c4cd2683c371bf
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 setTint(ColorStateList tint, Mode tintMode) { 171 final ColorState state = mColorState; 172 if (state.mTint != tint || state.mTintMode != tintMode) { 173 state.mTint = tint; 174 state.mTintMode = tintMode; 175 176 mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); 177 invalidateSelf(); 178 } 179 } 180 181 @Override 182 protected boolean onStateChange(int[] stateSet) { 183 final ColorState state = mColorState; 184 if (state.mTint != null && state.mTintMode != null) { 185 mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); 186 return true; 187 } 188 return false; 189 } 190 191 @Override 192 public boolean isStateful() { 193 return mColorState.mTint != null && mColorState.mTint.isStateful(); 194 } 195 196 @Override 197 public int getOpacity() { 198 if (mTintFilter != null || mPaint.getColorFilter() != null) { 199 return PixelFormat.TRANSLUCENT; 200 } 201 202 switch (mColorState.mUseColor >>> 24) { 203 case 255: 204 return PixelFormat.OPAQUE; 205 case 0: 206 return PixelFormat.TRANSPARENT; 207 } 208 return PixelFormat.TRANSLUCENT; 209 } 210 211 @Override 212 public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) 213 throws XmlPullParserException, IOException { 214 super.inflate(r, parser, attrs, theme); 215 216 final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ColorDrawable); 217 updateStateFromTypedArray(a); 218 a.recycle(); 219 } 220 221 /** 222 * Updates the constant state from the values in the typed array. 223 */ 224 private void updateStateFromTypedArray(TypedArray a) { 225 final ColorState state = mColorState; 226 227 // Account for any configuration changes. 228 state.mChangingConfigurations |= a.getChangingConfigurations(); 229 230 // Extract the theme attributes, if any. 231 state.mThemeAttrs = a.extractThemeAttrs(); 232 233 state.mBaseColor = a.getColor(R.styleable.ColorDrawable_color, state.mBaseColor); 234 state.mUseColor = state.mBaseColor; 235 } 236 237 @Override 238 public void applyTheme(Theme t) { 239 super.applyTheme(t); 240 241 final ColorState state = mColorState; 242 if (state == null || state.mThemeAttrs == null) { 243 return; 244 } 245 246 final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ColorDrawable); 247 updateStateFromTypedArray(a); 248 a.recycle(); 249 } 250 251 @Override 252 public ConstantState getConstantState() { 253 return mColorState; 254 } 255 256 final static class ColorState extends ConstantState { 257 int[] mThemeAttrs; 258 int mBaseColor; // base color, independent of setAlpha() 259 @ViewDebug.ExportedProperty 260 int mUseColor; // basecolor modulated by setAlpha() 261 int mChangingConfigurations; 262 ColorStateList mTint; 263 Mode mTintMode; 264 265 ColorState() { 266 // Empty constructor. 267 } 268 269 ColorState(ColorState state) { 270 mThemeAttrs = state.mThemeAttrs; 271 mBaseColor = state.mBaseColor; 272 mUseColor = state.mUseColor; 273 mChangingConfigurations = state.mChangingConfigurations; 274 mTint = state.mTint; 275 mTintMode = state.mTintMode; 276 } 277 278 @Override 279 public boolean canApplyTheme() { 280 return mThemeAttrs != null; 281 } 282 283 @Override 284 public Drawable newDrawable() { 285 return new ColorDrawable(this, null, null); 286 } 287 288 @Override 289 public Drawable newDrawable(Resources res) { 290 return new ColorDrawable(this, res, null); 291 } 292 293 @Override 294 public Drawable newDrawable(Resources res, Theme theme) { 295 return new ColorDrawable(this, res, theme); 296 } 297 298 @Override 299 public int getChangingConfigurations() { 300 return mChangingConfigurations; 301 } 302 } 303 304 private ColorDrawable(ColorState state, Resources res, Theme theme) { 305 if (theme != null && state.canApplyTheme()) { 306 mColorState = new ColorState(state); 307 applyTheme(theme); 308 } else { 309 mColorState = state; 310 } 311 312 mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); 313 } 314} 315