1 package com.android.mail.bitmap; 2 3 import android.animation.ValueAnimator; 4 import android.animation.ValueAnimator.AnimatorUpdateListener; 5 import android.graphics.Canvas; 6 import android.graphics.ColorFilter; 7 import android.graphics.Paint; 8 import android.graphics.Rect; 9 import android.graphics.drawable.Drawable; 10 11 /** 12 * A drawable that wraps another drawable and places it in the center of this space. This drawable 13 * allows a background color for the "tile", and has a fade-out transition when 14 * {@link #setVisible(boolean, boolean)} indicates that it is no longer visible. 15 */ 16 public class TileDrawable extends Drawable implements Drawable.Callback { 17 18 private final Paint mPaint = new Paint(); 19 private final Drawable mInner; 20 private final int mInnerWidth; 21 private final int mInnerHeight; 22 23 protected final ValueAnimator mFadeOutAnimator; 24 25 public TileDrawable(Drawable inner, int innerWidth, int innerHeight, 26 int backgroundColor, int fadeOutDurationMs) { 27 mInner = inner.mutate(); 28 mInnerWidth = innerWidth; 29 mInnerHeight = innerHeight; 30 mPaint.setColor(backgroundColor); 31 mInner.setCallback(this); 32 33 mFadeOutAnimator = ValueAnimator.ofInt(255, 0) 34 .setDuration(fadeOutDurationMs); 35 mFadeOutAnimator.addUpdateListener(new AnimatorUpdateListener() { 36 @Override 37 public void onAnimationUpdate(ValueAnimator animation) { 38 setAlpha((Integer) animation.getAnimatedValue()); 39 } 40 }); 41 42 reset(); 43 } 44 45 public void reset() { 46 setAlpha(0); 47 setVisible(false); 48 } 49 50 @Override 51 protected void onBoundsChange(Rect bounds) { 52 super.onBoundsChange(bounds); 53 54 if (bounds.isEmpty()) { 55 mInner.setBounds(0, 0, 0, 0); 56 } else { 57 final int l = bounds.left + (bounds.width() / 2) - (mInnerWidth / 2); 58 final int t = bounds.top + (bounds.height() / 2) - (mInnerHeight / 2); 59 mInner.setBounds(l, t, l + mInnerWidth, t + mInnerHeight); 60 } 61 } 62 63 @Override 64 public void draw(Canvas canvas) { 65 if (!isVisible() && mPaint.getAlpha() == 0) { 66 return; 67 } 68 canvas.drawRect(getBounds(), mPaint); 69 mInner.draw(canvas); 70 } 71 72 @Override 73 public void setAlpha(int alpha) { 74 final int old = mPaint.getAlpha(); 75 mPaint.setAlpha(alpha); 76 setInnerAlpha(alpha); 77 if (alpha != old) { 78 invalidateSelf(); 79 } 80 } 81 82 @Override 83 public void setColorFilter(ColorFilter cf) { 84 mPaint.setColorFilter(cf); 85 mInner.setColorFilter(cf); 86 } 87 88 @Override 89 public int getOpacity() { 90 return 0; 91 } 92 93 protected int getCurrentAlpha() { 94 return mPaint.getAlpha(); 95 } 96 97 public boolean setVisible(boolean visible) { 98 return setVisible(visible, true /* dontcare */); 99 } 100 101 @Override 102 public boolean setVisible(boolean visible, boolean restart) { 103 mInner.setVisible(visible, restart); 104 final boolean changed = super.setVisible(visible, restart); 105 if (changed) { 106 if (isVisible()) { 107 // pop in (no-op) 108 // the transition will still be smooth if the previous state's layer fades out 109 mFadeOutAnimator.cancel(); 110 setAlpha(255); 111 } else { 112 // fade out 113 if (mPaint.getAlpha() == 255 && !getBounds().isEmpty()) { 114 mFadeOutAnimator.start(); 115 } 116 } 117 } 118 return changed; 119 } 120 121 @Override 122 protected boolean onLevelChange(int level) { 123 return mInner.setLevel(level); 124 } 125 126 /** 127 * Changes the alpha on just the inner wrapped drawable. 128 */ 129 public void setInnerAlpha(int alpha) { 130 mInner.setAlpha(alpha); 131 } 132 133 @Override 134 public void invalidateDrawable(Drawable who) { 135 invalidateSelf(); 136 } 137 138 @Override 139 public void scheduleDrawable(Drawable who, Runnable what, long when) { 140 scheduleSelf(what, when); 141 } 142 143 @Override 144 public void unscheduleDrawable(Drawable who, Runnable what) { 145 unscheduleSelf(what); 146 } 147 148 } 149