From 2c6173822a612597c79be41b126367ddfbb5d518 Mon Sep 17 00:00:00 2001 From: Chih-Chung Chang Date: Fri, 20 Apr 2012 20:06:19 +0800 Subject: [PATCH] Add capture animation in Gallery. Change-Id: Ibf95cc64f37a4518377e64124af6606c4f14cdaa --- .../gallery3d/app/AbstractGalleryActivity.java | 12 ++ src/com/android/gallery3d/app/Gallery.java | 12 -- src/com/android/gallery3d/app/PhotoPage.java | 9 +- src/com/android/gallery3d/app/PickerActivity.java | 12 -- src/com/android/gallery3d/ui/CaptureAnimation.java | 56 ++++++++ src/com/android/gallery3d/ui/PhotoView.java | 159 +++++++++++++++------ .../android/gallery3d/ui/PositionController.java | 94 ++++++++---- 7 files changed, 263 insertions(+), 91 deletions(-) create mode 100644 src/com/android/gallery3d/ui/CaptureAnimation.java diff --git a/src/com/android/gallery3d/app/AbstractGalleryActivity.java b/src/com/android/gallery3d/app/AbstractGalleryActivity.java index 0b9461d9a..09e72c09b 100644 --- a/src/com/android/gallery3d/app/AbstractGalleryActivity.java +++ b/src/com/android/gallery3d/app/AbstractGalleryActivity.java @@ -206,6 +206,18 @@ public class AbstractGalleryActivity extends Activity implements GalleryActivity } @Override + public void onBackPressed() { + // send the back event to the top sub-state + GLRoot root = getGLRoot(); + root.lockRenderThread(); + try { + getStateManager().onBackPressed(); + } finally { + root.unlockRenderThread(); + } + } + + @Override public GalleryActionBar getGalleryActionBar() { if (mActionBar == null) { mActionBar = new GalleryActionBar(this); diff --git a/src/com/android/gallery3d/app/Gallery.java b/src/com/android/gallery3d/app/Gallery.java index 60eb069fa..c8fbd537e 100644 --- a/src/com/android/gallery3d/app/Gallery.java +++ b/src/com/android/gallery3d/app/Gallery.java @@ -233,18 +233,6 @@ public final class Gallery extends AbstractGalleryActivity implements OnCancelLi } @Override - public void onBackPressed() { - // send the back event to the top sub-state - GLRoot root = getGLRoot(); - root.lockRenderThread(); - try { - getStateManager().onBackPressed(); - } finally { - root.unlockRenderThread(); - } - } - - @Override protected void onResume() { Utils.assertTrue(getStateManager().getStateCount() > 0); super.onResume(); diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java index 6be302b24..6617ce668 100644 --- a/src/com/android/gallery3d/app/PhotoPage.java +++ b/src/com/android/gallery3d/app/PhotoPage.java @@ -403,11 +403,18 @@ public class PhotoPage extends ActivityState protected void onBackPressed() { if (mShowDetails) { hideDetails(); - } else { + } else if (!switchWithCaptureAnimation(-1)) { super.onBackPressed(); } } + // Switch to the previous or next picture using the capture animation. + // The offset is -1 to switch to the previous picture, 1 to switch to + // the next picture. + public boolean switchWithCaptureAnimation(int offset) { + return mPhotoView.switchWithCaptureAnimation(offset); + } + @Override protected boolean onCreateActionBar(Menu menu) { MenuInflater inflater = ((Activity) mActivity).getMenuInflater(); diff --git a/src/com/android/gallery3d/app/PickerActivity.java b/src/com/android/gallery3d/app/PickerActivity.java index d63e23733..f5b2cbdfc 100644 --- a/src/com/android/gallery3d/app/PickerActivity.java +++ b/src/com/android/gallery3d/app/PickerActivity.java @@ -78,18 +78,6 @@ public class PickerActivity extends AbstractGalleryActivity } @Override - public void onBackPressed() { - // send the back event to the top sub-state - GLRoot root = getGLRoot(); - root.lockRenderThread(); - try { - getStateManager().getTopState().onBackPressed(); - } finally { - root.unlockRenderThread(); - } - } - - @Override public void onClick(View v) { if (v.getId() == R.id.cancel) finish(); } diff --git a/src/com/android/gallery3d/ui/CaptureAnimation.java b/src/com/android/gallery3d/ui/CaptureAnimation.java new file mode 100644 index 000000000..87c054ab3 --- /dev/null +++ b/src/com/android/gallery3d/ui/CaptureAnimation.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.ui; + +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; + +public class CaptureAnimation { + // The amount of change for zooming out. + private static final float ZOOM_DELTA = 0.2f; + // Pre-calculated value for convenience. + private static final float ZOOM_IN_BEGIN = 1f - ZOOM_DELTA; + + private static final Interpolator sZoomOutInterpolator = + new DecelerateInterpolator(); + private static final Interpolator sZoomInInterpolator = + new AccelerateInterpolator(); + private static final Interpolator sSlideInterpolator = + new AccelerateDecelerateInterpolator(); + + // Calculate the slide factor based on the give time fraction. + public static float calculateSlide(float fraction) { + return sSlideInterpolator.getInterpolation(fraction); + } + + // Calculate the scale factor based on the given time fraction. + public static float calculateScale(float fraction) { + float value; + if (fraction <= 0.5f) { + // Zoom in for the beginning. + value = 1f - ZOOM_DELTA * + sZoomOutInterpolator.getInterpolation(fraction * 2); + } else { + // Zoom out for the ending. + value = ZOOM_IN_BEGIN + ZOOM_DELTA * + sZoomInInterpolator.getInterpolation((fraction - 0.5f) * 2f); + } + return value; + } +} diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java index 109a5d977..66941bee6 100644 --- a/src/com/android/gallery3d/ui/PhotoView.java +++ b/src/com/android/gallery3d/ui/PhotoView.java @@ -76,6 +76,7 @@ public class PhotoView extends GLView { private static final int MSG_SHOW_LOADING = 1; private static final int MSG_CANCEL_EXTRA_SCALING = 2; private static final int MSG_SWITCH_FOCUS = 3; + private static final int MSG_CAPTURE_ANIMATION_DONE = 4; private static final long DELAY_SHOW_LOADING = 250; // 250ms; @@ -89,6 +90,8 @@ public class PhotoView extends GLView { private static final float DEFAULT_TEXT_SIZE = 20; private static float TRANSITION_SCALE_FACTOR = 0.74f; + + // whether we want to apply card deck effect in page mode. private static final boolean CARD_EFFECT = true; // Used to calculate the scaling factor for the fading animation. @@ -140,6 +143,16 @@ public class PhotoView extends GLView { private int mPrevBound; private int mNextBound; + // This variable prevents us doing snapback until its values goes to 0. This + // happens if the user gesture is still in progress or we are in a capture + // animation. + // HOLD_TOUCH_DOWN_FROM_CAMERA is an extra flag set together with + // HOLD_TOUCH_DOWN if the touch down starts from camera preview. + private int mHolding; + private static final int HOLD_TOUCH_DOWN = 1; + private static final int HOLD_TOUCH_DOWN_FROM_CAMERA = 2; + private static final int HOLD_CAPTURE_ANIMATION = 4; + public PhotoView(GalleryActivity activity) { mTileView = new TileImageView(activity); addComponent(mTileView); @@ -164,8 +177,14 @@ public class PhotoView extends GLView { public void invalidate() { PhotoView.this.invalidate(); } - public boolean isDown() { - return mGestureRecognizer.isDown(); + public boolean isHolding() { + // We want the film mode change happen as soon as + // possible even if the touch is still down. + if ((mHolding & HOLD_TOUCH_DOWN_FROM_CAMERA) != 0) { + return false; + } else { + return mHolding != 0; + } } public void onPull(int offset, int direction) { mEdgeView.onPull(offset, direction); @@ -222,6 +241,10 @@ public class PhotoView extends GLView { switchFocus(); break; } + case MSG_CAPTURE_ANIMATION_DONE: { + captureAnimationDone(); + break; + } default: throw new AssertionError(message.what); } } @@ -316,14 +339,17 @@ public class PhotoView extends GLView { void reload(); void draw(GLCanvas canvas, Rect r); void setScreenNail(ScreenNail s); - boolean isEnabled(); + boolean isCamera(); // whether the picture is a camera preview }; + private boolean isCameraScreenNail(ScreenNail s) { + return s != null && !(s instanceof BitmapScreenNail); + } + class FullPicture implements Picture { private int mRotation; - - // This is a temporary hack to switch mode when entering/leaving camera. - private volatile boolean mIsNonBitmap; + private boolean mIsCamera; + private boolean mWasCenter; public void FullPicture(TileImageView tileView) { mTileView = tileView; @@ -333,7 +359,7 @@ public class PhotoView extends GLView { public void reload() { // mImageWidth and mImageHeight will get updated mTileView.notifyModelInvalidated(); - if (CARD_EFFECT) mTileView.setAlpha(1.0f); + mTileView.setAlpha(1.0f); mRotation = mModel.getImageRotation(0); int w = mTileView.mImageWidth; @@ -355,22 +381,31 @@ public class PhotoView extends GLView { renderMessage(canvas, r.centerX(), r.centerY()); boolean isCenter = r.centerX() == getWidth() / 2; - if (mIsNonBitmap && !isCenter && !mFilmMode) { - setFilmMode(true); - } else if (mIsNonBitmap && isCenter && mFilmMode) { - setFilmMode(false); + + // We want to have following transitions: + // (1) Move camera preview out of its place: switch to film mode + // (2) Move camera preview into its place: switch to page mode + // The extra mWasCenter check makes sure (1) does not apply if in + // page mode, we move _to_ the camera preview from another picture. + if ((mHolding & ~(HOLD_TOUCH_DOWN | HOLD_TOUCH_DOWN_FROM_CAMERA)) == 0) { + if (mWasCenter && !isCenter && mIsCamera && !mFilmMode) { + setFilmMode(true); + } else if (mIsCamera && isCenter && mFilmMode) { + setFilmMode(false); + } } + mWasCenter = isCenter; } @Override public void setScreenNail(ScreenNail s) { - mIsNonBitmap = (s != null && !(s instanceof BitmapScreenNail)); + mIsCamera = isCameraScreenNail(s); mTileView.setScreenNail(s); } @Override - public boolean isEnabled() { - return true; + public boolean isCamera() { + return mIsCamera; } private void setTileViewPosition(Rect r) { @@ -387,7 +422,9 @@ public class PhotoView extends GLView { int centerY = (int) (imageH / 2f + (viewH / 2f - r.exactCenterY()) / scale + 0.5f); - if (CARD_EFFECT && !mFilmMode) { + boolean wantsCardEffect = CARD_EFFECT && !mFilmMode + && !mPictures.get(-1).isCamera(); + if (wantsCardEffect) { // Calculate the move-out progress value. int left = r.left; int right = r.right; @@ -463,10 +500,10 @@ public class PhotoView extends GLView { private class ScreenNailPicture implements Picture { private int mIndex; - private boolean mEnabled; private int mRotation; private ScreenNail mScreenNail; private Size mSize = new Size(); + private boolean mIsCamera; public ScreenNailPicture(int index) { mIndex = index; @@ -494,20 +531,20 @@ public class PhotoView extends GLView { return; } - boolean applyFadingAnimation = - CARD_EFFECT && mIndex > 0 && !mFilmMode; + boolean wantsCardEffect = CARD_EFFECT && !mFilmMode + && (mIndex > 0) && !mPictures.get(0).isCamera(); int w = getWidth(); int drawW = getRotated(mRotation, r.width(), r.height()); int drawH = getRotated(mRotation, r.height(), r.width()); - int cx = applyFadingAnimation ? w / 2 : r.centerX(); + int cx = wantsCardEffect ? w / 2 : r.centerX(); int cy = r.centerY(); int flags = GLCanvas.SAVE_FLAG_MATRIX; - if (applyFadingAnimation) flags |= GLCanvas.SAVE_FLAG_ALPHA; + if (wantsCardEffect) flags |= GLCanvas.SAVE_FLAG_ALPHA; canvas.save(flags); canvas.translate(cx, cy); - if (applyFadingAnimation) { + if (wantsCardEffect) { float progress = (float) (w / 2 - r.centerX()) / w; progress = Utils.clamp(progress, -1, 1); float alpha = getScrollAlpha(progress); @@ -524,9 +561,9 @@ public class PhotoView extends GLView { @Override public void setScreenNail(ScreenNail s) { - mEnabled = (s != null); if (mScreenNail == s) return; mScreenNail = s; + mIsCamera = isCameraScreenNail(s); mRotation = mModel.getImageRotation(mIndex); int w = 0, h = 0; @@ -549,8 +586,8 @@ public class PhotoView extends GLView { } @Override - public boolean isEnabled() { - return mEnabled; + public boolean isCamera() { + return mIsCamera; } } @@ -677,10 +714,15 @@ public class PhotoView extends GLView { @Override public void onDown() { + mHolding |= HOLD_TOUCH_DOWN; + if (mPictures.get(0).isCamera()) { + mHolding |= HOLD_TOUCH_DOWN_FROM_CAMERA; + } } @Override public void onUp() { + mHolding &= ~(HOLD_TOUCH_DOWN | HOLD_TOUCH_DOWN_FROM_CAMERA); mEdgeView.onRelease(); if (mIgnoreUpEvent) { @@ -688,9 +730,7 @@ public class PhotoView extends GLView { return; } - if (!snapToNeighborImage()) { - mPositionController.up(); - } + snapback(); } } @@ -771,7 +811,7 @@ public class PhotoView extends GLView { // Runs in main thread. private void switchFocus() { - if (mGestureRecognizer.isDown()) return; + if (mHolding != 0) return; switch (switchPosition()) { case -1: switchToPrevImage(); @@ -788,14 +828,14 @@ public class PhotoView extends GLView { Rect curr = mPositionController.getPosition(0); int center = getWidth() / 2; - if (curr.left > center && mPictures.get(-1).isEnabled()) { + if (curr.left > center && mPrevBound < 0) { Rect prev = mPositionController.getPosition(-1); int currDist = curr.left - center; int prevDist = center - prev.right; if (prevDist < currDist) { return -1; } - } else if (curr.right < center && mPictures.get(1).isEnabled()) { + } else if (curr.right < center && mNextBound > 0) { Rect next = mPositionController.getPosition(1); int currDist = center - curr.right; int nextDist = next.left - center; @@ -841,6 +881,13 @@ public class PhotoView extends GLView { return false; } + private void snapback() { + if (mHolding != 0) return; + if (!snapToNeighborImage()) { + mPositionController.snapback(); + } + } + private boolean snapToNeighborImage() { if (mFilmMode) return false; @@ -859,22 +906,16 @@ public class PhotoView extends GLView { } private boolean slideToNextPicture() { - Picture next = mPictures.get(1); - if (!next.isEnabled()) return false; - int currentX = mPositionController.getPosition(1).centerX(); - int targetX = getWidth() / 2; - mPositionController.startHorizontalSlide(targetX - currentX); + if (mNextBound <= 0) return false; switchToNextImage(); + mPositionController.startHorizontalSlide(); return true; } private boolean slideToPrevPicture() { - Picture prev = mPictures.get(-1); - if (!prev.isEnabled()) return false; - int currentX = mPositionController.getPosition(-1).centerX(); - int targetX = getWidth() / 2; - mPositionController.startHorizontalSlide(targetX - currentX); + if (mPrevBound >= 0) return false; switchToPrevImage(); + mPositionController.startHorizontalSlide(); return true; } @@ -903,6 +944,44 @@ public class PhotoView extends GLView { } //////////////////////////////////////////////////////////////////////////// + // Capture Animation + //////////////////////////////////////////////////////////////////////////// + + public boolean switchWithCaptureAnimation(int offset) { + GLRoot root = getGLRoot(); + root.lockRenderThread(); + try { + return switchWithCaptureAnimationLocked(offset); + } finally { + root.unlockRenderThread(); + } + } + + private boolean switchWithCaptureAnimationLocked(int offset) { + if (mFilmMode) return false; + if (mHolding != 0) return true; + if (offset == 1) { + if (mNextBound <= 0) return false; + switchToNextImage(); + mPositionController.startCaptureAnimationSlide(-1); + } else if (offset == -1) { + if (mPrevBound >= 0) return false; + switchToPrevImage(); + mPositionController.startCaptureAnimationSlide(1); + } else { + return false; + } + mHolding |= HOLD_CAPTURE_ANIMATION; + mHandler.sendEmptyMessageDelayed(MSG_CAPTURE_ANIMATION_DONE, 800); + return true; + } + + private void captureAnimationDone() { + mHolding &= ~HOLD_CAPTURE_ANIMATION; + snapback(); + } + + //////////////////////////////////////////////////////////////////////////// // Card deck effect calculation //////////////////////////////////////////////////////////////////////////// diff --git a/src/com/android/gallery3d/ui/PositionController.java b/src/com/android/gallery3d/ui/PositionController.java index 46f01217f..e6c132b85 100644 --- a/src/com/android/gallery3d/ui/PositionController.java +++ b/src/com/android/gallery3d/ui/PositionController.java @@ -45,6 +45,7 @@ class PositionController { private static final int ANIM_KIND_ZOOM = 4; private static final int ANIM_KIND_OPENING = 5; private static final int ANIM_KIND_FLING = 6; + private static final int ANIM_KIND_CAPTURE = 7; // Animation time in milliseconds. The order must match ANIM_KIND_* above. private static final int ANIM_TIME[] = { @@ -55,6 +56,7 @@ class PositionController { 300, // ANIM_KIND_ZOOM 600, // ANIM_KIND_OPENING 0, // ANIM_KIND_FLING (the duration is calculated dynamically) + 800, // ANIM_KIND_CAPTURE }; // We try to scale up the image to fill the screen. But in order not to @@ -139,7 +141,7 @@ class PositionController { public interface Listener { void invalidate(); - boolean isDown(); + boolean isHolding(); // EdgeView void onPull(int offset, int direction); @@ -187,8 +189,8 @@ class PositionController { public void setImageSize(int index, int width, int height) { if (width == 0 || height == 0) { initBox(index); - } else { - setBoxSize(index, width, height, false); + } else if (!setBoxSize(index, width, height, false)) { + return; } updateScaleAndGapLimit(); @@ -196,17 +198,18 @@ class PositionController { snapAndRedraw(); } - private void setBoxSize(int i, int width, int height, boolean isViewSize) { + // Returns false if the box size doesn't change. + private boolean setBoxSize(int i, int width, int height, boolean isViewSize) { Box b = mBoxes.get(i); boolean wasViewSize = b.mUseViewSize; // If we already have an image size, we don't want to use the view size. - if (!wasViewSize && isViewSize) return; + if (!wasViewSize && isViewSize) return false; b.mUseViewSize = isViewSize; if (width == b.mImageW && height == b.mImageH) { - return; + return false; } // The ratio of the old size and the new size. @@ -232,6 +235,8 @@ class PositionController { mFocusX /= ratio; mFocusY /= ratio; } + + return true; } private void startOpeningAnimationIfNeeded() { @@ -339,7 +344,7 @@ class PositionController { redraw(); } - public void up() { + public void snapback() { snapAndRedraw(); } @@ -406,11 +411,26 @@ class PositionController { snapAndRedraw(); } - public void startHorizontalSlide(int distance) { + // Slide the focused box to the center of the view. + public void startHorizontalSlide() { Box b = mBoxes.get(0); - Platform p = mPlatform; - startAnimation(getTargetX(p) + distance, getTargetY(b), - b.mCurrentScale, ANIM_KIND_SLIDE); + startAnimation(mViewW / 2, mViewH / 2, b.mScaleMin, ANIM_KIND_SLIDE); + } + + // Slide the focused box to the center of the view with the capture + // animation. In addition to the sliding, the animation will also scale the + // the focused box, the specified neighbor box, and the gap between the + // two. The specified offset should be 1 or -1. + public void startCaptureAnimationSlide(int offset) { + Box b = mBoxes.get(0); + Box n = mBoxes.get(offset); // the neighbor box + Gap g = mGaps.get(offset); // the gap between the two boxes + + mPlatform.doAnimation(mViewW / 2, ANIM_KIND_CAPTURE); + b.doAnimation(mViewH / 2, b.mScaleMin, ANIM_KIND_CAPTURE); + n.doAnimation(mViewH / 2, n.mScaleMin, ANIM_KIND_CAPTURE); + g.doAnimation(g.mDefaultSize, ANIM_KIND_CAPTURE); + redraw(); } public void startScroll(float dx, float dy) { @@ -762,7 +782,7 @@ class PositionController { // N N N N N N N -- all new boxes // -3 -2 -1 0 1 2 3 -- nothing changed // -2 -1 0 1 2 3 N -- focus goes to the next box - // N-3 -2 -1 0 1 2 -- focuse goes to the previous box + // N -3 -2 -1 0 1 2 -- focuse goes to the previous box // -3 -2 -1 1 2 3 N -- the focused box was deleted. public void moveBox(int fromIndex[], boolean hasPrev, boolean hasNext) { //debugMoveBox(fromIndex); @@ -837,12 +857,12 @@ class PositionController { first = last = 0; } // Now for those boxes between first and last, just assign the same - // position as the previous box. (We can do better, but this should be + // position as the next box. (We can do better, but this should be // rare). For the boxes before first or after last, we will use a new // default gap size below. - for (int i = first + 1; i < last; i++) { + for (int i = last - 1; i > first; i--) { if (from.get(i) != Integer.MAX_VALUE) continue; - mBoxes.get(i).mAbsoluteX = mBoxes.get(i - 1).mAbsoluteX; + mBoxes.get(i).mAbsoluteX = mBoxes.get(i + 1).mAbsoluteX; } // 7. recycle the gaps that are not used in the new array. @@ -1089,6 +1109,7 @@ class PositionController { switch (kind) { case ANIM_KIND_SCROLL: case ANIM_KIND_FLING: + case ANIM_KIND_CAPTURE: progress = 1 - f; // linear break; case ANIM_KIND_SCALE: @@ -1116,7 +1137,7 @@ class PositionController { public boolean startSnapback() { if (mAnimationStartTime != NO_ANIMATION) return false; if (mAnimationKind == ANIM_KIND_SCROLL - && mListener.isDown()) return false; + && mListener.isHolding()) return false; Box b = mBoxes.get(0); float scaleMin = mExtraScalingRange ? @@ -1211,8 +1232,14 @@ class PositionController { mCurrentX = mToX; return true; } else { - mCurrentX = (int) (mFromX + progress * (mToX - mFromX)); - return (mCurrentX == mToX); + if (mAnimationKind == ANIM_KIND_CAPTURE) { + progress = CaptureAnimation.calculateSlide(progress); + mCurrentX = (int) (mFromX + progress * (mToX - mFromX)); + return false; + } else { + mCurrentX = (int) (mFromX + progress * (mToX - mFromX)); + return (mCurrentX == mToX); + } } } } @@ -1247,7 +1274,7 @@ class PositionController { public boolean startSnapback() { if (mAnimationStartTime != NO_ANIMATION) return false; if (mAnimationKind == ANIM_KIND_SCROLL - && mListener.isDown()) return false; + && mListener.isHolding()) return false; if (mInScale && this == mBoxes.get(0)) return false; int y; @@ -1288,7 +1315,8 @@ class PositionController { targetY = mViewH / 2; } - if (mCurrentY == targetY && mCurrentScale == targetScale) { + if (mCurrentY == targetY && mCurrentScale == targetScale + && kind != ANIM_KIND_CAPTURE) { return false; } @@ -1341,7 +1369,13 @@ class PositionController { } else { mCurrentY = (int) (mFromY + progress * (mToY - mFromY)); mCurrentScale = mFromScale + progress * (mToScale - mFromScale); - return (mCurrentY == mToY && mCurrentScale == mToScale); + if (mAnimationKind == ANIM_KIND_CAPTURE) { + float f = CaptureAnimation.calculateScale(progress); + mCurrentScale *= f; + return false; + } else { + return (mCurrentY == mToY && mCurrentScale == mToScale); + } } } } @@ -1361,13 +1395,15 @@ class PositionController { @Override public boolean startSnapback() { if (mAnimationStartTime != NO_ANIMATION) return false; - return doAnimation(mDefaultSize); + return doAnimation(mDefaultSize, ANIM_KIND_SNAPBACK); } // Starts an animation for a gap. - public boolean doAnimation(int targetSize) { - if (mCurrentGap == targetSize) return false; - mAnimationKind = ANIM_KIND_SNAPBACK; + public boolean doAnimation(int targetSize, int kind) { + if (mCurrentGap == targetSize && kind != ANIM_KIND_CAPTURE) { + return false; + } + mAnimationKind = kind; mFromGap = mCurrentGap; mToGap = targetSize; mAnimationStartTime = AnimationTime.startTime(); @@ -1383,7 +1419,13 @@ class PositionController { return true; } else { mCurrentGap = (int) (mFromGap + progress * (mToGap - mFromGap)); - return (mCurrentGap == mToGap); + if (mAnimationKind == ANIM_KIND_CAPTURE) { + float f = CaptureAnimation.calculateScale(progress); + mCurrentGap = (int) (mCurrentGap * f); + return false; + } else { + return (mCurrentGap == mToGap); + } } } } -- 2.11.0