TileDrawable.java revision cd728097ff189542877a2952879a3aa3c6cb5666
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.Color;
23import android.graphics.ColorFilter;
24import android.graphics.Paint;
25import android.graphics.Rect;
26import android.graphics.drawable.Drawable;
27
28import com.android.bitmap.drawable.ExtendedBitmapDrawable.ExtendedOptions;
29
30/**
31 * A drawable that wraps another drawable and places it in the center of this space. This drawable
32 * allows a background color for the "tile", and has a fade-out transition when
33 * {@link #setVisible(boolean, boolean)} indicates that it is no longer visible.
34 */
35public class TileDrawable extends Drawable implements Drawable.Callback {
36
37    private final ExtendedOptions mOpts;
38    private final Paint mPaint = new Paint();
39    private final Drawable mInner;
40    private final int mInnerWidth;
41    private final int mInnerHeight;
42
43    protected final ValueAnimator mFadeOutAnimator;
44
45    public TileDrawable(Drawable inner, int innerWidth, int innerHeight, int fadeOutDurationMs,
46            ExtendedOptions opts) {
47        mOpts = opts;
48        mInner = inner != null ? inner.mutate() : null;
49        mInnerWidth = innerWidth;
50        mInnerHeight = innerHeight;
51        if (inner != null) {
52            mInner.setCallback(this);
53        }
54
55        mFadeOutAnimator = ValueAnimator.ofInt(255, 0)
56                .setDuration(fadeOutDurationMs);
57        mFadeOutAnimator.addUpdateListener(new AnimatorUpdateListener() {
58            @Override
59            public void onAnimationUpdate(ValueAnimator animation) {
60                setAlpha((Integer) animation.getAnimatedValue());
61            }
62        });
63
64        reset();
65    }
66
67    public void reset() {
68        setAlpha(0);
69        setVisible(false);
70    }
71
72    @Override
73    protected void onBoundsChange(Rect bounds) {
74        super.onBoundsChange(bounds);
75
76        if (mInner == null) {
77            return;
78        }
79
80        if (bounds.isEmpty()) {
81            mInner.setBounds(0, 0, 0, 0);
82        } else {
83            final int l = bounds.left + (bounds.width() / 2) - (mInnerWidth / 2);
84            final int t = bounds.top + (bounds.height() / 2) - (mInnerHeight / 2);
85            mInner.setBounds(l, t, l + mInnerWidth, t + mInnerHeight);
86        }
87    }
88
89    @Override
90    public void draw(Canvas canvas) {
91        if (!isVisible() && mPaint.getAlpha() == 0) {
92            return;
93        }
94        // Save paint alpha.
95        final int alpha = mPaint.getAlpha();
96        mPaint.setColor(getColorWithAlpha(mOpts.backgroundColor, alpha));
97        canvas.drawRect(getBounds(), mPaint);
98        // Restore paint alpha.
99        mPaint.setAlpha(alpha);
100
101        if (mInner != null) mInner.draw(canvas);
102    }
103
104    @Override
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
115    public void setColorFilter(ColorFilter cf) {
116        mPaint.setColorFilter(cf);
117        if (mInner != null) mInner.setColorFilter(cf);
118    }
119
120    @Override
121    public int getOpacity() {
122        return 0;
123    }
124
125    protected int getCurrentAlpha() {
126        return mPaint.getAlpha();
127    }
128
129    public boolean setVisible(boolean visible) {
130        return setVisible(visible, true /* dontcare */);
131    }
132
133    @Override
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 && !getBounds().isEmpty()) {
146                    mFadeOutAnimator.start();
147                }
148            }
149        }
150        return changed;
151    }
152
153    @Override
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     */
165    public void setInnerAlpha(int alpha) {
166        if (mInner != null) mInner.setAlpha(alpha);
167    }
168
169    @Override
170    public void invalidateDrawable(Drawable who) {
171        invalidateSelf();
172    }
173
174    @Override
175    public void scheduleDrawable(Drawable who, Runnable what, long when) {
176        scheduleSelf(what, when);
177    }
178
179    @Override
180    public void unscheduleDrawable(Drawable who, Runnable what) {
181        unscheduleSelf(what);
182    }
183
184    private static int getColorWithAlpha(int color, int alpha) {
185        float fade = alpha / 255f;
186        return Color.argb((int) (fade * Color.alpha(color)), Color.red(color), Color.green(color),
187                Color.blue(color));
188    }
189}
190