Update the MediaRouter support demo for new UIs

Updates the MediaRouter support demo for the new material UI spec.

bug:17879842
Change-Id: I3340e65384050fbf561cf506cb5b80028d69d849
diff --git a/samples/Support7Demos/AndroidManifest.xml b/samples/Support7Demos/AndroidManifest.xml
index 703d657..1d087a4 100644
--- a/samples/Support7Demos/AndroidManifest.xml
+++ b/samples/Support7Demos/AndroidManifest.xml
@@ -86,6 +86,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".media.SampleMediaRouteSettingsActivity"
+                android:label="@string/sample_media_route_settings_activity"
+                android:theme="@style/Theme.AppCompat.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+        </activity>
+
         <service android:name=".media.SampleMediaRouteProviderService"
                 android:label="@string/sample_media_route_provider_service"
                 android:process=":mrp">
diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml
index 789e19e..4b3a28f 100644
--- a/samples/Support7Demos/res/values/strings.xml
+++ b/samples/Support7Demos/res/values/strings.xml
@@ -25,6 +25,7 @@
     <string name="sample_media_router_text">This activity demonstrates how to
             use MediaRouter from the support library.  Select a route from the action bar.</string>
     <string name="media_route_menu_title">Play on...</string>
+    <string name="sample_media_route_settings_activity">Sample route settings</string>
 
     <string name="library_tab_text">Library</string>
     <string name="playlist_tab_text">Playlist</string>
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
index 806df25..b3c14c2 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
@@ -28,6 +28,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
+import android.support.v4.media.session.MediaSessionCompat;
 import android.support.v7.media.MediaRouter.RouteInfo;
 import android.support.v7.media.MediaItemStatus;
 import android.util.Log;
@@ -56,12 +57,6 @@
     private static final String TAG = "LocalPlayer";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final int STATE_IDLE = 0;
-    private static final int STATE_PLAY_PENDING = 1;
-    private static final int STATE_READY = 2;
-    private static final int STATE_PLAYING = 3;
-    private static final int STATE_PAUSED = 4;
-
     private final Context mContext;
     private final Handler mHandler = new Handler();
     private MediaPlayer mMediaPlayer;
@@ -109,6 +104,11 @@
         }
     }
 
+    @Override
+    public MediaSessionCompat getMediaSession() {
+        return mMediaSession;
+    }
+
     // Player
     @Override
     public void play(final PlaylistItem item) {
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 32b1285..ae018ed 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
@@ -16,11 +16,14 @@
 
 package com.example.android.supportv7.media;
 
-import android.net.Uri;
 import android.content.Context;
 import android.graphics.Bitmap;
+import android.support.v4.media.MediaMetadataCompat;
+import android.support.v4.media.session.MediaSessionCompat;
+import android.support.v4.media.session.PlaybackStateCompat;
 import android.support.v7.media.MediaControlIntent;
 import android.support.v7.media.MediaRouter.RouteInfo;
+import android.util.Log;
 
 /**
  * Abstraction of common playback operations of media items, such as play,
@@ -28,7 +31,19 @@
  * of media items.
  */
 public abstract class Player {
+    private static final String TAG = "SampleMediaRoutePlayer";
+    protected static final int STATE_IDLE = 0;
+    protected static final int STATE_PLAY_PENDING = 1;
+    protected static final int STATE_READY = 2;
+    protected static final int STATE_PLAYING = 3;
+    protected static final int STATE_PAUSED = 4;
+
+    private static final long PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PAUSE
+            | PlaybackStateCompat.ACTION_PLAY;
+
     protected Callback mCallback;
+    protected MediaSessionCompat mMediaSession;
+    protected MediaSessionCallback mSessionCallback;
 
     public abstract boolean isRemotePlayback();
     public abstract boolean isQueuingSupported();
@@ -71,10 +86,71 @@
         } else {
             player = new LocalPlayer.OverlayPlayer(context);
         }
+        player.initMediaSession(context);
         player.connect(route);
         return player;
     }
 
