1d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague/*
2d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague * Copyright (C) 2014 The Android Open Source Project
3d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague *
4d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague * Licensed under the Apache License, Version 2.0 (the "License");
5d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague * you may not use this file except in compliance with the License.
6d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague * You may obtain a copy of the License at
7d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague *
8d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague *      http://www.apache.org/licenses/LICENSE-2.0
9d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague *
10d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague * Unless required by applicable law or agreed to in writing, software
11d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague * distributed under the License is distributed on an "AS IS" BASIS,
12d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague * See the License for the specific language governing permissions and
14d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague * limitations under the License.
15d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague */
16d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
17d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Spraguepackage com.android.camera.ui;
18d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
19d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Spragueimport android.animation.ValueAnimator;
20d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Spragueimport android.graphics.Canvas;
21d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Spragueimport android.graphics.ColorFilter;
22d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Spragueimport android.graphics.Paint;
23d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Spragueimport android.graphics.PixelFormat;
24d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Spragueimport android.graphics.drawable.Drawable;
25d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
26d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Spragueimport com.android.camera.util.Gusterpolator;
27d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
28d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Spraguepublic class AnimatedCircleDrawable extends Drawable {
29d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private static final int CIRCLE_ANIM_DURATION_MS = 300;
30d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private static int DRAWABLE_MAX_LEVEL = 10000;
31d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
32d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private int mCanvasWidth;
33d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private int mCanvasHeight;
34d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
35d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private int mAlpha = 0xff;
36d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private int mColor;
37d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private Paint mPaint;
38d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private int mRadius;
39d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private int mSmallRadiusTarget;
40d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
41d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    public AnimatedCircleDrawable(int smallRadiusTarget) {
42d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        mPaint = new Paint();
43d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        mPaint.setAntiAlias(true);
44d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        mSmallRadiusTarget = smallRadiusTarget;
45d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
46d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
47d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    public void setColor(int color) {
48d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        mColor = color;
49d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        updatePaintColor();
50d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
51d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
52d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private void updatePaintColor() {
53d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        int paintColor = (mAlpha << 24) | (mColor & 0x00ffffff);
54d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        mPaint.setColor(paintColor);
55d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        invalidateSelf();
56d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
57d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
58d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    // abstract overrides
59d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    @Override
60d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    public int getOpacity() {
61d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        return PixelFormat.TRANSLUCENT;
62d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
63d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
64d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    @Override
65d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    public void setAlpha(int alpha) {
66d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        mAlpha = alpha;
67d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        updatePaintColor();
68d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
69d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
70d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    @Override
71d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    public void setColorFilter(ColorFilter cf) {
72d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        //TODO support this?
73d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
74d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    // end abstract overrides
75d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
76d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    @Override
77d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    public boolean onLevelChange(int level) {
78c5ecbd6e0a6c2a2d93fc58f0ba3d273249b06da2Spike Sprague        if (level != getLevel()) {
79c5ecbd6e0a6c2a2d93fc58f0ba3d273249b06da2Spike Sprague            invalidateSelf();
80c5ecbd6e0a6c2a2d93fc58f0ba3d273249b06da2Spike Sprague            return true;
81c5ecbd6e0a6c2a2d93fc58f0ba3d273249b06da2Spike Sprague        }
82c5ecbd6e0a6c2a2d93fc58f0ba3d273249b06da2Spike Sprague        return false;
83d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
84d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
85d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    public void animateToSmallRadius() {
86d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        int smallLevel = map(mSmallRadiusTarget,
87d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague                0, diagonalLength(mCanvasWidth, mCanvasHeight)/2,
88d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague                0, DRAWABLE_MAX_LEVEL);
89d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        final ValueAnimator animator =
90d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague            ValueAnimator.ofInt(getLevel(), smallLevel);
91d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        animator.setDuration(CIRCLE_ANIM_DURATION_MS);
92d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        animator.setInterpolator(Gusterpolator.INSTANCE);
93d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
94d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague            @Override
95d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague            public void onAnimationUpdate(ValueAnimator animation) {
96d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague                setLevel((Integer) animation.getAnimatedValue());
97d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague            }
98d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        });
99d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        animator.start();
100d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
101d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
102d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    public void animateToFullSize() {
103d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        final ValueAnimator animator =
104d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague            ValueAnimator.ofInt(getLevel(), DRAWABLE_MAX_LEVEL);
105d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        animator.setDuration(CIRCLE_ANIM_DURATION_MS);
106d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        animator.setInterpolator(Gusterpolator.INSTANCE);
107d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
108d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague            @Override
109d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague            public void onAnimationUpdate(ValueAnimator animation) {
110d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague                setLevel((Integer) animation.getAnimatedValue());
111d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague            }
112d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        });
113d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        animator.start();
114d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
115d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
116d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    @Override
117d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    public void draw(Canvas canvas) {
118d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        mCanvasWidth = canvas.getWidth();
119d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        mCanvasHeight = canvas.getHeight();
120d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
121d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        mRadius = map(getLevel(), 0, DRAWABLE_MAX_LEVEL,
122d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague                0, diagonalLength(canvas.getWidth(), canvas.getHeight())/2);
123d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        canvas.drawCircle(canvas.getWidth()/2.0f, canvas.getHeight()/2.0f,
124d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague                mRadius, mPaint);
125d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
126d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
127d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    /**
128d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague     * Maps a given value x from one input range [in_min, in_max] to
129d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague     * another output range [out_min, out-max].
130d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague     * @param x Value to be mapped.
131d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague     * @param in_min Input range minimum.
132d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague     * @param in_max Input range maximum.
133d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague     * @param out_min Output range minimum.
134d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague     * @param out_max Output range maximum.
135d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague     * @return The mapped value.
136d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague     */
137d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private static int map(int x, int in_min, int in_max, int out_min, int out_max) {
138d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
139d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
140d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague
141d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    private static int diagonalLength(int w, int h) {
142d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague        return (int) Math.sqrt((w*w) + (h*h));
143d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague    }
144d9516f276cd45f87edc7eafe6aa476eeab7c29e7Spike Sprague}