Support7Demos: Update the MediaRouter demo

Change-Id: I661e17073bd71e45610360bbf5b372eaf41c4fe3
diff --git a/samples/Support7Demos/AndroidManifest.xml b/samples/Support7Demos/AndroidManifest.xml
index 164411a..1b88507 100644
--- a/samples/Support7Demos/AndroidManifest.xml
+++ b/samples/Support7Demos/AndroidManifest.xml
@@ -62,7 +62,7 @@
         <activity android:name=".media.SampleMediaRouterActivity"
                 android:configChanges="orientation|screenSize"
                 android:label="@string/sample_media_router_activity_dark"
-                android:theme="@style/Theme.AppCompat">
+                android:theme="@style/Theme.SampleMediaRouter">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
@@ -72,7 +72,7 @@
         <activity android:name=".media.SampleMediaRouterActivity$Light"
                 android:configChanges="orientation|screenSize"
                 android:label="@string/sample_media_router_activity_light"
-                android:theme="@style/Theme.AppCompat.Light">
+                android:theme="@style/Theme.SampleMediaRouter.Light">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
@@ -82,7 +82,7 @@
         <activity android:name=".media.SampleMediaRouterActivity$LightWithDarkActionBar"
                 android:configChanges="orientation|screenSize"
                 android:label="@string/sample_media_router_activity_light_with_dark_action_bar"
-                android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
+                android:theme="@style/Theme.SampleMediaRouter.Light.DarkActionBar">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.example.android.supportv7.SAMPLE_CODE" />
diff --git a/samples/Support7Demos/res/drawable-hdpi/ic_android.png b/samples/Support7Demos/res/drawable-hdpi/ic_android.png
new file mode 100755
index 0000000..94b8fb1
--- /dev/null
+++ b/samples/Support7Demos/res/drawable-hdpi/ic_android.png
Binary files differ
diff --git a/samples/Support7Demos/res/drawable-mdpi/ic_android.png b/samples/Support7Demos/res/drawable-mdpi/ic_android.png
new file mode 100755
index 0000000..afc43db
--- /dev/null
+++ b/samples/Support7Demos/res/drawable-mdpi/ic_android.png
Binary files differ
diff --git a/samples/Support7Demos/res/layout/sample_media_router.xml b/samples/Support7Demos/res/layout/sample_media_router.xml
index e2f7008..618a8e4 100644
--- a/samples/Support7Demos/res/layout/sample_media_router.xml
+++ b/samples/Support7Demos/res/layout/sample_media_router.xml
@@ -76,6 +76,12 @@
         </TabHost>
 
         <!-- Control buttons for the currently selected route. -->
+        <CheckBox android:id="@+id/custom_control_view_checkbox"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/use_default_media_control"
+                android:checked="true"
+                android:visibility="gone"/>
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/samples/Support7Demos/res/values/strings.xml b/samples/Support7Demos/res/values/strings.xml
index 85c1303..d0b97f1 100644
--- a/samples/Support7Demos/res/values/strings.xml
+++ b/samples/Support7Demos/res/values/strings.xml
@@ -27,6 +27,9 @@
     <string name="media_route_menu_title">Play on...</string>
     <string name="sample_media_route_settings_activity">Sample route settings</string>
 
+    <string name="use_default_media_control">Use default media control</string>
+    <string name="my_media_control_text">My Media Control</string>
+
     <string name="library_tab_text">Library</string>
     <string name="playlist_tab_text">Playlist</string>
     <string name="info_tab_text">Route Info</string>
@@ -36,6 +39,8 @@
     <string name="variable_volume_basic_route_name">Variable Volume (Basic) Remote Playback Route</string>
     <string name="variable_volume_queuing_route_name">Variable Volume (Queuing) Remote Playback Route</string>
     <string name="variable_volume_session_route_name">Variable Volume (Session) Remote Playback Route</string>
+    <string name="variable_volume_route_group_name">Variable Volume Route Group</string>
+    <string name="mixed_volume_route_group_name">Mixed Volume Route Group</string>
     <string name="sample_route_description">Sample route from Support7Demos</string>
 
     <!-- GridLayout -->
