DrawableContainer.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
1/* 2 * Copyright (C) 2006 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.*; 20 21public class DrawableContainer extends Drawable implements Drawable.Callback { 22 23 private DrawableContainerState mDrawableContainerState; 24 private Drawable mCurrDrawable; 25 private int mAlpha = 0xFF; 26 private ColorFilter mColorFilter; 27 private boolean mDither; 28 29 private int mCurIndex = -1; 30 31 // overrides from Drawable 32 33 @Override 34 public void draw(Canvas canvas) { 35 if (mCurrDrawable != null) { 36 mCurrDrawable.draw(canvas); 37 } 38 } 39 40 @Override 41 public int getChangingConfigurations() { 42 return super.getChangingConfigurations() 43 | mDrawableContainerState.mChangingConfigurations 44 | mDrawableContainerState.mChildrenChangingConfigurations; 45 } 46 47 @Override 48 public boolean getPadding(Rect padding) { 49 final Rect r = mDrawableContainerState.getConstantPadding(); 50 if (r != null) { 51 padding.set(r); 52 return true; 53 } 54 if (mCurrDrawable != null) { 55 return mCurrDrawable.getPadding(padding); 56 } else { 57 return super.getPadding(padding); 58 } 59 } 60 61 @Override 62 public void setAlpha(int alpha) { 63 if (mAlpha != alpha) { 64 mAlpha = alpha; 65 if (mCurrDrawable != null) { 66 mCurrDrawable.setAlpha(alpha); 67 } 68 } 69 } 70 71 @Override 72 public void setDither(boolean dither) { 73 if (mDither != dither) { 74 mDither = dither; 75 if (mCurrDrawable != null) { 76 mCurrDrawable.setDither(mDither); 77 } 78 } 79 } 80 81 @Override 82 public void setColorFilter(ColorFilter cf) { 83 if (mColorFilter != cf) { 84 mColorFilter = cf; 85 if (mCurrDrawable != null) { 86 mCurrDrawable.setColorFilter(cf); 87 } 88 } 89 } 90 91 @Override 92 protected void onBoundsChange(Rect bounds) { 93 if (mCurrDrawable != null) { 94 mCurrDrawable.setBounds(bounds); 95 } 96 } 97 98 @Override 99 public boolean isStateful() { 100 return mDrawableContainerState.isStateful(); 101 } 102 103 @Override 104 protected boolean onStateChange(int[] state) { 105 if (mCurrDrawable != null) { 106 return mCurrDrawable.setState(state); 107 } 108 return false; 109 } 110 111 @Override 112 protected boolean onLevelChange(int level) { 113 if (mCurrDrawable != null) { 114 return mCurrDrawable.setLevel(level); 115 } 116 return false; 117 } 118 119 @Override 120 public int getIntrinsicWidth() { 121 if (mDrawableContainerState.isConstantSize()) { 122 return mDrawableContainerState.getConstantWidth(); 123 } 124 return mCurrDrawable != null ? mCurrDrawable.getIntrinsicWidth() : -1; 125 } 126 127 @Override 128 public int getIntrinsicHeight() { 129 if (mDrawableContainerState.isConstantSize()) { 130 return mDrawableContainerState.getConstantHeight(); 131 } 132 return mCurrDrawable != null ? mCurrDrawable.getIntrinsicHeight() : -1; 133 } 134 135 @Override 136 public int getMinimumWidth() { 137 if (mDrawableContainerState.isConstantSize()) { 138 return mDrawableContainerState.getConstantMinimumWidth(); 139 } 140 return mCurrDrawable != null ? mCurrDrawable.getMinimumWidth() : 0; 141 } 142 143 @Override 144 public int getMinimumHeight() { 145 if (mDrawableContainerState.isConstantSize()) { 146 return mDrawableContainerState.getConstantMinimumHeight(); 147 } 148 return mCurrDrawable != null ? mCurrDrawable.getMinimumHeight() : 0; 149 } 150 151 public void invalidateDrawable(Drawable who) 152 { 153 if (who == mCurrDrawable && mCallback != null) { 154 mCallback.invalidateDrawable(this); 155 } 156 } 157 158 public void scheduleDrawable(Drawable who, Runnable what, long when) 159 { 160 if (who == mCurrDrawable && mCallback != null) { 161 mCallback.scheduleDrawable(this, what, when); 162 } 163 } 164 165 public void unscheduleDrawable(Drawable who, Runnable what) 166 { 167 if (who == mCurrDrawable && mCallback != null) { 168 mCallback.unscheduleDrawable(this, what); 169 } 170 } 171 172 @Override 173 public boolean setVisible(boolean visible, boolean restart) { 174 boolean changed = super.setVisible(visible, restart); 175 if (mCurrDrawable != null) { 176 mCurrDrawable.setVisible(visible, restart); 177 } 178 return changed; 179 } 180 181 @Override 182 public int getOpacity() { 183 return mDrawableContainerState.getOpacity(); 184 } 185 186 public boolean selectDrawable(int idx) 187 { 188 if (idx == mCurIndex) { 189 return false; 190 } 191 if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) { 192 Drawable d = mDrawableContainerState.mDrawables[idx]; 193 if (mCurrDrawable != null) { 194 mCurrDrawable.setVisible(false, false); 195 } 196 mCurrDrawable = d; 197 mCurIndex = idx; 198 if (d != null) { 199 d.setVisible(isVisible(), true); 200 d.setAlpha(mAlpha); 201 d.setDither(mDither); 202 d.setColorFilter(mColorFilter); 203 d.setState(getState()); 204 d.setLevel(getLevel()); 205 d.setBounds(getBounds()); 206 } 207 } else { 208 if (mCurrDrawable != null) { 209 mCurrDrawable.setVisible(false, false); 210 } 211 mCurrDrawable = null; 212 mCurIndex = -1; 213 } 214 invalidateSelf(); 215 return true; 216 } 217 218 @Override 219 public Drawable getCurrent() { 220 return mCurrDrawable; 221 } 222 223 @Override 224 public ConstantState getConstantState() { 225 if (mDrawableContainerState.canConstantState()) { 226 mDrawableContainerState.mChangingConfigurations = super.getChangingConfigurations(); 227 return mDrawableContainerState; 228 } 229 return null; 230 } 231 232 public abstract static class DrawableContainerState extends ConstantState { 233 final DrawableContainer mOwner; 234 235 int mChangingConfigurations; 236 int mChildrenChangingConfigurations; 237 238 Drawable[] mDrawables; 239 int mNumChildren; 240 241 boolean mVariablePadding = false; 242 Rect mConstantPadding = null; 243 244 boolean mConstantSize = false; 245 boolean mComputedConstantSize = false; 246 int mConstantWidth; 247 int mConstantHeight; 248 int mConstantMinimumWidth; 249 int mConstantMinimumHeight; 250 251 boolean mHaveOpacity = false; 252 int mOpacity; 253 254 boolean mHaveStateful = false; 255 boolean mStateful; 256 257 boolean mCheckedConstantState; 258 boolean mCanConstantState; 259 260 DrawableContainerState(DrawableContainerState orig, DrawableContainer owner) { 261 mOwner = owner; 262 263 if (orig != null) { 264 mChangingConfigurations = orig.mChangingConfigurations; 265 mChildrenChangingConfigurations = orig.mChildrenChangingConfigurations; 266 267 final Drawable[] origDr = orig.mDrawables; 268 269 mDrawables = new Drawable[origDr.length]; 270 mNumChildren = orig.mNumChildren; 271 272 final int N = mNumChildren; 273 for (int i=0; i<N; i++) { 274 mDrawables[i] = origDr[i].getConstantState().newDrawable(); 275 mDrawables[i].setCallback(owner); 276 } 277 278 mCheckedConstantState = mCanConstantState = true; 279 mVariablePadding = orig.mVariablePadding; 280 mConstantPadding = orig.mConstantPadding; 281 mConstantSize = orig.mConstantSize; 282 mComputedConstantSize = orig.mComputedConstantSize; 283 mConstantWidth = orig.mConstantWidth; 284 mConstantHeight = orig.mConstantHeight; 285 286 mHaveOpacity = orig.mHaveOpacity; 287 mOpacity = orig.mOpacity; 288 mHaveStateful = orig.mHaveStateful; 289 mStateful = orig.mStateful; 290 291 } else { 292 mDrawables = new Drawable[10]; 293 mNumChildren = 0; 294 mCheckedConstantState = mCanConstantState = false; 295 } 296 } 297 298 @Override 299 public int getChangingConfigurations() { 300 return mChangingConfigurations; 301 } 302 303 public final int addChild(Drawable dr) { 304 final int pos = mNumChildren; 305 306 if (pos >= mDrawables.length) { 307 growArray(pos, pos+10); 308 } 309 310 dr.setVisible(false, true); 311 dr.setCallback(mOwner); 312 313 mDrawables[pos] = dr; 314 mNumChildren++; 315 mChildrenChangingConfigurations |= dr.getChangingConfigurations(); 316 mHaveOpacity = false; 317 mHaveStateful = false; 318 319 mConstantPadding = null; 320 mComputedConstantSize = false; 321 322 return pos; 323 } 324 325 public final int getChildCount() 326 { 327 return mNumChildren; 328 } 329 330 public final Drawable[] getChildren() 331 { 332 return mDrawables; 333 } 334 335 /** A boolean value indicating whether to use the maximum padding value of 336 * all frames in the set (false), or to use the padding value of the frame 337 * being shown (true). Default value is false. 338 */ 339 public final void setVariablePadding(boolean variable) 340 { 341 mVariablePadding = variable; 342 } 343 344 public final Rect getConstantPadding() 345 { 346 if (mVariablePadding) { 347 return null; 348 } 349 if (mConstantPadding != null) { 350 return mConstantPadding; 351 } 352 353 Rect r = new Rect(0, 0, 0, 0); 354 Rect t = new Rect(); 355 final int N = getChildCount(); 356 for (int i=0; i<N; i++) { 357 if (mDrawables[i].getPadding(t)) { 358 if (t.left > r.left) r.left = t.left; 359 if (t.top > r.top) r.top = t.top; 360 if (t.right > r.right) r.right = t.right; 361 if (t.bottom > r.bottom) r.bottom = t.bottom; 362 } 363 } 364 return (mConstantPadding=r); 365 } 366 367 public final void setConstantSize(boolean constant) 368 { 369 mConstantSize = constant; 370 } 371 372 public final boolean isConstantSize() 373 { 374 return mConstantSize; 375 } 376 377 public final int getConstantWidth() 378 { 379 if (!mComputedConstantSize) { 380 computeConstantSize(); 381 } 382 383 return mConstantWidth; 384 } 385 386 public final int getConstantHeight() 387 { 388 if (!mComputedConstantSize) { 389 computeConstantSize(); 390 } 391 392 return mConstantHeight; 393 } 394 395 public final int getConstantMinimumWidth() 396 { 397 if (!mComputedConstantSize) { 398 computeConstantSize(); 399 } 400 401 return mConstantMinimumWidth; 402 } 403 404 public final int getConstantMinimumHeight() 405 { 406 if (!mComputedConstantSize) { 407 computeConstantSize(); 408 } 409 410 return mConstantMinimumHeight; 411 } 412 413 private void computeConstantSize() 414 { 415 mComputedConstantSize = true; 416 417 final int N = getChildCount(); 418 mConstantWidth = mConstantHeight = 0; 419 mConstantMinimumWidth = mConstantMinimumHeight = 0; 420 for (int i=0; i<N; i++) { 421 Drawable dr = mDrawables[i]; 422 int s = dr.getIntrinsicWidth(); 423 if (s > mConstantWidth) mConstantWidth = s; 424 s = dr.getIntrinsicHeight(); 425 if (s > mConstantHeight) mConstantHeight = s; 426 s = dr.getMinimumWidth(); 427 if (s > mConstantMinimumWidth) mConstantMinimumWidth = s; 428 s = dr.getMinimumHeight(); 429 if (s > mConstantMinimumHeight) mConstantMinimumHeight = s; 430 } 431 } 432 433 public final int getOpacity() 434 { 435 if (mHaveOpacity) { 436 return mOpacity; 437 } 438 439 final int N = getChildCount(); 440 int op = N > 0 441 ? mDrawables[0].getOpacity() : PixelFormat.TRANSPARENT; 442 for (int i=1; i<N; i++) { 443 op = Drawable.resolveOpacity(op, mDrawables[i].getOpacity()); 444 } 445 mOpacity = op; 446 mHaveOpacity = true; 447 return op; 448 } 449 450 public final boolean isStateful() { 451 if (mHaveStateful) { 452 return mStateful; 453 } 454 455 boolean stateful = false; 456 final int N = getChildCount(); 457 for (int i = 0; i < N; i++) { 458 if (mDrawables[i].isStateful()) { 459 stateful = true; 460 break; 461 } 462 } 463 464 mStateful = stateful; 465 mHaveStateful = true; 466 return stateful; 467 } 468 469 public void growArray(int oldSize, int newSize) 470 { 471 Drawable[] newDrawables = new Drawable[newSize]; 472 System.arraycopy(mDrawables, 0, newDrawables, 0, oldSize); 473 mDrawables = newDrawables; 474 } 475 476 public synchronized boolean canConstantState() { 477 if (!mCheckedConstantState) { 478 mCanConstantState = true; 479 final int N = mNumChildren; 480 for (int i=0; i<N; i++) { 481 if (mDrawables[i].getConstantState() == null) { 482 mCanConstantState = false; 483 break; 484 } 485 } 486 mCheckedConstantState = true; 487 } 488 489 return mCanConstantState; 490 } 491 } 492 493 protected void setConstantState(DrawableContainerState state) 494 { 495 mDrawableContainerState = state; 496 } 497} 498