• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.example.android.supportv7.R;
20 
21 import android.app.PendingIntent;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.media.AudioManager;
27 import android.media.AudioManager.OnAudioFocusChangeListener;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.os.Environment;
31 import android.os.Handler;
32 import android.os.SystemClock;
33 import android.support.v4.app.FragmentManager;
34 import android.support.v4.media.session.MediaSessionCompat;
35 import android.support.v4.view.MenuItemCompat;
36 import android.support.v7.app.AppCompatActivity;
37 import android.support.v7.app.MediaRouteActionProvider;
38 import android.support.v7.app.MediaRouteControllerDialog;
39 import android.support.v7.app.MediaRouteControllerDialogFragment;
40 import android.support.v7.app.MediaRouteDialogFactory;
41 import android.support.v7.app.MediaRouteDiscoveryFragment;
42 import android.support.v7.media.MediaControlIntent;
43 import android.support.v7.media.MediaItemStatus;
44 import android.support.v7.media.MediaRouteSelector;
45 import android.support.v7.media.MediaRouter;
46 import android.support.v7.media.MediaRouter.Callback;
47 import android.support.v7.media.MediaRouter.ProviderInfo;
48 import android.support.v7.media.MediaRouter.RouteInfo;
49 import android.util.Log;
50 import android.view.KeyEvent;
51 import android.view.Menu;
52 import android.view.MenuItem;
53 import android.view.View;
54 import android.view.View.OnClickListener;
55 import android.view.ViewGroup;
56 import android.widget.AdapterView;
57 import android.widget.AdapterView.OnItemClickListener;
58 import android.widget.ArrayAdapter;
59 import android.widget.ImageButton;
60 import android.widget.ListView;
61 import android.widget.SeekBar;
62 import android.widget.SeekBar.OnSeekBarChangeListener;
63 import android.widget.TabHost;
64 import android.widget.TabHost.OnTabChangeListener;
65 import android.widget.TabHost.TabSpec;
66 import android.widget.TextView;
67 
68 import java.io.File;
69 
70 /**
71  * <h3>Media Router Support Activity</h3>
72  *
73  * <p>
74  * This demonstrates how to use the {@link MediaRouter} API to build an
75  * application that allows the user to send content to various rendering
76  * targets.
77  * </p>
78  */
79 public class SampleMediaRouterActivity extends AppCompatActivity {
80     private static final String TAG = "SampleMediaRouterActivity";
81     private static final String DISCOVERY_FRAGMENT_TAG = "DiscoveryFragment";
82 
83     private MediaRouter mMediaRouter;
84     private MediaRouteSelector mSelector;
85     private LibraryAdapter mLibraryItems;
86     private PlaylistAdapter mPlayListItems;
87     private TextView mInfoTextView;
88     private ListView mLibraryView;
89     private ListView mPlayListView;
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 
216         // Add a fragment to take care of media route discovery.
217         // This fragment automatically adds or removes a callback whenever the activity
218         // is started or stopped.
219         FragmentManager fm = getSupportFragmentManager();
220         DiscoveryFragment fragment = (DiscoveryFragment)fm.findFragmentByTag(
221                 DISCOVERY_FRAGMENT_TAG);
222         if (fragment == null) {
223             fragment = new DiscoveryFragment(mMediaRouterCB);
224             fragment.setRouteSelector(mSelector);
225             fm.beginTransaction()
226                     .add(fragment, DISCOVERY_FRAGMENT_TAG)
227                     .commit();
228         } else {
229             fragment.setCallback(mMediaRouterCB);
230             fragment.setRouteSelector(mSelector);
231         }
232 
233         // Populate an array adapter with streaming media items.
234         String[] mediaNames = getResources().getStringArray(R.array.media_names);
235         String[] mediaUris = getResources().getStringArray(R.array.media_uris);
236         mLibraryItems = new LibraryAdapter();
237         for (int i = 0; i < mediaNames.length; i++) {
238             mLibraryItems.add(new MediaItem(
239                     "[streaming] "+mediaNames[i], Uri.parse(mediaUris[i]), "video/mp4"));
240         }
241 
242         // Scan local external storage directory for media files.
243         File externalDir = Environment.getExternalStorageDirectory();
244         if (externalDir != null) {
245             File list[] = externalDir.listFiles();
246             if (list != null) {
247                 for (int i = 0; i < list.length; i++) {
248                     String filename = list[i].getName();
249                     if (filename.matches(".*\\.(m4v|mp4)")) {
250                         mLibraryItems.add(new MediaItem("[local] " + filename,
251                                 Uri.fromFile(list[i]), "video/mp4"));
252                     }
253                 }
254             }
255         }
256 
257         mPlayListItems = new PlaylistAdapter();
258 
259         // Initialize the layout.
260         setContentView(R.layout.sample_media_router);
261 
262         TabHost tabHost=(TabHost)findViewById(R.id.tabHost);
263         tabHost.setup();
264         String tabName = getResources().getString(R.string.library_tab_text);
265         TabSpec spec1=tabHost.newTabSpec(tabName);
266         spec1.setContent(R.id.tab1);
267         spec1.setIndicator(tabName);
268 
269         tabName = getResources().getString(R.string.playlist_tab_text);
270         TabSpec spec2=tabHost.newTabSpec(tabName);
271         spec2.setIndicator(tabName);
272         spec2.setContent(R.id.tab2);
273 
274         tabName = getResources().getString(R.string.info_tab_text);
275         TabSpec spec3=tabHost.newTabSpec(tabName);
276         spec3.setIndicator(tabName);
277         spec3.setContent(R.id.tab3);
278 
279         tabHost.addTab(spec1);
280         tabHost.addTab(spec2);
281         tabHost.addTab(spec3);
282         tabHost.setOnTabChangedListener(new OnTabChangeListener() {
283             @Override
284             public void onTabChanged(String arg0) {
285                 updateUi();
286             }
287         });
288 
289         mLibraryView = (ListView) findViewById(R.id.media);
290         mLibraryView.setAdapter(mLibraryItems);
291         mLibraryView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
292         mLibraryView.setOnItemClickListener(new OnItemClickListener() {
293             @Override
294             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
295                 updateButtons();
296             }
297         });
298 
299         mPlayListView = (ListView) findViewById(R.id.playlist);
300         mPlayListView.setAdapter(mPlayListItems);
301         mPlayListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
302         mPlayListView.setOnItemClickListener(new OnItemClickListener() {
303             @Override
304             public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
305                 updateButtons();
306             }
307         });
308 
309         mInfoTextView = (TextView) findViewById(R.id.info);
310 
311         mPauseResumeButton = (ImageButton)findViewById(R.id.pause_resume_button);
312         mPauseResumeButton.setOnClickListener(new OnClickListener() {
313             @Override
314             public void onClick(View v) {
315                 if (mSessionManager.isPaused()) {
316                     mSessionManager.resume();
317                 } else {
318                     mSessionManager.pause();
319                 }
320             }
321         });
322 
323         mStopButton = (ImageButton)findViewById(R.id.stop_button);
324         mStopButton.setOnClickListener(new OnClickListener() {
325             @Override
326             public void onClick(View v) {
327                 mSessionManager.stop();
328             }
329         });
330 
331         mSeekBar = (SeekBar) findViewById(R.id.seekbar);
332         mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
333             @Override
334             public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
335                 PlaylistItem item = getCheckedPlaylistItem();
336                 if (fromUser && item != null && item.getDuration() > 0) {
337                     long pos = progress * item.getDuration() / 100;
338                     mSessionManager.seek(item.getItemId(), pos);
339                     item.setPosition(pos);
340                     item.setTimestamp(SystemClock.elapsedRealtime());
341                 }
342             }
343             @Override
344             public void onStartTrackingTouch(SeekBar seekBar) {
345                 mSeeking = true;
346             }
347             @Override
348             public void onStopTrackingTouch(SeekBar seekBar) {
349                 mSeeking = false;
350                 updateUi();
351             }
352         });
353 
354         // Schedule Ui update
355         mHandler.postDelayed(mUpdateSeekRunnable, 1000);
356 
357         // Build the PendingIntent for the remote control client
358         mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
359         mEventReceiver = new ComponentName(getPackageName(),
360                 SampleMediaButtonReceiver.class.getName());
361         Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
362         mediaButtonIntent.setComponent(mEventReceiver);
363         mMediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);
364 
365         // Create and register the remote control client
366         createMediaSession();
367         mMediaRouter.setMediaSessionCompat(mMediaSession);
368 
369         // Set up playback manager and player
370         mPlayer = Player.create(SampleMediaRouterActivity.this,
371                 mMediaRouter.getSelectedRoute(), mMediaSession);
372 
373         mSessionManager.setPlayer(mPlayer);
374         mSessionManager.setCallback(new SessionManager.Callback() {
375             @Override
376             public void onStatusChanged() {
377                 updateUi();
378             }
379 
380             @Override
381             public void onItemChanged(PlaylistItem item) {
382             }
383         });
384 
385         updateUi();
386     }
387 
createMediaSession()388     private void createMediaSession() {
389         // Create the MediaSession
390         mMediaSession = new MediaSessionCompat(this, "SampleMediaRouter", mEventReceiver,
391                 mMediaPendingIntent);
392         mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
393                 | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
394         mMediaSession.setCallback(new MediaSessionCompat.Callback() {
395             @Override
396             public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
397                 if (mediaButtonEvent != null) {
398                     return handleMediaKey(
399                             (KeyEvent) mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
400                 }
401                 return super.onMediaButtonEvent(mediaButtonEvent);
402             }
403 
404             @Override
405             public void onPlay() {
406                 mSessionManager.resume();
407             }
408 
409             @Override
410             public void onPause() {
411                 mSessionManager.pause();
412             }
413         });
414 
415         SampleMediaButtonReceiver.setActivity(SampleMediaRouterActivity.this);
416     }
417 
handleMediaKey(KeyEvent event)418     public boolean handleMediaKey(KeyEvent event) {
419         if (event != null && event.getAction() == KeyEvent.ACTION_DOWN
420                 && event.getRepeatCount() == 0) {
421             switch (event.getKeyCode()) {
422                 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
423                 case KeyEvent.KEYCODE_HEADSETHOOK:
424                 {
425                     Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
426                     if (mSessionManager.isPaused()) {
427                         mSessionManager.resume();
428                     } else {
429                         mSessionManager.pause();
430                     }
431                     return true;
432                 }
433                 case KeyEvent.KEYCODE_MEDIA_PLAY:
434                 {
435                     Log.d(TAG, "Received Play event from RemoteControlClient");
436                     if (mSessionManager.isPaused()) {
437                         mSessionManager.resume();
438                     }
439                     return true;
440                 }
441                 case KeyEvent.KEYCODE_MEDIA_PAUSE:
442                 {
443                     Log.d(TAG, "Received Pause event from RemoteControlClient");
444                     if (!mSessionManager.isPaused()) {
445                         mSessionManager.pause();
446                     }
447                     return true;
448                 }
449                 case KeyEvent.KEYCODE_MEDIA_STOP:
450                 {
451                     Log.d(TAG, "Received Stop event from RemoteControlClient");
452                     mSessionManager.stop();
453                     return true;
454                 }
455                 default:
456                     break;
457             }
458         }
459         return false;
460     }
461 
462     @Override
onKeyDown(int keyCode, KeyEvent event)463     public boolean onKeyDown(int keyCode, KeyEvent event) {
464         return handleMediaKey(event) || super.onKeyDown(keyCode, event);
465     }
466 
467     @Override
onKeyUp(int keyCode, KeyEvent event)468     public boolean onKeyUp(int keyCode, KeyEvent event) {
469         return handleMediaKey(event) || super.onKeyUp(keyCode, event);
470     }
471 
472     @Override
onStart()473     public void onStart() {
474         // Be sure to call the super class.
475         super.onStart();
476     }
477 
478     @Override
onPause()479     public void onPause() {
480         // pause media player for local playback case only
481         if (!mPlayer.isRemotePlayback() && !mSessionManager.isPaused()) {
482             mNeedResume = true;
483             mSessionManager.pause();
484         }
485         super.onPause();
486     }
487 
488     @Override
onResume()489     public void onResume() {
490         // resume media player for local playback case only
491         if (!mPlayer.isRemotePlayback() && mNeedResume) {
492             mSessionManager.resume();
493             mNeedResume = false;
494         }
495         super.onResume();
496     }
497 
498     @Override
onDestroy()499     public void onDestroy() {
500         mSessionManager.stop();
501         mPlayer.release();
502         mMediaSession.release();
503         super.onDestroy();
504     }
505 
506     @Override
onCreateOptionsMenu(Menu menu)507     public boolean onCreateOptionsMenu(Menu menu) {
508         // Be sure to call the super class.
509         super.onCreateOptionsMenu(menu);
510 
511         // Inflate the menu and configure the media router action provider.
512         getMenuInflater().inflate(R.menu.sample_media_router_menu, menu);
513 
514         MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item);
515         MediaRouteActionProvider mediaRouteActionProvider =
516                 (MediaRouteActionProvider)MenuItemCompat.getActionProvider(mediaRouteMenuItem);
517         mediaRouteActionProvider.setRouteSelector(mSelector);
518         mediaRouteActionProvider.setDialogFactory(new MediaRouteDialogFactory() {
519             @Override
520             public MediaRouteControllerDialogFragment onCreateControllerDialogFragment() {
521                 return new ControllerDialogFragment(mPlayer);
522             }
523         });
524 
525         // Return true to show the menu.
526         return true;
527     }
528 
updateProgress()529     private void updateProgress() {
530         // Estimate content position from last status time and elapsed time.
531         // (Note this might be slightly out of sync with remote side, however
532         // it avoids frequent polling the MRP.)
533         int progress = 0;
534         PlaylistItem item = getCheckedPlaylistItem();
535         if (item != null) {
536             int state = item.getState();
537             long duration = item.getDuration();
538             if (duration <= 0) {
539                 if (state == MediaItemStatus.PLAYBACK_STATE_PLAYING
540                         || state == MediaItemStatus.PLAYBACK_STATE_PAUSED) {
541                     mSessionManager.updateStatus();
542                 }
543             } else {
544                 long position = item.getPosition();
545                 long timeDelta = mSessionManager.isPaused() ? 0 :
546                         (SystemClock.elapsedRealtime() - item.getTimestamp());
547                 progress = (int)(100.0 * (position + timeDelta) / duration);
548             }
549         }
550         mSeekBar.setProgress(progress);
551     }
552 
updateUi()553     private void updateUi() {
554         updatePlaylist();
555         updateRouteDescription();
556         updateButtons();
557         if (mPlayer != null) {
558             mPlayer.updateMetadata();
559         }
560     }
561 
updatePlaylist()562     private void updatePlaylist() {
563         mPlayListItems.clear();
564         for (PlaylistItem item : mSessionManager.getPlaylist()) {
565             mPlayListItems.add(item);
566         }
567         mPlayListView.invalidate();
568     }
569 
updateRouteDescription()570     private void updateRouteDescription() {
571         RouteInfo route = mMediaRouter.getSelectedRoute();
572         mInfoTextView.setText("Currently selected route:"
573                 + "\nName: " + route.getName()
574                 + "\nProvider: " + route.getProvider().getPackageName()
575                 + "\nDescription: " + route.getDescription());
576     }
577 
updateButtons()578     private void updateButtons() {
579         MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute();
580         // show pause or resume icon depending on current state
581         mPauseResumeButton.setImageResource(mSessionManager.isPaused() ?
582                 R.drawable.ic_media_play : R.drawable.ic_media_pause);
583         // only enable seek bar when duration is known
584         PlaylistItem item = getCheckedPlaylistItem();
585         mSeekBar.setEnabled(item != null && item.getDuration() > 0);
586     }
587 
getCheckedPlaylistItem()588     private PlaylistItem getCheckedPlaylistItem() {
589         int count = mPlayListView.getCount();
590         int index = mPlayListView.getCheckedItemPosition();
591         if (count > 0) {
592             if (index < 0 || index >= count) {
593                 index = 0;
594                 mPlayListView.setItemChecked(0, true);
595             }
596             return mPlayListItems.getItem(index);
597         }
598         return null;
599     }
600 
601     public static final class DiscoveryFragment extends MediaRouteDiscoveryFragment {
602         private static final String TAG = "DiscoveryFragment";
603         private Callback mCallback;
604 
DiscoveryFragment()605         public DiscoveryFragment() {
606             mCallback = null;
607         }
608 
DiscoveryFragment(Callback cb)609         public DiscoveryFragment(Callback cb) {
610             mCallback = cb;
611         }
612 
setCallback(Callback cb)613         public void setCallback(Callback cb) {
614             mCallback = cb;
615         }
616 
617         @Override
onCreateCallback()618         public Callback onCreateCallback() {
619             return mCallback;
620         }
621 
622         @Override
onPrepareCallbackFlags()623         public int onPrepareCallbackFlags() {
624             // Add the CALLBACK_FLAG_UNFILTERED_EVENTS flag to ensure that we will
625             // observe and log all route events including those that are for routes
626             // that do not match our selector.  This is only for demonstration purposes
627             // and should not be needed by most applications.
628             return super.onPrepareCallbackFlags()
629                     | MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS;
630         }
631     }
632 
633     private static final class MediaItem {
634         public final String mName;
635         public final Uri mUri;
636         public final String mMime;
637 
MediaItem(String name, Uri uri, String mime)638         public MediaItem(String name, Uri uri, String mime) {
639             mName = name;
640             mUri = uri;
641             mMime = mime;
642         }
643 
644         @Override
toString()645         public String toString() {
646             return mName;
647         }
648     }
649 
650     private final class LibraryAdapter extends ArrayAdapter<MediaItem> {
LibraryAdapter()651         public LibraryAdapter() {
652             super(SampleMediaRouterActivity.this, R.layout.media_item);
653         }
654 
655         @Override
getView(int position, View convertView, ViewGroup parent)656         public View getView(int position, View convertView, ViewGroup parent) {
657             final View v;
658             if (convertView == null) {
659                 v = getLayoutInflater().inflate(R.layout.media_item, null);
660             } else {
661                 v = convertView;
662             }
663 
664             final MediaItem item = getItem(position);
665 
666             TextView tv = (TextView)v.findViewById(R.id.item_text);
667             tv.setText(item.mName);
668 
669             ImageButton b = (ImageButton)v.findViewById(R.id.item_action);
670             b.setImageResource(R.drawable.ic_menu_add);
671             b.setTag(item);
672             b.setOnClickListener(new OnClickListener() {
673                 @Override
674                 public void onClick(View v) {
675                     if (item != null) {
676                         mSessionManager.add(item.mUri, item.mMime);
677                     }
678                 }
679             });
680 
681             return v;
682         }
683     }
684 
685     private final class PlaylistAdapter extends ArrayAdapter<PlaylistItem> {
PlaylistAdapter()686         public PlaylistAdapter() {
687             super(SampleMediaRouterActivity.this, R.layout.media_item);
688         }
689 
690         @Override
getView(int position, View convertView, ViewGroup parent)691         public View getView(int position, View convertView, ViewGroup parent) {
692             final View v;
693             if (convertView == null) {
694                 v = getLayoutInflater().inflate(R.layout.media_item, null);
695             } else {
696                 v = convertView;
697             }
698 
699             final PlaylistItem item = getItem(position);
700 
701             TextView tv = (TextView)v.findViewById(R.id.item_text);
702             tv.setText(item.toString());
703 
704             ImageButton b = (ImageButton)v.findViewById(R.id.item_action);
705             b.setImageResource(R.drawable.ic_menu_delete);
706             b.setTag(item);
707             b.setOnClickListener(new OnClickListener() {
708                 @Override
709                 public void onClick(View v) {
710                     if (item != null) {
711                         mSessionManager.remove(item.getItemId());
712                     }
713                 }
714             });
715 
716             return v;
717         }
718     }
719 
720     /**
721      * Trivial subclass of this activity used to provide another copy of the
722      * same activity using a light theme instead of the dark theme.
723      */
724     public static class Light extends SampleMediaRouterActivity {
725     }
726 
727     /**
728      * Trivial subclass of this activity used to provide another copy of the
729      * same activity using a light theme with dark action bar instead of the dark theme.
730      */
731     public static class LightWithDarkActionBar extends SampleMediaRouterActivity {
732     }
733 
734     public static class ControllerDialogFragment extends MediaRouteControllerDialogFragment {
735         private MediaRouteControllerDialog mControllerDialog;
736         private Player mPlayer;
737 
ControllerDialogFragment()738         public ControllerDialogFragment() {
739             super();
740         }
741 
ControllerDialogFragment(Player player)742         public ControllerDialogFragment(Player player) {
743             mPlayer = player;
744         }
745 
746         @Override
onCreateControllerDialog( Context context, Bundle savedInstanceState)747         public MediaRouteControllerDialog onCreateControllerDialog(
748                 Context context, Bundle savedInstanceState) {
749             mControllerDialog = super.onCreateControllerDialog(context,
750                     savedInstanceState);
751             mControllerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
752                 @Override
753                 public void onDismiss(DialogInterface dialog) {
754                     mControllerDialog = null;
755                 }
756             });
757             return mControllerDialog;
758         }
759 
setPlayer(Player player)760         public void setPlayer(Player player) {
761             mPlayer = player;
762         }
763     }
764 }
765