CaptureAnimManager.java revision fef060d7ad352c44f3469628cae31fe64143993e
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 float ZOOM_TIME_FRACTION = 0.4f;  // The amount of the time we do zoom
40                                                           // animation for in/out respectively.
41    private static final long CAPTURE_ANIM_DURATION = 800;  // milliseconds.
42    private static final float VIEW_GAP_RATIO = 0.1f;  // The gap between preview and review based
43                                                       // on the view dimension.
44    private static final float TOTAL_RATIO = 1f + VIEW_GAP_RATIO;
45
46    private final ImageView mReview;
47    private final View mPreview;
48
49    private final float mXDelta;
50    private final float mYDelta;
51    private final float mXDeltaScaled;
52    private final float mYDeltaScaled;
53    private float mOffset; // The offset where preview should be put relative to the review.
54    private int mAnimOrientation;
55
56    private final Interpolator ZoomOutInterpolator = new DecelerateInterpolator();
57    private final Interpolator ZoomInInterpolator = new AccelerateInterpolator();
58
59    private final ValueAnimator mCaptureAnim = new ValueAnimator();
60    // The translation value for 4 different orientations.
61    private final PropertyValuesHolder[] mReviewSlideValue = new PropertyValuesHolder[4];
62
63    /* preview: camera preview view.
64     * review: view of picture just taken.
65     * xDelta, yDelta: The dimension of the viewfinder in which animation happens.
66     */
67    public CaptureAnimManager(View preview, ImageView review, int xDelta, int yDelta) {
68        mReview = review;
69        mPreview = preview;
70
71        mCaptureAnim.setInterpolator(new AccelerateDecelerateInterpolator());
72        mCaptureAnim.setDuration(CAPTURE_ANIM_DURATION);
73        mCaptureAnim.addListener(this);
74        mCaptureAnim.addUpdateListener(this);
75
76        mXDelta = xDelta;
77        mYDelta = yDelta;
78        mXDeltaScaled = mXDelta * TOTAL_RATIO;
79        mYDeltaScaled = mYDelta * TOTAL_RATIO;
80        mReviewSlideValue[0] = PropertyValuesHolder.ofFloat("", 0f, mXDeltaScaled);
81        mReviewSlideValue[1] = PropertyValuesHolder.ofFloat("", 0f, -mYDeltaScaled);
82        mReviewSlideValue[2] = PropertyValuesHolder.ofFloat("", 0f, -mXDeltaScaled);
83        mReviewSlideValue[3] = PropertyValuesHolder.ofFloat("", 0f, mYDeltaScaled);
84    }
85
86    public void startAnimation(Bitmap bitmap, int animOrientation) {
87        mAnimOrientation = animOrientation;
88        // Reset the views before the animation begins.
89        mCaptureAnim.cancel();
90        mCaptureAnim.setValues(mReviewSlideValue[mAnimOrientation / 90]);
91        switch (mAnimOrientation) {
92            case 0:
93                mPreview.setTranslationX(-mXDeltaScaled);
94                mPreview.setPivotX(mXDelta * (1f + VIEW_GAP_RATIO / 2f)); //left
95                mReview.setPivotX(mXDelta * -VIEW_GAP_RATIO / 2f); //right
96                mPreview.setPivotY(mYDeltaScaled / 2f);
97                mReview.setPivotY(mYDeltaScaled / 2f);
98                mOffset = -mXDeltaScaled;
99                break;
100            case 90:
101                mPreview.setTranslationY(mYDeltaScaled);
102                mPreview.setPivotX(mXDeltaScaled / 2f);
103                mReview.setPivotX(mXDeltaScaled / 2f);
104                mPreview.setPivotY(mYDelta * -VIEW_GAP_RATIO / 2f); //down
105                mReview.setPivotY(mYDelta * (1f + VIEW_GAP_RATIO / 2f)); //up
106                mOffset = (mYDeltaScaled);
107                break;
108            case 180:
109                mPreview.setTranslationX(mXDeltaScaled);
110                mPreview.setPivotX(mXDelta * -VIEW_GAP_RATIO / 2f); //right
111                mReview.setPivotX(mXDelta * (1f + VIEW_GAP_RATIO / 2f)); //left
112                mPreview.setPivotY(mYDeltaScaled / 2f);
113                mReview.setPivotY(mYDeltaScaled / 2f);
114                mOffset = mXDeltaScaled;
115                break;
116            case 270:
117                mPreview.setTranslationY(-mYDeltaScaled);
118                mPreview.setPivotX(mXDeltaScaled / 2f);
119                mReview.setPivotX(mXDeltaScaled / 2f);
120                mPreview.setPivotY(mYDelta * (1f + VIEW_GAP_RATIO / 2f)); //up
121                mReview.setPivotY(mYDelta * -VIEW_GAP_RATIO / 2f); //down
122                mOffset = -mYDeltaScaled;
123                break;
124        }
125
126        mReview.setImageBitmap(bitmap);
127        mReview.setTranslationX(0f);
128        mReview.setTranslationY(0f);
129        mReview.setScaleX(1f);
130        mReview.setScaleY(1f);
131        mReview.setVisibility(View.VISIBLE);
132        mCaptureAnim.start();
133    }
134
135    @Override
136    public void onAnimationStart(Animator anim) {
137    }
138
139    @Override
140    public void onAnimationEnd(Animator anim) {
141        mReview.setVisibility(View.GONE);
142        mReview.setImageBitmap(null);
143    }
144
145    @Override
146    public void onAnimationRepeat(Animator anim) {}
147
148    @Override
149    public void onAnimationCancel(Animator anim) {}
150
151    @Override
152    public void onAnimationUpdate(ValueAnimator anim) {
153        zoomAnimation(anim.getAnimatedFraction());
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 <= ZOOM_TIME_FRACTION) {
175            // Zoom in for the beginning.
176            value = 1f - ZOOM_DELTA * ZoomOutInterpolator.getInterpolation(
177                    fraction / ZOOM_TIME_FRACTION);
178        } else if (fraction >= 1f - ZOOM_TIME_FRACTION) {
179            // Zoom out for the last.
180            value = ZOOM_IN_BEGIN + ZOOM_DELTA * ZoomInInterpolator.getInterpolation(
181                    (fraction + ZOOM_TIME_FRACTION - 1f) / ZOOM_TIME_FRACTION);
182        } else {
183            return;
184        }
185        mReview.setScaleX(value);
186        mReview.setScaleY(value);
187        mPreview.setScaleX(value);
188        mPreview.setScaleY(value);
189    }
190}
191