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