Adding overscroll in recents view

Bug: 109828536
Change-Id: I4fe94bd157c2b65f80604751e6f0f7d5d81d058d
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 814d02d..aa51e52 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -271,7 +271,7 @@
     public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
-        enableFreeScroll(true);
+        setEnableFreeScroll(true);
 
         mFastFlingVelocity = getResources()
                 .getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
diff --git a/src/com/android/launcher3/LauncherScroller.java b/src/com/android/launcher3/LauncherScroller.java
deleted file mode 100644
index e5042c4..0000000
--- a/src/com/android/launcher3/LauncherScroller.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.animation.TimeInterpolator;
-import android.content.Context;
-import android.view.animation.Interpolator;
-import android.widget.Scroller;
-
-/**
- * Extension of {@link android.widget.Scroller} with the ability to modify the
- * Interpolator post-construction.
- */
-public class LauncherScroller extends Scroller {
-
-    private final InterpolatorWrapper mInterpolatorWrapper;
-
-    public LauncherScroller(Context context) {
-        this(context, new InterpolatorWrapper());
-    }
-
-    private LauncherScroller(Context context, InterpolatorWrapper interpolatorWrapper) {
-        super(context, interpolatorWrapper);
-        mInterpolatorWrapper = interpolatorWrapper;
-    }
-
-    public void setInterpolator(TimeInterpolator interpolator) {
-        mInterpolatorWrapper.interpolator = interpolator;
-    }
-
-    private static class InterpolatorWrapper implements Interpolator {
-
-        public TimeInterpolator interpolator;
-
-        @Override
-        public float getInterpolation(float v) {
-            return interpolator == null ? v : interpolator.getInterpolation(v);
-        }
-    }
-}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index c81f679..394b950 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -18,6 +18,7 @@
 
 import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
 import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
+import static com.android.launcher3.touch.OverScroll.OVERSCROLL_DAMP_FACTOR;
 
 import android.animation.LayoutTransition;
 import android.animation.TimeInterpolator;
@@ -47,6 +48,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.pageindicators.PageIndicator;
 import com.android.launcher3.touch.OverScroll;
+import com.android.launcher3.util.OverScroller;
 import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
@@ -82,7 +84,6 @@
     public static final int INVALID_RESTORE_PAGE = -1001;
 
     private boolean mFreeScroll = false;
-    private boolean mSettleOnPageInFreeScroll = false;
 
     protected int mFlingThresholdVelocity;
     protected int mMinFlingVelocity;
@@ -96,7 +97,7 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     protected int mNextPage = INVALID_PAGE;
     protected int mMaxScrollX;
-    protected LauncherScroller mScroller;
+    protected OverScroller mScroller;
     private Interpolator mDefaultInterpolator;
     private VelocityTracker mVelocityTracker;
     protected int mPageSpacing = 0;
@@ -122,11 +123,6 @@
 
     protected boolean mWasInOverscroll = false;
 
-    // mOverScrollX is equal to getScrollX() when we're within the normal scroll range. Otherwise
-    // it is equal to the scaled overscroll position. We use a separate value so as to prevent
-    // the screens from continuing to translate beyond the normal bounds.
-    protected int mOverScrollX;
-
     protected int mUnboundedScrollX;
 
     // Page Indicator
@@ -169,7 +165,7 @@
      * Initializes various states for this workspace.
      */
     protected void init() {
-        mScroller = new LauncherScroller(getContext());
+        mScroller = new OverScroller(getContext());
         setDefaultInterpolator(Interpolators.SCROLL);
         mCurrentPage = 0;
 
@@ -244,7 +240,7 @@
             newX = getScrollForPage(mCurrentPage);
         }
         scrollTo(newX, 0);
-        mScroller.setFinalX(newX);
+        mScroller.startScroll(mScroller.getCurrPos(), newX - mScroller.getCurrPos());
         forceFinishScroller(true);
     }
 
@@ -349,17 +345,6 @@
 
     @Override
     public void scrollTo(int x, int y) {
-        // In free scroll mode, we clamp the scrollX
-        if (mFreeScroll) {
-            // If the scroller is trying to move to a location beyond the maximum allowed
-            // in the free scroll mode, we make sure to end the scroll operation.
-            if (!mScroller.isFinished() && (x > mMaxScrollX || x < 0)) {
-                forceFinishScroller(false);
-            }
-
-            x = Utilities.boundToRange(x, 0, mMaxScrollX);
-        }
-
         mUnboundedScrollX = x;
 
         boolean isXBeforeFirstPage = mIsRtl ? (x > mMaxScrollX) : (x < 0);
@@ -389,9 +374,9 @@
                 overScroll(0);
                 mWasInOverscroll = false;
             }
