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