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