-            mOverScrollX = x;
             super.scrollTo(x, y);
         }
+
     }
 
     private void sendScrollAccessibilityEvent() {
@@ -425,10 +410,9 @@
     protected boolean computeScrollHelper(boolean shouldInvalidate) {
         if (mScroller.computeScrollOffset()) {
             // Don't bother scrolling if the page does not need to be moved
-            if (getUnboundedScrollX() != mScroller.getCurrX()
-                    || getScrollY() != mScroller.getCurrY()
-                    || mOverScrollX != mScroller.getCurrX()) {
-                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
+            if (getUnboundedScrollX() != mScroller.getCurrPos()
+                    || getScrollX() != mScroller.getCurrPos()) {
+                scrollTo(mScroller.getCurrPos(), 0);
             }
             if (shouldInvalidate) {
                 invalidate();
@@ -865,7 +849,7 @@
                  * otherwise don't.  mScroller.isFinished should be false when
                  * being flinged.
                  */
-                final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
+                final int xDist = Math.abs(mScroller.getFinalPos() - mScroller.getCurrPos());
                 final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop / 3);
 
                 if (finishedScrolling) {
@@ -996,31 +980,34 @@
         }
     }
 
-    protected void dampedOverScroll(float amount) {
-        if (Float.compare(amount, 0f) == 0) return;
+    protected void dampedOverScroll(int amount) {
+        if (amount == 0) return;
 
         int overScrollAmount = OverScroll.dampedScroll(amount, getMeasuredWidth());
         if (amount < 0) {
-            mOverScrollX = overScrollAmount;
-            super.scrollTo(mOverScrollX, getScrollY());
+            super.scrollTo(overScrollAmount, getScrollY());
         } else {
-            mOverScrollX = mMaxScrollX + overScrollAmount;
-            super.scrollTo(mOverScrollX, getScrollY());
+            super.scrollTo(mMaxScrollX + overScrollAmount, getScrollY());
         }
         invalidate();
     }
 
-    protected void overScroll(float amount) {
-        dampedOverScroll(amount);
+    protected void overScroll(int amount) {
+        if (amount == 0) return;
+
+        if (mFreeScroll && !mScroller.isFinished()) {
+            if (amount < 0) {
+                super.scrollTo(amount, getScrollY());
+            } else {
+                super.scrollTo(mMaxScrollX + amount, getScrollY());
+            }
+        } else {
+            dampedOverScroll(amount);
+        }
     }
 
 
-    protected void enableFreeScroll(boolean settleOnPageInFreeScroll) {
-        setEnableFreeScroll(true);
-        mSettleOnPageInFreeScroll = settleOnPageInFreeScroll;
-    }
-
-    private void setEnableFreeScroll(boolean freeScroll) {
+    protected void setEnableFreeScroll(boolean freeScroll) {
         boolean wasFreeScroll = mFreeScroll;
         mFreeScroll = freeScroll;
 
@@ -1029,8 +1016,6 @@
         } else if (wasFreeScroll) {
             snapToPage(getNextPage());
         }
-
-        setEnableOverscroll(!freeScroll);
     }
 
     protected void setEnableOverscroll(boolean enable) {
@@ -1113,6 +1098,8 @@
 
                 mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
                 boolean isFling = mTotalMotionX > mTouchSlop && shouldFlingForVelocity(velocityX);
+                boolean isDeltaXLeft = mIsRtl ? deltaX > 0 : deltaX < 0;
+                boolean isVelocityXLeft = mIsRtl ? velocityX > 0 : velocityX < 0;
 
                 if (!mFreeScroll) {
                     // In the case that the page is moved far to one direction and then is flung
@@ -1128,8 +1115,7 @@
                     // We give flings precedence over large moves, which is why we short-circuit our
                     // test for a large move if a fling has been registered. That is, a large
                     // move to the left and fling to the right will register as a fling to the right.
-                    boolean isDeltaXLeft = mIsRtl ? deltaX > 0 : deltaX < 0;
-                    boolean isVelocityXLeft = mIsRtl ? velocityX > 0 : velocityX < 0;
+
                     if (((isSignificantMove && !isDeltaXLeft && !isFling) ||
                             (isFling && !isVelocityXLeft)) && mCurrentPage > 0) {
                         finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
@@ -1147,35 +1133,39 @@
                         abortScrollerAnimation(true);
                     }
 
-                    float scaleX = getScaleX();
-                    int vX = (int) (-velocityX * scaleX);
-                    int initialScrollX = (int) (getScrollX() * scaleX);
+                    int initialScrollX = getScrollX();
 
-                    mScroller.setInterpolator(mDefaultInterpolator);
-                    mScroller.fling(initialScrollX,
-                            getScrollY(), vX, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
-                    int unscaledScrollX = (int) (mScroller.getFinalX() / scaleX);
-                    mNextPage = getPageNearestToCenterOfScreen(unscaledScrollX);
-                    int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
-                    int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
-                    if (mSettleOnPageInFreeScroll && unscaledScrollX > 0
-                            && unscaledScrollX < mMaxScrollX) {
-                        // If scrolling ends in the half of the added space that is closer to the
-                        // end, settle to the end. Otherwise snap to the nearest page.
-                        // If flinging past one of the ends, don't change the velocity as it will
-                        // get stopped at the end anyway.
-                        final int finalX = unscaledScrollX < firstPageScroll / 2 ?
-                                0 :
-                                unscaledScrollX > (lastPageScroll + mMaxScrollX) / 2 ?
-                                        mMaxScrollX :
-                                        getScrollForPage(mNextPage);
+                    if (((initialScrollX >= mMaxScrollX) && (isVelocityXLeft || !isFling)) ||
+                            ((initialScrollX <= 0) && (!isVelocityXLeft || !isFling))) {
+                        mScroller.springBack(getScrollX(), 0, mMaxScrollX);
+                    } else {
+                        mScroller.setInterpolator(mDefaultInterpolator);
+                        mScroller.fling(initialScrollX, -velocityX,
+                                0, mMaxScrollX,
+                                Math.round(getWidth() * 0.5f * OVERSCROLL_DAMP_FACTOR));
 
-                        mScroller.setFinalX((int) (finalX * getScaleX()));
-                        // Ensure the scroll/snap doesn't happen too fast;
-                        int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
-                                - mScroller.getDuration();
-                        if (extraScrollDuration > 0) {
-                            mScroller.extendDuration(extraScrollDuration);
+                        int finalX = mScroller.getFinalPos();
+                        mNextPage = getPageNearestToCenterOfScreen(finalX);
+
+                        int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
+                        int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
+                        if (finalX > 0 && finalX < mMaxScrollX) {
+                            // If scrolling ends in the half of the added space that is closer to
+                            // the end, settle to the end. Otherwise snap to the nearest page.
+                            // If flinging past one of the ends, don't change the velocity as it
+                            // will get stopped at the end anyway.
+                            int pageSnappedX = finalX < firstPageScroll / 2 ? 0
+                                    : finalX > (lastPageScroll + mMaxScrollX) / 2
+                                            ? mMaxScrollX
+                                            : getScrollForPage(mNextPage);
+
+                            mScroller.setFinalPos(pageSnappedX);
+                            // Ensure the scroll/snap doesn't happen too fast;
+                            int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
+                                    - mScroller.getDuration();
+                            if (extraScrollDuration > 0) {
+                                mScroller.extendDuration(extraScrollDuration);
+                            }
                         }
                     }
                     invalidate();
@@ -1324,7 +1314,7 @@
     }
 
     protected boolean isInOverScroll() {
-        return (mOverScrollX > mMaxScrollX || mOverScrollX < 0);
+        return (getScrollX() > mMaxScrollX || getScrollX() < 0);
     }
 
     protected int getPageSnapDuration() {
@@ -1443,7 +1433,7 @@
             mScroller.setInterpolator(mDefaultInterpolator);
         }
 
-        mScroller.startScroll(getUnboundedScrollX(), 0, delta, 0, duration);
+        mScroller.startScroll(getUnboundedScrollX(), delta, duration);
 
         updatePageIndicator();
 
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 28783fa..d652fe0 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1096,7 +1096,7 @@
     }
 
     @Override
-    protected void overScroll(float amount) {
+    protected void overScroll(int amount) {
         boolean shouldScrollOverlay = mLauncherOverlay != null &&
                 ((amount <= 0 && !mIsRtl) || (amount >= 0 && mIsRtl));
 
@@ -1109,7 +1109,7 @@
                 mLauncherOverlay.onScrollInteractionBegin();
             }
 
-            mLastOverlayScroll = Math.abs(amount / getMeasuredWidth());
+            mLastOverlayScroll = Math.abs(((float) amount) / getMeasuredWidth());
             mLauncherOverlay.onScrollChange(mLastOverlayScroll, mIsRtl);
         } else {
             dampedOverScroll(amount);
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 9be71f9..8439e79 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -493,7 +493,7 @@
         int delta = scroll - getScrollX();
         if (delta != 0) {
             mScroller.setInterpolator(Interpolators.DEACCEL);
-            mScroller.startScroll(getScrollX(), 0, delta, 0, Folder.SCROLL_HINT_DURATION);
+            mScroller.startScroll(getScrollX(), delta, Folder.SCROLL_HINT_DURATION);
             invalidate();
         }
     }
diff --git a/src/com/android/launcher3/touch/OverScroll.java b/src/com/android/launcher3/touch/OverScroll.java
index dc801ec..bf895ad 100644
--- a/src/com/android/launcher3/touch/OverScroll.java
+++ b/src/com/android/launcher3/touch/OverScroll.java
@@ -20,7 +20,7 @@
  */
 public class OverScroll {
 
-    private static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
+    public static final float OVERSCROLL_DAMP_FACTOR = 0.07f;
 
     /**
      * This curve determines how the effect of scrolling over the limits of the page diminishes
diff --git a/src/com/android/launcher3/util/OverScroller.java b/src/com/android/launcher3/util/OverScroller.java
index ec9abce..d697ece 100644
--- a/src/com/android/launcher3/util/OverScroller.java
+++ b/src/com/android/launcher3/util/OverScroller.java
@@ -18,6 +18,7 @@
 
 import static com.android.launcher3.anim.Interpolators.SCROLL;
 
+import android.animation.TimeInterpolator;
 import android.content.Context;
 import android.hardware.SensorManager;
 import android.util.Log;
@@ -26,17 +27,15 @@
 import android.view.animation.Interpolator;
 
 /**
- * This class encapsulates scrolling with the ability to overshoot the bounds
- * of a scrolling operation. This class is a drop-in replacement for
- * {@link android.widget.Scroller} in most cases.
+ * Based on {@link android.widget.OverScroller} supporting only 1-d scrolling and with more
+ * customization options.
  */
 public class OverScroller {
     private int mMode;
 
-    private final SplineOverScroller mScrollerX;
-    private final SplineOverScroller mScrollerY;
+    private final SplineOverScroller mScroller;
 
-    private Interpolator mInterpolator;
+    private TimeInterpolator mInterpolator;
 
     private final boolean mFlywheel;
 
@@ -68,7 +67,6 @@
      * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
      * be used.
      * @param flywheel If true, successive fling motions will keep on increasing scroll speed.
-     * @hide
      */
     public OverScroller(Context context, Interpolator interpolator, boolean flywheel) {
         if (interpolator == null) {
@@ -77,48 +75,10 @@
             mInterpolator = interpolator;
         }
         mFlywheel = flywheel;
-        mScrollerX = new SplineOverScroller(context);
-        mScrollerY = new SplineOverScroller(context);
+        mScroller = new SplineOverScroller(context);
     }
 
-    /**
-     * Creates an OverScroller with flywheel enabled.
-     * @param context The context of this application.
-     * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
-     * be used.
-     * @param bounceCoefficientX A value between 0 and 1 that will determine the proportion of the
-     * velocity which is preserved in the bounce when the horizontal edge is reached. A null value
-     * means no bounce. This behavior is no longer supported and this coefficient has no effect.
-     * @param bounceCoefficientY Same as bounceCoefficientX but for the vertical direction. This
-     * behavior is no longer supported and this coefficient has no effect.
-     * @deprecated Use {@link #OverScroller(Context, Interpolator)} instead.
-     */
-    @Deprecated
-    public OverScroller(Context context, Interpolator interpolator,
-            float bounceCoefficientX, float bounceCoefficientY) {
-        this(context, interpolator, true);
-    }
-
-    /**
-     * Creates an OverScroller.
-     * @param context The context of this application.
-     * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
-     * be used.
-     * @param bounceCoefficientX A value between 0 and 1 that will determine the proportion of the
-     * velocity which is preserved in the bounce when the horizontal edge is reached. A null value
-     * means no bounce. This behavior is no longer supported and this coefficient has no effect.
-     * @param bounceCoefficientY Same as bounceCoefficientX but for the vertical direction. This
-     * behavior is no longer supported and this coefficient has no effect.
-     * @param flywheel If true, successive fling motions will keep on increasing scroll speed.
-     * @deprecated Use {@link #OverScroller(Context, Interpolator)} instead.
-     */
-    @Deprecated
-    public OverScroller(Context context, Interpolator interpolator,
-            float bounceCoefficientX, float bounceCoefficientY, boolean flywheel) {
-        this(context, interpolator, flywheel);
-    }
-
-    void setInterpolator(Interpolator interpolator) {
+    public void setInterpolator(TimeInterpolator interpolator) {
         if (interpolator == null) {
             mInterpolator = SCROLL;
         } else {
@@ -134,8 +94,7 @@
      *         friction.
      */
     public final void setFriction(float friction) {
-        mScrollerX.setFriction(friction);
-        mScrollerY.setFriction(friction);
+        mScroller.setFriction(friction);
     }
 
     /**
@@ -145,7 +104,7 @@
      * @return True if the scroller has finished scrolling, false otherwise.
      */
     public final boolean isFinished() {
-        return mScrollerX.mFinished && mScrollerY.mFinished;
+        return mScroller.mFinished;
     }
 
     /**
@@ -157,25 +116,16 @@
      * @param finished The new finished value.
      */
     public final void forceFinished(boolean finished) {
-        mScrollerX.mFinished = mScrollerY.mFinished = finished;
+        mScroller.mFinished = finished;
     }
 
     /**
-     * Returns the current X offset in the scroll.
+     * Returns the current offset in the scroll.
      *
-     * @return The new X offset as an absolute distance from the origin.
+     * @return The new offset as an absolute distance from the origin.
      */
-    public final int getCurrX() {
-        return mScrollerX.mCurrentPosition;
-    }
-
-    /**
-     * Returns the current Y offset in the scroll.
-     *
-     * @return The new Y offset as an absolute distance from the origin.
-     */
-    public final int getCurrY() {
-        return mScrollerY.mCurrentPosition;
+    public final int getCurrPos() {
+        return mScroller.mCurrentPosition;
     }
 
     /**
@@ -184,113 +134,55 @@
      * @return The original velocity less the deceleration, norm of the X and Y velocity vector.
      */
     public float getCurrVelocity() {
-        return (float) Math.hypot(mScrollerX.mCurrVelocity, mScrollerY.mCurrVelocity);
+        return mScroller.mCurrVelocity;
     }
 
     /**
-     * Returns the start X offset in the scroll.
+     * Returns the start offset in the scroll.
      *
-     * @return The start X offset as an absolute distance from the origin.
+     * @return The start offset as an absolute distance from the origin.
      */
-    public final int getStartX() {
-        return mScrollerX.mStart;
-    }
-
-    /**
-     * Returns the start Y offset in the scroll.
-     *
-     * @return The start Y offset as an absolute distance from the origin.
-     */
-    public final int getStartY() {
-        return mScrollerY.mStart;
+    public final int getStartPos() {
+        return mScroller.mStart;
     }
 
     /**
      * Returns where the scroll will end. Valid only for "fling" scrolls.
      *
-     * @return The final X offset as an absolute distance from the origin.
+     * @return The final offset as an absolute distance from the origin.
      */
-    public final int getFinalX() {
-        return mScrollerX.mFinal;
-    }
-
-    /**
-     * Returns where the scroll will end. Valid only for "fling" scrolls.
-     *
-     * @return The final Y offset as an absolute distance from the origin.
-     */
-    public final int getFinalY() {
-        return mScrollerY.mFinal;
+    public final int getFinalPos() {
+        return mScroller.mFinal;
     }
 
     /**
      * Returns how long the scroll event will take, in milliseconds.
      *
      * @return The duration of the scroll in milliseconds.
-     *
-     * @hide Pending removal once nothing depends on it
-     * @deprecated OverScrollers don't necessarily have a fixed duration.
-     *             This function will lie to the best of its ability.
      */
-    @Deprecated
     public final int getDuration() {
-        return Math.max(mScrollerX.mDuration, mScrollerY.mDuration);
+        return mScroller.mDuration;
     }
 
     /**
      * Extend the scroll animation. This allows a running animation to scroll
-     * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
+     * further and longer, when used with {@link #setFinalPos(int)}.
      *
      * @param extend Additional time to scroll in milliseconds.
-     * @see #setFinalX(int)
-     * @see #setFinalY(int)
-     *
-     * @hide Pending removal once nothing depends on it
-     * @deprecated OverScrollers don't necessarily have a fixed duration.
-     *             Instead of setting a new final position and extending
-     *             the duration of an existing scroll, use startScroll
-     *             to begin a new animation.
+     * @see #setFinalPos(int)
      */
-    @Deprecated
     public void extendDuration(int extend) {
-        mScrollerX.extendDuration(extend);
-        mScrollerY.extendDuration(extend);
+        mScroller.extendDuration(extend);
     }
 
     /**
-     * Sets the final position (X) for this scroller.
+     * Sets the final position for this scroller.
      *
-     * @param newX The new X offset as an absolute distance from the origin.
+     * @param newPos The new offset as an absolute distance from the origin.
      * @see #extendDuration(int)
-     * @see #setFinalY(int)
-     *
-     * @hide Pending removal once nothing depends on it
-     * @deprecated OverScroller's final position may change during an animation.
-     *             Instead of setting a new final position and extending
-     *             the duration of an existing scroll, use startScroll
-     *             to begin a new animation.
      */
-    @Deprecated
-    public void setFinalX(int newX) {
-        mScrollerX.setFinalPosition(newX);
-    }
-
-    /**
-     * Sets the final position (Y) for this scroller.
-     *
-     * @param newY The new Y offset as an absolute distance from the origin.
-     * @see #extendDuration(int)
-     * @see #setFinalX(int)
-     *
-     * @hide Pending removal once nothing depends on it
-     * @deprecated OverScroller's final position may change during an animation.
-     *             Instead of setting a new final position and extending
-     *             the duration of an existing scroll, use startScroll
-     *             to begin a new animation.
-     */
-    @Deprecated
-    public void setFinalY(int newY) {
-        mScrollerY.setFinalPosition(newY);
+    public void setFinalPos(int newPos) {
+        mScroller.setFinalPosition(newPos);
     }
 
     /**
@@ -307,31 +199,22 @@
                 long time = AnimationUtils.currentAnimationTimeMillis();
                 // Any scroller can be used for time, since they were started
                 // together in scroll mode. We use X here.
-                final long elapsedTime = time - mScrollerX.mStartTime;
+                final long elapsedTime = time - mScroller.mStartTime;
 
-                final int duration = mScrollerX.mDuration;
+                final int duration = mScroller.mDuration;
                 if (elapsedTime < duration) {
                     final float q = mInterpolator.getInterpolation(elapsedTime / (float) duration);
-                    mScrollerX.updateScroll(q);
-                    mScrollerY.updateScroll(q);
+                    mScroller.updateScroll(q);
                 } else {
                     abortAnimation();
                 }
                 break;
 
             case FLING_MODE:
-                if (!mScrollerX.mFinished) {
-                    if (!mScrollerX.update()) {
-                        if (!mScrollerX.continueWhenFinished()) {
-                            mScrollerX.finish();
-                        }
-                    }
-                }
-
-                if (!mScrollerY.mFinished) {
-                    if (!mScrollerY.update()) {
-                        if (!mScrollerY.continueWhenFinished()) {
-                            mScrollerY.finish();
+                if (!mScroller.mFinished) {
+                    if (!mScroller.update()) {
+                        if (!mScroller.continueWhenFinished()) {
+                            mScroller.finish();
                         }
                     }
                 }
@@ -347,107 +230,73 @@
      * The scroll will use the default value of 250 milliseconds for the
      * duration.
      *
-     * @param startX Starting horizontal scroll offset in pixels. Positive
+     * @param start Starting horizontal scroll offset in pixels. Positive
      *        numbers will scroll the content to the left.
-     * @param startY Starting vertical scroll offset in pixels. Positive numbers
-     *        will scroll the content up.
-     * @param dx Horizontal distance to travel. Positive numbers will scroll the
+     * @param delta Distance to travel. Positive numbers will scroll the
      *        content to the left.
-     * @param dy Vertical distance to travel. Positive numbers will scroll the
-     *        content up.
      */
-    public void startScroll(int startX, int startY, int dx, int dy) {
-        startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
+    public void startScroll(int start, int delta) {
+        startScroll(start, delta, DEFAULT_DURATION);
     }
 
     /**
      * Start scrolling by providing a starting point and the distance to travel.
      *
-     * @param startX Starting horizontal scroll offset in pixels. Positive
+     * @param start Starting scroll offset in pixels. Positive
      *        numbers will scroll the content to the left.
-     * @param startY Starting vertical scroll offset in pixels. Positive numbers
-     *        will scroll the content up.
-     * @param dx Horizontal distance to travel. Positive numbers will scroll the
+     * @param delta Distance to travel. Positive numbers will scroll the
      *        content to the left.
-     * @param dy Vertical distance to travel. Positive numbers will scroll the
-     *        content up.
      * @param duration Duration of the scroll in milliseconds.
      */
-    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
+    public void startScroll(int start, int delta, int duration) {
         mMode = SCROLL_MODE;
-        mScrollerX.startScroll(startX, dx, duration);
-        mScrollerY.startScroll(startY, dy, duration);
+        mScroller.startScroll(start, delta, duration);
     }
 
     /**
      * Call this when you want to 'spring back' into a valid coordinate range.
      *
-     * @param startX Starting X coordinate
-     * @param startY Starting Y coordinate
-     * @param minX Minimum valid X value
-     * @param maxX Maximum valid X value
-     * @param minY Minimum valid Y value
-     * @param maxY Minimum valid Y value
+     * @param start Starting X coordinate
+     * @param min Minimum valid X value
+     * @param max Maximum valid X value
      * @return true if a springback was initiated, false if startX and startY were
      *          already within the valid range.
      */
-    public boolean springBack(int startX, int startY, int minX, int maxX, int minY, int maxY) {
+    public boolean springBack(int start, int min, int max) {
         mMode = FLING_MODE;
-
-        // Make sure both methods are called.
-        final boolean spingbackX = mScrollerX.springback(startX, minX, maxX);
-        final boolean spingbackY = mScrollerY.springback(startY, minY, maxY);
-        return spingbackX || spingbackY;
+        return mScroller.springback(start, min, max);
     }
 
-    public void fling(int startX, int startY, int velocityX, int velocityY,
-            int minX, int maxX, int minY, int maxY) {
-        fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0);
+    public void fling(int start, int velocity, int min, int max) {
+        fling(start, velocity, min, max, 0);
     }
 
     /**
      * Start scrolling based on a fling gesture. The distance traveled will
      * depend on the initial velocity of the fling.
-     *
-     * @param startX Starting point of the scroll (X)
-     * @param startY Starting point of the scroll (Y)
-     * @param velocityX Initial velocity of the fling (X) measured in pixels per
+     *  @param start Starting point of the scroll (X)
+     * @param velocity Initial velocity of the fling (X) measured in pixels per
      *            second.
-     * @param velocityY Initial velocity of the fling (Y) measured in pixels per
-     *            second
-     * @param minX Minimum X value. The scroller will not scroll past this point
-     *            unless overX > 0. If overfling is allowed, it will use minX as
-     *            a springback boundary.
-     * @param maxX Maximum X value. The scroller will not scroll past this point
-     *            unless overX > 0. If overfling is allowed, it will use maxX as
-     *            a springback boundary.
-     * @param minY Minimum Y value. The scroller will not scroll past this point
-     *            unless overY > 0. If overfling is allowed, it will use minY as
-     *            a springback boundary.
-     * @param maxY Maximum Y value. The scroller will not scroll past this point
-     *            unless overY > 0. If overfling is allowed, it will use maxY as
-     *            a springback boundary.
-     * @param overX Overfling range. If > 0, horizontal overfling in either
-     *            direction will be possible.
-     * @param overY Overfling range. If > 0, vertical overfling in either
-     *            direction will be possible.
+     * @param min Minimum X value. The scroller will not scroll past this point
+ *            unless overX > 0. If overfling is allowed, it will use minX as
+ *            a springback boundary.
+     * @param max Maximum X value. The scroller will not scroll past this point
+*            unless overX > 0. If overfling is allowed, it will use maxX as
+*            a springback boundary.
+     * @param over Overfling range. If > 0, horizontal overfling in either
+*            direction will be possible.
      */
-    public void fling(int startX, int startY, int velocityX, int velocityY,
-            int minX, int maxX, int minY, int maxY, int overX, int overY) {
+    public void fling(int start, int velocity, int min, int max, int over) {
         // Continue a scroll or fling in progress
         if (mFlywheel && !isFinished()) {
-            float oldVelocityX = mScrollerX.mCurrVelocity;
-            float oldVelocityY = mScrollerY.mCurrVelocity;
-            if (Math.signum(velocityX) == Math.signum(oldVelocityX) &&
-                    Math.signum(velocityY) == Math.signum(oldVelocityY)) {
-                velocityX += oldVelocityX;
-                velocityY += oldVelocityY;
+            float oldVelocityX = mScroller.mCurrVelocity;
+            if (Math.signum(velocity) == Math.signum(oldVelocityX)) {
+                velocity += oldVelocityX;
             }
         }
 
         mMode = FLING_MODE;
-        mScrollerX.fling(startX, velocityX, minX, maxX, overX);
-        mScrollerY.fling(startY, velocityY, minY, maxY, overY);
+        mScroller.fling(start, velocity, min, max, over);
     }
 
     /**
@@ -457,40 +306,21 @@
      * fling functions. However there are cases where this cannot be known
      * in advance. This function will transition the current motion and
      * animate from startX to finalX as appropriate.
-     *
-     * @param startX Starting/current X position
-     * @param finalX Desired final X position
-     * @param overX Magnitude of overscroll allowed. This should be the maximum
-     *              desired distance from finalX. Absolute value - must be positive.
+     *  @param start Starting/current X position
+     * @param finalPos Desired final X position
+     * @param over Magnitude of overscroll allowed. This should be the maximum
      */
-    public void notifyHorizontalEdgeReached(int startX, int finalX, int overX) {
-        mScrollerX.notifyEdgeReached(startX, finalX, overX);
-    }
-
-    /**
-     * Notify the scroller that we've reached a vertical boundary.
-     * Normally the information to handle this will already be known
-     * when the animation is started, such as in a call to one of the
-     * fling functions. However there are cases where this cannot be known
-     * in advance. This function will animate a parabolic motion from
-     * startY to finalY.
-     *
-     * @param startY Starting/current Y position
-     * @param finalY Desired final Y position
-     * @param overY Magnitude of overscroll allowed. This should be the maximum
-     *              desired distance from finalY. Absolute value - must be positive.
-     */
-    public void notifyVerticalEdgeReached(int startY, int finalY, int overY) {
-        mScrollerY.notifyEdgeReached(startY, finalY, overY);
+    public void notifyEdgeReached(int start, int finalPos, int over) {
+        mScroller.notifyEdgeReached(start, finalPos, over);
     }
 
     /**
      * Returns whether the current Scroller is currently returning to a valid position.
      * Valid bounds were provided by the
-     * {@link #fling(int, int, int, int, int, int, int, int, int, int)} method.
+     * {@link #fling(int, int, int, int, int)} method.
      *
      * One should check this value before calling
-     * {@link #startScroll(int, int, int, int)} as the interpolation currently in progress
+     * {@link #startScroll(int, int)} as the interpolation currently in progress
      * to restore a valid position will then be stopped. The caller has to take into account
      * the fact that the started scroll will start from an overscrolled position.
      *
@@ -498,10 +328,7 @@
      *         interpolating back to a valid value.
      */
     public boolean isOverScrolled() {
-        return ((!mScrollerX.mFinished &&
-                mScrollerX.mState != SplineOverScroller.SPLINE) ||
-                (!mScrollerY.mFinished &&
-                        mScrollerY.mState != SplineOverScroller.SPLINE));
+        return (!mScroller.mFinished && mScroller.mState != SplineOverScroller.SPLINE);
     }
 
     /**
@@ -512,8 +339,7 @@
      * @see #forceFinished(boolean)
      */
     public void abortAnimation() {
-        mScrollerX.finish();
-        mScrollerY.finish();
+        mScroller.finish();
     }
 
     /**
@@ -525,18 +351,7 @@
      */
     public int timePassed() {
         final long time = AnimationUtils.currentAnimationTimeMillis();
-        final long startTime = Math.min(mScrollerX.mStartTime, mScrollerY.mStartTime);
-        return (int) (time - startTime);
-    }
-
-    /**
-     * @hide
-     */
-    public boolean isScrollingInDirection(float xvel, float yvel) {
-        final int dx = mScrollerX.mFinal - mScrollerX.mStart;
-        final int dy = mScrollerY.mFinal - mScrollerY.mStart;
-        return !isFinished() && Math.signum(xvel) == Math.signum(dx) &&
-                Math.signum(yvel) == Math.signum(dy);
+        return (int) (time - mScroller.mStartTime);
     }
 
     static class SplineOverScroller {
@@ -703,13 +518,14 @@
 
         void setFinalPosition(int position) {
             mFinal = position;
+            mSplineDistance = mFinal - mStart;
             mFinished = false;
         }
 
         void extendDuration(int extend) {
             final long time = AnimationUtils.currentAnimationTimeMillis();
             final int elapsedTime = (int) (time - mStartTime);
-            mDuration = elapsedTime + extend;
+            mDuration  = mSplineDuration = elapsedTime + extend;
             mFinished = false;
         }