Support7Demos: Build metadata using the stored title in the playlist

Currently the media session retrieves the title of current media from
the provider by sending a private control intent. However, because the
title is already known, it is unnecessary to get this information from
the provider.

This CL stores title in the playlist in order to use it for building the
media metadata. Therefore it can show the title in the controller
dialog, even when the current route provider is not a sample provider.

Bug: 25732463
Change-Id: Ia9f859f02f45e5fed0bb6ede06c79b5bc98712cb
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
index a5d5897..5e94413 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
@@ -34,6 +34,7 @@
  */
 public abstract class Player {
     private static final String TAG = "SampleMediaRoutePlayer";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     protected static final int STATE_IDLE = 0;
     protected static final int STATE_PREPARING_FOR_PLAY = 1;
     protected static final int STATE_PREPARING_FOR_PAUSE = 2;
@@ -68,9 +69,7 @@
     public abstract void enqueue(final PlaylistItem item);
     public abstract PlaylistItem remove(String iid);
 
-    // track info for current media item
-    public void updateTrackInfo() {}
-    public String getDescription() { return ""; }
+    public void takeSnapshot() {}
     public Bitmap getSnapshot() { return null; }
 
     // presentation display
@@ -104,12 +103,19 @@
         mMediaSession.setPlaybackState(INIT_PLAYBACK_STATE);
     }
 
-    protected void updateMetadata() {
+    protected void updateMetadata(PlaylistItem currentItem) {
         if (mMediaSession == null) {
             return;
         }
+        if (DEBUG) {
+            Log.d(TAG, "Update metadata: currentItem=" + currentItem);
+        }
+        if (currentItem == null) {
+            mMediaSession.setMetadata(null);
+            return;
+        }
         MediaMetadataCompat.Builder bob = new MediaMetadataCompat.Builder();
-        bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, getDescription());
+        bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, currentItem.getTitle());
         bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Subtitle of the thing");
         bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION,
                 "Description of the thing");
@@ -131,6 +137,10 @@
             case STATE_PAUSED:
                 bob.setState(PlaybackStateCompat.STATE_PAUSED, -1, 0);
                 break;
+            case STATE_PREPARING_FOR_PLAY:
+            case STATE_PREPARING_FOR_PAUSE:
+                bob.setState(PlaybackStateCompat.STATE_BUFFERING, -1, 0);
+                break;
             case STATE_IDLE:
                 bob.setState(PlaybackStateCompat.STATE_STOPPED, -1, 0);
                 break;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/PlaylistItem.java b/samples/Support7Demos/src/com/example/android/supportv7/media/PlaylistItem.java
index 9a12d59..64928ec 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/PlaylistItem.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/PlaylistItem.java
@@ -29,6 +29,7 @@
     private final String mSessionId;
     private final String mItemId;
     private final Uri mUri;
+    private final String mTitle;
     private final String mMime;
     private final PendingIntent mUpdateReceiver;
     // changeable states
@@ -38,9 +39,11 @@
     private long mTimestamp;
     private String mRemoteItemId;
 
-    public PlaylistItem(String qid, String iid, Uri uri, String mime, PendingIntent pi) {
+    public PlaylistItem(String qid, String iid, String title, Uri uri, String mime,
+            PendingIntent pi) {
         mSessionId = qid;
         mItemId = iid;
+        mTitle = title;
         mUri = uri;
         mMime = mime;
         mUpdateReceiver = pi;
@@ -79,6 +82,10 @@
         return mRemoteItemId;
     }
 
+    public String getTitle() {
+        return mTitle;
+    }
+
     public Uri getUri() {
         return mUri;
     }
@@ -125,6 +132,6 @@
         };
         return "[" + mSessionId + "|" + mItemId + "|"
             + (mRemoteItemId != null ? mRemoteItemId : "-") + "|"
-            + state[mPlaybackState] + "] " + mUri.toString();
+            + state[mPlaybackState] + "] " + mTitle + ": " + mUri.toString();
     }
-}
\ No newline at end of file
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
index eafdb9f..d0cf89b 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
@@ -46,7 +46,6 @@
     private Context mContext;
     private RouteInfo mRoute;
     private boolean mEnqueuePending;
-    private String mTrackInfo = "";
     private Bitmap mSnapshot;
     private List<PlaylistItem> mTempQueue = new ArrayList<PlaylistItem>();
 
