MediaRouter: Enable volume group expansion

Bug: 23115937
Change-Id: I97f14d0d74b20723406068caa652d6afe1fcaf74
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack.png
new file mode 100644
index 0000000..71db6b4
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..d7c8252
--- /dev/null
+++ b/v7/mediarouter/res/drawable-hdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack.png
new file mode 100644
index 0000000..dc1200e
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..2cf7e0c
--- /dev/null
+++ b/v7/mediarouter/res/drawable-mdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack.png
new file mode 100644
index 0000000..b5c899f
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..4778e00
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack.png b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack.png
new file mode 100644
index 0000000..0546539
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_light.png b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_light.png
new file mode 100644
index 0000000..8e38265
--- /dev/null
+++ b/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml b/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml
index f53cc7a..66544ec 100644
--- a/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml
+++ b/v7/mediarouter/res/layout/mr_media_route_controller_material_dialog_b.xml
@@ -123,6 +123,11 @@
                          android:background="?attr/selectableItemBackgroundBorderless"
                          android:visibility="gone"/>
         </LinearLayout>
+        <ListView android:id="@+id/media_route_volume_group_list"
+                  android:layout_width="fill_parent"
+                  android:layout_height="wrap_content"
+                  android:visibility="gone">
+        </ListView>
         <LinearLayout android:id="@+id/buttons"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
diff --git a/v7/mediarouter/res/layout/mr_media_route_controller_volume_item.xml b/v7/mediarouter/res/layout/mr_media_route_controller_volume_item.xml
new file mode 100644
index 0000000..d07d94b
--- /dev/null
+++ b/v7/mediarouter/res/layout/mr_media_route_controller_volume_item.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="fill_parent"
+              android:layout_height="64dp"
+              android:padding="8dp">
+    <TextView android:id="@+id/media_route_name"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_alignParentTop="true"
+              android:layout_alignParentLeft="true" />
+    <ImageView android:id="@+id/media_route_volume_item_icon"
+               android:layout_width="48dp"
+               android:layout_height="48dp"
+               android:layout_below="@id/media_route_name"
+               android:layout_alignParentLeft="true"
+               android:src="?attr/mediaRouteAudioTrackDrawable"
+               android:gravity="center"
+               android:scaleType="center" />
+    <SeekBar android:id="@+id/media_route_volume_slider"
+             android:layout_width="fill_parent"
+             android:layout_height="wrap_content"
+             android:layout_below="@id/media_route_name"
+             android:layout_toRightOf="@id/media_route_volume_item_icon"
+             android:layout_gravity="center_vertical"
+             android:layout_marginTop="8dp"
+             android:layout_marginLeft="8dp"
+             android:layout_marginRight="8dp" />
+</RelativeLayout>
diff --git a/v7/mediarouter/res/values/attrs.xml b/v7/mediarouter/res/values/attrs.xml
index 73f589f..56381c7 100644
--- a/v7/mediarouter/res/values/attrs.xml
+++ b/v7/mediarouter/res/values/attrs.xml
@@ -34,6 +34,7 @@
     <attr name="mediaRoutePlayDrawable" format="reference" />
     <attr name="mediaRoutePauseDrawable" format="reference" />
     <attr name="mediaRouteCastDrawable" format="reference" />
+    <attr name="mediaRouteAudioTrackDrawable" format="reference" />
     <attr name="mediaRouteDefaultIconDrawable" format="reference" />
     <attr name="mediaRouteSpeakerIconDrawable" format="reference" />
     <attr name="mediaRouteSpeakerGroupIconDrawable" format="reference" />
diff --git a/v7/mediarouter/res/values/themes.xml b/v7/mediarouter/res/values/themes.xml
index eb2d8ac..8c5a072 100644
--- a/v7/mediarouter/res/values/themes.xml
+++ b/v7/mediarouter/res/values/themes.xml
@@ -27,6 +27,7 @@
         <item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_dark</item>
         <item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_dark</item>
         <item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_dark</item>
+        <item name="mediaRouteAudioTrackDrawable">@drawable/ic_audiotrack</item>
         <item name="mediaRouteDefaultIconDrawable">@drawable/ic_tv_dark</item>
         <item name="mediaRouteSpeakerIconDrawable">@drawable/ic_speaker_dark</item>
         <item name="mediaRouteSpeakerGroupIconDrawable">@drawable/ic_speaker_group_dark</item>
