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 
17 package com.android.camera.ui;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorSet;
21 import android.animation.ValueAnimator;
22 import android.content.Context;
23 import android.graphics.Canvas;
24 import android.graphics.Color;
25 import android.graphics.Paint;
26 import android.graphics.RectF;
27 import android.util.AttributeSet;
28 import android.view.View;
29 import android.view.animation.Interpolator;
30 import android.view.animation.LinearInterpolator;
31 
32 import com.android.camera.debug.Log;
33 
34 /**
35  * This class handles all the animations at capture time. Post capture animations
36  * will be handled in a separate place.
37  */
38 public class CaptureAnimationOverlay extends View
39         implements PreviewStatusListener.PreviewAreaChangedListener {
40     private final static Log.Tag TAG = new Log.Tag("CaptureAnimOverlay");
41 
42     private final static int FLASH_COLOR = Color.WHITE;
43 
44     private static final float FLASH_MAX_ALPHA = 0.85f;
45     private static final long FLASH_FULL_DURATION_MS = 65;
46     private static final long FLASH_DECREASE_DURATION_MS = 150;
47     private static final float SHORT_FLASH_MAX_ALPHA = 0.75f;
48     private static final long SHORT_FLASH_FULL_DURATION_MS = 34;
49     private static final long SHORT_FLASH_DECREASE_DURATION_MS = 100;
50 
51     private AnimatorSet mFlashAnimation;
52     private final RectF mPreviewArea = new RectF();
53     private final Paint mPaint = new Paint();
54     private final Interpolator mFlashAnimInterpolator;
55     private final ValueAnimator.AnimatorUpdateListener mFlashAnimUpdateListener;
56     private final Animator.AnimatorListener mFlashAnimListener;
57 
CaptureAnimationOverlay(Context context, AttributeSet attrs)58     public CaptureAnimationOverlay(Context context, AttributeSet attrs) {
59         super(context, attrs);
60         mPaint.setColor(FLASH_COLOR);
61         mFlashAnimInterpolator = new LinearInterpolator();
62         mFlashAnimUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
63             @Override
64             public void onAnimationUpdate(ValueAnimator animation) {
65                 float alpha = 255.0f * (Float) animation.getAnimatedValue();
66                 mPaint.setAlpha((int) alpha);
67                 invalidate();
68             }
69         };
70         mFlashAnimListener = new Animator.AnimatorListener() {
71             @Override
72             public void onAnimationStart(Animator animation) {
73                 setVisibility(VISIBLE);
74             }
75 
76             @Override
77             public void onAnimationEnd(Animator animation) {
78                 mFlashAnimation = null;
79                 setVisibility(INVISIBLE);
80             }
81 
82             @Override
83             public void onAnimationCancel(Animator animation) {
84                 // End is always called after cancel.
85             }
86 
87             @Override
88             public void onAnimationRepeat(Animator animation) {
89 
90             }
91         };
92     }
93 
94     /**
95      * Start flash animation.
96      *
97      * @param shortFlash show shortest possible flash instead of regular long version.
98      */
startFlashAnimation(boolean shortFlash)99     public void startFlashAnimation(boolean shortFlash) {
100         if (mFlashAnimation != null && mFlashAnimation.isRunning()) {
101             mFlashAnimation.cancel();
102         }
103         float maxAlpha;
104 
105         if (shortFlash) {
106             maxAlpha = SHORT_FLASH_MAX_ALPHA;
107         } else {
108             maxAlpha = FLASH_MAX_ALPHA;
109         }
110 
111         ValueAnimator flashAnim1 = ValueAnimator.ofFloat(maxAlpha, maxAlpha);
112         ValueAnimator flashAnim2 = ValueAnimator.ofFloat(maxAlpha, .0f);
113 
114         if (shortFlash) {
115             flashAnim1.setDuration(SHORT_FLASH_FULL_DURATION_MS);
116             flashAnim2.setDuration(SHORT_FLASH_DECREASE_DURATION_MS);
117         } else {
118             flashAnim1.setDuration(FLASH_FULL_DURATION_MS);
119             flashAnim2.setDuration(FLASH_DECREASE_DURATION_MS);
120         }
121 
122         flashAnim1.addUpdateListener(mFlashAnimUpdateListener);
123         flashAnim2.addUpdateListener(mFlashAnimUpdateListener);
124         flashAnim1.setInterpolator(mFlashAnimInterpolator);
125         flashAnim2.setInterpolator(mFlashAnimInterpolator);
126 
127         mFlashAnimation = new AnimatorSet();
128         mFlashAnimation.play(flashAnim1).before(flashAnim2);
129         mFlashAnimation.addListener(mFlashAnimListener);
130         mFlashAnimation.start();
131     }
132 
133     @Override
onPreviewAreaChanged(RectF previewArea)134     public void onPreviewAreaChanged(RectF previewArea) {
135         mPreviewArea.set(previewArea);
136     }
137 
138     @Override
onDraw(Canvas canvas)139     public void onDraw(Canvas canvas) {
140         if (mFlashAnimation != null && mFlashAnimation.isRunning()) {
141             // mPaint alpha is animated by the animation.
142             canvas.drawRect(mPreviewArea, mPaint);
143             canvas.clipRect(mPreviewArea);
144         }
145     }
146 
147     @Override
hasOverlappingRendering()148     public boolean hasOverlappingRendering() {
149         // The internal draw method will NOT have draw calls that overlap.
150         return false;
151     }
152 }
153