@@ -57,23 +56,14 @@
                 String sessionId, MediaSessionStatus sessionStatus,
                 String itemId, MediaItemStatus itemStatus) {
             logStatus("onItemStatusChanged", sessionId, sessionStatus, itemId, itemStatus);
-            switch (itemStatus.getPlaybackState()) {
-                case MediaItemStatus.PLAYBACK_STATE_PLAYING:
-                    publishState(STATE_PLAYING);
-                    break;
-                case MediaItemStatus.PLAYBACK_STATE_PAUSED:
-                    publishState(STATE_PAUSED);
-                    break;
-                case MediaItemStatus.PLAYBACK_STATE_FINISHED:
-                    if (mCallback != null) {
-                        mCallback.onCompletion();
-                    }
-                    break;
-                case MediaItemStatus.PLAYBACK_STATE_ERROR:
-                    if (mCallback != null) {
-                        mCallback.onError();
-                    }
-                    break;
+            if (mCallback != null) {
+                mCallback.onPlaylistChanged();
+                int state = itemStatus.getPlaybackState();
+                if (state == MediaItemStatus.PLAYBACK_STATE_FINISHED) {
+                    mCallback.onCompletion();
+                } else if (state == MediaItemStatus.PLAYBACK_STATE_ERROR) {
+                    mCallback.onError();
+                }
             }
         }
 
@@ -332,12 +322,10 @@
     }
 
     @Override