@@ -36,8 +37,7 @@
         <item name="mediaRouteCollapseGroupDrawable">@drawable/ic_keyboard_arrow_up_white</item>
     </style>
 
-    <style name="Theme.MediaRouter.Light" parent="">
-        <item name="android:windowNoTitle">false</item>
+    <style name="Theme.MediaRouter.Light">
         <item name="mediaRouteButtonStyle">@style/Widget.MediaRouter.Light.MediaRouteButton</item>
 
         <item name="mediaRouteOffDrawable">@drawable/ic_cast_off_light</item>
@@ -47,6 +47,7 @@
         <item name="mediaRoutePlayDrawable">@drawable/mr_ic_play_light</item>
         <item name="mediaRoutePauseDrawable">@drawable/mr_ic_pause_light</item>
         <item name="mediaRouteCastDrawable">@drawable/mr_ic_cast_light</item>
+        <item name="mediaRouteAudioTrackDrawable">@drawable/ic_audiotrack_light</item>
         <item name="mediaRouteDefaultIconDrawable">@drawable/ic_tv_light</item>
         <item name="mediaRouteSpeakerIconDrawable">@drawable/ic_speaker_light</item>
         <item name="mediaRouteSpeakerGroupIconDrawable">@drawable/ic_speaker_group_light</item>
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
index 569c736..8b5d6fc 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
@@ -207,14 +207,14 @@
         public RouteAdapter(Context context, List<MediaRouter.RouteInfo> routes) {
             super(context, 0, routes);
             mInflater = LayoutInflater.from(context);
-            int[] attrs = new int[] {
+            TypedArray styledAttributes = getContext().obtainStyledAttributes(new int[] {
                     R.attr.mediaRouteDefaultIconDrawable,
                     R.attr.mediaRouteSpeakerIconDrawable,
-                    R.attr.mediaRouteSpeakerGroupIconDrawable };
-            TypedArray styledAttributes = getContext().obtainStyledAttributes(attrs);
+                    R.attr.mediaRouteSpeakerGroupIconDrawable });
             mDefaultIcon = styledAttributes.getDrawable(0);
             mSpeakerIcon = styledAttributes.getDrawable(1);
             mSpeakerGroupIcon = styledAttributes.getDrawable(2);
+            styledAttributes.recycle();
         }
 
         @Override
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
index 3fa67d2..6f69388 100644
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
+++ b/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
@@ -16,9 +16,12 @@
 
 package android.support.v7.app;
 
+import static android.widget.SeekBar.OnSeekBarChangeListener;
+
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.IntentSender;
+import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.Drawable;
@@ -38,19 +41,22 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
+import android.widget.ListView;
 import android.widget.SeekBar;
 import android.widget.TextView;
 
 import java.io.BufferedInputStream;
