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