diff --git a/samples/Support7Demos/res/values/styles.xml b/samples/Support7Demos/res/values/styles.xml
index 26a9f70..a788938 100644
--- a/samples/Support7Demos/res/values/styles.xml
+++ b/samples/Support7Demos/res/values/styles.xml
@@ -29,8 +29,41 @@
         <item name="colorAccent">#ffff00</item>
     </style>
 
+    <style name="Theme.SampleMediaRouter" parent="Theme.AppCompat">
+        <item name="colorPrimary">#fff44336</item>
+        <item name="colorPrimaryDark">#d32f2f</item>
+        <item name="alertDialogTheme">@style/Theme.SampleMediaRouter.Dialog.Alert</item>
+    </style>
+
+    <style name="Theme.SampleMediaRouter.Light" parent="Theme.AppCompat.Light">
+        <item name="colorPrimary">#ffff9800</item>
+        <item name="colorPrimaryDark">#f57c00</item>
+        <item name="alertDialogTheme">@style/Theme.SampleMediaRouter.Light.Dialog.Alert</item>
+    </style>
+
+    <style name="Theme.SampleMediaRouter.Light.DarkActionBar" parent="Theme.AppCompat.Light.DarkActionBar">
+        <item name="colorPrimary">#ff2196f3</item>
+        <item name="colorPrimaryDark">#1976d2</item>
+        <item name="alertDialogTheme">@style/Theme.SampleMediaRouter.Light.DarkActionBar.Dialog.Alert</item>
+    </style>
+
+    <style name="Theme.SampleMediaRouter.Dialog.Alert" parent="Theme.AppCompat.Dialog.Alert">
+        <item name="colorPrimary">#fff44336</item>
+        <item name="colorPrimaryDark">#d32f2f</item>
+    </style>
+
+    <style name="Theme.SampleMediaRouter.Light.Dialog.Alert" parent="Theme.AppCompat.Light.Dialog.Alert">
+        <item name="colorPrimary">#ffff9800</item>
+        <item name="colorPrimaryDark">#f57c00</item>
+    </style>
+
+    <style name="Theme.SampleMediaRouter.Light.DarkActionBar.Dialog.Alert" parent="Theme.AppCompat.Light.Dialog.Alert">
+        <item name="colorPrimary">#ff2196f3</item>
+        <item name="colorPrimaryDark">#1976d2</item>
+    </style>
+
     <style name="SortedListItem" parent="@android:style/TextAppearance.Medium">
         <item name="android:minHeight">35dp</item>
     </style>
 
-</resources>
\ No newline at end of file
+</resources>
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 b3c14c2..b62f76e 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/LocalPlayer.java
@@ -20,15 +20,12 @@
 import android.app.Presentation;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.media.MediaPlayer;
-import android.net.Uri;
 import android.os.Build;
 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;
@@ -59,6 +56,7 @@
 
     private final Context mContext;
     private final Handler mHandler = new Handler();
+    private final Handler mUpdateSurfaceHandler = new Handler(mHandler.getLooper());
     private MediaPlayer mMediaPlayer;
     private int mState = STATE_IDLE;
     private int mSeekToPos;
@@ -104,11 +102,6 @@
         }
     }
 
-    @Override
-    public MediaSessionCompat getMediaSession() {
-        return mMediaSession;
-    }
-
     // Player
     @Override
     public void play(final PlaylistItem item) {
@@ -145,7 +138,8 @@
         if (mState == STATE_PLAYING || mState == STATE_PAUSED) {
             mMediaPlayer.seekTo(pos);
             mSeekToPos = pos;
-        } else if (mState == STATE_IDLE || mState == STATE_PLAY_PENDING) {
+        } else if (mState == STATE_IDLE || mState == STATE_PREPARING_FOR_PLAY
+                || mState == STATE_PREPARING_FOR_PAUSE) {
             // Seek before onPrepared() arrives,
             // need to performed delayed seek in onPrepared()
             mSeekToPos = pos;
@@ -175,6 +169,8 @@
         if (mState == STATE_PLAYING) {
             mMediaPlayer.pause();
             mState = STATE_PAUSED;
+        } else if (mState == STATE_PREPARING_FOR_PLAY) {
+            mState = STATE_PREPARING_FOR_PAUSE;
         }
     }
 
@@ -186,8 +182,8 @@
         if (mState == STATE_READY || mState == STATE_PAUSED) {
             mMediaPlayer.start();
             mState = STATE_PLAYING;
-        } else if (mState == STATE_IDLE){
-            mState = STATE_PLAY_PENDING;
+        } else if (mState == STATE_IDLE || mState == STATE_PREPARING_FOR_PAUSE) {
+            mState = STATE_PREPARING_FOR_PLAY;
         }
     }
 