-    public void updateTrackInfo() {
-        // clear stats info first
-        mTrackInfo = "";
+    public void takeSnapshot() {
         mSnapshot = null;
 
-        Intent intent = new Intent(SampleMediaRouteProvider.ACTION_GET_TRACK_INFO);
+        Intent intent = new Intent(SampleMediaRouteProvider.ACTION_TAKE_SNAPSHOT);
         intent.addCategory(SampleMediaRouteProvider.CATEGORY_SAMPLE_ROUTE);
 
         if (mRoute != null && mRoute.supportsControlRequest(intent)) {
@@ -345,18 +333,16 @@
                 @Override
                 public void onResult(Bundle data) {
                     if (DEBUG) {
-                        Log.d(TAG, "getStatistics: succeeded: data=" + data);
+                        Log.d(TAG, "takeSnapshot: succeeded: data=" + data);
                     }
                     if (data != null) {
-                        mTrackInfo = data.getString(SampleMediaRouteProvider.TRACK_INFO_DESC);
-                        mSnapshot = data.getParcelable(
-                                SampleMediaRouteProvider.TRACK_INFO_SNAPSHOT);
+                        mSnapshot = data.getParcelable(SampleMediaRouteProvider.EXTRA_SNAPSHOT);
                     }
                 }
 
                 @Override
                 public void onError(String error, Bundle data) {
-                    Log.d(TAG, "getStatistics: failed: error=" + error + ", data=" + data);
+                    Log.d(TAG, "takeSnapshot: failed: error=" + error + ", data=" + data);
                 }
             };
 
@@ -365,11 +351,6 @@
     }
 
     @Override
-    public String getDescription() {
-        return mTrackInfo;
-    }
-
-    @Override
     public Bitmap getSnapshot() {
         return mSnapshot;
     }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
index 4208f58..f919e8b 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
@@ -62,29 +62,20 @@
             "com.example.android.supportv7.media.CATEGORY_SAMPLE_ROUTE";
 
     /**
-     * A custom media control intent action for special requests that are
-     * supported by this provider's routes.
+     * A custom media control intent action to take a snapshot.
      * </p>
      *
-     * @see #TRACK_INFO_DESC
-     * @see #TRACK_INFO_SNAPSHOT
+     * @see #EXTRA_SNAPSHOT
      */
-    public static final String ACTION_GET_TRACK_INFO =
-            "com.example.android.supportv7.media.ACTION_GET_TRACK_INFO";
+    public static final String ACTION_TAKE_SNAPSHOT =
+            "com.example.android.supportv7.media.action.TAKE_SNAPSHOT";
 
     /**
-     * {@link #ACTION_GET_TRACK_INFO} result data: a string of information about
-     * the currently playing media item
-     */
-    public static final String TRACK_INFO_DESC =
-            "com.example.android.supportv7.media.EXTRA_TRACK_INFO_DESC";
-
-    /**
-     * {@link #ACTION_GET_TRACK_INFO} result data: a bitmap containing a snapshot
+     * {@link #ACTION_TAKE_SNAPSHOT} result data: a bitmap containing a snapshot
      * of the currently playing media item
      */
-    public static final String TRACK_INFO_SNAPSHOT =
-            "com.example.android.supportv7.media.EXTRA_TRACK_INFO_SNAPSHOT";
+    public static final String EXTRA_SNAPSHOT =
+            "com.example.android.supportv7.media.extra.SNAPSHOT";
 
     private static final ArrayList<IntentFilter> CONTROL_FILTERS_BASIC;
     private static final ArrayList<IntentFilter> CONTROL_FILTERS_QUEUING;
@@ -93,7 +84,7 @@
     static {
         IntentFilter f1 = new IntentFilter();
         f1.addCategory(CATEGORY_SAMPLE_ROUTE);
-        f1.addAction(ACTION_GET_TRACK_INFO);
+        f1.addAction(ACTION_TAKE_SNAPSHOT);
 
         IntentFilter f2 = new IntentFilter();
         f2.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
@@ -326,16 +317,14 @@
                 return success;
             }
 
-            if (action.equals(ACTION_GET_TRACK_INFO)
+            if (callback != null && action.equals(ACTION_TAKE_SNAPSHOT)
                     && intent.hasCategory(CATEGORY_SAMPLE_ROUTE)) {
-                Bundle data = new Bundle();
-                PlaylistItem item = mSessionManager.getCurrentItem();
-                if (item != null) {
-                    data.putString(TRACK_INFO_DESC, item.toString());
-                    data.putParcelable(TRACK_INFO_SNAPSHOT, mPlayer.getSnapshot());
-                }
-                if (callback != null) {
+                if (mSessionManager.getCurrentItem() != null) {
+                    Bundle data = new Bundle();
+                    data.putParcelable(EXTRA_SNAPSHOT, mPlayer.getSnapshot());
                     callback.onResult(data);
+                } else {
+                    callback.onError("Failed to take a snapshot", null);
                 }
                 return true;
             }
@@ -394,7 +383,7 @@
                     + ", metadata=" + metadata
                     + ", headers=" + headers
                     + ", receiver=" + receiver);
-            PlaylistItem item = mSessionManager.add(uri, mime, receiver);
+            PlaylistItem item = mSessionManager.add(null, uri, mime, receiver);
             if (callback != null) {
                 if (item != null) {
                     Bundle result = new Bundle();
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
index be66cca..375d4a0 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
@@ -542,8 +542,25 @@
         updatePlaylist();
         updateRouteDescription();
         updateButtons();
-        if (mPlayer != null) {
-            mPlayer.updateMetadata();
+        if (mPlayer != null && mSessionManager != null) {
+            PlaylistItem currentItem = mSessionManager.getCurrentItem();
+            if (currentItem != null) {
+                mPlayer.updateMetadata(currentItem);
+                int currentItemState = Player.STATE_IDLE;
+                switch(currentItem.getState()) {
+                    case MediaItemStatus.PLAYBACK_STATE_PLAYING:
+                        currentItemState = Player.STATE_PLAYING;
+                        break;
+                    case MediaItemStatus.PLAYBACK_STATE_PAUSED:
+                        currentItemState = Player.STATE_PAUSED;
+                        break;
+                    case MediaItemStatus.PLAYBACK_STATE_PENDING:
+                    case MediaItemStatus.PLAYBACK_STATE_BUFFERING:
+                        currentItemState = Player.STATE_PREPARING_FOR_PLAY;
+                        break;
+                }
+                mPlayer.publishState(currentItemState);
+            }
         }
     }
 
@@ -559,8 +576,7 @@
         RouteInfo route = mMediaRouter.getSelectedRoute();
         mInfoTextView.setText("Currently selected route:"
                 + "\nName: " + route.getName()
-                + "\nProvider: " + route.getProvider().getPackageName()
-                + "\nDescription: " + route.getDescription());
+                + "\nProvider: " + route.getProvider().getPackageName());
     }
 
     private void updateButtons() {
@@ -629,7 +645,7 @@
                 @Override
                 public void onClick(View v) {
                     if (item != null) {
-                        mSessionManager.add(item.mUri, item.mMime);
+                        mSessionManager.add(item.mName, item.mUri, item.mMime);
                     }
                 }
             });
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java
index 6fab2eb..c63335e 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java
@@ -79,7 +79,7 @@
         checkPlayer();
         // update the statistics first, so that the stats string is valid when
         // onPlaylistReady() gets called in the end
-        mPlayer.updateTrackInfo();
+        mPlayer.takeSnapshot();
 
         if (mPlaylist.isEmpty()) {
             // If queue is empty, don't forget to call onPlaylistReady()!
@@ -99,21 +99,21 @@
         }
     }
 
-    public PlaylistItem add(Uri uri, String mime) {
-        return add(uri, mime, null);
+    public PlaylistItem add(String title, Uri uri, String mime) {
+        return add(title, uri, mime, null);
     }
 
-    public PlaylistItem add(Uri uri, String mime, PendingIntent receiver) {
+    public PlaylistItem add(String title, Uri uri, String mime, PendingIntent receiver) {
         if (DEBUG) {
-            log("add: uri=" + uri + ", receiver=" + receiver);
+            log("add: title=" + title + ", uri=" + uri + ", receiver=" + receiver);
         }
         // create new session if needed
         startSession();
         checkPlayerAndSession();
 
         // append new item with initial status PLAYBACK_STATE_PENDING
-        PlaylistItem item = new PlaylistItem(
-                Integer.toString(mSessionId), Integer.toString(mItemId), uri, mime, receiver);
+        PlaylistItem item = new PlaylistItem(Integer.toString(mSessionId),
+                Integer.toString(mItemId), title, uri, mime, receiver);
         mPlaylist.add(item);
         mItemId++;