CaptureAnimManager.java revision 6fc7917e8636118a3a1bbfe6411ed5f11b974cf1
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 final float mXDelta;
48    private final float mYDelta;
49    private final float mXDeltaScaled;
50    private final 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     * xDelta, yDelta: The dimension of the viewfinder in which animation happens.
64     */
65    public CaptureAnimManager(View preview, ImageView review, int xDelta, int yDelta) {
66        mReview = review;
67        mPreview = preview;
68
69        mCaptureAnim.setInterpolator(new AccelerateDecelerateInterpolator());
70        mCaptureAnim.setDuration(CAPTURE_ANIM_DURATION);
71        mCaptureAnim.addListener(this);
72        mCaptureAnim.addUpdateListener(this);
73
74        mXDelta = xDelta;
75        mYDelta = yDelta;
76        mXDeltaScaled = mXDelta * TOTAL_RATIO;
77        mYDeltaScaled = mYDelta * TOTAL_RATIO;
78        mReviewSlideValue[0] = PropertyValuesHolder.ofFloat("", 0f, mXDeltaScaled);
79        mReviewSlideValue[1] = PropertyValuesHolder.ofFloat("", 0f, -mYDeltaScaled);
80        mReviewSlideValue[2] = PropertyValuesHolder.ofFloat("", 0f, -mXDeltaScaled);
81        mReviewSlideValue[3] = PropertyValuesHolder.ofFloat("", 0f, mYDeltaScaled);
82    }
83
84    public void startAnimation(Bitmap bitmap, int animOrientation) {
85        mAnimOrientation = animOrientation;
86        // Reset the views before the animation begins.
87        mCaptureAnim.cancel();
88        mCaptureAnim.setValues(mReviewSlideValue[(mAnimOrientation / 90) % 4]);
89        switch (mAnimOrientation) {
90            case 0:
91                mPreview.setTranslationX(-mXDeltaScaled);
92                mPreview.setPivotX(mXDelta * (1f + VIEW_GAP_RATIO / 2f)); //left
93                mReview.setPivotX(mXDelta * -VIEW_GAP_RATIO / 2f); //right
94                mPreview.setPivotY(mYDeltaScaled / 2f);
95                mReview.setPivotY(mYDeltaScaled / 2f);
96                mOffset = -mXDeltaScaled;
97                break;
98            case 90:
99                mPreview.setTranslationY(mYDeltaScaled);
100                mPreview.setPivotX(mXDeltaScaled / 2f);
101                mReview.setPivotX(mXDeltaScaled / 2f);
102                mPreview.setPivotY(mYDelta * -VIEW_GAP_RATIO / 2f); //down
103                mReview.setPivotY(mYDelta * (1f + VIEW_GAP_RATIO / 2f)); //up
104                mOffset = (mYDeltaScaled);
105                break;
106            case 180:
107                mPreview.setTranslationX(mXDeltaScaled);
108                mPreview.setPivotX(mXDelta * -VIEW_GAP_RATIO / 2f); //right
109                mReview.setPivotX(mXDelta * (1f + VIEW_GAP_RATIO / 2f)); //left
110                mPreview.setPivotY(mYDeltaScaled / 2f);
111                mReview.setPivotY(mYDeltaScaled / 2f);
112                mOffset = mXDeltaScaled;
113                break;
114            case 270:
115                mPreview.setTranslationY(-mYDeltaScaled);
116                mPreview.setPivotX(mXDeltaScaled / 2f);
117                mReview.setPivotX(mXDeltaScaled / 2f);
118                mPreview.setPivotY(mYDelta * (1f + VIEW_GAP_RATIO / 2f)); //up
119                mReview.setPivotY(mYDelta * -VIEW_GAP_RATIO / 2f); //down
120                mOffset = -mYDeltaScaled;
121                break;
122        }
123
124        mReview.setImageBitmap(bitmap);
125        mReview.setTranslationX(0f);
126        mReview.setTranslationY(0f);
127        mReview.setScaleX(1f);
128        mReview.setScaleY(1f);
129        mReview.setVisibility(View.VISIBLE);
130        mCaptureAnim.start();
131    }
132
133    @Override
134    public void onAnimationStart(Animator anim) {
135    }
136
137    @Override
138    public void onAnimationEnd(Animator anim) {
139        mReview.setVisibility(View.GONE);
140        mReview.setImageBitmap(null);
141    }
142
143    @Override
144    public void onAnimationRepeat(Animator anim) {}
145
146    @Override
147    public void onAnimationCancel(Animator anim) {}
148
149    @Override
150    public void onAnimationUpdate(ValueAnimator anim) {
151        float fraction = anim.getAnimatedFraction();
152        zoomAnimation(fraction);
153        mPreview.setAlpha(fraction);
154        slideAnimation((Float) anim.getAnimatedValue());
155    }
156
157    // Take a translation value of the review and calculate the corresponding value for
158    // the preview.
159    private void slideAnimation(float value) {
160        if (mAnimOrientation == 0 || mAnimOrientation == 180) {
161            // Slide horizontally.
162            mReview.setTranslationX(value);
163            mPreview.setTranslationX(value + mOffset);
164        } else {
165            // Slide vertically.
166            mReview.setTranslationY(value);
167            mPreview.setTranslationY(value + mOffset);
168        }
169    }
170
171    // Calculate the zoom factor based on the given time fraction.
172    private void zoomAnimation(float fraction) {
173        float value = 1f;
174        if (fraction <= 0.5f) {
175            // Zoom in for the beginning.
176            value = 1f - ZOOM_DELTA * ZoomOutInterpolator.getInterpolation(
177                    fraction * 2);
178        } else {
179            // Zoom out for the last.
180            value = ZOOM_IN_BEGIN + ZOOM_DELTA * ZoomInInterpolator.getInterpolation(
181                    (fraction - 0.5f) * 2f);
182        }
183        mReview.setScaleX(value);
184        mReview.setScaleY(value);
185        mPreview.setScaleX(value);
186        mPreview.setScaleY(value);
187    }
188}
189