193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/*
293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Copyright (C) 2013 The Android Open Source Project
393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Licensed under the Apache License, Version 2.0 (the "License");
593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * you may not use this file except in compliance with the License.
693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * You may obtain a copy of the License at
793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *      http://www.apache.org/licenses/LICENSE-2.0
993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein *
1093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * Unless required by applicable law or agreed to in writing, software
1193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * distributed under the License is distributed on an "AS IS" BASIS,
1293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * See the License for the specific language governing permissions and
1493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * limitations under the License.
1593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */
1693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
1793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpackage com.android.bitmap.drawable;
1893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
1993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.animation.ValueAnimator;
2093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.animation.ValueAnimator.AnimatorUpdateListener;
2193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Canvas;
2293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.ColorFilter;
2393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Paint;
2493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.Rect;
2593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinimport android.graphics.drawable.Drawable;
2693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
275030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Weiimport com.android.bitmap.drawable.ExtendedBitmapDrawable.ExtendedOptions;
285030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei
2993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein/**
3093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * A drawable that wraps another drawable and places it in the center of this space. This drawable
3193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * allows a background color for the "tile", and has a fade-out transition when
3293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein * {@link #setVisible(boolean, boolean)} indicates that it is no longer visible.
3393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein */
3493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzsteinpublic class TileDrawable extends Drawable implements Drawable.Callback {
3593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
365030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei    private final ExtendedOptions mOpts;
3793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final Paint mPaint = new Paint();
3893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final Drawable mInner;
3993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final int mInnerWidth;
4093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    private final int mInnerHeight;
4193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
4293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    protected final ValueAnimator mFadeOutAnimator;
4393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
445030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei    public TileDrawable(Drawable inner, int innerWidth, int innerHeight, int fadeOutDurationMs,
455030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei            ExtendedOptions opts) {
465030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        mOpts = opts;
475030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        mInner = inner != null ? inner.mutate() : null;
4893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mInnerWidth = innerWidth;
4993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mInnerHeight = innerHeight;
505030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        if (inner != null) {
515030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei            mInner.setCallback(this);
525030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        }
5393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
5493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mFadeOutAnimator = ValueAnimator.ofInt(255, 0)
5593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                .setDuration(fadeOutDurationMs);
5693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mFadeOutAnimator.addUpdateListener(new AnimatorUpdateListener() {
5793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            @Override
5893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            public void onAnimationUpdate(ValueAnimator animation) {
5993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                setAlpha((Integer) animation.getAnimatedValue());
6093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
6193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        });
6293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
6393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        reset();
6493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
6593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
6693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void reset() {
6793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        setAlpha(0);
6893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        setVisible(false);
6993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
7093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
7109f46006437e7de33afdb51192bf0bdc08e97040Mark Wei    public Drawable getInnerDrawable() {
7209f46006437e7de33afdb51192bf0bdc08e97040Mark Wei        return mInner;
7309f46006437e7de33afdb51192bf0bdc08e97040Mark Wei    }
7409f46006437e7de33afdb51192bf0bdc08e97040Mark Wei
7593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
7693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    protected void onBoundsChange(Rect bounds) {
7793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        super.onBoundsChange(bounds);
7893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
795030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        if (mInner == null) {
805030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei            return;
815030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        }
825030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei
8393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (bounds.isEmpty()) {
8493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mInner.setBounds(0, 0, 0, 0);
8593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        } else {
8693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final int l = bounds.left + (bounds.width() / 2) - (mInnerWidth / 2);
8793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            final int t = bounds.top + (bounds.height() / 2) - (mInnerHeight / 2);
8893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            mInner.setBounds(l, t, l + mInnerWidth, t + mInnerHeight);
8993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
9093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
9193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
9293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
9393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void draw(Canvas canvas) {
9493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (!isVisible() && mPaint.getAlpha() == 0) {
9593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            return;
9693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
975030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        final int alpha = mPaint.getAlpha();
98df3da61c8f2f54604376d9761649bdba54aa858bMark Wei        mPaint.setColor(mOpts.backgroundColor);
99cd728097ff189542877a2952879a3aa3c6cb5666Mark Wei        mPaint.setAlpha(alpha);
100df3da61c8f2f54604376d9761649bdba54aa858bMark Wei        canvas.drawRect(getBounds(), mPaint);
1015030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        if (mInner != null) mInner.draw(canvas);
10293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
10393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
10493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
10593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void setAlpha(int alpha) {
10693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final int old = mPaint.getAlpha();
10793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mPaint.setAlpha(alpha);
10893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        setInnerAlpha(alpha);
10993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (alpha != old) {
11093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            invalidateSelf();
11193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
11293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
11393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
11493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
11593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void setColorFilter(ColorFilter cf) {
11693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        mPaint.setColorFilter(cf);
1175030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        if (mInner != null) mInner.setColorFilter(cf);
11893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
11993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
12093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
12193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public int getOpacity() {
12293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return 0;
12393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
12493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
12593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    protected int getCurrentAlpha() {
12693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return mPaint.getAlpha();
12793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
12893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
12993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public boolean setVisible(boolean visible) {
13093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return setVisible(visible, true /* dontcare */);
13193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
13293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
13393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
13493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public boolean setVisible(boolean visible, boolean restart) {
1355030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        if (mInner != null) mInner.setVisible(visible, restart);
13693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        final boolean changed = super.setVisible(visible, restart);
13793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        if (changed) {
13893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            if (isVisible()) {
13993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                // pop in (no-op)
14093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                // the transition will still be smooth if the previous state's layer fades out
14193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                mFadeOutAnimator.cancel();
14293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                setAlpha(255);
14393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            } else {
14493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                // fade out
145d732a611bd661fc2ac3c801a545cfbba0f179484Mark Wei                if (mPaint.getAlpha() == 255) {
14693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                    mFadeOutAnimator.start();
14793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein                }
14893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein            }
14993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        }
15093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        return changed;
15193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
15293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
15393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
15493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    protected boolean onLevelChange(int level) {
1555030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        if (mInner != null)
1565030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei            return mInner.setLevel(level);
1575030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        else {
1585030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei            return super.onLevelChange(level);
1595030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        }
16093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
16193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
16293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    /**
16393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     * Changes the alpha on just the inner wrapped drawable.
16493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein     */
16593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void setInnerAlpha(int alpha) {
1665030ae34cd5978a8ab8a06f6c3b69b8645873122Mark Wei        if (mInner != null) mInner.setAlpha(alpha);
16793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
16893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
16993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
17093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void invalidateDrawable(Drawable who) {
17193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        invalidateSelf();
17293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
17393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
17493a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
17593a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void scheduleDrawable(Drawable who, Runnable what, long when) {
17693a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        scheduleSelf(what, when);
17793a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
17893a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein
17993a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    @Override
18093a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    public void unscheduleDrawable(Drawable who, Runnable what) {
18193a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein        unscheduleSelf(what);
18293a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein    }
18393a35b93dc582e38ff8ee5979754a16b4bf4da0cSam Blitzstein}
184