+    public MediaSessionCompat getMediaSession() {
+        return mMediaSession;
+    }
+
+    protected void updateMetadata() {
+        MediaMetadataCompat.Builder bob = new MediaMetadataCompat.Builder();
+        bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, getDescription());
+        bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Subtitle of the thing");
+        bob.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_DESCRIPTION,
+                "Description of the thing");
+        bob.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, getSnapshot());
+        mMediaSession.setMetadata(bob.build());
+    }
+
+    protected void publishState(int state) {
+        PlaybackStateCompat.Builder bob = new PlaybackStateCompat.Builder();
+        bob.setActions(PLAYBACK_ACTIONS);
+        switch (state) {
+            case STATE_PLAYING:
+                bob.setState(PlaybackStateCompat.STATE_PLAYING, -1, 1);
+                break;
+            case STATE_READY:
+            case STATE_PAUSED:
+                bob.setState(PlaybackStateCompat.STATE_PAUSED, -1, 0);
+                break;
+            case STATE_IDLE:
+                bob.setState(PlaybackStateCompat.STATE_STOPPED, -1, 0);
+                break;
+        }
+        PlaybackStateCompat pbState = bob.build();
+        Log.d(TAG, "Setting state to " + pbState);
+        mMediaSession.setPlaybackState(pbState);
+        if (state != STATE_IDLE) {
+            mMediaSession.setActive(true);
+        } else {
+            mMediaSession.setActive(false);
+        }
+    }
+
+    private void initMediaSession(Context context) {
+        mSessionCallback = new MediaSessionCallback();
+        mMediaSession = new MediaSessionCompat(context, "Support7Demos");
+        mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
+                | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
+        mMediaSession.setCallback(mSessionCallback);
+        updateMetadata();
+    }
+
+    private final class MediaSessionCallback extends MediaSessionCompat.Callback {
+        @Override
+        public void onPlay() {
+            resume();
+        }
+
+        @Override
+        public void onPause() {
+            pause();
+        }
+    }
+
     public interface Callback {
         void onError();
         void onCompletion();
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 5020c37..d47c260 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
@@ -140,6 +140,9 @@
                 }
                 if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
                     pause();
+                    publishState(STATE_PAUSED);
+                } else {
+                    publishState(STATE_PLAYING);
                 }
                 if (mCallback != null) {
                     mCallback.onPlaylistChanged();
@@ -214,6 +217,7 @@
                 if (mCallback != null) {
                     mCallback.onPlaylistChanged();
                 }
+                publishState(STATE_PAUSED);
             }
 
             @Override
@@ -239,6 +243,7 @@
                 if (mCallback != null) {
                     mCallback.onPlaylistChanged();
                 }
+                publishState(STATE_PLAYING);
             }
 
             @Override
@@ -254,6 +259,7 @@
             // ignore if no session
             return;
         }
+        publishState(STATE_IDLE);
         if (DEBUG) {
             Log.d(TAG, "stop");
         }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java