-import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.InputStream;
+import java.util.List;
 
 /**
  * This class implements the route controller dialog for {@link MediaRouter}.
@@ -96,6 +102,7 @@
 
     private boolean mVolumeControlEnabled = true;
     private LinearLayout mVolumeLayout;
+    private ListView mVolumeGroupList;
     private SeekBar mVolumeSlider;
     private boolean mVolumeSliderTouched;
 
@@ -128,6 +135,13 @@
         return mRoute;
     }
 
+    private MediaRouter.RouteGroup getGroup() {
+        if (mRoute instanceof MediaRouter.RouteGroup) {
+            return (MediaRouter.RouteGroup) mRoute;
+        }
+        return null;
+    }
+
     /**
      * Provides the subclass an opportunity to create a view that will
      * be included within the body of the dialog to offer additional media controls
@@ -239,8 +253,34 @@
         mPlayPauseButton.setOnClickListener(listener);
         mRouteNameView = (TextView) findViewById(R.id.route_name);
         mVolumeLayout = (LinearLayout)findViewById(R.id.media_route_volume_layout);
+        mVolumeGroupList = (ListView)findViewById(R.id.media_route_volume_group_list);
+
+        TypedArray styledAttributes = getContext().obtainStyledAttributes(new int[] {
+                R.attr.mediaRouteExpandGroupDrawable,
+                R.attr.mediaRouteCollapseGroupDrawable });
+        final Drawable expandGroupDrawable = styledAttributes.getDrawable(0);
+        final Drawable collapseGroupDrawable = styledAttributes.getDrawable(1);
+        styledAttributes.recycle();
+
         mGroupExpandCollapseButton = (ImageButton)findViewById(
                 R.id.media_route_group_expand_collapse);
+        mGroupExpandCollapseButton.setOnClickListener(new View.OnClickListener() {
+            private boolean mIsExpanded;
+
+            @Override
+            public void onClick(View v) {
+                mIsExpanded = !mIsExpanded;
+                if (mIsExpanded) {
+                    mGroupExpandCollapseButton.setImageDrawable(collapseGroupDrawable);
+                    mVolumeGroupList.setVisibility(View.VISIBLE);
+                    mVolumeGroupList.setAdapter(
+                            new VolumeGroupAdapter(getContext(), getGroup().getRoutes()));
+                } else {
+                    mGroupExpandCollapseButton.setImageDrawable(expandGroupDrawable);
+                    mVolumeGroupList.setVisibility(View.GONE);
+                }
+            }
+        });
         mVolumeSlider = (SeekBar)findViewById(R.id.media_route_volume_slider);
         mVolumeSlider.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
             private final Runnable mStopTrackingTouch = new Runnable() {
@@ -431,7 +471,7 @@
                 mVolumeSlider.setProgress(mRoute.getVolume());
                 if (USE_GROUP) {
                     mGroupExpandCollapseButton.setVisibility(
-                            mRoute instanceof MediaRouter.RouteGroup ? View.VISIBLE : View.GONE);
+                            getGroup() != null ? View.VISIBLE : View.GONE);
                 }
             } else {
                 mVolumeLayout.setVisibility(View.GONE);
@@ -518,6 +558,51 @@
         }
     }
 
+    private class VolumeGroupAdapter extends ArrayAdapter<MediaRouter.RouteInfo> {
+        final OnSeekBarChangeListener mOnSeekBarChangeListener = new OnSeekBarChangeListener() {
+            @Override
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                if (fromUser) {
+                    int position = (int) seekBar.getTag();
+                    getGroup().getRouteAt(position).requestSetVolume(progress);
+                }
+            }
+
+            @Override
+            public void onStartTrackingTouch(SeekBar seekBar) {
+                // TODO: Implement
+            }
+
+            @Override
+            public void onStopTrackingTouch(SeekBar seekBar) {
+                // TODO: Implement
+            }
+        };
+
+        public VolumeGroupAdapter(Context context, List<MediaRouter.RouteInfo> objects) {
+            super(context, 0, objects);
+        }
+
+        @Override
+        public View getView(final int position, View convertView, ViewGroup parent) {
+            View v = convertView;
+            if (v == null) {
+                v = LayoutInflater.from(getContext()).inflate(
+                        R.layout.mr_media_route_controller_volume_item, null);
+            }
+            MediaRouter.RouteInfo route = getItem(position);
+            if (route != null) {
+                TextView textView = (TextView) v.findViewById(R.id.media_route_name);
+                textView.setText(route.getName());
+
+                SeekBar volumeSlider = (SeekBar) v.findViewById(R.id.media_route_volume_slider);
+                volumeSlider.setTag(position);
+                volumeSlider.setOnSeekBarChangeListener(mOnSeekBarChangeListener);
+            }
+            return v;
+        }
+    }
+
     private class FetchArtTask extends AsyncTask<Void, Void, Bitmap> {
         private int mBackgroundColor;
 
@@ -621,4 +706,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
index a09879d..5f1b1ec 100644
--- a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
+++ b/v7/mediarouter/src/android/support/v7/media/MediaRouter.java
@@ -1458,6 +1458,15 @@
             return mRoutes.get(index);
         }
 
+        /**
+         * Returns the routes in this group
+         *
+         * @return The list of the routes in this group
+         */
+        public List<RouteInfo> getRoutes() {
+            return mRoutes;
+        }
+
         @Override
         public String toString() {
             StringBuilder sb = new StringBuilder(super.toString());