CaptureAnimManager.java revision 3a5b0163009c43a2e2969568baa5fe0efbaf07f5
1/*
2 * Copyright (C) 2012 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;
18
19import android.animation.Animator;
20import android.animation.PropertyValuesHolder;
21import android.animation.ValueAnimator;
22import android.graphics.Bitmap;
23import android.view.View;
24import android.view.animation.AccelerateDecelerateInterpolator;
25import android.view.animation.AccelerateInterpolator;
26import android.view.animation.DecelerateInterpolator;
27import android.view.animation.Interpolator;
28import android.widget.ImageView;
29
30/**
31 * Class to handle the capture animation.
32 */
33public class CaptureAnimManager implements
34        ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
35
36    private static final float ZOOM_DELTA = 0.2f;  // The amount of change for zooming out.
37    private static final float ZOOM_IN_BEGIN = 1f - ZOOM_DELTA;  // Pre-calculated value for
38                                                                 // convenience.
39    private static final long CAPTURE_ANIM_DURATION = 800;  // milliseconds.
40    private static final float VIEW_GAP_RATIO = 0.1f;  // The gap between preview and review based
41                                                       // on the view dimension.
42    private static final float TOTAL_RATIO = 1f + VIEW_GAP_RATIO;
43
44    private final ImageView mReview;
45    private final View mPreview;
46
47    private float mXDelta;
48    private float mYDelta;
49    private float mXDeltaScaled;
50    private float mYDeltaScaled;
51    private float mOffset; // The offset where preview should be put relative to the review.
52    private int mAnimOrientation;
53
54    private final Interpolator ZoomOutInterpolator = new DecelerateInterpolator();
55    private final Interpolator ZoomInInterpolator = new AccelerateInterpolator();
56
57    private final ValueAnimator mCaptureAnim = new ValueAnimator();
58    // The translation value for 4 different orientations.
59    private final PropertyValuesHolder[] mReviewSlideValue = new PropertyValuesHolder[4];
60
61    /* preview: camera preview view.
62     * review: view of picture just taken.
63     */
64    public CaptureAnimManager(View preview, ImageView review) {
65        mReview = review;
66        mPreview = preview;
67
68        mCaptureAnim.setInterpolator(new AccelerateDecelerateInterpolator());
69        mCaptureAnim.setDuration(CAPTURE_ANIM_DURATION);
70        mCaptureAnim.addListener(this);
71        mCaptureAnim.addUpdateListener(this);
72    }
73
74    void initializeDelta(int xDelta, int yDelta) {
75        mXDelta = xDelta;
76        mYDelta = yDelta;
77        mXDeltaScaled = mXDelta * TOTAL_RATIO;
78        mYDeltaScaled = mYDelta * TOTAL_RATIO;
79        mReviewSlideValue[0] = PropertyValuesHolder.ofFloat("", 0f, mXDeltaScaled);
80        mReviewSlideValue[1] = PropertyValuesHolder.ofFloat("", 0f, -mYDeltaScaled);
81        mReviewSlideValue[2] = PropertyValuesHolder.ofFloat("", 0f, -mXDeltaScaled);
82        mReviewSlideValue[3] = PropertyValuesHolder.ofFloat("", 0f, mYDeltaScaled);
83    }
84
85    // xDelta, yDelta: The dimension of the viewfinder in which animation happens.
86    public void startAnimation(Bitmap bitmap, int animOrientation, int xDelta, int yDelta) {
87        if (xDelta != mXDelta || mYDelta != yDelta) {
88            initializeDelta(xDelta, yDelta);
89        }
90        mAnimOrientation = animOrientation;
91        // Reset the views before the animation begins.
92        mCaptureAnim.cancel();
93        mCaptureAnim.setValues(mReviewSlideValue[(mAnimOrientation / 90) % 4]);
94        switch (mAnimOrientation) {
95            case 0:
96                mPreview.setTranslationX(-mXDeltaScaled);
97                mPreview.setPivotX(mXDelta * (1f + VIEW_GAP_RATIO / 2f)); //left
98                mReview.setPivotX(mXDelta * -VIEW_GAP_RATIO / 2f); //right
99                mPreview.setPivotY(mYDeltaScaled / 2f);
100                mReview.setPivotY(mYDeltaScaled / 2f);
101                mOffset = -mXDeltaScaled;
102                break;
103            case 90:
104                mPreview.setTranslationY(mYDeltaScaled);
105                mPreview.setPivotX(mXDeltaScaled / 2f);
106                mReview.setPivotX(mXDeltaScaled / 2f);
107                mPreview.setPivotY(mYDelta * -VIEW_GAP_RATIO / 2f); //down
108                mReview.setPivotY(mYDelta * (1f + VIEW_GAP_RATIO / 2f)); //up
109                mOffset = (mYDeltaScaled);
110                break;
111            case 180:
112                mPreview.setTranslationX(mXDeltaScaled);
113                mPreview.setPivotX(mXDelta * -VIEW_GAP_RATIO / 2f); //right
114                mReview.setPivotX(mXDelta * (1f + VIEW_GAP_RATIO / 2f)); //left
115                mPreview.setPivotY(mYDeltaScaled / 2f);
116                mReview.setPivotY(mYDeltaScaled / 2f);
117                mOffset = mXDeltaScaled;
118                break;
119            case 270:
120                mPreview.setTranslationY(-mYDeltaScaled);
121                mPreview.setPivotX(mXDeltaScaled / 2f);
122                mReview.setPivotX(mXDeltaScaled / 2f);
123                mPreview.setPivotY(mYDelta * (1f + VIEW_GAP_RATIO / 2f)); //up
124                mReview.setPivotY(mYDelta * -VIEW_GAP_RATIO / 2f); //down
125                mOffset = -mYDeltaScaled;
126                break;
127        }
128
129        mReview.setImageBitmap(bitmap);
130        mReview.setTranslationX(0f);
131        mReview.setTranslationY(0f);
132        mReview.setScaleX(1f);
133        mReview.setScaleY(1f);
134        mReview.setVisibility(View.VISIBLE);
135        mCaptureAnim.start();
136    }
137
138    @Override
139    public void onAnimationStart(Animator anim) {
140    }
141
142    @Override
143    public void onAnimationEnd(Animator anim) {
144        mReview.setVisibility(View.GONE);
145        mReview.setImageBitmap(null);
146    }
147
148    @Override
149    public void onAnimationRepeat(Animator anim) {}
150
151    @Override
152    public void onAnimationCancel(Animator anim) {}
153
154    @Override
155    public void onAnimationUpdate(ValueAnimator anim) {
156        float fraction = anim.getAnimatedFraction();
157        zoomAnimation(fraction);
158        mPreview.setAlpha(fraction);
159        slideAnimation((Float) anim.getAnimatedValue());
160    }
161
162    // Take a translation value of the review and calculate the corresponding value for
163    // the preview.
164    private void slideAnimation(float value) {
165        if (mAnimOrientation == 0 || mAnimOrientation == 180) {
166            // Slide horizontally.
167            mReview.setTranslationX(value);
168            mPreview.setTranslationX(value + mOffset);
169        } else {
170            // Slide vertically.
171            mReview.setTranslationY(value);
172            mPreview.setTranslationY(value + mOffset);
173        }
174    }
175
176    // Calculate the zoom factor based on the given time fraction.
177    private void zoomAnimation(float fraction) {
178        float value = 1f;
179        if (fraction <= 0.5f) {
180            // Zoom in for the beginning.
181            value = 1f - ZOOM_DELTA * ZoomOutInterpolator.getInterpolation(
182                    fraction * 2);
183        } else {
184            // Zoom out for the last.
185            value = ZOOM_IN_BEGIN + ZOOM_DELTA * ZoomInInterpolator.getInterpolation(
186                    (fraction - 0.5f) * 2f);
187        }
188        mReview.setScaleX(value);
189        mReview.setScaleY(value);
190        mPreview.setScaleX(value);
191        mPreview.setScaleY(value);
192    }
193}
194