deleted file mode 100644
index a2cacc3..0000000
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteControllerDialog.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2013 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.example.android.supportv7.media;
-
-import com.example.android.supportv7.R;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.os.Bundle;
-import android.support.v7.app.MediaRouteControllerDialog;
-import android.support.v7.media.MediaRouteSelector;
-import android.support.v7.media.MediaRouter;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-/**
- * This class serves as an example on how to customize the media router control
- * dialog. It is derived from the standard MediaRouteControllerDialog with the
- * following overrides:
- *
- *   1. Shows thumbnail/snapshot of the current item
- *
- *   2. For variable volume routes, only allow volume control via Volume Up/Down
- *      keys (to prevent accidental tapping on the volume adjust seekbar that sets
- *      volume to maximum)
- *
- *   3. Provides transport control buttons (play/pause, stop)
- */
-public class SampleMediaRouteControllerDialog extends MediaRouteControllerDialog {
-    private static final String TAG = "SampleMediaRouteControllerDialog";
-    private final SampleMediaRouterActivity mActivity;
-    private final SessionManager mSessionManager;
-    private final Player mPlayer;
-    private ImageButton mPauseResumeButton;
-    private ImageButton mStopButton;
-    private ImageView mThumbnail;
-    private TextView mTextView;
-    private LinearLayout mInfoLayout;
-    private LinearLayout mVolumeLayout;
-
-    public SampleMediaRouteControllerDialog(Context context,
-            SessionManager manager, Player player) {
-        super(context);
-        mActivity = (SampleMediaRouterActivity) context;
-        mSessionManager = manager;
-        mPlayer = player;
-    }
-
-    @Override
-    public View onCreateMediaControlView(Bundle savedInstanceState) {
-        // Thumbnail and Track info
-        View v = getLayoutInflater().inflate(R.layout.sample_media_controller, null);
-        mInfoLayout = (LinearLayout)v.findViewById(R.id.media_route_info);
-        mTextView = (TextView)v.findViewById(R.id.track_info);
-        mThumbnail = (ImageView)v.findViewById(R.id.snapshot);
-
-        // Transport controls
-        mPauseResumeButton = (ImageButton)v.findViewById(R.id.pause_resume_button);
-        mPauseResumeButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (mActivity != null) {
-                    mActivity.handleMediaKey(new KeyEvent(KeyEvent.ACTION_DOWN,
-                        KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
-                }
-            }
-        });
-
-        mStopButton = (ImageButton)v.findViewById(R.id.stop_button);
-        mStopButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                if (mActivity != null) {
-                    mActivity.handleMediaKey(new KeyEvent(KeyEvent.ACTION_DOWN,
-                        KeyEvent.KEYCODE_MEDIA_STOP));
-                }
-            }
-        });
-
-        // update session status (will callback to updateUi at the end)
-        mSessionManager.updateStatus();
-        return v;
-    }
-
-    public void updateUi() {
-        String trackInfo = mPlayer.getDescription();
-        Bitmap snapshot = mPlayer.getSnapshot();
-        if (mPlayer.isRemotePlayback() && !trackInfo.isEmpty() && snapshot != null) {
-            mInfoLayout.setVisibility(View.VISIBLE);
-            mThumbnail.setImageBitmap(snapshot);
-            mTextView.setText(trackInfo);
-        } else {
-            mInfoLayout.setVisibility(View.GONE);
-        }
-        // show pause or resume icon depending on current state
-        mPauseResumeButton.setImageResource(mSessionManager.isPaused() ?
-                R.drawable.ic_media_play : R.drawable.ic_media_pause);
-    }
-}
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 8a20564..2e26630 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentFilter.MalformedMimeTypeException;
+import android.content.IntentSender;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.media.AudioManager;
@@ -173,6 +174,10 @@
 
     private void publishRoutes() {
         Resources r = getContext().getResources();
+        Intent settingsIntent = new Intent(Intent.ACTION_MAIN);
+        settingsIntent.setClass(getContext(), SampleMediaRouteSettingsActivity.class);
+        IntentSender is = PendingIntent.getActivity(getContext(), 99, settingsIntent,
+                Intent.FLAG_ACTIVITY_NEW_TASK).getIntentSender();
 
         MediaRouteDescriptor routeDescriptor1 = new MediaRouteDescriptor.Builder(
                 FIXED_VOLUME_ROUTE_ID,
@@ -183,6 +188,8 @@
                 .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
                 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)
                 .setVolume(VOLUME_MAX)
+                .setCanDisconnect(true)
+                .setSettingsActivity(is)
                 .build();
 
         MediaRouteDescriptor routeDescriptor2 = new MediaRouteDescriptor.Builder(
@@ -195,6 +202,7 @@
                 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
                 .setVolumeMax(VOLUME_MAX)
                 .setVolume(mVolume)
+                .setSettingsActivity(is)
                 .build();
 
         MediaRouteDescriptor routeDescriptor3 = new MediaRouteDescriptor.Builder(
@@ -207,6 +215,7 @@
                 .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
                 .setVolumeMax(VOLUME_MAX)
                 .setVolume(mVolume)
+                .setCanDisconnect(true)
                 .build();
 
         MediaRouteDescriptor routeDescriptor4 = new MediaRouteDescriptor.Builder(
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java
new file mode 100644
index 0000000..a1d07fb
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteSettingsActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 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.example.android.supportv7.media;
+
+import android.support.v7.app.ActionBarActivity;
+
+/**
+ * This activity is a dummy settings activity for the
+ * {@link SampleMediaRouteProvider}.
+ */
+public class SampleMediaRouteSettingsActivity extends ActionBarActivity {
+
+}
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 dfa1416..164831f 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
@@ -20,6 +20,7 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.app.PendingIntent;
@@ -37,6 +38,7 @@
 import android.support.v4.view.MenuItemCompat;
 import android.support.v7.app.ActionBarActivity;
 import android.support.v7.app.MediaRouteActionProvider;
+import android.support.v7.app.MediaRouteButton;
 import android.support.v7.app.MediaRouteControllerDialog;
 import android.support.v7.app.MediaRouteControllerDialogFragment;
 import android.support.v7.app.MediaRouteDiscoveryFragment;
@@ -66,6 +68,7 @@
 import android.widget.TabHost.OnTabChangeListener;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
+
 import java.io.File;
 
 /**
@@ -93,7 +96,6 @@
     private SeekBar mSeekBar;
     private boolean mNeedResume;
     private boolean mSeeking;
-    private SampleMediaRouteControllerDialog mControllerDialog;
 
     private final Handler mHandler = new Handler();
     private final Runnable mUpdateSeekRunnable = new Runnable() {
@@ -152,7 +154,6 @@
             }
             mPlayer.updatePresentation();
             mPlayer.release();
-            mControllerDialog = null;
         }
 
         @Override
@@ -372,6 +373,8 @@
         // Set up playback manager and player
         mPlayer = Player.create(SampleMediaRouterActivity.this,
                 mMediaRouter.getSelectedRoute());
+        mMediaRouter.setMediaSessionCompat(mPlayer.getMediaSession());
+
         mSessionManager.setPlayer(mPlayer);
         mSessionManager.setCallback(new SessionManager.Callback() {
             @Override
@@ -520,15 +523,7 @@
         mediaRouteActionProvider.setDialogFactory(new MediaRouteDialogFactory() {
             @Override
             public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
-                return new MediaRouteControllerDialogFragment() {
-                    @Override
-                    public MediaRouteControllerDialog onCreateControllerDialog(
-                            Context context, Bundle savedInstanceState) {
-                        mControllerDialog = new SampleMediaRouteControllerDialog(
-                                context, mSessionManager, mPlayer);
-                        return mControllerDialog;
-                    }
-                };
+                return new ControllerDialogFragment(mPlayer);
             }
         });
 
@@ -564,8 +559,8 @@
         updatePlaylist();
         updateRouteDescription();
         updateButtons();
-        if (mControllerDialog != null) {
-            mControllerDialog.updateUi();
+        if (mPlayer != null) {
+            mPlayer.updateMetadata();
         }
     }
 
@@ -745,4 +740,41 @@
      */
     public static class LightWithDarkActionBar extends SampleMediaRouterActivity {
     }
+
+    public static class ControllerDialogFragment extends MediaRouteControllerDialogFragment {
+        private MediaRouteControllerDialog mControllerDialog;
+        private Player mPlayer;
+
+        public ControllerDialogFragment() {
+            super();
+        }
+
+        public ControllerDialogFragment(Player player) {
+            mPlayer = player;
+        }
+
+        @Override
+        public MediaRouteControllerDialog onCreateControllerDialog(
+                Context context, Bundle savedInstanceState) {
+            mControllerDialog = super.onCreateControllerDialog(context,
+                    savedInstanceState);
+            if (mPlayer != null) {
+                mControllerDialog.setMediaSession(mPlayer.getMediaSession().getSessionToken());
+            }
+            mControllerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+                @Override
+                public void onDismiss(DialogInterface dialog) {
+                    mControllerDialog = null;
+                }
+            });
+            return mControllerDialog;
+        }
+
+        public void setPlayer(Player player) {
+            mPlayer = player;
+            if (mControllerDialog != null) {
+                mControllerDialog.setMediaSession(mPlayer.getMediaSession().getSessionToken());
+            }
+        }
+    }
 }