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