Ensuring that fast scrolling to predictions scrolls list to the top

- Fixes a long standing issue with fast-scrolling to the predicted apps
  not quite scrolling the list to the top of the screen.
- Fixes an issue where we don’t scroll exactly to the fast scroll 
  position due to rounding
- Also fixes a small issue where the thumb would not update when the 
  fast scroll popup was no longer showing, even while dragging.

Bug: 30023608

Change-Id: I6b5080c6aea521ff03dca24317f0405c02725061
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index 8bd5eba..401b699 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -246,13 +246,18 @@
                 (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
 
         // Calculate the position and size of the scroll bar
-        int scrollBarX;
+        mScrollbar.setThumbOffset(getScrollBarX(), scrollBarY);
+    }
+
+    /**
+     * @return the x position for the scrollbar thumb
+     */
+    protected int getScrollBarX() {
         if (Utilities.isRtl(getResources())) {
-            scrollBarX = mBackgroundPadding.left;
+            return mBackgroundPadding.left;
         } else {
-            scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getThumbWidth();
+            return getWidth() - mBackgroundPadding.right - mScrollbar.getThumbWidth();
         }
-        mScrollbar.setThumbOffset(scrollBarX, scrollBarY);
     }
 
     /**
diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
index 4ab0ea3..89f7286 100644
--- a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
+++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
@@ -156,10 +156,6 @@
         return mThumbMaxWidth;
     }
 
-    public float getLastTouchY() {
-        return mLastTouchY;
-    }
-
     public boolean isDraggingThumb() {
         return mIsDragging;
     }
@@ -210,6 +206,7 @@
                     mPopup.animateVisibility(!sectionName.isEmpty());
                     mRv.invalidate(mPopup.updateFastScrollerBounds(lastY));
                     mLastTouchY = boundedY;
+                    setThumbOffset(mRv.getScrollBarX(), (int) mLastTouchY);
                 }
                 break;
             case MotionEvent.ACTION_UP:
diff --git a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
index 6d9094f..76934af 100644
--- a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
+++ b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
@@ -23,6 +23,7 @@
 import com.android.launcher3.util.Thunk;
 
 import java.util.HashSet;
+import java.util.List;
 
 public class AllAppsFastScrollHelper implements AllAppsGridAdapter.BindViewCallback {
 
@@ -142,13 +143,22 @@
         }
 
         // Calculate the full animation from the current scroll position to the final scroll
-        // position, and then run the animation for the duration.
+        // position, and then run the animation for the duration.  If we are scrolling to the
+        // first fast scroll section, then just scroll to the top of the list itself.
+        List<AlphabeticalAppsList.FastScrollSectionInfo> fastScrollSections =
+                mApps.getFastScrollerSections();
         int newPosition = info.fastScrollToItem.position;
-        int newScrollY = Math.min(availableScrollHeight, mRv.getCurrentScrollY(newPosition, 0));
+        int newScrollY = fastScrollSections.size() > 0 && fastScrollSections.get(0) == info
+                        ? 0
+                        : Math.min(availableScrollHeight, mRv.getCurrentScrollY(newPosition, 0));
         int numFrames = mFastScrollFrames.length;
+        int deltaY = newScrollY - scrollY;
+        float ySign = Math.signum(deltaY);
+        int step = (int) (ySign * Math.ceil((float) Math.abs(deltaY) / numFrames));
         for (int i = 0; i < numFrames; i++) {
             // TODO(winsonc): We can interpolate this as well.
-            mFastScrollFrames[i] = (newScrollY - scrollY) / numFrames;
+            mFastScrollFrames[i] = (int) (ySign * Math.min(Math.abs(step), Math.abs(deltaY)));
+            deltaY -= step;
         }
         mFastScrollFrameIndex = 0;
         mRv.postOnAnimation(mSmoothSnapNextFrameRunnable);
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 2680197..0f0c333 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -377,10 +377,6 @@
         return isViewType(viewType, VIEW_TYPE_MASK_ICON);
     }
 
-    public static boolean isPredictionIconViewType(int viewType) {
-        return isViewType(viewType, VIEW_TYPE_PREDICTION_ICON);
-    }
-
     public static boolean isViewType(int viewType, int viewTypeMask) {
         return (viewType & viewTypeMask) != 0;
     }
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 3a44853..c2be01f 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -325,25 +325,15 @@
             return;
         }
 
-        // Calculate the current scroll position, the scrollY of the recycler view accounts for the
-        // view padding, while the scrollBarY is drawn right up to the background padding (ignoring
-        // padding)
-        int scrollBarY = mBackgroundPadding.top +
-                (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
-
         if (mScrollbar.isThumbDetached()) {
-            int scrollBarX;
-            if (Utilities.isRtl(getResources())) {
-                scrollBarX = mBackgroundPadding.left;
-            } else {
-                scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getThumbWidth();
-            }
+            if (!mScrollbar.isDraggingThumb()) {
+                // Calculate the current scroll position, the scrollY of the recycler view accounts
+                // for the view padding, while the scrollBarY is drawn right up to the background
+                // padding (ignoring padding)
+                int scrollBarX = getScrollBarX();
+                int scrollBarY = mBackgroundPadding.top +
+                        (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight);
 
-            if (mScrollbar.isDraggingThumb()) {
-                // If the thumb is detached, then just update the thumb to the current
-                // touch position
-                mScrollbar.setThumbOffset(scrollBarX, (int) mScrollbar.getLastTouchY());
-            } else {
                 int thumbScrollY = mScrollbar.getThumbOffset().y;
                 int diffScrollY = scrollBarY - thumbScrollY;
                 if (diffScrollY * dy > 0f) {