@@ -224,8 +220,10 @@
                 if (mState == STATE_IDLE) {
                     mState = STATE_READY;
                     updateVideoRect();
-                } else if (mState == STATE_PLAY_PENDING) {
-                    mState = STATE_PLAYING;
+                } else if (mState == STATE_PREPARING_FOR_PLAY
+                        || mState == STATE_PREPARING_FOR_PAUSE) {
+                    int prevState = mState;
+                    mState = mState == STATE_PREPARING_FOR_PLAY ? STATE_PLAYING : STATE_PAUSED;
                     updateVideoRect();
                     if (mSeekToPos > 0) {
                         if (DEBUG) {
@@ -233,7 +231,9 @@
                         }
                         mMediaPlayer.seekTo(mSeekToPos);
                     }
-                    mMediaPlayer.start();
+                    if (prevState == STATE_PREPARING_FOR_PLAY) {
+                        mMediaPlayer.start();
+                    }
                 }
                 if (mCallback != null) {
                     mCallback.onPlaylistChanged();
@@ -294,6 +294,7 @@
     protected MediaPlayer getMediaPlayer() { return mMediaPlayer; }
     protected int getVideoWidth() { return mVideoWidth; }
     protected int getVideoHeight() { return mVideoHeight; }
+    protected int getState() { return mState; }
     protected void setSurface(Surface surface) {
         mSurface = surface;
         mSurfaceHolder = null;
@@ -313,23 +314,29 @@
     }
 
     protected void updateSurface() {
-        if (mMediaPlayer == null) {
-            // just return if media player is already gone
-            return;
-        }
-        if (mSurface != null) {
-            // The setSurface API does not exist until V14+.
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-                ICSMediaPlayer.setSurface(mMediaPlayer, mSurface);
-            } else {
-                throw new UnsupportedOperationException("MediaPlayer does not support "
-                        + "setSurface() on this version of the platform.");
+        mUpdateSurfaceHandler.removeCallbacksAndMessages(null);
+        mUpdateSurfaceHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mMediaPlayer == null) {
+                    // just return if media player is already gone
+                    return;
+                }
+                if (mSurface != null) {
+                    // The setSurface API does not exist until V14+.
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+                        ICSMediaPlayer.setSurface(mMediaPlayer, mSurface);
+                    } else {
+                        throw new UnsupportedOperationException("MediaPlayer does not support "
+                                + "setSurface() on this version of the platform.");
+                    }
+                } else if (mSurfaceHolder != null) {
+                    mMediaPlayer.setDisplay(mSurfaceHolder);
+                } else {
+                    mMediaPlayer.setDisplay(null);
+                }
             }
-        } else if (mSurfaceHolder != null) {
-            mMediaPlayer.setDisplay(mSurfaceHolder);
-        } else {
-            mMediaPlayer.setDisplay(null);
-        }
+        });
     }
 
     protected abstract void updateSize();
