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