PeekView.java revision 75fc98f248f4383e3dc10048bfdf0292fd8dd970
1/* 2 * Copyright (C) 2014 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.widget; 18 19import android.animation.Animator; 20import android.animation.AnimatorSet; 21import android.animation.ValueAnimator; 22import android.content.Context; 23import android.graphics.Bitmap; 24import android.graphics.Canvas; 25import android.graphics.Point; 26import android.graphics.Rect; 27import android.graphics.drawable.BitmapDrawable; 28import android.graphics.drawable.Drawable; 29import android.util.AttributeSet; 30import android.view.animation.AccelerateInterpolator; 31import android.view.animation.DecelerateInterpolator; 32import android.widget.ImageView; 33 34import com.android.camera.util.CameraUtil; 35import com.android.camera2.R; 36 37/** 38 * An ImageView which has the built-in peek animation support. 39 */ 40public class PeekView extends ImageView { 41 42 private static final float ROTATE_ANGLE = -7f; 43 private static final long PEEK_IN_DURATION_MS = 200; 44 private static final long PEEK_STAY_DURATION_MS = 100; 45 private static final long PEEK_OUT_DURATION_MS = 200; 46 private static final float FILMSTRIP_SCALE = 0.7f; 47 48 private AnimatorSet mPeekAnimator; 49 private float mPeekRotateAngle; 50 private Point mRotationPivot; 51 private float mRotateScale; 52 private boolean mAnimationCanceled; 53 private Drawable mImageDrawable; 54 private Rect mDrawableBound; 55 56 public PeekView(Context context) { 57 super(context); 58 init(); 59 } 60 61 public PeekView(Context context, AttributeSet attrs) { 62 super(context, attrs); 63 init(); 64 } 65 66 public PeekView(Context context, AttributeSet attrs, int defStyle) { 67 super(context, attrs, defStyle); 68 init(); 69 } 70 71 private void init() { 72 mRotationPivot = new Point(); 73 } 74 75 @Override 76 protected void onDraw(Canvas c) { 77 super.onDraw(c); 78 if (mImageDrawable == null) { 79 return; 80 } 81 c.save(); 82 c.rotate(mPeekRotateAngle, mRotationPivot.x, mRotationPivot.y); 83 mImageDrawable.setBounds(mDrawableBound); 84 mImageDrawable.draw(c); 85 c.restore(); 86 } 87 88 /** 89 * Starts the peek animation. 90 * 91 * @param bitmap The bitmap for the animation. 92 * @param strong {@code true} if the animation is the strong version which 93 * shows more portion of the bitmap. 94 */ 95 public void startPeekAnimation(final Bitmap bitmap, boolean strong) { 96 ValueAnimator.AnimatorUpdateListener updateListener = 97 new ValueAnimator.AnimatorUpdateListener() { 98 @Override 99 public void onAnimationUpdate(ValueAnimator valueAnimator) { 100 mPeekRotateAngle = mRotateScale * (Float) valueAnimator.getAnimatedValue(); 101 invalidate(); 102 } 103 }; 104 ValueAnimator peekAnimateIn = ValueAnimator.ofFloat(0f, ROTATE_ANGLE); 105 ValueAnimator peekAnimateStay = ValueAnimator.ofFloat(ROTATE_ANGLE, ROTATE_ANGLE); 106 ValueAnimator peekAnimateOut = ValueAnimator.ofFloat(ROTATE_ANGLE, 0f); 107 peekAnimateIn.addUpdateListener(updateListener); 108 peekAnimateOut.addUpdateListener(updateListener); 109 peekAnimateIn.setDuration(PEEK_IN_DURATION_MS); 110 peekAnimateStay.setDuration(PEEK_STAY_DURATION_MS); 111 peekAnimateOut.setDuration(PEEK_OUT_DURATION_MS); 112 peekAnimateIn.setInterpolator(new DecelerateInterpolator()); 113 peekAnimateOut.setInterpolator(new AccelerateInterpolator()); 114 mPeekAnimator = new AnimatorSet(); 115 mPeekAnimator.playSequentially(peekAnimateIn, peekAnimateStay, peekAnimateOut); 116 mPeekAnimator.addListener(new Animator.AnimatorListener() { 117 @Override 118 public void onAnimationStart(Animator animator) { 119 setVisibility(VISIBLE); 120 mAnimationCanceled = false; 121 invalidate(); 122 } 123 124 @Override 125 public void onAnimationEnd(Animator animator) { 126 if (!mAnimationCanceled) { 127 clear(); 128 } 129 } 130 131 @Override 132 public void onAnimationCancel(Animator animator) { 133 mAnimationCanceled = true; 134 } 135 136 @Override 137 public void onAnimationRepeat(Animator animator) { 138 139 } 140 }); 141 142 mRotateScale = (strong ? 1.0f : 0.5f); 143 mImageDrawable = new BitmapDrawable(getResources(), bitmap); 144 Point drawDim = CameraUtil.resizeToFill(mImageDrawable.getIntrinsicWidth(), 145 mImageDrawable.getIntrinsicHeight(), 0, (int) (getWidth() * FILMSTRIP_SCALE), 146 (int) (getHeight() * FILMSTRIP_SCALE)); 147 int x = getMeasuredWidth(); 148 int y = (getMeasuredHeight() - drawDim.y) / 2; 149 mDrawableBound = new Rect(x, y, x + drawDim.x, y + drawDim.y); 150 mRotationPivot.set(x, (int) (y + drawDim.y * 1.1)); 151 mPeekAnimator.start(); 152 announceForAccessibility( 153 getContext().getResources().getString(R.string.accessibility_peek)); 154 } 155 156 /** 157 * @return whether the animation is running. 158 */ 159 public boolean isPeekAnimationRunning() { 160 return mPeekAnimator.isRunning(); 161 } 162 163 /** 164 * Stops the animation. See {@link android.animation.Animator#end()}. 165 */ 166 public void stopPeekAnimation() { 167 if (isPeekAnimationRunning()) { 168 mPeekAnimator.end(); 169 } else { 170 clear(); 171 } 172 } 173 174 /** 175 * Cancels the animation. See {@link android.animation.Animator#cancel()}. 176 */ 177 public void cancelPeekAnimation() { 178 if (isPeekAnimationRunning()) { 179 mPeekAnimator.cancel(); 180 } else { 181 clear(); 182 } 183 } 184 185 private void clear() { 186 setVisibility(INVISIBLE); 187 setImageDrawable(null); 188 } 189} 190