@@ -351,7 +358,8 @@
     }
 
     private void updateVideoRect() {
-        if (mState != STATE_IDLE && mState != STATE_PLAY_PENDING) {
+        if (mState != STATE_IDLE && mState != STATE_PREPARING_FOR_PLAY
+                && mState != STATE_PREPARING_FOR_PAUSE) {
             int width = mMediaPlayer.getVideoWidth();
             int height = mMediaPlayer.getVideoHeight();
             if (width > 0 && height > 0) {
@@ -632,7 +640,10 @@
 
         @Override
         public Bitmap getSnapshot() {
-            return mOverlay.getSnapshot();
+            if (getState() == STATE_PLAYING || getState() == STATE_PAUSED) {
+                return mOverlay.getSnapshot();
+            }
+            return null;
         }
     }
 }
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/MyMediaRouteControllerDialog.java b/samples/Support7Demos/src/com/example/android/supportv7/media/MyMediaRouteControllerDialog.java
new file mode 100644
index 0000000..3264671
--- /dev/null
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/MyMediaRouteControllerDialog.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 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.graphics.Color;
+import android.os.Bundle;
+import android.support.v7.app.MediaRouteControllerDialog;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.TextView;
+import com.example.android.supportv7.R;
+
+/**
+ * An example MediaRouteControllerDialog for demonstrating
+ * {@link android.support.v7.app.MediaRouteControllerDialog#onCreateMediaControlView}.
+ */
+public class MyMediaRouteControllerDialog extends MediaRouteControllerDialog {
+    public MyMediaRouteControllerDialog(Context context) {
+        super(context);
+    }
+
+    @Override
+    public View onCreateMediaControlView(Bundle savedInstanceState) {
+        TextView view = new TextView(getContext());
+        view.setText(R.string.my_media_control_text);
+        view.setBackgroundColor(Color.GRAY);
+        return view;
+    }
+}
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java b/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
index 80cc77d..1d4aaa1 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/OverlayDisplayWindow.java
@@ -19,7 +19,6 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.Point;
 import android.graphics.SurfaceTexture;
 import android.hardware.display.DisplayManager;
 import android.os.Build;
@@ -95,9 +94,9 @@
 
     // Watches for significant changes in the overlay display window lifecycle.
     public interface OverlayWindowListener {
-        public void onWindowCreated(Surface surface);
-        public void onWindowCreated(SurfaceHolder surfaceHolder);
-        public void onWindowDestroyed();
+        void onWindowCreated(Surface surface);
+        void onWindowCreated(SurfaceHolder surfaceHolder);
+        void onWindowDestroyed();
     }
 
     /**
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 fcab57d..a5d5897 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/Player.java
@@ -16,10 +16,7 @@
 
 package com.example.android.supportv7.media;
 
-import android.app.PendingIntent;
-import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.graphics.Bitmap;
 import android.support.v4.media.MediaMetadataCompat;
 import android.support.v4.media.session.MediaSessionCompat;
@@ -32,17 +29,22 @@
  * Abstraction of common playback operations of media items, such as play,
  * seek, etc. Used by PlaybackManager as a backend to handle actual playback
  * of media items.
+ *
+ * TODO: Introduce prepare() method and refactor subclasses accordingly.
  */
 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;
+    protected static final int STATE_PREPARING_FOR_PLAY = 1;
+    protected static final int STATE_PREPARING_FOR_PAUSE = 2;
+    protected static final int STATE_READY = 3;
+    protected static final int STATE_PLAYING = 4;
+    protected static final int STATE_PAUSED = 5;
 
     private static final long PLAYBACK_ACTIONS = PlaybackStateCompat.ACTION_PAUSE
             | PlaybackStateCompat.ACTION_PLAY;
+    private static final PlaybackStateCompat INIT_PLAYBACK_STATE = new PlaybackStateCompat.Builder()
+            .setState(PlaybackStateCompat.STATE_NONE, 0, .0f).build();
 
     protected Callback mCallback;
     protected MediaSessionCompat mMediaSession;
@@ -88,13 +90,18 @@
         } else {
             player = new LocalPlayer.OverlayPlayer(context);
         }
-        player.initMediaSession(session);
+        player.setMediaSession(session);
+        player.initMediaSession();
         player.connect(route);
         return player;
     }
 
-    public MediaSessionCompat getMediaSession() {
-        return mMediaSession;
+    protected void initMediaSession() {
+        if (mMediaSession == null) {
+            return;
+        }
+        mMediaSession.setMetadata(null);
+        mMediaSession.setPlaybackState(INIT_PLAYBACK_STATE);
     }
 
     protected void updateMetadata() {
@@ -138,16 +145,14 @@
         }
     }
 
