From b21215a1a59812592380f31891becedbdec7468b Mon Sep 17 00:00:00 2001 From: Angus Kong Date: Fri, 20 Sep 2013 18:41:46 -0700 Subject: [PATCH] Improve the animation to filmstrip. 1. Remove the snap-in-center check at the end of scale animation. 2. Don't go back to full-screen when animating from camera preview to filmstrip. bug:10806298 bug:10864100 Change-Id: I751040a22e2758709c22e7230a5418a871ef85f9 --- src/com/android/camera/data/CameraPreviewData.java | 2 +- src/com/android/camera/data/LocalMediaData.java | 4 +- src/com/android/camera/data/SimpleViewData.java | 2 +- src/com/android/camera/ui/FilmStripView.java | 178 ++++++++++++--------- src/com/android/camera/util/CameraUtil.java | 12 +- 5 files changed, 113 insertions(+), 85 deletions(-) diff --git a/src/com/android/camera/data/CameraPreviewData.java b/src/com/android/camera/data/CameraPreviewData.java index f6127e46f..d13465e93 100644 --- a/src/com/android/camera/data/CameraPreviewData.java +++ b/src/com/android/camera/data/CameraPreviewData.java @@ -41,7 +41,7 @@ public class CameraPreviewData extends SimpleViewData { @Override public int getViewType() { - return ImageData.TYPE_STICKY_VIEW; + return ImageData.VIEW_TYPE_STICKY; } @Override diff --git a/src/com/android/camera/data/LocalMediaData.java b/src/com/android/camera/data/LocalMediaData.java index 17ddbca42..1f31f5f33 100644 --- a/src/com/android/camera/data/LocalMediaData.java +++ b/src/com/android/camera/data/LocalMediaData.java @@ -402,7 +402,7 @@ public abstract class LocalMediaData implements LocalData { @Override public int getViewType() { - return TYPE_REMOVABLE_VIEW; + return VIEW_TYPE_REMOVABLE; } @Override @@ -638,7 +638,7 @@ public abstract class LocalMediaData implements LocalData { @Override public int getViewType() { - return TYPE_REMOVABLE_VIEW; + return VIEW_TYPE_REMOVABLE; } @Override diff --git a/src/com/android/camera/data/SimpleViewData.java b/src/com/android/camera/data/SimpleViewData.java index a73a52ece..c440296b8 100644 --- a/src/com/android/camera/data/SimpleViewData.java +++ b/src/com/android/camera/data/SimpleViewData.java @@ -81,7 +81,7 @@ public class SimpleViewData implements LocalData { @Override public int getViewType() { - return FilmStripView.ImageData.TYPE_REMOVABLE_VIEW; + return FilmStripView.ImageData.VIEW_TYPE_REMOVABLE; } @Override diff --git a/src/com/android/camera/ui/FilmStripView.java b/src/com/android/camera/ui/FilmStripView.java index cbbc54e82..f28637c9d 100644 --- a/src/com/android/camera/ui/FilmStripView.java +++ b/src/com/android/camera/ui/FilmStripView.java @@ -26,6 +26,7 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.RectF; import android.net.Uri; +import android.os.Handler; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; @@ -118,9 +119,9 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { } // View types. - public static final int TYPE_NONE = 0; - public static final int TYPE_STICKY_VIEW = 1; - public static final int TYPE_REMOVABLE_VIEW = 2; + public static final int VIEW_TYPE_NONE = 0; + public static final int VIEW_TYPE_STICKY = 1; + public static final int VIEW_TYPE_REMOVABLE = 2; // Actions allowed to be performed on the image data. // The actions are defined bit-wise so we can use bit operations like @@ -705,7 +706,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { private int getCurrentViewType() { ViewItem curr = mViewItem[mCurrentItem]; if (curr == null) { - return ImageData.TYPE_NONE; + return ImageData.VIEW_TYPE_NONE; } return mDataAdapter.getImageData(curr.getId()).getViewType(); } @@ -1048,7 +1049,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { / mDrawArea.width()); mController.scrollToPosition(currentViewCenter, snapInTime, false); - if (getCurrentViewType() == ImageData.TYPE_STICKY_VIEW + if (getCurrentViewType() == ImageData.VIEW_TYPE_STICKY && !mController.isScaling() && mScale != FULL_SCREEN_SCALE) { // Now going to full screen camera @@ -1332,7 +1333,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { // Keeps the view in the view hierarchy if it's camera preview. // Remove from the hierarchy otherwise. private void checkForRemoval(ImageData data, View v) { - if (data.getViewType() != ImageData.TYPE_STICKY_VIEW) { + if (data.getViewType() != ImageData.VIEW_TYPE_STICKY) { removeView(v); data.recycle(); } else { @@ -1615,7 +1616,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { public boolean inCameraFullscreen() { return isDataAtCenter(0) && inFullScreen() - && (getCurrentViewType() == ImageData.TYPE_STICKY_VIEW); + && (getCurrentViewType() == ImageData.VIEW_TYPE_STICKY); } @Override @@ -1816,10 +1817,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { * MyController controls all the geometry animations. It passively tells the * geometry information on demand. */ - private class MyController implements - Controller, - ValueAnimator.AnimatorUpdateListener, - Animator.AnimatorListener { + private class MyController implements Controller { private final ValueAnimator mScaleAnimator; private ValueAnimator mZoomAnimator; @@ -1827,50 +1825,50 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { private final Scroller mScroller; private boolean mCanStopScroll; private final DecelerateInterpolator mDecelerateInterpolator; - private final TimeInterpolator mDecelerateAccelerateInterpolator = - new TimeInterpolator() { - private final TimeInterpolator interpolator = - new AccelerateInterpolator(); + private final MyScroller.Listener mScrollerListener = + new MyScroller.Listener() { @Override - public float getInterpolation(float v) { - float v2 = v * 2f; - return ((v2 < 1f) ? - mDecelerateInterpolator.getInterpolation(v2) / 2f : - interpolator.getInterpolation(v2 - 1f) / 2f + 0.5f); + public void onScrollUpdate(int currX, int currY) { + mCenterX = currX; + clampCenterX(); + invalidate(); } - }; - private final Runnable mScrollUpdater = new Runnable() { - @Override - public void run() { - boolean newPosition = !mScroller.isFinished(); - if (!newPosition) { - mCanStopScroll = true; - if (mViewItem[mCurrentItem] != null) { + @Override + public void onScrollEnd() { + mCanStopScroll = true; + if (mViewItem[mCurrentItem] == null) { + return; + } snapInCenter(); if (mCenterX == mViewItem[mCurrentItem].getCenterX() - && getCurrentViewType() == ImageData.TYPE_STICKY_VIEW) { + && getCurrentViewType() == ImageData.VIEW_TYPE_STICKY) { + // Special case for the scrolling end on the camera preview. goToFullScreen(); } } - return; - } - mScroller.computeScrollOffset(); - mCenterX = mScroller.getCurrX(); - clampCenterX(); - invalidate(); - FilmStripView.this.post(this); - } - }; + }; + + private ValueAnimator.AnimatorUpdateListener mScaleAnimatorUpdateListener = + new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + if (mViewItem[mCurrentItem] == null) { + return; + } + mScale = (Float) animation.getAnimatedValue(); + invalidate(); + } + }; MyController(Context context) { - mScroller = new Scroller(context); + mScroller = new MyScroller(mActivity, + new Handler(mActivity.getMainLooper()), mScrollerListener); mCanStopScroll = true; mScaleAnimator = new ValueAnimator(); - mScaleAnimator.addUpdateListener(MyController.this); - mScaleAnimator.addListener(MyController.this); + mScaleAnimator.addUpdateListener(mScaleAnimatorUpdateListener); mDecelerateInterpolator = new DecelerateInterpolator(1.5f); } @@ -1983,7 +1981,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { } float scaledVelocityX = velocityX / mScale; - if (inFullScreen() && getCurrentViewType() == ImageData.TYPE_STICKY_VIEW + if (inFullScreen() && getCurrentViewType() == ImageData.VIEW_TYPE_STICKY && scaledVelocityX < 0) { // Swipe left in camera preview. goToFilmStrip(); @@ -1998,7 +1996,6 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { // the possible maximum too. int maxX = estimateMaxX(item.getId(), item.getLeftPosition(), w); mScroller.fling(mCenterX, 0, (int) -velocityX, 0, minX, maxX, 0, 0); - FilmStripView.this.post(mScrollUpdater); } @Override @@ -2024,21 +2021,21 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { mCanStopScroll = interruptible; mScroller.startScroll(mCenterX, 0, position - mCenterX, 0, duration); - FilmStripView.this.post(mScrollUpdater); } @Override public boolean goToNextItem() { - ViewItem nextItem = mViewItem[mCurrentItem + 1]; + final ViewItem nextItem = mViewItem[mCurrentItem + 1]; if (nextItem == null) { return false; } - stopScale(); + stopScrolling(true); scrollToPosition(nextItem.getCenterX(), GEOMETRY_ADJUST_TIME_MS * 2, false); - mScaleAnimator.setFloatValues(FULL_SCREEN_SCALE, FILM_STRIP_SCALE, FULL_SCREEN_SCALE); - mScaleAnimator.setInterpolator(mDecelerateAccelerateInterpolator); - mScaleAnimator.setDuration(GEOMETRY_ADJUST_TIME_MS * 2); - mScaleAnimator.start(); + + if (getCurrentViewType() == ImageData.VIEW_TYPE_STICKY) { + // Special case when moving from camera preview. + scaleTo(FILM_STRIP_SCALE, GEOMETRY_ADJUST_TIME_MS); + } return true; } @@ -2059,7 +2056,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { final ViewItem nextItem = mViewItem[mCurrentItem + 1]; if (mViewItem[mCurrentItem].getId() == 0 && - getCurrentViewType() == ImageData.TYPE_STICKY_VIEW && + getCurrentViewType() == ImageData.VIEW_TYPE_STICKY && nextItem != null) { // Deal with the special case of swiping in camera preview. scrollToPosition(nextItem.getCenterX(), GEOMETRY_ADJUST_TIME_MS, false); @@ -2160,46 +2157,71 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { reload(); } - @Override - public void onAnimationUpdate(ValueAnimator animation) { - if (mViewItem[mCurrentItem] == null) { - return; - } - mScale = (Float) animation.getAnimatedValue(); - invalidate(); + public boolean isZoomStarted() { + return mScale > FULL_SCREEN_SCALE; } - @Override - public void onAnimationStart(Animator anim) { + public boolean isZoomAnimationRunning() { + return mZoomAnimator != null && mZoomAnimator.isRunning(); } + } - @Override - public void onAnimationEnd(Animator anim) { - ViewItem item = mViewItem[mCurrentItem]; - if (item == null) { - return; - } - if (mCenterX != item.getCenterX()) { - if (inFilmStrip()) { - snapInCenter(); + private static class MyScroller extends Scroller { + public interface Listener { + public void onScrollUpdate(int currX, int currY); + public void onScrollEnd(); + } + + private Handler mHandler; + private Listener mListener; + private Runnable mScrollChecker = new Runnable() { + @Override + public void run() { + boolean newPosition = computeScrollOffset(); + if (!newPosition) { + mListener.onScrollEnd(); + return; } + mListener.onScrollUpdate(getCurrX(), getCurrY()); + mHandler.removeCallbacks(this); + mHandler.post(this); } + }; + + public MyScroller(Context ctx, Handler handler, Listener listener) { + super(ctx); + mHandler = handler; + mListener = listener; } @Override - public void onAnimationCancel(Animator anim) { + public void fling( + int startX, int startY, + int velocityX, int velocityY, + int minX, int maxX, + int minY, int maxY) { + super.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY); + runChecker(); } @Override - public void onAnimationRepeat(Animator anim) { + public void startScroll(int startX, int startY, int dx, int dy) { + super.startScroll(startX, startY, dx, dy); + runChecker(); } - public boolean isZoomStarted() { - return mScale > FULL_SCREEN_SCALE; + @Override + public void startScroll(int startX, int startY, int dx, int dy, int duration) { + super.startScroll(startX, startY, dx, dy, duration); + runChecker(); } - public boolean isZoomAnimationRunning() { - return mZoomAnimator != null && mZoomAnimator.isRunning(); + private void runChecker() { + if (mHandler == null || mListener == null) { + return; + } + mHandler.removeCallbacks(mScrollChecker); + mHandler.post(mScrollChecker); } } @@ -2305,7 +2327,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { if (mCenterX > currItem.getCenterX() + CAMERA_PREVIEW_SWIPE_THRESHOLD && currItem.getId() == 0 - && getCurrentViewType() == ImageData.TYPE_STICKY_VIEW + && getCurrentViewType() == ImageData.VIEW_TYPE_STICKY && mDataIdOnUserScrolling == 0) { mController.goToFilmStrip(); // Special case to go from camera preview to the next photo. @@ -2318,7 +2340,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { snapInCenter(); } } if (mCenterX == currItem.getCenterX() && currItem.getId() == 0 - && getCurrentViewType() == ImageData.TYPE_STICKY_VIEW) { + && getCurrentViewType() == ImageData.VIEW_TYPE_STICKY) { mController.goToFullScreen(); } else { if (mDataIdOnUserScrolling == 0 && currItem.getId() != 0) { @@ -2436,7 +2458,7 @@ public class FilmStripView extends ViewGroup implements BottomControlsListener { } mController.scrollToPosition( nextItem.getCenterX(), GEOMETRY_ADJUST_TIME_MS, true); - if (getCurrentViewType() == ImageData.TYPE_STICKY_VIEW) { + if (getCurrentViewType() == ImageData.VIEW_TYPE_STICKY) { mController.goToFilmStrip(); } } diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java index bb72ba70c..fc80c5c3e 100644 --- a/src/com/android/camera/util/CameraUtil.java +++ b/src/com/android/camera/util/CameraUtil.java @@ -830,14 +830,20 @@ public class CameraUtil { } } + /** + * Dumps the stack trace. + * + * @param level How many levels of the stack are dumped. 0 means all. + * @return A {@link java.lang.String} of all the output with newline + * between each. + */ public static String dumpStackTrace(int level) { StackTraceElement[] elems = Thread.currentThread().getStackTrace(); // Ignore the first 3 elements. - level += 3; - level = (level == 0 ? elems.length : Math.min(level, elems.length)); + level = (level == 0 ? elems.length : Math.min(level + 3, elems.length)); String ret = new String(); for (int i = 3; i < level; i++) { - ret = ret + elems[i].toString() + '\n'; + ret = ret + "\t" + elems[i].toString() + '\n'; } return ret; } -- 2.11.0