1/*
2 * Copyright (C) 2014 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.camera.ui;
18
19import android.animation.ValueAnimator;
20import android.graphics.Canvas;
21import android.graphics.ColorFilter;
22import android.graphics.Paint;
23import android.graphics.PixelFormat;
24import android.graphics.drawable.Drawable;
25
26import com.android.camera.util.Gusterpolator;
27
28public class AnimatedCircleDrawable extends Drawable {
29    private static final int CIRCLE_ANIM_DURATION_MS = 300;
30    private static int DRAWABLE_MAX_LEVEL = 10000;
31
32    private int mCanvasWidth;
33    private int mCanvasHeight;
34
35    private int mAlpha = 0xff;
36    private int mColor;
37    private Paint mPaint;
38    private int mRadius;
39    private int mSmallRadiusTarget;
40
41    public AnimatedCircleDrawable(int smallRadiusTarget) {
42        mPaint = new Paint();
43        mPaint.setAntiAlias(true);
44        mSmallRadiusTarget = smallRadiusTarget;
45    }
46
47    public void setColor(int color) {
48        mColor = color;
49        updatePaintColor();
50    }
51
52    private void updatePaintColor() {
53        int paintColor = (mAlpha << 24) | (mColor & 0x00ffffff);
54        mPaint.setColor(paintColor);
55        invalidateSelf();
56    }
57
58    // abstract overrides
59    @Override
60    public int getOpacity() {
61        return PixelFormat.TRANSLUCENT;
62    }
63
64    @Override
65    public void setAlpha(int alpha) {
66        mAlpha = alpha;
67        updatePaintColor();
68    }
69
70    @Override
71    public void setColorFilter(ColorFilter cf) {
72        //TODO support this?
73    }
74    // end abstract overrides
75
76    @Override
77    public boolean onLevelChange(int level) {
78        if (level != getLevel()) {
79            invalidateSelf();
80            return true;
81        }
82        return false;
83    }
84
85    public void animateToSmallRadius() {
86        int smallLevel = map(mSmallRadiusTarget,
87                0, diagonalLength(mCanvasWidth, mCanvasHeight)/2,
88                0, DRAWABLE_MAX_LEVEL);
89        final ValueAnimator animator =
90            ValueAnimator.ofInt(getLevel(), smallLevel);
91        animator.setDuration(CIRCLE_ANIM_DURATION_MS);
92        animator.setInterpolator(Gusterpolator.INSTANCE);
93        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
94            @Override
95            public void onAnimationUpdate(ValueAnimator animation) {
96                setLevel((Integer) animation.getAnimatedValue());
97            }
98        });
99        animator.start();
100    }
101
102    public void animateToFullSize() {
103        final ValueAnimator animator =
104            ValueAnimator.ofInt(getLevel(), DRAWABLE_MAX_LEVEL);
105        animator.setDuration(CIRCLE_ANIM_DURATION_MS);
106        animator.setInterpolator(Gusterpolator.INSTANCE);
107        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
108            @Override
109            public void onAnimationUpdate(ValueAnimator animation) {
110                setLevel((Integer) animation.getAnimatedValue());
111            }
112        });
113        animator.start();
114    }
115
116    @Override
117    public void draw(Canvas canvas) {
118        mCanvasWidth = canvas.getWidth();
119        mCanvasHeight = canvas.getHeight();
120
121        mRadius = map(getLevel(), 0, DRAWABLE_MAX_LEVEL,
122                0, diagonalLength(canvas.getWidth(), canvas.getHeight())/2);
123        canvas.drawCircle(canvas.getWidth()/2.0f, canvas.getHeight()/2.0f,
124                mRadius, mPaint);
125    }
126
127    /**
128     * Maps a given value x from one input range [in_min, in_max] to
129     * another output range [out_min, out-max].
130     * @param x Value to be mapped.
131     * @param in_min Input range minimum.
132     * @param in_max Input range maximum.
133     * @param out_min Output range minimum.
134     * @param out_max Output range maximum.
135     * @return The mapped value.
136     */
137    private static int map(int x, int in_min, int in_max, int out_min, int out_max) {
138        return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
139    }
140
141    private static int diagonalLength(int w, int h) {
142        return (int) Math.sqrt((w*w) + (h*h));
143    }
144}