Scroll to currently playing item.

We moved to showing the whole queue so make the list scroll
to the currently playing item. We need to scroll both on the
queue open and during the viewholder binding since the viewholders
for positions that don't show up on the screen are not guaranteed
to be called when the list becomes visible. By forcing the
initial scroll, we can make sure the updates while binding take
place.

Bug: 37999972
Test: 1. Skipped forward many tracks and opened the queue. Verified
         that the currently playing song was scrolled to.
      2. Stayed with the queue open and watched the list scroll when
         the track changed.

Change-Id: I424b68c0fe3a74073e53495246065ca6f0244891
diff --git a/src/com/android/car/media/drawer/MediaBrowserItemsFetcher.java b/src/com/android/car/media/drawer/MediaBrowserItemsFetcher.java
index 16b0cfe..b64c48b 100644
--- a/src/com/android/car/media/drawer/MediaBrowserItemsFetcher.java
+++ b/src/com/android/car/media/drawer/MediaBrowserItemsFetcher.java
@@ -180,4 +180,9 @@
         mMediaPlaybackModel.getMediaBrowser().unsubscribe(mMediaId);
         mCallback = null;
     }
+
+    @Override
+    public int getScrollPosition() {
+        return MediaItemsFetcher.DONT_SCROLL;
+    }
 }
diff --git a/src/com/android/car/media/drawer/MediaDrawerAdapter.java b/src/com/android/car/media/drawer/MediaDrawerAdapter.java
index b8520b5..93bc085 100644
--- a/src/com/android/car/media/drawer/MediaDrawerAdapter.java
+++ b/src/com/android/car/media/drawer/MediaDrawerAdapter.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.support.annotation.Nullable;
+import com.android.car.app.CarDrawerActivity;
 import com.android.car.app.CarDrawerAdapter;
 import com.android.car.app.DrawerItemViewHolder;
 
@@ -27,8 +28,10 @@
  * {@link MediaItemsFetcher}. The current fetcher being used can be updated at runtime.
  */
 class MediaDrawerAdapter extends CarDrawerAdapter {
+    private final CarDrawerActivity mActivity;
     private MediaItemsFetcher mCurrentFetcher;
     private MediaFetchCallback mFetchCallback;
+    private int mCurrentScrollPosition;
 
     /**
      * Interface for a callback object that will be notified of changes to the fetch status of
@@ -46,8 +49,9 @@
         void onFetchEnd();
     }
 
-    MediaDrawerAdapter(Context context) {
-        super(context, true /* showDisabledListOnEmpty */);
+    MediaDrawerAdapter(CarDrawerActivity activity) {
+        super(activity, true /* showDisabledListOnEmpty */);
+        mActivity = activity;
     }
 
     /**
@@ -93,9 +97,12 @@
 
     @Override
     protected void populateViewHolder(DrawerItemViewHolder holder, int position) {
-        if (mCurrentFetcher != null) {
-            mCurrentFetcher.populateViewHolder(holder, position);
+        if (mCurrentFetcher == null) {
+            return;
         }
+
+        mCurrentFetcher.populateViewHolder(holder, position);
+        scrollToCurrent();
     }
 
     @Override
@@ -114,4 +121,16 @@
         }
         mFetchCallback = null;
     }
+
+    public void scrollToCurrent() {
+        if (mCurrentFetcher == null) {
+            return;
+        }
+        int scrollPosition = mCurrentFetcher.getScrollPosition();
+        if (scrollPosition != MediaItemsFetcher.DONT_SCROLL
+                && mCurrentScrollPosition != scrollPosition) {
+            mActivity.scrollToPosition(scrollPosition);
+            mCurrentScrollPosition = scrollPosition;
+        }
+    }
 }
diff --git a/src/com/android/car/media/drawer/MediaDrawerController.java b/src/com/android/car/media/drawer/MediaDrawerController.java
index feedfb5..c9ef26e 100644
--- a/src/com/android/car/media/drawer/MediaDrawerController.java
+++ b/src/com/android/car/media/drawer/MediaDrawerController.java
@@ -134,6 +134,7 @@
         mRootAdapter.setFetcher(createMediaQueueItemsFetcher());
         mRootAdapter.setTitle(mMediaPlaybackModel.getQueueTitle());
         mActivity.openDrawer();
+        mRootAdapter.scrollToCurrent();
         mActivity.addDrawerListener(mQueueDrawerListener);
     }
 
diff --git a/src/com/android/car/media/drawer/MediaItemsFetcher.java b/src/com/android/car/media/drawer/MediaItemsFetcher.java
index c613abd..db7d06a 100644
--- a/src/com/android/car/media/drawer/MediaItemsFetcher.java
+++ b/src/com/android/car/media/drawer/MediaItemsFetcher.java
@@ -33,6 +33,8 @@
  * It also handles ViewHolder population and item clicks.
  */
 interface MediaItemsFetcher {
+    public static final int DONT_SCROLL = -1;
+
     /**
      * Used to inform owning {@link MediaDrawerAdapter} that items have changed.
      */
@@ -82,6 +84,14 @@
      */
     void cleanup();
 
+
+    /**
+     * Get the position to scroll to if any.
+     * @return An integer greater than or equal to 0 if there is a position to scroll to, the
+     *         constant {@link DONT_SCROLL} otherwise.
+     */
+    int getScrollPosition();
+
     /**
      * Utility method to determine if description can be displayed in a small layout.
      */
@@ -121,4 +131,4 @@
             BitmapDownloader.getInstance(context).loadBitmap(options, holder.getIcon());
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/car/media/drawer/MediaQueueItemsFetcher.java b/src/com/android/car/media/drawer/MediaQueueItemsFetcher.java
index 374d5fa..7ed0336 100644
--- a/src/com/android/car/media/drawer/MediaQueueItemsFetcher.java
+++ b/src/com/android/car/media/drawer/MediaQueueItemsFetcher.java
@@ -103,6 +103,21 @@
         mMediaPlaybackModel.removeListener(mListener);
     }
 
+    @Override
+    public int getScrollPosition() {
+        long activeId = getActiveQueueItemId();
+        // A linear scan isn't really the best thing to do for large lists but we suspect that
+        // the queue isn't going to be very long anyway so we can just do the trivial thing. If
+        // it starts becoming a problem, we can build an index over the ids.
+        for (int position = 0; position < mItems.size(); position++) {
+            MediaSession.QueueItem item = mItems.get(position);
+            if (item.getQueueId() == activeId) {
+                return position;
+            }
+        }
+        return MediaItemsFetcher.DONT_SCROLL;
+    }
+
     private void updateItemsFrom(List<MediaSession.QueueItem> queue) {
         mItems.clear();
         mItems.addAll(queue);