SampleMediaRouterActivity.java revision 9a2de97bec8126f8c8c05e9c995f378c5a73319a
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 17package com.example.android.supportv7.media; 18 19import com.example.android.supportv7.R; 20 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.DialogInterface; 24import android.content.Intent; 25import android.content.res.Resources; 26import android.app.PendingIntent; 27import android.media.AudioManager; 28import android.media.AudioManager.OnAudioFocusChangeListener; 29import android.media.MediaMetadataRetriever; 30import android.media.RemoteControlClient; 31import android.net.Uri; 32import android.os.Build; 33import android.os.Environment; 34import android.os.Handler; 35import android.os.Bundle; 36import android.os.SystemClock; 37import android.support.v4.app.FragmentManager; 38import android.support.v4.media.session.MediaSessionCompat; 39import android.support.v4.view.MenuItemCompat; 40import android.support.v7.app.ActionBarActivity; 41import android.support.v7.app.MediaRouteActionProvider; 42import android.support.v7.app.MediaRouteButton; 43import android.support.v7.app.MediaRouteControllerDialog; 44import android.support.v7.app.MediaRouteControllerDialogFragment; 45import android.support.v7.app.MediaRouteDiscoveryFragment; 46import android.support.v7.app.MediaRouteDialogFactory; 47import android.support.v7.media.MediaControlIntent; 48import android.support.v7.media.MediaRouter; 49import android.support.v7.media.MediaRouter.Callback; 50import android.support.v7.media.MediaRouter.RouteInfo; 51import android.support.v7.media.MediaRouter.ProviderInfo; 52import android.support.v7.media.MediaRouteSelector; 53import android.support.v7.media.MediaItemStatus; 54import android.util.Log; 55import android.view.KeyEvent; 56import android.view.Menu; 57import android.view.MenuItem; 58import android.view.View; 59import android.view.View.OnClickListener; 60import android.view.ViewGroup; 61import android.widget.AdapterView; 62import android.widget.AdapterView.OnItemClickListener; 63import android.widget.ArrayAdapter; 64import android.widget.ImageButton; 65import android.widget.ListView; 66import android.widget.TextView; 67import android.widget.TabHost; 68import android.widget.TabHost.TabSpec; 69import android.widget.TabHost.OnTabChangeListener; 70import android.widget.SeekBar; 71import android.widget.SeekBar.OnSeekBarChangeListener; 72 73import 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 */ 84public 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 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 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 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 468 public boolean onKeyDown(int keyCode, KeyEvent event) { 469 return handleMediaKey(event) || super.onKeyDown(keyCode, event); 470 } 471 472 @Override 473 public boolean onKeyUp(int keyCode, KeyEvent event) { 474 return handleMediaKey(event) || super.onKeyUp(keyCode, event); 475 } 476 477 @Override 478 public void onStart() { 479 // Be sure to call the super class. 480 super.onStart(); 481 } 482 483 @Override 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 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 504 public void onDestroy() { 505 mSessionManager.stop(); 506 mPlayer.release(); 507 mMediaSession.release(); 508 super.onDestroy(); 509 } 510 511 @Override 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 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 558 private void updateUi() { 559 updatePlaylist(); 560 updateRouteDescription(); 561 updateButtons(); 562 if (mPlayer != null) { 563 mPlayer.updateMetadata(); 564 } 565 } 566 567 private void updatePlaylist() { 568 mPlayListItems.clear(); 569 for (PlaylistItem item : mSessionManager.getPlaylist()) { 570 mPlayListItems.add(item); 571 } 572 mPlayListView.invalidate(); 573 } 574 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 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 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 610 public DiscoveryFragment() { 611 mCallback = null; 612 } 613 614 public DiscoveryFragment(Callback cb) { 615 mCallback = cb; 616 } 617 618 public void setCallback(Callback cb) { 619 mCallback = cb; 620 } 621 622 @Override 623 public Callback onCreateCallback() { 624 return mCallback; 625 } 626 627 @Override 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 643 public MediaItem(String name, Uri uri, String mime) { 644 mName = name; 645 mUri = uri; 646 mMime = mime; 647 } 648 649 @Override 650 public String toString() { 651 return mName; 652 } 653 } 654 655 private final class LibraryAdapter extends ArrayAdapter<MediaItem> { 656 public LibraryAdapter() { 657 super(SampleMediaRouterActivity.this, R.layout.media_item); 658 } 659 660 @Override 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> { 691 public PlaylistAdapter() { 692 super(SampleMediaRouterActivity.this, R.layout.media_item); 693 } 694 695 @Override 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 743 public ControllerDialogFragment() { 744 super(); 745 } 746 747 public ControllerDialogFragment(Player player) { 748 mPlayer = player; 749 } 750 751 @Override 752 public MediaRouteControllerDialog onCreateControllerDialog( 753 Context context, Bundle savedInstanceState) { 754 mControllerDialog = super.onCreateControllerDialog(context, 755 savedInstanceState); 756 if (mPlayer != null) { 757 mControllerDialog.setMediaSession(mPlayer.getMediaSession().getSessionToken()); 758 } 759 mControllerDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { 760 @Override 761 public void onDismiss(DialogInterface dialog) { 762 mControllerDialog = null; 763 } 764 }); 765 return mControllerDialog; 766 } 767 768 public void setPlayer(Player player) { 769 mPlayer = player; 770 if (mControllerDialog != null) { 771 mControllerDialog.setMediaSession(mPlayer.getMediaSession().getSessionToken()); 772 } 773 } 774 } 775} 776