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