ColorDrawable.java revision cda212d79d449468384cc7744878b8c99984059c
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.content.res.Resources; 21import android.content.res.Resources.Theme; 22import android.content.res.TypedArray; 23import android.util.AttributeSet; 24import android.view.ViewDebug; 25 26import com.android.internal.R; 27 28import org.xmlpull.v1.XmlPullParser; 29import org.xmlpull.v1.XmlPullParserException; 30 31import java.io.IOException; 32 33/** 34 * A specialized Drawable that fills the Canvas with a specified color. 35 * Note that a ColorDrawable ignores the ColorFilter. 36 * 37 * <p>It can be defined in an XML file with the <code><color></code> element.</p> 38 * 39 * @attr ref android.R.styleable#ColorDrawable_color 40 */ 41public class ColorDrawable extends Drawable { 42 @ViewDebug.ExportedProperty(deepExport = true, prefix = "state_") 43 private ColorState mColorState; 44 private final Paint mPaint = new Paint(); 45 private boolean mMutated; 46 47 /** 48 * Creates a new black ColorDrawable. 49 */ 50 public ColorDrawable() { 51 mColorState = new ColorState(); 52 } 53 54 /** 55 * Creates a new ColorDrawable with the specified color. 56 * 57 * @param color The color to draw. 58 */ 59 public ColorDrawable(int color) { 60 mColorState = new ColorState(); 61 62 setColor(color); 63 } 64 65 @Override 66 public int getChangingConfigurations() { 67 return super.getChangingConfigurations() | mColorState.mChangingConfigurations; 68 } 69 70 /** 71 * A mutable BitmapDrawable still shares its Bitmap with any other Drawable 72 * that comes from the same resource. 73 * 74 * @return This drawable. 75 */ 76 @Override 77 public Drawable mutate() { 78 if (!mMutated && super.mutate() == this) { 79 mColorState = new ColorState(mColorState); 80 mMutated = true; 81 } 82 return this; 83 } 84 85 @Override 86 public void draw(Canvas canvas) { 87 if ((mColorState.mUseColor >>> 24) != 0) { 88 mPaint.setColor(mColorState.mUseColor); 89 canvas.drawRect(getBounds(), mPaint); 90 } 91 } 92 93 /** 94 * Gets the drawable's color value. 95 * 96 * @return int The color to draw. 97 */ 98 public int getColor() { 99 return mColorState.mUseColor; 100 } 101 102 /** 103 * Sets the drawable's color value. This action will clobber the results of 104 * prior calls to {@link #setAlpha(int)} on this object, which side-affected 105 * the underlying color. 106 * 107 * @param color The color to draw. 108 */ 109 public void setColor(int color) { 110 if (mColorState.mBaseColor != color || mColorState.mUseColor != color) { 111 mColorState.mBaseColor = mColorState.mUseColor = color; 112 invalidateSelf(); 113 } 114 } 115 116 /** 117 * Returns the alpha value of this drawable's color. 118 * 119 * @return A value between 0 and 255. 120 */ 121 @Override 122 public int getAlpha() { 123 return mColorState.mUseColor >>> 24; 124 } 125 126 /** 127 * Sets the color's alpha value. 128 * 129 * @param alpha The alpha value to set, between 0 and 255. 130 */ 131 @Override 132 public void setAlpha(int alpha) { 133 alpha += alpha >> 7; // make it 0..256 134 final int baseAlpha = mColorState.mBaseColor >>> 24; 135 final int useAlpha = baseAlpha * alpha >> 8; 136 final int useColor = (mColorState.mBaseColor << 8 >>> 8) | (useAlpha << 24); 137 if (mColorState.mUseColor != useColor) { 138 mColorState.mUseColor = useColor; 139 invalidateSelf(); 140 } 141 } 142 143 /** 144 * Setting a color filter on a ColorDrawable has no effect. 145 * 146 * @param colorFilter Ignore. 147 */ 148 @Override 149 public void setColorFilter(ColorFilter colorFilter) { 150 } 151 152 @Override 153 public int getOpacity() { 154 switch (mColorState.mUseColor >>> 24) { 155 case 255: 156 return PixelFormat.OPAQUE; 157 case 0: 158 return PixelFormat.TRANSPARENT; 159 } 160 return PixelFormat.TRANSLUCENT; 161 } 162 163 @Override 164 public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) 165 throws XmlPullParserException, IOException { 166 super.inflate(r, parser, attrs, theme); 167 168 final TypedArray a = obtainAttributes( 169 r, theme, attrs, R.styleable.ColorDrawable); 170 inflateStateFromTypedArray(a); 171 a.recycle(); 172 } 173 174 /** 175 * Initializes the constant state from the values in the typed array. 176 */ 177 private void inflateStateFromTypedArray(TypedArray a) { 178 final ColorState state = mColorState; 179 180 // Extract the theme attributes, if any. 181 final int[] themeAttrs = a.extractThemeAttrs(); 182 state.mThemeAttrs = themeAttrs; 183 184 if (themeAttrs == null || themeAttrs[R.styleable.ColorDrawable_color] == 0) { 185 final int color = a.getColor(R.styleable.ColorDrawable_color, 0); 186 state.mBaseColor = color; 187 state.mUseColor = color; 188 } 189 } 190 191 @Override 192 public void applyTheme(Theme t) { 193 super.applyTheme(t); 194 195 final ColorState state = mColorState; 196 if (state == null) { 197 throw new RuntimeException("Can't apply theme to <color> with no constant state"); 198 } 199 200 final int[] themeAttrs = state.mThemeAttrs; 201 if (themeAttrs != null) { 202 final TypedArray a = t.resolveAttributes(themeAttrs, R.styleable.ColorDrawable); 203 updateStateFromTypedArray(a); 204 a.recycle(); 205 } 206 } 207 208 /** 209 * Updates the constant state from the values in the typed array. 210 */ 211 private void updateStateFromTypedArray(TypedArray a) { 212 final ColorState state = mColorState; 213 214 if (a.hasValue(R.styleable.ColorDrawable_color)) { 215 final int color = a.getColor(R.styleable.ColorDrawable_color, 0); 216 state.mBaseColor = color; 217 state.mUseColor = color; 218 } 219 } 220 221 @Override 222 public ConstantState getConstantState() { 223 mColorState.mChangingConfigurations = getChangingConfigurations(); 224 return mColorState; 225 } 226 227 final static class ColorState extends ConstantState { 228 int mBaseColor; // base color, independent of setAlpha() 229 @ViewDebug.ExportedProperty 230 int mUseColor; // basecolor modulated by setAlpha() 231 int mChangingConfigurations; 232 int[] mThemeAttrs; 233 234 ColorState() { 235 // Empty constructor. 236 } 237 238 ColorState(ColorState state) { 239 mBaseColor = state.mBaseColor; 240 mUseColor = state.mUseColor; 241 mChangingConfigurations = state.mChangingConfigurations; 242 mThemeAttrs = state.mThemeAttrs; 243 } 244 245 @Override 246 public boolean canApplyTheme() { 247 return mThemeAttrs != null; 248 } 249 250 @Override 251 public Drawable newDrawable() { 252 return new ColorDrawable(this, null, null); 253 } 254 255 @Override 256 public Drawable newDrawable(Resources res) { 257 return new ColorDrawable(this, res, null); 258 } 259 260 @Override 261 public Drawable newDrawable(Resources res, Theme theme) { 262 return new ColorDrawable(this, res, theme); 263 } 264 265 @Override 266 public int getChangingConfigurations() { 267 return mChangingConfigurations; 268 } 269 } 270 271 private ColorDrawable(ColorState state, Resources res, Theme theme) { 272 if (theme != null && state.canApplyTheme()) { 273 mColorState = new ColorState(state); 274 applyTheme(theme); 275 } else { 276 mColorState = state; 277 } 278 279 // No local properties to initialize. 280 } 281} 282