14c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein/* 24c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Copyright (C) 2013 The Android Open Source Project 34c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 44c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Licensed under the Apache License, Version 2.0 (the "License"); 54c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * you may not use this file except in compliance with the License. 64c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * You may obtain a copy of the License at 74c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 84c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * http://www.apache.org/licenses/LICENSE-2.0 94c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 104c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Unless required by applicable law or agreed to in writing, software 114c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * distributed under the License is distributed on an "AS IS" BASIS, 124c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * See the License for the specific language governing permissions and 144c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * limitations under the License. 154c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 164c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 174c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzsteinpackage com.android.deskclock.widget.sgv; 184c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 194c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzsteinimport android.content.Context; 204c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzsteinimport android.hardware.SensorManager; 214c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzsteinimport android.util.FloatMath; 224c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzsteinimport android.util.Log; 234c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzsteinimport android.view.ViewConfiguration; 244c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzsteinimport android.view.animation.AnimationUtils; 254c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzsteinimport android.view.animation.Interpolator; 264c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 274c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein/** 284c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Temporarily copied from the framework so that StaggeredGridView can properly show the bounce at 294c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * the end of flings. See TODO and b/8252293 for more info. 304c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 314c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein/** 324c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * This class encapsulates scrolling with the ability to overshoot the bounds 334c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * of a scrolling operation. This class is a drop-in replacement for 344c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * {@link android.widget.Scroller} in most cases. 354c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 364c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzsteinpublic class OverScrollerSGV { 374c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private int mMode; 384c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 394c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private final SplineOverScroller mScrollerX; 404c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private final SplineOverScroller mScrollerY; 414c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 424c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private Interpolator mInterpolator; 434c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 444c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private final boolean mFlywheel; 454c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 464c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final int DEFAULT_DURATION = 250; 474c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final int SCROLL_MODE = 0; 484c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final int FLING_MODE = 1; 494c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 504c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 514c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Creates an OverScroller with a viscous fluid scroll interpolator and flywheel. 524c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param context 534c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 544c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public OverScrollerSGV(Context context) { 554c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein this(context, null); 564c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 574c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 584c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 594c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Creates an OverScroller with flywheel enabled. 604c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param context The context of this application. 614c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will 624c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * be used. 634c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 644c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public OverScrollerSGV(Context context, Interpolator interpolator) { 654c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein this(context, interpolator, true); 664c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 674c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 684c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 694c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Creates an OverScroller. 704c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param context The context of this application. 714c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will 724c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * be used. 734c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param flywheel If true, successive fling motions will keep on increasing scroll speed. 744c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @hide 754c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 764c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public OverScrollerSGV(Context context, Interpolator interpolator, boolean flywheel) { 774c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mInterpolator = interpolator; 784c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFlywheel = flywheel; 794c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX = new SplineOverScroller(context); 804c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerY = new SplineOverScroller(context); 814c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 824c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 834c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 844c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Creates an OverScroller with flywheel enabled. 854c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param context The context of this application. 864c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will 874c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * be used. 884c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param bounceCoefficientX A value between 0 and 1 that will determine the proportion of the 894c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * velocity which is preserved in the bounce when the horizontal edge is reached. A null value 904c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * means no bounce. This behavior is no longer supported and this coefficient has no effect. 914c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param bounceCoefficientY Same as bounceCoefficientX but for the vertical direction. This 924c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * behavior is no longer supported and this coefficient has no effect. 934c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * !deprecated Use {!link #OverScroller(Context, Interpolator, boolean)} instead. 944c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 954c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public OverScrollerSGV(Context context, Interpolator interpolator, 964c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float bounceCoefficientX, float bounceCoefficientY) { 974c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein this(context, interpolator, true); 984c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 994c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 1004c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 1014c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Creates an OverScroller. 1024c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param context The context of this application. 1034c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will 1044c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * be used. 1054c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param bounceCoefficientX A value between 0 and 1 that will determine the proportion of the 1064c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * velocity which is preserved in the bounce when the horizontal edge is reached. A null value 1074c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * means no bounce. This behavior is no longer supported and this coefficient has no effect. 1084c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param bounceCoefficientY Same as bounceCoefficientX but for the vertical direction. This 1094c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * behavior is no longer supported and this coefficient has no effect. 1104c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param flywheel If true, successive fling motions will keep on increasing scroll speed. 1114c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * !deprecated Use {!link OverScroller(Context, Interpolator, boolean)} instead. 1124c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 1134c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public OverScrollerSGV(Context context, Interpolator interpolator, 1144c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float bounceCoefficientX, float bounceCoefficientY, boolean flywheel) { 1154c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein this(context, interpolator, flywheel); 1164c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 1174c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 1184c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein void setInterpolator(Interpolator interpolator) { 1194c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mInterpolator = interpolator; 1204c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 1214c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 1224c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 1234c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * The amount of friction applied to flings. The default value 1244c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * is {@link ViewConfiguration#getScrollFriction}. 1254c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 1264c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param friction A scalar dimension-less value representing the coefficient of 1274c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * friction. 1284c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 1294c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public final void setFriction(float friction) { 1304c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX.setFriction(friction); 1314c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerY.setFriction(friction); 1324c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 1334c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 1344c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 1354c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 1364c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Returns whether the scroller has finished scrolling. 1374c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 1384c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return True if the scroller has finished scrolling, false otherwise. 1394c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 1404c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public final boolean isFinished() { 1414c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return mScrollerX.mFinished && mScrollerY.mFinished; 1424c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 1434c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 1444c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 1454c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Force the finished field to a particular value. Contrary to 1464c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * {@link #abortAnimation()}, forcing the animation to finished 1474c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * does NOT cause the scroller to move to the final x and y 1484c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * position. 1494c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 1504c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param finished The new finished value. 1514c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 1524c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public final void forceFinished(boolean finished) { 1534c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX.mFinished = mScrollerY.mFinished = finished; 1544c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 1554c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 1564c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 1574c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Returns the current X offset in the scroll. 1584c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 1594c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return The new X offset as an absolute distance from the origin. 1604c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 1614c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public final int getCurrX() { 1624c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return mScrollerX.mCurrentPosition; 1634c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 1644c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 1654c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 1664c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Returns the current Y offset in the scroll. 1674c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 1684c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return The new Y offset as an absolute distance from the origin. 1694c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 1704c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public final int getCurrY() { 1714c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return mScrollerY.mCurrentPosition; 1724c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 1734c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 1744c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 1754c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Returns the absolute value of the current velocity. 1764c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 1774c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return The original velocity less the deceleration, norm of the X and Y velocity vector. 1784c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 1794c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public float getCurrVelocity() { 1804c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float squaredNorm = mScrollerX.mCurrVelocity * mScrollerX.mCurrVelocity; 1814c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein squaredNorm += mScrollerY.mCurrVelocity * mScrollerY.mCurrVelocity; 1824c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return FloatMath.sqrt(squaredNorm); 1834c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 1844c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 1854c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 1864c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Returns the start X offset in the scroll. 1874c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 1884c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return The start X offset as an absolute distance from the origin. 1894c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 1904c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public final int getStartX() { 1914c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return mScrollerX.mStart; 1924c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 1934c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 1944c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 1954c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Returns the start Y offset in the scroll. 1964c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 1974c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return The start Y offset as an absolute distance from the origin. 1984c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 1994c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public final int getStartY() { 2004c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return mScrollerY.mStart; 2014c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 2024c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 2034c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 2044c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Returns where the scroll will end. Valid only for "fling" scrolls. 2054c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 2064c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return The final X offset as an absolute distance from the origin. 2074c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 2084c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public final int getFinalX() { 2094c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return mScrollerX.mFinal; 2104c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 2114c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 2124c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 2134c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Returns where the scroll will end. Valid only for "fling" scrolls. 2144c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 2154c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return The final Y offset as an absolute distance from the origin. 2164c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 2174c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public final int getFinalY() { 2184c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return mScrollerY.mFinal; 2194c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 2204c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 2214c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 2224c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Returns how long the scroll event will take, in milliseconds. 2234c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 2244c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return The duration of the scroll in milliseconds. 2254c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 2264c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @hide Pending removal once nothing depends on it 2274c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @deprecated OverScrollers don't necessarily have a fixed duration. 2284c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * This function will lie to the best of its ability. 2294c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 2304c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein @Deprecated 2314c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public final int getDuration() { 2324c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return Math.max(mScrollerX.mDuration, mScrollerY.mDuration); 2334c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 2344c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 2354c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 2364c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Extend the scroll animation. This allows a running animation to scroll 2374c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}. 2384c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 2394c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param extend Additional time to scroll in milliseconds. 2404c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @see #setFinalX(int) 2414c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @see #setFinalY(int) 2424c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 2434c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @hide Pending removal once nothing depends on it 2444c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @deprecated OverScrollers don't necessarily have a fixed duration. 2454c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Instead of setting a new final position and extending 2464c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * the duration of an existing scroll, use startScroll 2474c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * to begin a new animation. 2484c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 2494c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein @Deprecated 2504c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public void extendDuration(int extend) { 2514c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX.extendDuration(extend); 2524c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerY.extendDuration(extend); 2534c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 2544c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 2554c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 2564c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Sets the final position (X) for this scroller. 2574c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 2584c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param newX The new X offset as an absolute distance from the origin. 2594c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @see #extendDuration(int) 2604c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @see #setFinalY(int) 2614c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 2624c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @hide Pending removal once nothing depends on it 2634c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @deprecated OverScroller's final position may change during an animation. 2644c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Instead of setting a new final position and extending 2654c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * the duration of an existing scroll, use startScroll 2664c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * to begin a new animation. 2674c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 2684c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein @Deprecated 2694c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public void setFinalX(int newX) { 2704c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX.setFinalPosition(newX); 2714c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 2724c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 2734c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 2744c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Sets the final position (Y) for this scroller. 2754c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 2764c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param newY The new Y offset as an absolute distance from the origin. 2774c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @see #extendDuration(int) 2784c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @see #setFinalX(int) 2794c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 2804c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @hide Pending removal once nothing depends on it 2814c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @deprecated OverScroller's final position may change during an animation. 2824c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Instead of setting a new final position and extending 2834c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * the duration of an existing scroll, use startScroll 2844c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * to begin a new animation. 2854c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 2864c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein @Deprecated 2874c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public void setFinalY(int newY) { 2884c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerY.setFinalPosition(newY); 2894c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 2904c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 2914c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 2924c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Call this when you want to know the new location. If it returns true, the 2934c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * animation is not yet finished. 2944c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 2954c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public boolean computeScrollOffset() { 2964c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (isFinished()) { 2974c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return false; 2984c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 2994c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3004c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein switch (mMode) { 3014c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein case SCROLL_MODE: 3024c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein long time = AnimationUtils.currentAnimationTimeMillis(); 3034c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Any scroller can be used for time, since they were started 3044c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // together in scroll mode. We use X here. 3054c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final long elapsedTime = time - mScrollerX.mStartTime; 3064c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3074c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final int duration = mScrollerX.mDuration; 3084c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (elapsedTime < duration) { 3094c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float q = (float) (elapsedTime) / duration; 3104c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3114c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (mInterpolator == null) { 3124c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein q = mInterpolator.getInterpolation(q); 3134c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } else { 3144c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein q = mInterpolator.getInterpolation(q); 3154c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3164c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3174c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX.updateScroll(q); 3184c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerY.updateScroll(q); 3194c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } else { 3204c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein abortAnimation(); 3214c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3224c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein break; 3234c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3244c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein case FLING_MODE: 3254c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (!mScrollerX.mFinished) { 3264c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (!mScrollerX.update()) { 3274c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (!mScrollerX.continueWhenFinished()) { 3284c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX.finish(); 3294c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3304c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3314c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3324c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3334c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (!mScrollerY.mFinished) { 3344c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (!mScrollerY.update()) { 3354c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (!mScrollerY.continueWhenFinished()) { 3364c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerY.finish(); 3374c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3384c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3394c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3404c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3414c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein break; 3424c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3434c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3444c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return true; 3454c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3464c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3474c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 3484c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Start scrolling by providing a starting point and the distance to travel. 3494c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * The scroll will use the default value of 250 milliseconds for the 3504c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * duration. 3514c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 3524c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param startX Starting horizontal scroll offset in pixels. Positive 3534c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * numbers will scroll the content to the left. 3544c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param startY Starting vertical scroll offset in pixels. Positive numbers 3554c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * will scroll the content up. 3564c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param dx Horizontal distance to travel. Positive numbers will scroll the 3574c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * content to the left. 3584c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param dy Vertical distance to travel. Positive numbers will scroll the 3594c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * content up. 3604c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 3614c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public void startScroll(int startX, int startY, int dx, int dy) { 3624c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein startScroll(startX, startY, dx, dy, DEFAULT_DURATION); 3634c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3644c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3654c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 3664c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Start scrolling by providing a starting point and the distance to travel. 3674c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 3684c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param startX Starting horizontal scroll offset in pixels. Positive 3694c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * numbers will scroll the content to the left. 3704c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param startY Starting vertical scroll offset in pixels. Positive numbers 3714c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * will scroll the content up. 3724c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param dx Horizontal distance to travel. Positive numbers will scroll the 3734c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * content to the left. 3744c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param dy Vertical distance to travel. Positive numbers will scroll the 3754c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * content up. 3764c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param duration Duration of the scroll in milliseconds. 3774c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 3784c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public void startScroll(int startX, int startY, int dx, int dy, int duration) { 3794c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mMode = SCROLL_MODE; 3804c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX.startScroll(startX, dx, duration); 3814c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerY.startScroll(startY, dy, duration); 3824c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 3834c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3844c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 3854c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Call this when you want to 'spring back' into a valid coordinate range. 3864c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 3874c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param startX Starting X coordinate 3884c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param startY Starting Y coordinate 3894c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param minX Minimum valid X value 3904c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param maxX Maximum valid X value 3914c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param minY Minimum valid Y value 3924c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param maxY Minimum valid Y value 3934c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return true if a springback was initiated, false if startX and startY were 3944c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * already within the valid range. 3954c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 3964c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public boolean springBack(int startX, int startY, int minX, int maxX, int minY, int maxY) { 3974c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mMode = FLING_MODE; 3984c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 3994c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Make sure both methods are called. 4004c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final boolean spingbackX = mScrollerX.springback(startX, minX, maxX); 4014c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final boolean spingbackY = mScrollerY.springback(startY, minY, maxY); 4024c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return spingbackX || spingbackY; 4034c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 4044c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 4054c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public void fling(int startX, int startY, int velocityX, int velocityY, 4064c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein int minX, int maxX, int minY, int maxY) { 4074c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0); 4084c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 4094c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 4104c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 4114c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Start scrolling based on a fling gesture. The distance traveled will 4124c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * depend on the initial velocity of the fling. 4134c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 4144c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param startX Starting point of the scroll (X) 4154c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param startY Starting point of the scroll (Y) 4164c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param velocityX Initial velocity of the fling (X) measured in pixels per 4174c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * second. 4184c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param velocityY Initial velocity of the fling (Y) measured in pixels per 4194c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * second 4204c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param minX Minimum X value. The scroller will not scroll past this point 4214c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * unless overX > 0. If overfling is allowed, it will use minX as 4224c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * a springback boundary. 4234c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param maxX Maximum X value. The scroller will not scroll past this point 4244c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * unless overX > 0. If overfling is allowed, it will use maxX as 4254c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * a springback boundary. 4264c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param minY Minimum Y value. The scroller will not scroll past this point 4274c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * unless overY > 0. If overfling is allowed, it will use minY as 4284c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * a springback boundary. 4294c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param maxY Maximum Y value. The scroller will not scroll past this point 4304c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * unless overY > 0. If overfling is allowed, it will use maxY as 4314c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * a springback boundary. 4324c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param overX Overfling range. If > 0, horizontal overfling in either 4334c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * direction will be possible. 4344c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param overY Overfling range. If > 0, vertical overfling in either 4354c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * direction will be possible. 4364c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 4374c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public void fling(int startX, int startY, int velocityX, int velocityY, 4384c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein int minX, int maxX, int minY, int maxY, int overX, int overY) { 4394c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Continue a scroll or fling in progress 4404c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (mFlywheel && !isFinished()) { 4414c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float oldVelocityX = mScrollerX.mCurrVelocity; 4424c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float oldVelocityY = mScrollerY.mCurrVelocity; 4434c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (Math.signum(velocityX) == Math.signum(oldVelocityX) && 4444c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein Math.signum(velocityY) == Math.signum(oldVelocityY)) { 4454c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein velocityX += oldVelocityX; 4464c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein velocityY += oldVelocityY; 4474c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 4484c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 4494c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 4504c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mMode = FLING_MODE; 4514c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX.fling(startX, velocityX, minX, maxX, overX); 4524c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerY.fling(startY, velocityY, minY, maxY, overY); 4534c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 4544c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 4554c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 4564c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Notify the scroller that we've reached a horizontal boundary. 4574c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Normally the information to handle this will already be known 4584c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * when the animation is started, such as in a call to one of the 4594c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * fling functions. However there are cases where this cannot be known 4604c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * in advance. This function will transition the current motion and 4614c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * animate from startX to finalX as appropriate. 4624c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 4634c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param startX Starting/current X position 4644c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param finalX Desired final X position 4654c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param overX Magnitude of overscroll allowed. This should be the maximum 4664c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * desired distance from finalX. Absolute value - must be positive. 4674c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 4684c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public void notifyHorizontalEdgeReached(int startX, int finalX, int overX) { 4694c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX.notifyEdgeReached(startX, finalX, overX); 4704c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 4714c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 4724c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 4734c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Notify the scroller that we've reached a vertical boundary. 4744c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Normally the information to handle this will already be known 4754c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * when the animation is started, such as in a call to one of the 4764c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * fling functions. However there are cases where this cannot be known 4774c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * in advance. This function will animate a parabolic motion from 4784c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * startY to finalY. 4794c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 4804c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param startY Starting/current Y position 4814c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param finalY Desired final Y position 4824c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @param overY Magnitude of overscroll allowed. This should be the maximum 4834c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * desired distance from finalY. Absolute value - must be positive. 4844c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 4854c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public void notifyVerticalEdgeReached(int startY, int finalY, int overY) { 4864c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerY.notifyEdgeReached(startY, finalY, overY); 4874c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 4884c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 4894c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 4904c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Returns whether the current Scroller is currently returning to a valid position. 4914c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Valid bounds were provided by the 4924c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * {@link #fling(int, int, int, int, int, int, int, int, int, int)} method. 4934c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 4944c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * One should check this value before calling 4954c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * {@link #startScroll(int, int, int, int)} as the interpolation currently in progress 4964c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * to restore a valid position will then be stopped. The caller has to take into account 4974c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * the fact that the started scroll will start from an overscrolled position. 4984c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 4994c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return true when the current position is overscrolled and in the process of 5004c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * interpolating back to a valid value. 5014c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 5024c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public boolean isOverScrolled() { 5034c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return ((!mScrollerX.mFinished && 5044c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX.mState != SplineOverScroller.SPLINE) || 5054c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein (!mScrollerY.mFinished && 5064c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerY.mState != SplineOverScroller.SPLINE)); 5074c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 5084c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5094c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 5104c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Stops the animation. Contrary to {@link #forceFinished(boolean)}, 5114c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * aborting the animating causes the scroller to move to the final x and y 5124c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * positions. 5134c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 5144c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @see #forceFinished(boolean) 5154c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 5164c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public void abortAnimation() { 5174c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerX.finish(); 5184c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mScrollerY.finish(); 5194c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 5204c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5214c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 5224c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Returns the time elapsed since the beginning of the scrolling. 5234c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 5244c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @return The elapsed time in milliseconds. 5254c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 5264c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @hide 5274c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 5284c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public int timePassed() { 5294c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final long time = AnimationUtils.currentAnimationTimeMillis(); 5304c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final long startTime = Math.min(mScrollerX.mStartTime, mScrollerY.mStartTime); 5314c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return (int) (time - startTime); 5324c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 5334c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5344c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /** 5354c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * @hide 5364c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 5374c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein public boolean isScrollingInDirection(float xvel, float yvel) { 5384c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final int dx = mScrollerX.mFinal - mScrollerX.mStart; 5394c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final int dy = mScrollerY.mFinal - mScrollerY.mStart; 5404c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return !isFinished() && Math.signum(xvel) == Math.signum(dx) && 5414c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein Math.signum(yvel) == Math.signum(dy); 5424c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 5434c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5444c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein static class SplineOverScroller { 5454c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Initial position 5464c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private int mStart; 5474c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5484c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Current position 5494c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private int mCurrentPosition; 5504c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5514c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Final position 5524c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private int mFinal; 5534c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5544c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Initial velocity 5554c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private int mVelocity; 5564c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5574c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Current velocity 5584c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private float mCurrVelocity; 5594c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5604c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Constant current deceleration 5614c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private float mDeceleration; 5624c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5634c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Animation starting time, in system milliseconds 5644c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private long mStartTime; 5654c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5664c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Animation duration, in milliseconds 5674c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private int mDuration; 5684c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5694c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Duration to complete spline component of animation 5704c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private int mSplineDuration; 5714c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5724c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Distance to travel along spline animation 5734c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private int mSplineDistance; 5744c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5754c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Whether the animation is currently in progress 5764c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private boolean mFinished; 5774c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5784c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // The allowed overshot distance before boundary is reached. 5794c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private int mOver; 5804c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5814c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Fling friction 5824c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private float mFlingFriction = ViewConfiguration.getScrollFriction(); 5834c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5844c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Current state of the animation. 5854c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private int mState = SPLINE; 5864c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5874c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Constant gravity value, used in the deceleration phase. 5884c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final float GRAVITY = 2000.0f; 5894c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5904c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // A context-specific coefficient adjusted to physical values. 5914c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private final float mPhysicalCoeff; 5924c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 5934c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9)); 5944c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1) 5954c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final float START_TENSION = 0.5f; 5964c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final float END_TENSION = 1.0f; 5974c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final float P1 = START_TENSION * INFLEXION; 5984c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION); 5994c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6004c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final int NB_SAMPLES = 100; 6014c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1]; 6024c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1]; 6034c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6044c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final int SPLINE = 0; 6054c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final int CUBIC = 1; 6064c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private static final int BALLISTIC = 2; 6074c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6084c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein static { 6094c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float x_min = 0.0f; 6104c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float y_min = 0.0f; 6114c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein for (int i = 0; i < NB_SAMPLES; i++) { 6124c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float alpha = (float) i / NB_SAMPLES; 6134c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6144c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float x_max = 1.0f; 6154c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float x, tx, coef; 6164c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein while (true) { 6174c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein x = x_min + (x_max - x_min) / 2.0f; 6184c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein coef = 3.0f * x * (1.0f - x); 6194c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x; 6204c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (Math.abs(tx - alpha) < 1E-5) break; 6214c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (tx > alpha) x_max = x; 6224c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein else x_min = x; 6234c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 6244c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x; 6254c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6264c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float y_max = 1.0f; 6274c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float y, dy; 6284c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein while (true) { 6294c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein y = y_min + (y_max - y_min) / 2.0f; 6304c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein coef = 3.0f * y * (1.0f - y); 6314c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y; 6324c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (Math.abs(dy - alpha) < 1E-5) break; 6334c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (dy > alpha) y_max = y; 6344c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein else y_min = y; 6354c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 6364c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y; 6374c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 6384c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f; 6394c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 6404c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6414c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein void setFriction(float friction) { 6424c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFlingFriction = friction; 6434c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 6444c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6454c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein SplineOverScroller(Context context) { 6464c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinished = true; 6474c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float ppi = context.getResources().getDisplayMetrics().density * 160.0f; 6484c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2) 6494c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 39.37f // inch/meter 6504c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * ppi 6514c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * 0.84f; // look and feel tuning 6524c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 6534c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6544c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein void updateScroll(float q) { 6554c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mCurrentPosition = mStart + Math.round(q * (mFinal - mStart)); 6564c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 6574c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6584c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /* 6594c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Get a signed deceleration that will reduce the velocity. 6604c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 6614c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein static private float getDeceleration(int velocity) { 6624c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return velocity > 0 ? -GRAVITY : GRAVITY; 6634c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 6644c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6654c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /* 6664c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Modifies mDuration to the duration it takes to get from start to newFinal using the 6674c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * spline interpolation. The previous duration was needed to get to oldFinal. 6684c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 6694c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private void adjustDuration(int start, int oldFinal, int newFinal) { 6704c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final int oldDistance = oldFinal - start; 6714c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final int newDistance = newFinal - start; 6724c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float x = Math.abs((float) newDistance / oldDistance); 6734c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final int index = (int) (NB_SAMPLES * x); 6744c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (index < NB_SAMPLES) { 6754c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float x_inf = (float) index / NB_SAMPLES; 6764c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float x_sup = (float) (index + 1) / NB_SAMPLES; 6774c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float t_inf = SPLINE_TIME[index]; 6784c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float t_sup = SPLINE_TIME[index + 1]; 6794c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float timeCoef = t_inf + (x - x_inf) / (x_sup - x_inf) * (t_sup - t_inf); 6804c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDuration *= timeCoef; 6814c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 6824c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 6834c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6844c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein void startScroll(int start, int distance, int duration) { 6854c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinished = false; 6864c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6874c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStart = start; 6884c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinal = start + distance; 6894c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6904c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStartTime = AnimationUtils.currentAnimationTimeMillis(); 6914c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDuration = duration; 6924c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6934c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Unused 6944c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDeceleration = 0.0f; 6954c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mVelocity = 0; 6964c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 6974c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 6984c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein void finish() { 6994c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mCurrentPosition = mFinal; 7004c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Not reset since WebView relies on this value for fast fling. 7014c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // TODO: restore when WebView uses the fast fling implemented in this class. 7024c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // mCurrVelocity = 0.0f; 7034c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinished = true; 7044c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7054c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7064c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein void setFinalPosition(int position) { 7074c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinal = position; 7084c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinished = false; 7094c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7104c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7114c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein void extendDuration(int extend) { 7124c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final long time = AnimationUtils.currentAnimationTimeMillis(); 7134c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final int elapsedTime = (int) (time - mStartTime); 7144c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDuration = elapsedTime + extend; 7154c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinished = false; 7164c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7174c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7184c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein boolean springback(int start, int min, int max) { 7194c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinished = true; 7204c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7214c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStart = mFinal = start; 7224c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mVelocity = 0; 7234c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7244c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStartTime = AnimationUtils.currentAnimationTimeMillis(); 7254c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDuration = 0; 7264c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7274c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (start < min) { 7284c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein startSpringback(start, min, 0); 7294c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } else if (start > max) { 7304c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein startSpringback(start, max, 0); 7314c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7324c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7334c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return !mFinished; 7344c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7354c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7364c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private void startSpringback(int start, int end, int velocity) { 7374c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // mStartTime has been set 7384c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinished = false; 7394c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mState = CUBIC; 7404c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStart = start; 7414c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinal = end; 7424c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final int delta = start - end; 7434c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDeceleration = getDeceleration(delta); 7444c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // TODO take velocity into account 7454c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mVelocity = -delta; // only sign is used 7464c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mOver = Math.abs(delta); 7474c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDuration = (int) (1000.0 * Math.sqrt(-2.0 * delta / mDeceleration)); 7484c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7494c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7504c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein void fling(int start, int velocity, int min, int max, int over) { 7514c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mOver = over; 7524c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinished = false; 7534c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mCurrVelocity = mVelocity = velocity; 7544c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDuration = mSplineDuration = 0; 7554c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStartTime = AnimationUtils.currentAnimationTimeMillis(); 7564c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mCurrentPosition = mStart = start; 7574c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7584c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (start > max || start < min) { 7594c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein startAfterEdge(start, min, max, velocity); 7604c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return; 7614c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7624c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7634c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mState = SPLINE; 7644c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein double totalDistance = 0.0; 7654c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7664c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (velocity != 0) { 7674c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDuration = mSplineDuration = getSplineFlingDuration(velocity); 7684c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein totalDistance = getSplineFlingDistance(velocity); 7694c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7704c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7714c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mSplineDistance = (int) (totalDistance * Math.signum(velocity)); 7724c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinal = start + mSplineDistance; 7734c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7744c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Clamp to a valid final position 7754c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (mFinal < min) { 7764c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein adjustDuration(mStart, mFinal, min); 7774c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinal = min; 7784c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7794c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7804c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (mFinal > max) { 7814c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein adjustDuration(mStart, mFinal, max); 7824c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinal = max; 7834c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7844c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7854c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7864c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private double getSplineDeceleration(int velocity) { 7874c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff)); 7884c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7894c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7904c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private double getSplineFlingDistance(int velocity) { 7914c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final double l = getSplineDeceleration(velocity); 7924c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final double decelMinusOne = DECELERATION_RATE - 1.0; 7934c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l); 7944c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 7954c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 7964c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /* Returns the duration, expressed in milliseconds */ 7974c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private int getSplineFlingDuration(int velocity) { 7984c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final double l = getSplineDeceleration(velocity); 7994c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final double decelMinusOne = DECELERATION_RATE - 1.0; 8004c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return (int) (1000.0 * Math.exp(l / decelMinusOne)); 8014c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8024c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 8034c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private void fitOnBounceCurve(int start, int end, int velocity) { 8044c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Simulate a bounce that started from edge 8054c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float durationToApex = - velocity / mDeceleration; 8064c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float distanceToApex = velocity * velocity / 2.0f / Math.abs(mDeceleration); 8074c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float distanceToEdge = Math.abs(end - start); 8084c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float totalDuration = (float) Math.sqrt( 8094c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 2.0 * (distanceToApex + distanceToEdge) / Math.abs(mDeceleration)); 8104c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStartTime -= (int) (1000.0f * (totalDuration - durationToApex)); 8114c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStart = end; 8124c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mVelocity = (int) (- mDeceleration * totalDuration); 8134c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8144c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 8154c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private void startBounceAfterEdge(int start, int end, int velocity) { 8164c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDeceleration = getDeceleration(velocity == 0 ? start - end : velocity); 8174c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein fitOnBounceCurve(start, end, velocity); 8184c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein onEdgeReached(); 8194c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8204c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 8214c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private void startAfterEdge(int start, int min, int max, int velocity) { 8224c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (start > min && start < max) { 8234c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein Log.e("OverScroller", "startAfterEdge called from a valid position"); 8244c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinished = true; 8254c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return; 8264c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8274c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final boolean positive = start > max; 8284c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final int edge = positive ? max : min; 8294c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final int overDistance = start - edge; 8304c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein boolean keepIncreasing = overDistance * velocity >= 0; 8314c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (keepIncreasing) { 8324c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Will result in a bounce or a to_boundary depending on velocity. 8334c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein startBounceAfterEdge(start, edge, velocity); 8344c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } else { 8354c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // TODO: figure out how to absorb the velocity properly. 8364c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final double totalDistance = getSplineFlingDistance(velocity); 8374c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (false) { 8384c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein fling(start, velocity, positive ? min : start, positive ? start : max, mOver); 8394c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } else { 8404c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein startSpringback(start, edge, velocity); 8414c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8424c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8434c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8444c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 8454c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein void notifyEdgeReached(int start, int end, int over) { 8464c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // mState is used to detect successive notifications 8474c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (mState == SPLINE) { 8484c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mOver = over; 8494c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStartTime = AnimationUtils.currentAnimationTimeMillis(); 8504c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // We were in fling/scroll mode before: current velocity is such that distance to 8514c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // edge is increasing. This ensures that startAfterEdge will not start a new fling. 8524c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein startAfterEdge(start, end, end, (int) mCurrVelocity); 8534c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8544c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8554c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 8564c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein private void onEdgeReached() { 8574c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // mStart, mVelocity and mStartTime were adjusted to their values when edge was reached. 8584c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float distance = mVelocity * mVelocity / (2.0f * Math.abs(mDeceleration)); 8594c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float sign = Math.signum(mVelocity); 8604c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 8614c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (distance > mOver) { 8624c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Default deceleration is not sufficient to slow us down before boundary 8634c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDeceleration = - sign * mVelocity * mVelocity / (2.0f * mOver); 8644c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein distance = mOver; 8654c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8664c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 8674c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mOver = (int) distance; 8684c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mState = BALLISTIC; 8694c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mFinal = mStart + (int) (mVelocity > 0 ? distance : -distance); 8704c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDuration = - (int) (1000.0f * mVelocity / mDeceleration); 8714c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8724c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 8734c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein boolean continueWhenFinished() { 8744c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein switch (mState) { 8754c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein case SPLINE: 8764c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Duration from start to null velocity 8774c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (mDuration < mSplineDuration) { 8784c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // If the animation was clamped, we reached the edge 8794c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStart = mFinal; 8804c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // TODO Better compute speed when edge was reached 8814c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mVelocity = (int) mCurrVelocity; 8824c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mDeceleration = getDeceleration(mVelocity); 8834c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStartTime += mDuration; 8844c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein onEdgeReached(); 8854c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } else { 8864c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein // Normal stop, no need to continue 8874c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return false; 8884c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8894c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein break; 8904c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein case BALLISTIC: 8914c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mStartTime += mDuration; 8924c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein startSpringback(mFinal, mStart, 0); 8934c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein break; 8944c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein case CUBIC: 8954c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return false; 8964c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 8974c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 8984c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein update(); 8994c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return true; 9004c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 9014c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 9024c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein /* 9034c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * Update the current position and velocity for current time. Returns 9044c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * true if update has been done and false if animation duration has been 9054c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein * reached. 9064c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein */ 9074c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein boolean update() { 9084c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final long time = AnimationUtils.currentAnimationTimeMillis(); 9094c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final long currentTime = time - mStartTime; 9104c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 9114c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (currentTime > mDuration) { 9124c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return false; 9134c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 9144c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 9154c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein double distance = 0.0; 9164c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein switch (mState) { 9174c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein case SPLINE: { 9184c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float t = (float) currentTime / mSplineDuration; 9194c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final int index = (int) (NB_SAMPLES * t); 9204c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float distanceCoef = 1.f; 9214c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein float velocityCoef = 0.f; 9224c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein if (index < NB_SAMPLES) { 9234c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float t_inf = (float) index / NB_SAMPLES; 9244c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float t_sup = (float) (index + 1) / NB_SAMPLES; 9254c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float d_inf = SPLINE_POSITION[index]; 9264c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float d_sup = SPLINE_POSITION[index + 1]; 9274c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein velocityCoef = (d_sup - d_inf) / (t_sup - t_inf); 9284c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein distanceCoef = d_inf + (t - t_inf) * velocityCoef; 9294c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 9304c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 9314c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein distance = distanceCoef * mSplineDistance; 9324c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mCurrVelocity = velocityCoef * mSplineDistance / mSplineDuration * 1000.0f; 9334c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein break; 9344c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 9354c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 9364c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein case BALLISTIC: { 9374c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float t = currentTime / 1000.0f; 9384c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mCurrVelocity = mVelocity + mDeceleration * t; 9394c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein distance = mVelocity * t + mDeceleration * t * t / 2.0f; 9404c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein break; 9414c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 9424c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 9434c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein case CUBIC: { 9444c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float t = (float) (currentTime) / mDuration; 9454c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float t2 = t * t; 9464c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein final float sign = Math.signum(mVelocity); 9474c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein distance = sign * mOver * (3.0f * t2 - 2.0f * t * t2); 9484c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mCurrVelocity = sign * mOver * 6.0f * (- t + t2); 9494c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein break; 9504c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 9514c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 9524c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 9534c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein mCurrentPosition = mStart + (int) Math.round(distance); 9544c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein 9554c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein return true; 9564c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 9574c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein } 9584c68a4b737d7776fd23e857eb612f89c6dba3ec0Sam Blitzstein} 959