-    private void initMediaSession(MediaSessionCompat session) {
+    private void setMediaSession(MediaSessionCompat session) {
         mMediaSession = session;
-        updateMetadata();
     }
 
-
     public interface Callback {
         void onError();
         void onCompletion();
         void onPlaylistChanged();
         void onPlaylistReady();
     }
-}
\ 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 d47c260..6ad4f75 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/RemotePlayer.java
@@ -19,10 +19,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.net.Uri;
 import android.os.Bundle;
 import android.support.v7.media.MediaItemStatus;
-import android.support.v7.media.MediaControlIntent;
 import android.support.v7.media.MediaRouter.ControlRequestCallback;
 import android.support.v7.media.MediaRouter.RouteInfo;
 import android.support.v7.media.MediaSessionStatus;
@@ -140,7 +138,6 @@
                 }
                 if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
                     pause();
-                    publishState(STATE_PAUSED);
                 } else {
                     publishState(STATE_PLAYING);
                 }
@@ -385,6 +382,8 @@
                 }
                 if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
                     pause();
+                } else if (item.getState() == MediaItemStatus.PLAYBACK_STATE_PLAYING) {
+                    publishState(STATE_PLAYING);
                 }
                 if (mEnqueuePending) {
                     mEnqueuePending = false;
diff --git a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaButtonReceiver.java b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaButtonReceiver.java
index c2eec8e..d356446 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaButtonReceiver.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaButtonReceiver.java
@@ -16,12 +16,9 @@
 
 package com.example.android.supportv7.media;
 
-import com.example.android.supportv7.R;
-
 import android.content.Context;
 import android.content.Intent;
 import android.content.BroadcastReceiver;
-import android.util.Log;
 import android.view.KeyEvent;
 
 /**
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 8aefacf..9c90910 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouteProvider.java
@@ -51,6 +51,8 @@
     private static final String VARIABLE_VOLUME_BASIC_ROUTE_ID = "variable_basic";
     private static final String VARIABLE_VOLUME_QUEUING_ROUTE_ID = "variable_queuing";
     private static final String VARIABLE_VOLUME_SESSION_ROUTE_ID = "variable_session";
+    private static final String VARIABLE_VOLUME_ROUTE_GROUP_ID = "variable_group";
+    private static final String MIXED_VOLUME_ROUTE_GROUP_ID = "mixed_group";
 
     private static final int VOLUME_MAX = 10;
 
@@ -223,11 +225,46 @@
                 .setVolume(mVolume)
                 .build();
 
+        MediaRouteDescriptor routeDescriptor5 = new MediaRouteDescriptor.Builder(
+                VARIABLE_VOLUME_ROUTE_GROUP_ID,
+                r.getString(R.string.variable_volume_route_group_name))
+                .addGroupMemberId(VARIABLE_VOLUME_BASIC_ROUTE_ID)
+                .addGroupMemberId(VARIABLE_VOLUME_QUEUING_ROUTE_ID)
+                .setDescription(r.getString(R.string.sample_route_description))
+                .addControlFilters(CONTROL_FILTERS_SESSION)
+                .setPlaybackStream(AudioManager.STREAM_MUSIC)
+                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
+                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
+                .setVolumeMax(VOLUME_MAX)
+                .setVolume(mVolume)
+                .build();
+
+        Uri iconUri = Uri.parse("android.resource://com.example.android.supportv7/"
+                + R.drawable.ic_android);
+        MediaRouteDescriptor routeDescriptor6 = new MediaRouteDescriptor.Builder(
+                MIXED_VOLUME_ROUTE_GROUP_ID,
+                r.getString(R.string.mixed_volume_route_group_name))
+                .addGroupMemberId(FIXED_VOLUME_ROUTE_ID)
+                .addGroupMemberId(VARIABLE_VOLUME_BASIC_ROUTE_ID)
+                .addGroupMemberId(VARIABLE_VOLUME_QUEUING_ROUTE_ID)
+                .addGroupMemberId(VARIABLE_VOLUME_SESSION_ROUTE_ID)
+                .setDescription(r.getString(R.string.sample_route_description))
+                .setIconUri(iconUri)
+                .addControlFilters(CONTROL_FILTERS_SESSION)
+                .setPlaybackStream(AudioManager.STREAM_MUSIC)
+                .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
+                .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
+                .setVolumeMax(VOLUME_MAX)
+                .setVolume(mVolume)
+                .build();
+
         MediaRouteProviderDescriptor providerDescriptor = new MediaRouteProviderDescriptor.Builder()
                 .addRoute(routeDescriptor1)
                 .addRoute(routeDescriptor2)
                 .addRoute(routeDescriptor3)
                 .addRoute(routeDescriptor4)
+                .addRoute(routeDescriptor5)
+                .addRoute(routeDescriptor6)
                 .build();
         setDescriptor(providerDescriptor);
     }
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 0a64c55..a40992302 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SampleMediaRouterActivity.java
@@ -56,6 +56,7 @@
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
 import android.widget.ImageButton;
 import android.widget.ListView;
 import android.widget.SeekBar;
@@ -79,6 +80,7 @@
 public class SampleMediaRouterActivity extends AppCompatActivity {
     private static final String TAG = "SampleMediaRouterActivity";
     private static final String DISCOVERY_FRAGMENT_TAG = "DiscoveryFragment";
+    private static final boolean ENABLE_DEFAULT_CONTROL_CHECK_BOX = false;
 
     private MediaRouter mMediaRouter;
     private MediaRouteSelector mSelector;
@@ -87,6 +89,7 @@
     private TextView mInfoTextView;
     private ListView mLibraryView;
     private ListView mPlayListView;
+    private CheckBox mUseDefaultControlCheckBox;
     private ImageButton mPauseResumeButton;
     private ImageButton mStopButton;
     private SeekBar mSeekBar;
@@ -308,6 +311,10 @@
 
         mInfoTextView = (TextView) findViewById(R.id.info);
 
+        mUseDefaultControlCheckBox = (CheckBox) findViewById(R.id.custom_control_view_checkbox);
+        if (ENABLE_DEFAULT_CONTROL_CHECK_BOX) {
+            mUseDefaultControlCheckBox.setVisibility(View.VISIBLE);
+        }
         mPauseResumeButton = (ImageButton)findViewById(R.id.pause_resume_button);
         mPauseResumeButton.setOnClickListener(new OnClickListener() {
             @Override
@@ -518,7 +525,7 @@
         mediaRouteActionProvider.setDialogFactory(new MediaRouteDialogFactory() {
             @Override
             public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
-                return new ControllerDialogFragment(mPlayer);
+                return new ControllerDialogFragment(mPlayer, mUseDefaultControlCheckBox);
             }
         });
 
@@ -734,20 +741,23 @@
     public static class ControllerDialogFragment extends MediaRouteControllerDialogFragment {
         private MediaRouteControllerDialog mControllerDialog;
         private Player mPlayer;
+        private CheckBox mUseDefaultControlCheckBox;
 
         public ControllerDialogFragment() {
             super();
         }
 
-        public ControllerDialogFragment(Player player) {
+        public ControllerDialogFragment(Player player, CheckBox customControlViewCheckBox) {
             mPlayer = player;
+            this.mUseDefaultControlCheckBox = customControlViewCheckBox;
         }
 
         @Override
         public MediaRouteControllerDialog onCreateControllerDialog(
                 Context context, Bundle savedInstanceState) {
-            mControllerDialog = super.onCreateControllerDialog(context,
-                    savedInstanceState);
+            mControllerDialog = this.mUseDefaultControlCheckBox.isChecked()
+                    ? super.onCreateControllerDialog(context, savedInstanceState)
+                    : new MyMediaRouteControllerDialog(context);
             mControllerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                 @Override
                 public void onDismiss(DialogInterface dialog) {
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 1c00192..6fab2eb 100644
--- a/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java
+++ b/samples/Support7Demos/src/com/example/android/supportv7/media/SessionManager.java
@@ -349,6 +349,8 @@
             if (mCallback != null) {
                 mCallback.onItemChanged(item);
             }
+        } else {
+            mPlayer.initMediaSession();
         }
         updateStatus();
     }