CaptureAnimManager.java revision 351b7a85f40c6a2bcb5fb0e7eeb61002c376bb29
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.view.animation.AccelerateDecelerateInterpolator;
20import android.view.animation.AccelerateInterpolator;
21import android.view.animation.DecelerateInterpolator;
22import android.view.animation.Interpolator;
23import android.os.SystemClock;
24
25import com.android.gallery3d.ui.GLCanvas;
26import com.android.gallery3d.ui.Raw2DTexture;
27
28/**
29 * Class to handle the capture animation.
30 */
31public class CaptureAnimManager {
32
33    private static final String TAG = "CaptureAnimManager";
34    private static final float ZOOM_DELTA = 0.2f;  // The amount of change for zooming out.
35    private static final float ZOOM_IN_BEGIN = 1f - ZOOM_DELTA;  // Pre-calculated value for
36                                                                 // convenience.
37    private static final float CAPTURE_ANIM_DURATION = 800;  // milliseconds.
38    private static final float GAP_RATIO = 0.1f;  // The gap between preview and review based
39                                                  // on the view dimension.
40    private static final float TOTAL_RATIO = 1f + GAP_RATIO;
41
42    private final Interpolator mZoomOutInterpolator = new DecelerateInterpolator();
43    private final Interpolator mZoomInInterpolator = new AccelerateInterpolator();
44    private final Interpolator mSlideInterpolator = new AccelerateDecelerateInterpolator();
45
46    private int mAnimOrientation;  // Could be 0, 90, 180 or 270 degrees.
47    private long mAnimStartTime;  // milliseconds.
48    private float mCenterX;  // The center of the whole view including preview and review.
49    private float mCenterY;
50    private float mCenterDelta;  // The amount of the center will move after whole animation.
51    private float mGap;  // mGap = (width or height) * GAP_RATIO. (depends on orientation)
52    private int mDrawWidth;
53    private int mDrawHeight;
54    private int mDrawX;
55    private int mDrawY;
56    private float mHalfGap;  // mHalfGap = mGap / 2f.
57    private float[] mTextureTransformMatrix;
58
59    /* preview: camera preview view.
60     * review: view of picture just taken.
61     */
62    public CaptureAnimManager() {
63    }
64
65    public void setOrientation(int animOrientation) {
66        mAnimOrientation = animOrientation;
67    }
68
69    // x, y, h and h: the rectangle area where the animation takes place in.
70    // transformMatrix: used to show the texture.
71    public void startAnimation(int x, int y, int w, int h, float[] transformMatrix) {
72        mAnimStartTime = SystemClock.uptimeMillis();
73        mTextureTransformMatrix = transformMatrix;
74        // Set the views to the initial positions.
75        mDrawWidth = w;
76        mDrawHeight = h;
77        mDrawX = x;
78        mDrawY = y;
79        switch (mAnimOrientation) {
80            case 0:  // Preview is on the left.
81                mGap = w * GAP_RATIO;
82                mHalfGap = mGap / 2f;
83                mCenterX = x - mHalfGap;
84                mCenterDelta = w * (TOTAL_RATIO);
85                mCenterY = y + h / 2f;
86                break;
87            case 90:  // Preview is below.
88                mGap = h * GAP_RATIO;
89                mHalfGap = mGap / 2f;
90                mCenterY = y + h + mHalfGap;
91                mCenterDelta = -h * (TOTAL_RATIO);
92                mCenterX = x + w / 2f;
93                break;
94            case 180:  // Preview on the right.
95                mGap = w * GAP_RATIO;
96                mHalfGap = mGap / 2f;
97                mCenterX = x + mHalfGap;
98                mCenterDelta = -w * (TOTAL_RATIO);
99                mCenterY = y + h / 2f;
100                break;
101            case 270:  // Preview is above.
102                mGap = h * GAP_RATIO;
103                mHalfGap = mGap / 2f;
104                mCenterY = y - mHalfGap;
105                mCenterDelta = h * (TOTAL_RATIO);
106                mCenterX = x + w / 2f;
107                break;
108        }
109    }
110
111    // Returns true if the animation has been drawn.
112    public boolean drawAnimation(GLCanvas canvas, CameraScreenNail preview,
113                Raw2DTexture review) {
114        long timeDiff = SystemClock.uptimeMillis() - mAnimStartTime;;
115        if (timeDiff > CAPTURE_ANIM_DURATION) return false;
116        float fraction = timeDiff / CAPTURE_ANIM_DURATION;
117        float scale = calculateScale(fraction);
118        float centerX = mCenterX;
119        float centerY = mCenterY;
120        if (mAnimOrientation == 0 || mAnimOrientation == 180) {
121            centerX = mCenterX + mCenterDelta * mSlideInterpolator.getInterpolation(fraction);
122        } else {
123            centerY = mCenterY + mCenterDelta * mSlideInterpolator.getInterpolation(fraction);
124        }
125
126        float height = mDrawHeight * scale;
127        float width = mDrawWidth * scale;
128        int previewX = (int) centerX;
129        int previewY = (int) centerY;
130        int reviewX = (int) centerX;
131        int reviewY = (int) centerY;
132        switch (mAnimOrientation) {
133            case 0:
134                previewX = Math.round(centerX - width - mHalfGap * scale);
135                previewY = Math.round(centerY - height / 2f);
136                reviewX = Math.round(centerX + mHalfGap * scale);
137                reviewY = previewY;
138                break;
139            case 90:
140                previewY = Math.round(centerY + mHalfGap * scale);
141                previewX = Math.round(centerX - width / 2f);
142                reviewY = Math.round(centerY - height - mHalfGap * scale);
143                reviewX = previewX;
144                break;
145            case 180:
146                previewX = Math.round(centerX + width + mHalfGap * scale);
147                previewY = Math.round(centerY - height / 2f);
148                reviewX = Math.round(centerX - mHalfGap * scale);
149                reviewY = previewY;
150                break;
151            case 270:
152                previewY = Math.round(centerY - height - mHalfGap * scale);
153                previewX = Math.round(centerX - width / 2f);
154                reviewY = Math.round(centerY + mHalfGap * scale);
155                reviewX = previewX;
156                break;
157        }
158        float alpha = canvas.getAlpha();
159        canvas.setAlpha(fraction);
160        preview.directDraw(canvas, previewX, previewY, Math.round(width), Math.round(height));
161        canvas.setAlpha(alpha);
162
163        // Flip animation texture vertically. OpenGL uses bottom left point as the origin (0,0).
164        canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
165        int cx = Math.round(reviewX + width / 2);
166        int cy = Math.round(reviewY + height / 2);
167        canvas.translate(cx, cy);
168        canvas.scale(1, -1, 1);
169        canvas.translate(-cx, -cy);
170        canvas.drawTexture(review, mTextureTransformMatrix,
171                reviewX, reviewY, (int) width, (int) height);
172        canvas.restore();
173
174        return true;
175    }
176
177    // Calculate the zoom factor based on the given time fraction.
178    private float calculateScale(float fraction) {
179        float value = 1f;
180        if (fraction <= 0.5f) {
181            // Zoom in for the beginning.
182            value = 1f - ZOOM_DELTA * mZoomOutInterpolator.getInterpolation(
183                    fraction * 2);
184        } else {
185            // Zoom out for the last.
186            value = ZOOM_IN_BEGIN + ZOOM_DELTA * mZoomInInterpolator.getInterpolation(
187                    (fraction - 0.5f) * 2f);
188        }
189        return value;
190    }
191}
192