TileDrawable.java revision 5030ae34cd5978a8ab8a06f6c3b69b8645873122
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
17package com.android.bitmap.drawable;
18
19import android.animation.ValueAnimator;
20import android.animation.ValueAnimator.AnimatorUpdateListener;
21import android.graphics.Canvas;
22import android.graphics.ColorFilter;
23import android.graphics.Paint;
24import android.graphics.Rect;
25import android.graphics.drawable.Drawable;
26
27import 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 */
34public 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
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
66    public void reset() {
67        setAlpha(0);
68        setVisible(false);
69    }
70
71    @Override
72    protected void onBoundsChange(Rect bounds) {
73        super.onBoundsChange(bounds);
74
75        if (mInner == null) {
76            return;
77        }
78
79        if (bounds.isEmpty()) {
80            mInner.setBounds(0, 0, 0, 0);
81        } else {
82            final int l = bounds.left + (bounds.width() / 2) - (mInnerWidth / 2);
83            final int t = bounds.top + (bounds.height() / 2) - (mInnerHeight / 2);
84            mInner.setBounds(l, t, l + mInnerWidth, t + mInnerHeight);
85        }
86    }
87
88    @Override
89    public void draw(Canvas canvas) {
90        if (!isVisible() && mPaint.getAlpha() == 0) {
91            return;
92        }
93        final int alpha = mPaint.getAlpha();
94        mPaint.setColor(mOpts.backgroundColor);
95        mPaint.setAlpha(alpha);
96        canvas.drawRect(getBounds(), mPaint);
97        if (mInner != null) mInner.draw(canvas);
98    }
99
100    @Override
101    public void setAlpha(int alpha) {
102        final int old = mPaint.getAlpha();
103        mPaint.setAlpha(alpha);
104        setInnerAlpha(alpha);
105        if (alpha != old) {
106            invalidateSelf();
107        }
108    }
109
110    @Override
111    public void setColorFilter(ColorFilter cf) {
112        mPaint.setColorFilter(cf);
113        if (mInner != null) mInner.setColorFilter(cf);
114    }
115
116    @Override
117    public int getOpacity() {
118        return 0;
119    }
120
121    protected int getCurrentAlpha() {
122        return mPaint.getAlpha();
123    }
124
125    public boolean setVisible(boolean visible) {
126        return setVisible(visible, true /* dontcare */);
127    }
128
129    @Override
130    public boolean setVisible(boolean visible, boolean restart) {
131        if (mInner != null) mInner.setVisible(visible, restart);
132        final boolean changed = super.setVisible(visible, restart);
133        if (changed) {
134            if (isVisible()) {
135                // pop in (no-op)
136                // the transition will still be smooth if the previous state's layer fades out
137                mFadeOutAnimator.cancel();
138                setAlpha(255);
139            } else {
140                // fade out
141                if (mPaint.getAlpha() == 255 && !getBounds().isEmpty()) {
142                    mFadeOutAnimator.start();
143                }
144            }
145        }
146        return changed;
147    }
148
149    @Override
150    protected boolean onLevelChange(int level) {
151        if (mInner != null)
152            return mInner.setLevel(level);
153        else {
154            return super.onLevelChange(level);
155        }
156    }
157
158    /**
159     * Changes the alpha on just the inner wrapped drawable.
160     */
161    public void setInnerAlpha(int alpha) {
162        if (mInner != null) mInner.setAlpha(alpha);
163    }
164
165    @Override
166    public void invalidateDrawable(Drawable who) {
167        invalidateSelf();
168    }
169
170    @Override
171    public void scheduleDrawable(Drawable who, Runnable what, long when) {
172        scheduleSelf(what, when);
173    }
174
175    @Override
176    public void unscheduleDrawable(Drawable who, Runnable what) {
177        unscheduleSelf(what);
178    }
179
180}
181