Fix some smooth scrolling bugs in lists and update on the animation
timer.

Change-Id: I0cb03c6da204a34c9e942c3953b87287c3d4763d
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index e68049c..53d5e0b 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -403,7 +403,7 @@
     /**
      * Handles scrolling between positions within the list.
      */
-    private PositionScroller mPositionScroller;
+    PositionScroller mPositionScroller;
 
     /**
      * The offset in pixels form the top of the AdapterView to the top
@@ -3080,6 +3080,10 @@
             return isClickable() || isLongClickable();
         }
 
+        if (mPositionScroller != null) {
+            mPositionScroller.stop();
+        }
+
         if (mFastScroller != null) {
             boolean intercepted = mFastScroller.onTouchEvent(ev);
             if (intercepted) {
@@ -3564,6 +3568,10 @@
         int action = ev.getAction();
         View v;
 
+        if (mPositionScroller != null) {
+            mPositionScroller.stop();
+        }
+
         if (mFastScroller != null) {
             boolean intercepted = mFastScroller.onInterceptTouchEvent(ev);
             if (intercepted) {
@@ -3748,7 +3756,7 @@
             mScroller.fling(0, initialY, 0, initialVelocity,
                     0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
             mTouchMode = TOUCH_MODE_FLING;
-            post(this);
+            postOnAnimation(this);
 
             if (PROFILE_FLINGING) {
                 if (!mFlingProfilingStarted) {
@@ -3766,7 +3774,7 @@
             if (mScroller.springBack(0, mScrollY, 0, 0, 0, 0)) {
                 mTouchMode = TOUCH_MODE_OVERFLING;
                 invalidate();
-                post(this);
+                postOnAnimation(this);
             } else {
                 mTouchMode = TOUCH_MODE_REST;
                 reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
@@ -3778,7 +3786,7 @@
                     Integer.MIN_VALUE, Integer.MAX_VALUE, 0, getHeight());
             mTouchMode = TOUCH_MODE_OVERFLING;
             invalidate();
-            post(this);
+            postOnAnimation(this);
         }
 
         void edgeReached(int delta) {
@@ -3800,7 +3808,7 @@
                 }
             }
             invalidate();
-            post(this);
+            postOnAnimation(this);
         }
 
         void startScroll(int distance, int duration) {
@@ -3808,7 +3816,7 @@
             mLastFlingY = initialY;
             mScroller.startScroll(0, initialY, 0, distance, duration);
             mTouchMode = TOUCH_MODE_FLING;
-            post(this);
+            postOnAnimation(this);
         }
 
         void endFling() {
@@ -3907,7 +3915,7 @@
                 if (more && !atEnd) {
                     if (atEdge) invalidate();
                     mLastFlingY = y;
-                    post(this);
+                    postOnAnimation(this);
                 } else {
                     endFling();
 
@@ -3948,7 +3956,7 @@
                         }
                     } else {
                         invalidate();
-                        post(this);
+                        postOnAnimation(this);
                     }
                 } else {
                     endFling();
@@ -3959,7 +3967,6 @@
         }
     }
 
-
     class PositionScroller implements Runnable {
         private static final int SCROLL_DURATION = 400;
 
@@ -4009,7 +4016,7 @@
             mBoundPos = INVALID_POSITION;
             mLastSeenPos = INVALID_POSITION;
 
-            post(this);
+            postOnAnimation(this);
         }
 
         void start(int position, int boundPosition) {
@@ -4070,7 +4077,7 @@
             mBoundPos = boundPosition;
             mLastSeenPos = INVALID_POSITION;
 
-            post(this);
+            postOnAnimation(this);
         }
 
         void startWithOffset(int position, int offset) {
@@ -4080,6 +4087,8 @@
         void startWithOffset(int position, int offset, int duration) {
             stop();
 
+            offset += getPaddingTop();
+
             mTargetPos = position;
             mOffsetFromTop = offset;
             mBoundPos = INVALID_POSITION;
@@ -4108,7 +4117,7 @@
                     (int) (duration / screenTravelCount);
             mLastSeenPos = INVALID_POSITION;
 
-            post(this);
+            postOnAnimation(this);
         }
 
         void stop() {
@@ -4116,10 +4125,6 @@
         }
 
         public void run() {
-            if (mTouchMode != TOUCH_MODE_FLING && mLastSeenPos != INVALID_POSITION) {
-                return;
-            }
-
             final int listHeight = getHeight();
             final int firstPos = mFirstPosition;
 
@@ -4134,7 +4139,7 @@
 
                 if (lastPos == mLastSeenPos) {
                     // No new views, let things keep going.
-                    post(this);
+                    postOnAnimation(this);
                     return;
                 }
 
@@ -4142,14 +4147,15 @@
                 final int lastViewHeight = lastView.getHeight();
                 final int lastViewTop = lastView.getTop();
                 final int lastViewPixelsShowing = listHeight - lastViewTop;
-                final int extraScroll = lastPos < mItemCount - 1 ? mExtraScroll : mListPadding.bottom;
+                final int extraScroll = lastPos < mItemCount - 1 ?
+                        Math.max(mListPadding.bottom, mExtraScroll) : mListPadding.bottom;
 
-                smoothScrollBy(lastViewHeight - lastViewPixelsShowing + extraScroll,
-                        mScrollDuration);
+                final int scrollBy = lastViewHeight - lastViewPixelsShowing + extraScroll;
+                smoothScrollBy(scrollBy, mScrollDuration);
 
                 mLastSeenPos = lastPos;
                 if (lastPos < mTargetPos) {
-                    post(this);
+                    postOnAnimation(this);
                 }
                 break;
             }
@@ -4166,21 +4172,21 @@
 
                 if (nextPos == mLastSeenPos) {
                     // No new views, let things keep going.
-                    post(this);
+                    postOnAnimation(this);
                     return;
                 }
 
                 final View nextView = getChildAt(nextViewIndex);
                 final int nextViewHeight = nextView.getHeight();
                 final int nextViewTop = nextView.getTop();
-                final int extraScroll = mExtraScroll;
+                final int extraScroll = Math.max(mListPadding.bottom, mExtraScroll);
                 if (nextPos < mBoundPos) {
                     smoothScrollBy(Math.max(0, nextViewHeight + nextViewTop - extraScroll),
                             mScrollDuration);
 
                     mLastSeenPos = nextPos;
 
-                    post(this);
+                    postOnAnimation(this);
                 } else  {
                     if (nextViewTop > extraScroll) {
                         smoothScrollBy(nextViewTop - extraScroll, mScrollDuration);
@@ -4192,7 +4198,7 @@
             case MOVE_UP_POS: {
                 if (firstPos == mLastSeenPos) {
                     // No new views, let things keep going.
-                    post(this);
+                    postOnAnimation(this);
                     return;
                 }
 
@@ -4201,14 +4207,15 @@
                     return;
                 }
                 final int firstViewTop = firstView.getTop();
-                final int extraScroll = firstPos > 0 ? mExtraScroll : mListPadding.top;
+                final int extraScroll = firstPos > 0 ?
+                        Math.max(mExtraScroll, mListPadding.top) : mListPadding.top;
 
                 smoothScrollBy(firstViewTop - extraScroll, mScrollDuration);
 
                 mLastSeenPos = firstPos;
 
                 if (firstPos > mTargetPos) {
-                    post(this);
+                    postOnAnimation(this);
                 }
                 break;
             }
@@ -4230,12 +4237,13 @@
                 final int lastViewHeight = lastView.getHeight();
                 final int lastViewTop = lastView.getTop();
                 final int lastViewPixelsShowing = listHeight - lastViewTop;
+                final int extraScroll = Math.max(mListPadding.top, mExtraScroll);
                 mLastSeenPos = lastPos;
                 if (lastPos > mBoundPos) {
-                    smoothScrollBy(-(lastViewPixelsShowing - mExtraScroll), mScrollDuration);
-                    post(this);
+                    smoothScrollBy(-(lastViewPixelsShowing - extraScroll), mScrollDuration);
+                    postOnAnimation(this);
                 } else {
-                    final int bottom = listHeight - mExtraScroll;
+                    final int bottom = listHeight - extraScroll;
                     final int lastViewBottom = lastViewTop + lastViewHeight;
                     if (bottom > lastViewBottom) {
                         smoothScrollBy(-(bottom - lastViewBottom), mScrollDuration);
@@ -4270,10 +4278,10 @@
                 final float modifier = Math.min(Math.abs(screenTravelCount), 1.f);
                 if (position < firstPos) {
                     smoothScrollBy((int) (-getHeight() * modifier), mScrollDuration);
-                    post(this);
+                    postOnAnimation(this);
                 } else if (position > lastPos) {
                     smoothScrollBy((int) (getHeight() * modifier), mScrollDuration);
-                    post(this);
+                    postOnAnimation(this);
                 } else {
                     // On-screen, just scroll.
                     final int targetTop = getChildAt(position - firstPos).getTop();
@@ -4620,7 +4628,7 @@
         // invalidate before moving the children to avoid unnecessary invalidate
         // calls to bubble up from the children all the way to the top
         if (!awakenScrollBars()) {
-            invalidate();
+           invalidate();
         }
 
         offsetChildrenTopAndBottom(incrementalDeltaY);
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 0f1dab5..0a40d5e 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1463,6 +1463,9 @@
             mResurrectToPosition = position;
         }
         mLayoutMode = LAYOUT_SET_SELECTION;
+        if (mPositionScroller != null) {
+            mPositionScroller.stop();
+        }
         requestLayout();
     }
 
@@ -1475,6 +1478,10 @@
     void setSelectionInt(int position) {
         int previousSelectedPosition = mNextSelectedPosition;
 
+        if (mPositionScroller != null) {
+            mPositionScroller.stop();
+        }
+
         setNextSelectedPositionInt(position);
         layoutChildren();
         
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 71700b3..5098523 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1926,6 +1926,9 @@
                 mSyncRowId = mAdapter.getItemId(position);
             }
 
+            if (mPositionScroller != null) {
+                mPositionScroller.stop();
+            }
             requestLayout();
         }
     }
@@ -1950,6 +1953,10 @@
             }
         }
 
+        if (mPositionScroller != null) {
+            mPositionScroller.stop();
+        }
+
         layoutChildren();
 
         if (awakeScrollbars) {