1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.supportv7.media;
18 
19 import android.app.PendingIntent;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.DialogInterface;
23 import android.content.Intent;
24 import android.media.AudioManager;
25 import android.media.AudioManager.OnAudioFocusChangeListener;
26 import android.net.Uri;
27 import android.os.Bundle;
28 import android.os.Environment;
29 import android.os.Handler;
30 import android.os.SystemClock;
31 import android.support.v4.media.session.MediaSessionCompat;
32 import android.support.v4.view.MenuItemCompat;
33 import android.support.v7.app.AppCompatActivity;
34 import android.support.v7.app.MediaRouteActionProvider;
35 import android.support.v7.app.MediaRouteControllerDialog;
36 import android.support.v7.app.MediaRouteControllerDialogFragment;
37 import android.support.v7.app.MediaRouteDialogFactory;
38 import android.support.v7.media.MediaControlIntent;
39 import android.support.v7.media.MediaItemStatus;
40 import android.support.v7.media.MediaRouteSelector;
41 import android.support.v7.media.MediaRouter;
42 import android.support.v7.media.MediaRouter.ProviderInfo;
43 import android.support.v7.media.MediaRouter.RouteInfo;
44 import android.util.Log;
45 import android.view.KeyEvent;
46 import android.view.Menu;
47 import android.view.MenuItem;
48 import android.view.View;
49 import android.view.View.OnClickListener;
50 import android.view.ViewGroup;
51 import android.widget.AdapterView;
52 import android.widget.AdapterView.OnItemClickListener;
53 import android.widget.ArrayAdapter;
54 import android.widget.CheckBox;
55 import android.widget.ImageButton;
56 import android.widget.ListView;
57 import android.widget.SeekBar;
58 import android.widget.SeekBar.OnSeekBarChangeListener;
59 import android.widget.TabHost;
60 import android.widget.TabHost.OnTabChangeListener;
61 import android.widget.TabHost.TabSpec;
62 import android.widget.TextView;
63 
64 import com.example.android.supportv7.R;
65 
66 import java.io.File;
67 
68 /**
69  * <h3>Media Router Support Activity</h3>
70  *
71  * <p>
72  * This demonstrates how to use the {@link MediaRouter} API to build an
73  * application that allows the user to send content to various rendering
74  * targets.
75  * </p>
76  */
77 public class SampleMediaRouterActivity extends AppCompatActivity {
78     private static final String TAG = "SampleMediaRouterActivity";
79     private static final String DISCOVERY_FRAGMENT_TAG = "DiscoveryFragment";
80     private static final boolean ENABLE_DEFAULT_CONTROL_CHECK_BOX = false;
81 
82     private MediaRouter mMediaRouter;
83     private MediaRouteSelector mSelector;
84     private LibraryAdapter mLibraryItems;
85     private PlaylistAdapter mPlayListItems;
86     private TextView mInfoTextView;
87     private ListView mLibraryView;
88     private ListView mPlayListView;
89     private CheckBox mUseDefaultControlCheckBox;
90     private ImageButton mPauseResumeButton;
91     private ImageButton mStopButton;
92     private SeekBar mSeekBar;
93     private boolean mNeedResume;
94     private boolean mSeeking;
95 
96     private final Handler mHandler = new Handler();
97     private final Runnable mUpdateSeekRunnable = new Runnable() {
98         @Override
99         public void run() {
100             updateProgress();
101             // update Ui every 1 second
102             mHandler.postDelayed(this, 1000);
103         }
104     };
105 
106     private final SessionManager mSessionManager = new SessionManager("app");
107     private Player mPlayer;
108 
109     private final MediaRouter.Callback mMediaRouterCB = new MediaRouter.Callback() {
110         // Return a custom callback that will simply log all of the route events
111         // for demonstration purposes.
112         @Override
113         public void onRouteAdded(MediaRouter router, RouteInfo route) {
114             Log.d(TAG, "onRouteAdded: route=" + route);
115         }
116 
117         @Override
118         public void onRouteChanged(MediaRouter router, RouteInfo route) {
119             Log.d(TAG, "onRouteChanged: route=" + route);
120         }
121 
122         @Override
123         public void onRouteRemoved(MediaRouter router, RouteInfo route) {
124             Log.d(TAG, "onRouteRemoved: route=" + route);
125         }
126 
127         @Override
128         public void onRouteSelected(MediaRouter router, RouteInfo route) {
129             Log.d(TAG, "onRouteSelected: route=" + route);
130 
131             mPlayer = Player.create(SampleMediaRouterActivity.this, route, mMediaSession);
132             mPlayer.updatePresentation();
133             mSessionManager.setPlayer(mPlayer);
134             mSessionManager.unsuspend();
135 
136             updateUi();
137         }
138 
139         @Override
140         public void onRouteUnselected(MediaRouter router, RouteInfo route) {
141             Log.d(TAG, "onRouteUnselected: route=" + route);
142             mMediaSession.setActive(false);
143 
144             PlaylistItem item = getCheckedPlaylistItem();
145             if (item != null) {
146                 long pos = item.getPosition() + (mSessionManager.isPaused() ?
147                         0 : (SystemClock.elapsedRealtime() - item.getTimestamp()));
148                 mSessionManager.suspend(pos);
149             }
150             mPlayer.updatePresentation();
151             mPlayer.release();
152         }
153 
154         @Override
155         public void onRouteVolumeChanged(MediaRouter router, RouteInfo route) {
156             Log.d(TAG, "onRouteVolumeChanged: route=" + route);
157         }
158 
159         @Override
160         public void onRoutePresentationDisplayChanged(
161                 MediaRouter router, RouteInfo route) {
162             Log.d(TAG, "onRoutePresentationDisplayChanged: route=" + route);
163             mPlayer.updatePresentation();
164         }
165 
166         @Override
167         public void onProviderAdded(MediaRouter router, ProviderInfo provider) {
168             Log.d(TAG, "onRouteProviderAdded: provider=" + provider);
169         }
170 
171         @Override
172         public void onProviderRemoved(MediaRouter router, ProviderInfo provider) {
173             Log.d(TAG, "onRouteProviderRemoved: provider=" + provider);
174         }
175 
176         @Override
177         public void onProviderChanged(MediaRouter router, ProviderInfo provider) {
178             Log.d(TAG, "onRouteProviderChanged: provider=" + provider);
179         }
180     };
181 
182     private MediaSessionCompat mMediaSession;
183     private ComponentName mEventReceiver;
184     private AudioManager mAudioManager;
185     private PendingIntent mMediaPendingIntent;
186     private final OnAudioFocusChangeListener mAfChangeListener =
187             new OnAudioFocusChangeListener() {
188         @Override
189         public void onAudioFocusChange(int focusChange) {
190             if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
191                 Log.d(TAG, "onAudioFocusChange: LOSS_TRANSIENT");
192             } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
193                 Log.d(TAG, "onAudioFocusChange: AUDIOFOCUS_GAIN");
194             } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
195                 Log.d(TAG, "onAudioFocusChange: AUDIOFOCUS_LOSS");
196             }
197         }
198     };
199 
200     @Override
onCreate(Bundle savedInstanceState)201     protected void onCreate(Bundle savedInstanceState) {
202         // Be sure to call the super class.
203         super.onCreate(savedInstanceState);
204 
205         // Get the media router service.
206         mMediaRouter = MediaRouter.getInstance(this);
207 
208         // Create a route selector for the type of routes that we care about.
209         mSelector = new MediaRouteSelector.Builder()
210                 .addControlCategory(MediaControlIntent.CATEGORY_LIVE_AUDIO)
211                 .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)
212                 .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
213                 .addControlCategory(SampleMediaRouteProvider.CATEGORY_SAMPLE_ROUTE)
214                 .build();
215         mMediaRouter.addCallback(mSelector, mMediaRouterCB);
216 
217         // Populate an array adapter with streaming media items.
218         String[] mediaNames = getResources().getStringArray(R.array.media_names);
219         String[] mediaUris = getResources().getStringArray(R.array.media_uris);
220         mLibraryItems = new LibraryAdapter();
221         for (int i = 0; i < mediaNames.length; i++) {
222             mLibraryItems.add(new MediaItem(
223                     "[streaming] "+mediaNames[i], Uri.parse(mediaUris[i]), "video/mp4"));
224         }
225 
226         // Scan local external storage directory for media files.
227         File externalDir = Environment.getExternalStorageDirectory();
228         if (externalDir != null) {
229             File list[] = externalDir.listFiles();
230             if (list != null) {
231                 for (int i = 0; i < list.length; i++) {
232                     String filename = list[i].getName();
233                     if (filename.matches(".*\\.(m4v|mp4)")) {
234                         mLibraryItems.add(new MediaItem("[local] " + filename,
235                                 Uri.fromFile(list[i]), "video/mp4"));
236                     }
237                 }
238             }
239         }
240 
241         mPlayListItems = new PlaylistAdapter();
242 
243         // Initialize the layout.
244         setContentView(R.layout.sample_media_router);
245 
246         TabHost tabHost=(TabHost)findViewById(R.id.tabHost);
247         tabHost.setup();
248         String tabName = getResources().getString(R.string.library_tab_text);
249         TabSpec spec1=tabHost.newTabSpec(tabName);
250         spec1.setContent(R.id.tab1);
251         spec1.setIndicator(tabName);
252 
253         tabName = getResources().getString(R.string.playlist_tab_text);
254         TabSpec spec2=tabHost.newTabSpec(tabName);
255         spec2.setIndicator(tabName);
256         spec2.setContent(R.id.tab2);
257 
258         tabName = getResources().getString(R.string.info_tab_text);
259         TabSpec spec3=tabHost.newTabSpec(tabName);
260         spec3.setIndicator(tabName);
261         spec3.setContent(R.id.tab3);
262 
263         tabHost.addTab(spec1);
264         tabHost.addTab(spec2);
265         tabHost.addTab(spec3);
266         tabHost.setOnTabChangedListener(new OnTabChangeListener() {
267             @Override
268             public void onTabChanged(String arg0) {
269                 updateUi();
270             }
271         });
272 
273         mLibraryView = (ListView) findViewById(R.id.media);
274         mLibraryView.setAdapter(mLibraryItems);
275         mLibraryView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
276         mLibraryView.setOnItemClickListener(new OnItemClickListener() {
277             @Override
278             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
279                 updateButtons();
280             }
281         });
282 
283         mPlayListView = (ListView) findViewById(R.id.playlist);
284         mPlayListView.setAdapter(mPlayListItems);
285         mPlayListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
286         mPlayListView.setOnItemClickListener(new OnItemClickListener() {
287             @Override
288             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
289                 updateButtons();
290             }
291         });
292 
293         mInfoTextView = (TextView) findViewById(R.id.info);
294 
295         mUseDefaultControlCheckBox = (CheckBox) findViewById(R.id.custom_control_view_checkbox);
296         if (ENABLE_DEFAULT_CONTROL_CHECK_BOX) {
297             mUseDefaultControlCheckBox.setVisibility(View.VISIBLE);
298         }
299         mPauseResumeButton = (ImageButton)findViewById(R.id.pause_resume_button);
300         mPauseResumeButton.setOnClickListener(new OnClickListener() {
301             @Override
302             public void onClick(View v) {
303                 if (mSessionManager.isPaused()) {
304                     mSessionManager.resume();
305                 } else {
306                     mSessionManager.pause();
307                 }
308             }
309         });
310 
311         mStopButton = (ImageButton)findViewById(R.id.stop_button);
312         mStopButton.setOnClickListener(new OnClickListener() {
313             @Override
314             public void onClick(View v) {
315                 mSessionManager.stop();
316             }
317         });
318 
319         mSeekBar = (SeekBar) findViewById(R.id.seekbar);
320         mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
321             @Override
322             public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
323                 PlaylistItem item = getCheckedPlaylistItem();
324                 if (fromUser && item != null && item.getDuration() > 0) {
325                     long pos = progress * item.getDuration() / 100;
326                     mSessionManager.seek(item.getItemId(), pos);
327                     item.setPosition(pos);
328                     item.setTimestamp(SystemClock.elapsedRealtime());
329                 }
330             }
331             @Override
332             public void onStartTrackingTouch(SeekBar seekBar) {
333                 mSeeking = true;
334             }
335             @Override
336             public void onStopTrackingTouch(SeekBar seekBar) {
337                 mSeeking = false;
338                 updateUi();
339             }
340         });
341 
342         // Schedule Ui update
343         mHandler.postDelayed(mUpdateSeekRunnable, 1000);
344 
345         // Build the PendingIntent for the remote control client
346         mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
347         mEventReceiver = new ComponentName(getPackageName(),
348                 SampleMediaButtonReceiver.class.getName());
349         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
350         mediaButtonIntent.setComponent(mEventReceiver);
351         mMediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
352 
353         // Create and register the remote control client
354         createMediaSession();
355         mMediaRouter.setMediaSessionCompat(mMediaSession);
356 
357         // Set up playback manager and player
358         mPlayer = Player.create(SampleMediaRouterActivity.this,
359                 mMediaRouter.getSelectedRoute(), mMediaSession);
360 
361         mSessionManager.setPlayer(mPlayer);
362         mSessionManager.setCallback(new SessionManager.Callback() {
363             @Override
364             public void onStatusChanged() {
365                 updateUi();
366             }
367 
368             @Override
369             public void onItemChanged(PlaylistItem item) {
370             }
371         });
372 
373         updateUi();
374     }
375 
createMediaSession()376     private void createMediaSession() {
377         // Create the MediaSession
378         mMediaSession = new MediaSessionCompat(this, "SampleMediaRouter", mEventReceiver,
379                 mMediaPendingIntent);
380         mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
381                 | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
382         mMediaSession.setCallback(new MediaSessionCompat.Callback() {
383             @Override
384             public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
385                 if (mediaButtonEvent != null) {
386                     return handleMediaKey(
387                             (KeyEvent) mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
388                 }
389                 return super.onMediaButtonEvent(mediaButtonEvent);
390             }
391 
392             @Override
393             public void onPlay() {
394                 mSessionManager.resume();
395             }
396 
397             @Override
398             public void onPause() {
399                 mSessionManager.pause();
400             }
401         });
402 
403         SampleMediaButtonReceiver.setActivity(SampleMediaRouterActivity.this);
404     }
405 
handleMediaKey(KeyEvent event)406     public boolean handleMediaKey(KeyEvent event) {
407         if (event != null && event.getAction() == KeyEvent.ACTION_DOWN
408                 && event.getRepeatCount() == 0) {
409             switch (event.getKeyCode()) {
410                 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
411                 case KeyEvent.KEYCODE_HEADSETHOOK:
412                 {
413                     Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
414                     if (mSessionManager.isPaused()) {
415                         mSessionManager.resume();
416                     } else {
417                         mSessionManager.pause();
418                     }
419                     return true;
420                 }
421                 case KeyEvent.KEYCODE_MEDIA_PLAY:
422                 {
423                     Log.d(TAG, "Received Play event from RemoteControlClient");
424                     if (mSessionManager.isPaused()) {
425                         mSessionManager.resume();
426                     }
427                     return true;
428                 }
429                 case KeyEvent.KEYCODE_MEDIA_PAUSE:
430                 {
431                     Log.d(TAG, "Received Pause event from RemoteControlClient");
432                     if (!mSessionManager.isPaused()) {
433                         mSessionManager.pause();
434                     }
435                     return true;
436                 }
437                 case KeyEvent.KEYCODE_MEDIA_STOP:
438                 {
439                     Log.d(TAG, "Received Stop event from RemoteControlClient");
440                     mSessionManager.stop();
441                     return true;
442                 }
443                 default:
444                     break;
445             }
446         }
447         return false;
448     }
449 
450     @Override
onKeyDown(int keyCode, KeyEvent event)451     public boolean onKeyDown(int keyCode, KeyEvent event) {
452         return handleMediaKey(event) || super.onKeyDown(keyCode, event);
453     }
454 
455     @Override
onKeyUp(int keyCode, KeyEvent event)456     public boolean onKeyUp(int keyCode, KeyEvent event) {
457         return handleMediaKey(event) || super.onKeyUp(keyCode, event);
458     }
459 
460     @Override
onStart()461     public void onStart() {
462         // Be sure to call the super class.
463         super.onStart();
464     }
465 
466     @Override
onPause()467     public void onPause() {
468         // pause media player for local playback case only
469         if (!mPlayer.isRemotePlayback() && !mSessionManager.isPaused()) {
470             mNeedResume = true;
471             mSessionManager.pause();
472         }
473         super.onPause();
474     }
475 
476     @Override
onResume()477     public void onResume() {
478         // resume media player for local playback case only
479         if (!mPlayer.isRemotePlayback() && mNeedResume) {
480             mSessionManager.resume();
481             mNeedResume = false;
482         }
483         super.onResume();
484     }
485 
486     @Override
onDestroy()487     public void onDestroy() {
488         mSessionManager.stop();
489         mPlayer.release();
490         mMediaSession.release();
491         super.onDestroy();
492     }
493 
494     @Override
onCreateOptionsMenu(Menu menu)495     public boolean onCreateOptionsMenu(Menu menu) {
496         // Be sure to call the super class.
497         super.onCreateOptionsMenu(menu);
498 
499         // Inflate the menu and configure the media router action provider.
500         getMenuInflater().inflate(R.menu.sample_media_router_menu, menu);
501 
502         MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
503         MyMediaRouteActionProvider mediaRouteActionProvider =
504                 (MyMediaRouteActionProvider)MenuItemCompat.getActionProvider(mediaRouteMenuItem);
505         mediaRouteActionProvider.setRouteSelector(mSelector);
506         mediaRouteActionProvider.setDialogFactory(new MediaRouteDialogFactory() {
507             @Override
508             public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
509                 return new ControllerDialogFragment(mPlayer, mUseDefaultControlCheckBox);
510             }
511         });
512 
513         // Return true to show the menu.
514         return true;
515     }
516 
updateProgress()517     private void updateProgress() {
518         // Estimate content position from last status time and elapsed time.
519         // (Note this might be slightly out of sync with remote side, however
520         // it avoids frequent polling the MRP.)
521         int progress = 0;
522         PlaylistItem item = getCheckedPlaylistItem();
523         if (item != null) {
524             int state = item.getState();
525             long duration = item.getDuration();
526             if (duration <= 0) {
527                 if (state == MediaItemStatus.PLAYBACK_STATE_PLAYING
528                         || state == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
529                     mSessionManager.updateStatus();
530                 }
531             } else {
532                 long position = item.getPosition();
533                 long timeDelta = mSessionManager.isPaused() ? 0 :
534                         (SystemClock.elapsedRealtime() - item.getTimestamp());
535                 progress = (int)(100.0 * (position + timeDelta) / duration);
536             }
537         }
538         mSeekBar.setProgress(progress);
539     }
540 
updateUi()541     private void updateUi() {
542         updatePlaylist();
543         updateRouteDescription();
544         updateButtons();
545         if (mPlayer != null) {
546             mPlayer.updateMetadata();
547         }
548     }
549 
updatePlaylist()550     private void updatePlaylist() {
551         mPlayListItems.clear();
552         for (PlaylistItem item : mSessionManager.getPlaylist()) {
553             mPlayListItems.add(item);
554         }
555         mPlayListView.invalidate();
556     }
557 
updateRouteDescription()558     private void updateRouteDescription() {
559         RouteInfo route = mMediaRouter.getSelectedRoute();
560         mInfoTextView.setText("Currently selected route:"
561                 + "\nName: " + route.getName()
562                 + "\nProvider: " + route.getProvider().getPackageName()
563                 + "\nDescription: " + route.getDescription());
564     }
565 
updateButtons()566     private void updateButtons() {
567         MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute();
568         // show pause or resume icon depending on current state
569         mPauseResumeButton.setImageResource(mSessionManager.isPaused() ?
570                 R.drawable.ic_media_play : R.drawable.ic_media_pause);
571         // only enable seek bar when duration is known
572         PlaylistItem item = getCheckedPlaylistItem();
573         mSeekBar.setEnabled(item != null && item.getDuration() > 0);
574     }
575 
getCheckedPlaylistItem()576     private PlaylistItem getCheckedPlaylistItem() {
577         int count = mPlayListView.getCount();
578         int index = mPlayListView.getCheckedItemPosition();
579         if (count > 0) {
580             if (index < 0 || index >= count) {
581                 index = 0;
582                 mPlayListView.setItemChecked(0, true);
583             }
584             return mPlayListItems.getItem(index);
585         }
586         return null;
587     }
588 
589     private static final class MediaItem {
590         public final String mName;
591         public final Uri mUri;
592         public final String mMime;
593 
MediaItem(String name, Uri uri, String mime)594         public MediaItem(String name, Uri uri, String mime) {
595             mName = name;
596             mUri = uri;
597             mMime = mime;
598         }
599 
600         @Override
toString()601         public String toString() {
602             return mName;
603         }
604     }
605 
606     private final class LibraryAdapter extends ArrayAdapter<MediaItem> {
LibraryAdapter()607         public LibraryAdapter() {
608             super(SampleMediaRouterActivity.this, R.layout.media_item);
609         }
610 
611         @Override
getView(int position, View convertView, ViewGroup parent)612         public View getView(int position, View convertView, ViewGroup parent) {
613             final View v;
614             if (convertView == null) {
615                 v = getLayoutInflater().inflate(R.layout.media_item, null);
616             } else {
617                 v = convertView;
618             }
619 
620             final MediaItem item = getItem(position);
621 
622             TextView tv = (TextView)v.findViewById(R.id.item_text);
623             tv.setText(item.mName);
624 
625             ImageButton b = (ImageButton)v.findViewById(R.id.item_action);
626             b.setImageResource(R.drawable.ic_menu_add);
627             b.setTag(item);
628             b.setOnClickListener(new OnClickListener() {
629                 @Override
630                 public void onClick(View v) {
631                     if (item != null) {
632                         mSessionManager.add(item.mUri, item.mMime);
633                     }
634                 }
635             });
636 
637             return v;
638         }
639     }
640 
641     private final class PlaylistAdapter extends ArrayAdapter<PlaylistItem> {
PlaylistAdapter()642         public PlaylistAdapter() {
643             super(SampleMediaRouterActivity.this, R.layout.media_item);
644         }
645 
646         @Override
getView(int position, View convertView, ViewGroup parent)647         public View getView(int position, View convertView, ViewGroup parent) {
648             final View v;
649             if (convertView == null) {
650                 v = getLayoutInflater().inflate(R.layout.media_item, null);
651             } else {
652                 v = convertView;
653             }
654 
655             final PlaylistItem item = getItem(position);
656 
657             TextView tv = (TextView)v.findViewById(R.id.item_text);
658             tv.setText(item.toString());
659 
660             ImageButton b = (ImageButton)v.findViewById(R.id.item_action);
661             b.setImageResource(R.drawable.ic_menu_delete);
662             b.setTag(item);
663             b.setOnClickListener(new OnClickListener() {
664                 @Override
665                 public void onClick(View v) {
666                     if (item != null) {
667                         mSessionManager.remove(item.getItemId());
668                     }
669                 }
670             });
671 
672             return v;
673         }
674     }
675 
676     /**
677      * Trivial subclass of this activity used to provide another copy of the
678      * same activity using a light theme instead of the dark theme.
679      */
680     public static class Light extends SampleMediaRouterActivity {
681     }
682 
683     /**
684      * Trivial subclass of this activity used to provide another copy of the
685      * same activity using a light theme with dark action bar instead of the dark theme.
686      */
687     public static class LightWithDarkActionBar extends SampleMediaRouterActivity {
688     }
689 
690     public static class MyMediaRouteActionProvider extends MediaRouteActionProvider {
MyMediaRouteActionProvider(Context context)691         public MyMediaRouteActionProvider(Context context) {
692             super(context);
693         }
694 
695         @Override
isVisible()696         public boolean isVisible() {
697             return true;
698         }
699     }
700 
701     public static class ControllerDialogFragment extends MediaRouteControllerDialogFragment {
702         private MediaRouteControllerDialog mControllerDialog;
703         private Player mPlayer;
704         private CheckBox mUseDefaultControlCheckBox;
705 
ControllerDialogFragment()706         public ControllerDialogFragment() {
707             super();
708         }
709 
ControllerDialogFragment(Player player, CheckBox customControlViewCheckBox)710         public ControllerDialogFragment(Player player, CheckBox customControlViewCheckBox) {
711             mPlayer = player;
712             this.mUseDefaultControlCheckBox = customControlViewCheckBox;
713         }
714 
715         @Override
onCreateControllerDialog( Context context, Bundle savedInstanceState)716         public MediaRouteControllerDialog onCreateControllerDialog(
717                 Context context, Bundle savedInstanceState) {
718             mControllerDialog = this.mUseDefaultControlCheckBox.isChecked()
719                     ? super.onCreateControllerDialog(context, savedInstanceState)
720                     : new MyMediaRouteControllerDialog(context);
721             mControllerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
722                 @Override
723                 public void onDismiss(DialogInterface dialog) {
724                     mControllerDialog = null;
725                 }
726             });
727             return mControllerDialog;
728         }
729 
setPlayer(Player player)730         public void setPlayer(Player player) {
731             mPlayer = player;
732         }
733     }
734 }
735