15052117cc429d85cf446421ca74859f4365747d3Angus Kong/* 25052117cc429d85cf446421ca74859f4365747d3Angus Kong * Copyright (C) 2014 The Android Open Source Project 35052117cc429d85cf446421ca74859f4365747d3Angus Kong * 45052117cc429d85cf446421ca74859f4365747d3Angus Kong * Licensed under the Apache License, Version 2.0 (the "License"); 55052117cc429d85cf446421ca74859f4365747d3Angus Kong * you may not use this file except in compliance with the License. 65052117cc429d85cf446421ca74859f4365747d3Angus Kong * You may obtain a copy of the License at 75052117cc429d85cf446421ca74859f4365747d3Angus Kong * 85052117cc429d85cf446421ca74859f4365747d3Angus Kong * http://www.apache.org/licenses/LICENSE-2.0 95052117cc429d85cf446421ca74859f4365747d3Angus Kong * 105052117cc429d85cf446421ca74859f4365747d3Angus Kong * Unless required by applicable law or agreed to in writing, software 115052117cc429d85cf446421ca74859f4365747d3Angus Kong * distributed under the License is distributed on an "AS IS" BASIS, 125052117cc429d85cf446421ca74859f4365747d3Angus Kong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135052117cc429d85cf446421ca74859f4365747d3Angus Kong * See the License for the specific language governing permissions and 145052117cc429d85cf446421ca74859f4365747d3Angus Kong * limitations under the License. 155052117cc429d85cf446421ca74859f4365747d3Angus Kong */ 165052117cc429d85cf446421ca74859f4365747d3Angus Kong 175052117cc429d85cf446421ca74859f4365747d3Angus Kongpackage com.android.camera.widget; 185052117cc429d85cf446421ca74859f4365747d3Angus Kong 195052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.animation.Animator; 205052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.animation.AnimatorSet; 215052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.animation.ValueAnimator; 225052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.content.Context; 235052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.graphics.Bitmap; 24c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kongimport android.graphics.Canvas; 255052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.graphics.Point; 26c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kongimport android.graphics.Rect; 275052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.graphics.drawable.BitmapDrawable; 28c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kongimport android.graphics.drawable.Drawable; 295052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.util.AttributeSet; 305052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.view.animation.AccelerateInterpolator; 315052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.view.animation.DecelerateInterpolator; 325052117cc429d85cf446421ca74859f4365747d3Angus Kongimport android.widget.ImageView; 335052117cc429d85cf446421ca74859f4365747d3Angus Kong 34c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kongimport com.android.camera.util.CameraUtil; 3575fc98f248f4383e3dc10048bfdf0292fd8dd970Alan Newbergerimport com.android.camera2.R; 36c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong 375052117cc429d85cf446421ca74859f4365747d3Angus Kong/** 385052117cc429d85cf446421ca74859f4365747d3Angus Kong * An ImageView which has the built-in peek animation support. 395052117cc429d85cf446421ca74859f4365747d3Angus Kong */ 405052117cc429d85cf446421ca74859f4365747d3Angus Kongpublic class PeekView extends ImageView { 415052117cc429d85cf446421ca74859f4365747d3Angus Kong 42d02de7808c906f89c1d331feebcefba6696d8668Angus Kong private static final float ROTATE_ANGLE = -7f; 43c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong private static final long PEEK_IN_DURATION_MS = 200; 44c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong private static final long PEEK_STAY_DURATION_MS = 100; 45c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong private static final long PEEK_OUT_DURATION_MS = 200; 46c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong private static final float FILMSTRIP_SCALE = 0.7f; 475052117cc429d85cf446421ca74859f4365747d3Angus Kong 485052117cc429d85cf446421ca74859f4365747d3Angus Kong private AnimatorSet mPeekAnimator; 495052117cc429d85cf446421ca74859f4365747d3Angus Kong private float mPeekRotateAngle; 505052117cc429d85cf446421ca74859f4365747d3Angus Kong private Point mRotationPivot; 515052117cc429d85cf446421ca74859f4365747d3Angus Kong private float mRotateScale; 525052117cc429d85cf446421ca74859f4365747d3Angus Kong private boolean mAnimationCanceled; 53c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong private Drawable mImageDrawable; 54c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong private Rect mDrawableBound; 555052117cc429d85cf446421ca74859f4365747d3Angus Kong 565052117cc429d85cf446421ca74859f4365747d3Angus Kong public PeekView(Context context) { 575052117cc429d85cf446421ca74859f4365747d3Angus Kong super(context); 585052117cc429d85cf446421ca74859f4365747d3Angus Kong init(); 595052117cc429d85cf446421ca74859f4365747d3Angus Kong } 605052117cc429d85cf446421ca74859f4365747d3Angus Kong 615052117cc429d85cf446421ca74859f4365747d3Angus Kong public PeekView(Context context, AttributeSet attrs) { 625052117cc429d85cf446421ca74859f4365747d3Angus Kong super(context, attrs); 635052117cc429d85cf446421ca74859f4365747d3Angus Kong init(); 645052117cc429d85cf446421ca74859f4365747d3Angus Kong } 655052117cc429d85cf446421ca74859f4365747d3Angus Kong 665052117cc429d85cf446421ca74859f4365747d3Angus Kong public PeekView(Context context, AttributeSet attrs, int defStyle) { 675052117cc429d85cf446421ca74859f4365747d3Angus Kong super(context, attrs, defStyle); 685052117cc429d85cf446421ca74859f4365747d3Angus Kong init(); 695052117cc429d85cf446421ca74859f4365747d3Angus Kong } 705052117cc429d85cf446421ca74859f4365747d3Angus Kong 715052117cc429d85cf446421ca74859f4365747d3Angus Kong private void init() { 725052117cc429d85cf446421ca74859f4365747d3Angus Kong mRotationPivot = new Point(); 73c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong } 74c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong 75c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong @Override 76c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong protected void onDraw(Canvas c) { 77c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong super.onDraw(c); 78c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong if (mImageDrawable == null) { 79c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong return; 80c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong } 81c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong c.save(); 82c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong c.rotate(mPeekRotateAngle, mRotationPivot.x, mRotationPivot.y); 83c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong mImageDrawable.setBounds(mDrawableBound); 84c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong mImageDrawable.draw(c); 85c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong c.restore(); 86c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong } 87c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong 88c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong /** 89c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong * Starts the peek animation. 90c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong * 91c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong * @param bitmap The bitmap for the animation. 92c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong * @param strong {@code true} if the animation is the strong version which 93c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong * shows more portion of the bitmap. 94159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague * @param accessibilityString An accessibility String to be announced 95159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague during the peek animation. 96c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong */ 97159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague public void startPeekAnimation(final Bitmap bitmap, boolean strong, 98159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague String accessibilityString) { 995052117cc429d85cf446421ca74859f4365747d3Angus Kong ValueAnimator.AnimatorUpdateListener updateListener = 1005052117cc429d85cf446421ca74859f4365747d3Angus Kong new ValueAnimator.AnimatorUpdateListener() { 1015052117cc429d85cf446421ca74859f4365747d3Angus Kong @Override 1025052117cc429d85cf446421ca74859f4365747d3Angus Kong public void onAnimationUpdate(ValueAnimator valueAnimator) { 1035052117cc429d85cf446421ca74859f4365747d3Angus Kong mPeekRotateAngle = mRotateScale * (Float) valueAnimator.getAnimatedValue(); 104c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong invalidate(); 1055052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1065052117cc429d85cf446421ca74859f4365747d3Angus Kong }; 1075052117cc429d85cf446421ca74859f4365747d3Angus Kong ValueAnimator peekAnimateIn = ValueAnimator.ofFloat(0f, ROTATE_ANGLE); 1085052117cc429d85cf446421ca74859f4365747d3Angus Kong ValueAnimator peekAnimateStay = ValueAnimator.ofFloat(ROTATE_ANGLE, ROTATE_ANGLE); 1095052117cc429d85cf446421ca74859f4365747d3Angus Kong ValueAnimator peekAnimateOut = ValueAnimator.ofFloat(ROTATE_ANGLE, 0f); 1105052117cc429d85cf446421ca74859f4365747d3Angus Kong peekAnimateIn.addUpdateListener(updateListener); 1115052117cc429d85cf446421ca74859f4365747d3Angus Kong peekAnimateOut.addUpdateListener(updateListener); 1125052117cc429d85cf446421ca74859f4365747d3Angus Kong peekAnimateIn.setDuration(PEEK_IN_DURATION_MS); 1135052117cc429d85cf446421ca74859f4365747d3Angus Kong peekAnimateStay.setDuration(PEEK_STAY_DURATION_MS); 1145052117cc429d85cf446421ca74859f4365747d3Angus Kong peekAnimateOut.setDuration(PEEK_OUT_DURATION_MS); 1155052117cc429d85cf446421ca74859f4365747d3Angus Kong peekAnimateIn.setInterpolator(new DecelerateInterpolator()); 1165052117cc429d85cf446421ca74859f4365747d3Angus Kong peekAnimateOut.setInterpolator(new AccelerateInterpolator()); 1175052117cc429d85cf446421ca74859f4365747d3Angus Kong mPeekAnimator = new AnimatorSet(); 1185052117cc429d85cf446421ca74859f4365747d3Angus Kong mPeekAnimator.playSequentially(peekAnimateIn, peekAnimateStay, peekAnimateOut); 1195052117cc429d85cf446421ca74859f4365747d3Angus Kong mPeekAnimator.addListener(new Animator.AnimatorListener() { 1205052117cc429d85cf446421ca74859f4365747d3Angus Kong @Override 1215052117cc429d85cf446421ca74859f4365747d3Angus Kong public void onAnimationStart(Animator animator) { 1225052117cc429d85cf446421ca74859f4365747d3Angus Kong setVisibility(VISIBLE); 1235052117cc429d85cf446421ca74859f4365747d3Angus Kong mAnimationCanceled = false; 1245052117cc429d85cf446421ca74859f4365747d3Angus Kong invalidate(); 1255052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1265052117cc429d85cf446421ca74859f4365747d3Angus Kong 1275052117cc429d85cf446421ca74859f4365747d3Angus Kong @Override 1285052117cc429d85cf446421ca74859f4365747d3Angus Kong public void onAnimationEnd(Animator animator) { 1295052117cc429d85cf446421ca74859f4365747d3Angus Kong if (!mAnimationCanceled) { 1305052117cc429d85cf446421ca74859f4365747d3Angus Kong clear(); 1315052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1325052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1335052117cc429d85cf446421ca74859f4365747d3Angus Kong 1345052117cc429d85cf446421ca74859f4365747d3Angus Kong @Override 1355052117cc429d85cf446421ca74859f4365747d3Angus Kong public void onAnimationCancel(Animator animator) { 1365052117cc429d85cf446421ca74859f4365747d3Angus Kong mAnimationCanceled = true; 1375052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1385052117cc429d85cf446421ca74859f4365747d3Angus Kong 1395052117cc429d85cf446421ca74859f4365747d3Angus Kong @Override 1405052117cc429d85cf446421ca74859f4365747d3Angus Kong public void onAnimationRepeat(Animator animator) { 1415052117cc429d85cf446421ca74859f4365747d3Angus Kong 1425052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1435052117cc429d85cf446421ca74859f4365747d3Angus Kong }); 1445052117cc429d85cf446421ca74859f4365747d3Angus Kong 1455052117cc429d85cf446421ca74859f4365747d3Angus Kong mRotateScale = (strong ? 1.0f : 0.5f); 146c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong mImageDrawable = new BitmapDrawable(getResources(), bitmap); 147c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong Point drawDim = CameraUtil.resizeToFill(mImageDrawable.getIntrinsicWidth(), 148c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong mImageDrawable.getIntrinsicHeight(), 0, (int) (getWidth() * FILMSTRIP_SCALE), 149c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong (int) (getHeight() * FILMSTRIP_SCALE)); 150c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong int x = getMeasuredWidth(); 151c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong int y = (getMeasuredHeight() - drawDim.y) / 2; 152c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong mDrawableBound = new Rect(x, y, x + drawDim.x, y + drawDim.y); 153c195e7a9208c90d7a55e184d4b2b9c747e9c90f1Angus Kong mRotationPivot.set(x, (int) (y + drawDim.y * 1.1)); 1545052117cc429d85cf446421ca74859f4365747d3Angus Kong mPeekAnimator.start(); 155159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague 156159e6e9ca0d0ecb53d49765c75fd7a0b2afef965Spike Sprague announceForAccessibility(accessibilityString); 1575052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1585052117cc429d85cf446421ca74859f4365747d3Angus Kong 1595052117cc429d85cf446421ca74859f4365747d3Angus Kong /** 1605052117cc429d85cf446421ca74859f4365747d3Angus Kong * @return whether the animation is running. 1615052117cc429d85cf446421ca74859f4365747d3Angus Kong */ 1625052117cc429d85cf446421ca74859f4365747d3Angus Kong public boolean isPeekAnimationRunning() { 1635052117cc429d85cf446421ca74859f4365747d3Angus Kong return mPeekAnimator.isRunning(); 1645052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1655052117cc429d85cf446421ca74859f4365747d3Angus Kong 1665052117cc429d85cf446421ca74859f4365747d3Angus Kong /** 1675052117cc429d85cf446421ca74859f4365747d3Angus Kong * Stops the animation. See {@link android.animation.Animator#end()}. 1685052117cc429d85cf446421ca74859f4365747d3Angus Kong */ 1695052117cc429d85cf446421ca74859f4365747d3Angus Kong public void stopPeekAnimation() { 1705052117cc429d85cf446421ca74859f4365747d3Angus Kong if (isPeekAnimationRunning()) { 1715052117cc429d85cf446421ca74859f4365747d3Angus Kong mPeekAnimator.end(); 1725052117cc429d85cf446421ca74859f4365747d3Angus Kong } else { 1735052117cc429d85cf446421ca74859f4365747d3Angus Kong clear(); 1745052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1755052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1765052117cc429d85cf446421ca74859f4365747d3Angus Kong 1775052117cc429d85cf446421ca74859f4365747d3Angus Kong /** 1785052117cc429d85cf446421ca74859f4365747d3Angus Kong * Cancels the animation. See {@link android.animation.Animator#cancel()}. 1795052117cc429d85cf446421ca74859f4365747d3Angus Kong */ 1805052117cc429d85cf446421ca74859f4365747d3Angus Kong public void cancelPeekAnimation() { 1815052117cc429d85cf446421ca74859f4365747d3Angus Kong if (isPeekAnimationRunning()) { 1825052117cc429d85cf446421ca74859f4365747d3Angus Kong mPeekAnimator.cancel(); 1835052117cc429d85cf446421ca74859f4365747d3Angus Kong } else { 1845052117cc429d85cf446421ca74859f4365747d3Angus Kong clear(); 1855052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1865052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1875052117cc429d85cf446421ca74859f4365747d3Angus Kong 1885052117cc429d85cf446421ca74859f4365747d3Angus Kong private void clear() { 1895052117cc429d85cf446421ca74859f4365747d3Angus Kong setVisibility(INVISIBLE); 1905052117cc429d85cf446421ca74859f4365747d3Angus Kong setImageDrawable(null); 1915052117cc429d85cf446421ca74859f4365747d3Angus Kong } 1925052117cc429d85cf446421ca74859f4365747d3Angus Kong} 193