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.mediarouter.player; 18 19 import android.app.PendingIntent; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.media.AudioManager; 24 import android.media.AudioManager.OnAudioFocusChangeListener; 25 import android.media.RemoteControlClient; 26 import android.net.Uri; 27 import android.os.Build; 28 import android.os.Bundle; 29 import android.os.Environment; 30 import android.os.Handler; 31 import android.os.SystemClock; 32 import android.support.v4.app.FragmentManager; 33 import android.support.v4.view.MenuItemCompat; 34 import android.support.v7.app.AppCompatActivity; 35 import android.support.v7.app.MediaRouteActionProvider; 36 import android.support.v7.app.MediaRouteDiscoveryFragment; 37 import android.support.v7.media.MediaControlIntent; 38 import android.support.v7.media.MediaItemStatus; 39 import android.support.v7.media.MediaRouteSelector; 40 import android.support.v7.media.MediaRouter; 41 import android.support.v7.media.MediaRouter.Callback; 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.ImageButton; 55 import android.widget.ListView; 56 import android.widget.SeekBar; 57 import android.widget.SeekBar.OnSeekBarChangeListener; 58 import android.widget.TabHost; 59 import android.widget.TabHost.OnTabChangeListener; 60 import android.widget.TabHost.TabSpec; 61 import android.widget.TextView; 62 import android.widget.Toast; 63 64 import com.example.android.mediarouter.R; 65 import com.example.android.mediarouter.provider.SampleMediaRouteProvider; 66 67 import java.io.File; 68 69 /** 70 * <h3>Media Router Support Activity</h3> 71 * <p/> 72 * <p> 73 * This demonstrates how to use the {@link MediaRouter} API to build an 74 * application that allows the user to send content to various rendering 75 * targets. 76 * </p> 77 */ 78 public class MainActivity extends AppCompatActivity { 79 private static final String TAG = "MainActivity"; 80 private static final String DISCOVERY_FRAGMENT_TAG = "DiscoveryFragment"; 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 ImageButton mPauseResumeButton; 90 private ImageButton mStopButton; 91 private SeekBar mSeekBar; 92 private boolean mPaused; 93 private boolean mNeedResume; 94 private boolean mSeeking; 95 96 private RemoteControlClient mRemoteControlClient; 97 private ComponentName mEventReceiver; 98 private AudioManager mAudioManager; 99 private PendingIntent mMediaPendingIntent; 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(MainActivity.this, route); 137 mPlayer.updatePresentation(); 138 mSessionManager.setPlayer(mPlayer); 139 mSessionManager.unsuspend(); 140 141 registerRemoteControlClient(); 142 updateUi(); 143 } 144 145 @Override 146 public void onRouteUnselected(MediaRouter router, RouteInfo route) { 147 Log.d(TAG, "onRouteUnselected: route=" + route); 148 unregisterRemoteControlClient(); 149 150 PlaylistItem item = getCheckedPlaylistItem(); 151 if (item != null) { 152 long pos = item.getPosition() + 153 (mPaused ? 0 : (SystemClock.elapsedRealtime() - item.getTimestamp())); 154 mSessionManager.suspend(pos); 155 } 156 mPlayer.updatePresentation(); 157 mPlayer.release(); 158 } 159 160 @Override 161 public void onRouteVolumeChanged(MediaRouter router, RouteInfo route) { 162 Log.d(TAG, "onRouteVolumeChanged: route=" + route); 163 } 164 165 @Override 166 public void onRoutePresentationDisplayChanged(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 final OnAudioFocusChangeListener mAfChangeListener = 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 201 protected void onCreate(Bundle savedInstanceState) { 202 // Be sure to call the super class. 203 super.onCreate(savedInstanceState); 204 if (savedInstanceState != null) { 205 mPlayer = (Player) savedInstanceState.getSerializable("mPlayer"); 206 } 207 208 // Get the media router service. 209 mMediaRouter = MediaRouter.getInstance(this); 210 211 // Create a route selector for the type of routes that we care about. 212 mSelector = 213 new MediaRouteSelector.Builder().addControlCategory(MediaControlIntent 214 .CATEGORY_LIVE_AUDIO).addControlCategory(MediaControlIntent 215 .CATEGORY_LIVE_VIDEO).addControlCategory(MediaControlIntent 216 .CATEGORY_REMOTE_PLAYBACK).addControlCategory(SampleMediaRouteProvider 217 .CATEGORY_SAMPLE_ROUTE).build(); 218 219 // Add a fragment to take care of media route discovery. 220 // This fragment automatically adds or removes a callback whenever the activity 221 // is started or stopped. 222 FragmentManager fm = getSupportFragmentManager(); 223 DiscoveryFragment fragment = 224 (DiscoveryFragment) fm.findFragmentByTag(DISCOVERY_FRAGMENT_TAG); 225 if (fragment == null) { 226 fragment = new DiscoveryFragment(); 227 fragment.setCallback(mMediaRouterCB); 228 fragment.setRouteSelector(mSelector); 229 fm.beginTransaction().add(fragment, DISCOVERY_FRAGMENT_TAG).commit(); 230 } else { 231 fragment.setCallback(mMediaRouterCB); 232 fragment.setRouteSelector(mSelector); 233 } 234 235 // Populate an array adapter with streaming media items. 236 String[] mediaNames = getResources().getStringArray(R.array.media_names); 237 String[] mediaUris = getResources().getStringArray(R.array.media_uris); 238 mLibraryItems = new LibraryAdapter(); 239 for (int i = 0; i < mediaNames.length; i++) { 240 mLibraryItems.add(new MediaItem( 241 "[streaming] " + mediaNames[i], Uri.parse(mediaUris[i]), "video/mp4")); 242 } 243 244 // Scan local external storage directory for media files. 245 File externalDir = Environment.getExternalStorageDirectory(); 246 if (externalDir != null) { 247 File list[] = externalDir.listFiles(); 248 if (list != null) { 249 for (int i = 0; i < list.length; i++) { 250 String filename = list[i].getName(); 251 if (filename.matches(".*\\.(m4v|mp4)")) { 252 mLibraryItems.add(new MediaItem( 253 "[local] " + filename, Uri.fromFile(list[i]), "video/mp4")); 254 } 255 } 256 } 257 } 258 259 mPlayListItems = new PlaylistAdapter(); 260 261 // Initialize the layout. 262 setContentView(R.layout.sample_media_router); 263 264 TabHost tabHost = (TabHost) findViewById(R.id.tabHost); 265 tabHost.setup(); 266 String tabName = getResources().getString(R.string.library_tab_text); 267 TabSpec spec1 = tabHost.newTabSpec(tabName); 268 spec1.setContent(R.id.tab1); 269 spec1.setIndicator(tabName); 270 271 tabName = getResources().getString(R.string.playlist_tab_text); 272 TabSpec spec2 = tabHost.newTabSpec(tabName); 273 spec2.setIndicator(tabName); 274 spec2.setContent(R.id.tab2); 275 276 tabName = getResources().getString(R.string.statistics_tab_text); 277 TabSpec spec3 = tabHost.newTabSpec(tabName); 278 spec3.setIndicator(tabName); 279 spec3.setContent(R.id.tab3); 280 281 tabHost.addTab(spec1); 282 tabHost.addTab(spec2); 283 tabHost.addTab(spec3); 284 tabHost.setOnTabChangedListener(new OnTabChangeListener() { 285 @Override 286 public void onTabChanged(String arg0) { 287 updateUi(); 288 } 289 }); 290 291 mLibraryView = (ListView) findViewById(R.id.media); 292 mLibraryView.setAdapter(mLibraryItems); 293 mLibraryView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 294 mLibraryView.setOnItemClickListener(new OnItemClickListener() { 295 @Override 296 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 297 updateButtons(); 298 } 299 }); 300 301 mPlayListView = (ListView) findViewById(R.id.playlist); 302 mPlayListView.setAdapter(mPlayListItems); 303 mPlayListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 304 mPlayListView.setOnItemClickListener(new OnItemClickListener() { 305 @Override 306 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 307 updateButtons(); 308 } 309 }); 310 311 mInfoTextView = (TextView) findViewById(R.id.info); 312 313 mPauseResumeButton = (ImageButton) findViewById(R.id.pause_resume_button); 314 mPauseResumeButton.setOnClickListener(new OnClickListener() { 315 @Override 316 public void onClick(View v) { 317 mPaused = !mPaused; 318 if (mPaused) { 319 mSessionManager.pause(); 320 } else { 321 mSessionManager.resume(); 322 } 323 } 324 }); 325 326 mStopButton = (ImageButton) findViewById(R.id.stop_button); 327 mStopButton.setOnClickListener(new OnClickListener() { 328 @Override 329 public void onClick(View v) { 330 mPaused = false; 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 348 @Override 349 public void onStartTrackingTouch(SeekBar seekBar) { 350 mSeeking = true; 351 } 352 353 @Override 354 public void onStopTrackingTouch(SeekBar seekBar) { 355 mSeeking = false; 356 updateUi(); 357 } 358 }); 359 360 // Schedule Ui update 361 mHandler.postDelayed(mUpdateSeekRunnable, 1000); 362 363 // Build the PendingIntent for the remote control client 364 mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 365 mEventReceiver = 366 new ComponentName(getPackageName(), SampleMediaButtonReceiver.class.getName()); 367 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 368 mediaButtonIntent.setComponent(mEventReceiver); 369 mMediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0); 370 371 // Create and register the remote control client 372 registerRemoteControlClient(); 373 374 // Set up playback manager and player 375 mPlayer = Player.create(MainActivity.this, mMediaRouter.getSelectedRoute()); 376 mSessionManager.setPlayer(mPlayer); 377 mSessionManager.setCallback(new SessionManager.Callback() { 378 @Override 379 public void onStatusChanged() { 380 updateUi(); 381 } 382 383 @Override 384 public void onItemChanged(PlaylistItem item) { 385 } 386 }); 387 388 updateUi(); 389 } 390 391 private void registerRemoteControlClient() { 392 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 393 // Create the RCC and register with AudioManager and MediaRouter 394 mAudioManager.requestAudioFocus(mAfChangeListener, AudioManager.STREAM_MUSIC, 395 AudioManager.AUDIOFOCUS_GAIN); 396 mAudioManager.registerMediaButtonEventReceiver(mEventReceiver); 397 mRemoteControlClient = new RemoteControlClient(mMediaPendingIntent); 398 mAudioManager.registerRemoteControlClient(mRemoteControlClient); 399 mMediaRouter.addRemoteControlClient(mRemoteControlClient); 400 SampleMediaButtonReceiver.setActivity(MainActivity.this); 401 mRemoteControlClient.setTransportControlFlags(RemoteControlClient 402 .FLAG_KEY_MEDIA_PLAY_PAUSE); 403 mRemoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); 404 } 405 } 406 407 private void unregisterRemoteControlClient() { 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 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 Log.d(TAG, "Received Play/Pause event from RemoteControlClient"); 425 mPaused = !mPaused; 426 if (mPaused) { 427 mSessionManager.pause(); 428 } else { 429 mSessionManager.resume(); 430 } 431 return true; 432 } 433 case KeyEvent.KEYCODE_MEDIA_PLAY: { 434 Log.d(TAG, "Received Play event from RemoteControlClient"); 435 if (mPaused) { 436 mPaused = false; 437 mSessionManager.resume(); 438 } 439 return true; 440 } 441 case KeyEvent.KEYCODE_MEDIA_PAUSE: { 442 Log.d(TAG, "Received Pause event from RemoteControlClient"); 443 if (!mPaused) { 444 mPaused = true; 445 mSessionManager.pause(); 446 } 447 return true; 448 } 449 case KeyEvent.KEYCODE_MEDIA_STOP: { 450 Log.d(TAG, "Received Stop event from RemoteControlClient"); 451 mPaused = false; 452 mSessionManager.stop(); 453 return true; 454 } 455 default: 456 break; 457 } 458 } 459 return false; 460 } 461 462 @Override 463 public boolean onKeyDown(int keyCode, KeyEvent event) { 464 return handleMediaKey(event) || super.onKeyDown(keyCode, event); 465 } 466 467 @Override 468 public boolean onKeyUp(int keyCode, KeyEvent event) { 469 return handleMediaKey(event) || super.onKeyUp(keyCode, event); 470 } 471 472 @Override 473 public void onStart() { 474 // Be sure to call the super class. 475 super.onStart(); 476 } 477 478 @Override 479 public void onPause() { 480 // pause media player for local playback case only 481 if (!mPlayer.isRemotePlayback() && !mPaused) { 482 mNeedResume = true; 483 mSessionManager.pause(); 484 } 485 super.onPause(); 486 } 487 488 @Override 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 499 public void onDestroy() { 500 // Unregister the remote control client 501 unregisterRemoteControlClient(); 502 503 mPaused = false; 504 mSessionManager.stop(); 505 mPlayer.release(); 506 super.onDestroy(); 507 } 508 509 @Override 510 public boolean onCreateOptionsMenu(Menu menu) { 511 // Be sure to call the super class. 512 super.onCreateOptionsMenu(menu); 513 514 // Inflate the menu and configure the media router action provider. 515 getMenuInflater().inflate(R.menu.sample_media_router_menu, menu); 516 517 MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); 518 MediaRouteActionProvider mediaRouteActionProvider = 519 (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem); 520 mediaRouteActionProvider.setRouteSelector(mSelector); 521 522 // Return true to show the menu. 523 return true; 524 } 525 526 private void updateProgress() { 527 // Estimate content position from last status time and elapsed time. 528 // (Note this might be slightly out of sync with remote side, however 529 // it avoids frequent polling the MRP.) 530 int progress = 0; 531 PlaylistItem item = getCheckedPlaylistItem(); 532 if (item != null) { 533 int state = item.getState(); 534 long duration = item.getDuration(); 535 if (duration <= 0) { 536 if (state == MediaItemStatus.PLAYBACK_STATE_PLAYING || 537 state == MediaItemStatus.PLAYBACK_STATE_PAUSED) { 538 mSessionManager.updateStatus(); 539 } 540 } else { 541 long position = item.getPosition(); 542 long timeDelta = 543 mPaused ? 0 : (SystemClock.elapsedRealtime() - item.getTimestamp()); 544 progress = (int) (100.0 * (position + timeDelta) / duration); 545 } 546 } 547 mSeekBar.setProgress(progress); 548 } 549 550 private void updateUi() { 551 updatePlaylist(); 552 updateRouteDescription(); 553 updateButtons(); 554 } 555 556 private void updatePlaylist() { 557 mPlayListItems.clear(); 558 for (PlaylistItem item : mSessionManager.getPlaylist()) { 559 mPlayListItems.add(item); 560 } 561 mPlayListView.invalidate(); 562 } 563 564 565 private void updateRouteDescription() { 566 RouteInfo route = mMediaRouter.getSelectedRoute(); 567 mInfoTextView.setText( 568 "Currently selected route:" + "\nName: " + route.getName() + "\nProvider: " + 569 route.getProvider().getPackageName() + "\nDescription: " + 570 route.getDescription() + "\nStatistics: " + 571 mSessionManager.getStatistics()); 572 } 573 574 private void updateButtons() { 575 MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(); 576 // show pause or resume icon depending on current state 577 mPauseResumeButton.setImageResource( 578 mPaused ? R.drawable.ic_action_play : R.drawable.ic_action_pause); 579 // disable pause/resume/stop if no session 580 mPauseResumeButton.setEnabled(mSessionManager.hasSession()); 581 mStopButton.setEnabled(mSessionManager.hasSession()); 582 // only enable seek bar when duration is known 583 PlaylistItem item = getCheckedPlaylistItem(); 584 mSeekBar.setEnabled(item != null && item.getDuration() > 0); 585 if (mRemoteControlClient != null) { 586 mRemoteControlClient.setPlaybackState(mPaused ? RemoteControlClient.PLAYSTATE_PAUSED : 587 RemoteControlClient.PLAYSTATE_PLAYING); 588 } 589 } 590 591 private PlaylistItem getCheckedPlaylistItem() { 592 int count = mPlayListView.getCount(); 593 int index = mPlayListView.getCheckedItemPosition(); 594 if (count > 0) { 595 if (index < 0 || index >= count) { 596 index = 0; 597 mPlayListView.setItemChecked(0, true); 598 } 599 return mPlayListItems.getItem(index); 600 } 601 return null; 602 } 603 604 public static final class DiscoveryFragment extends MediaRouteDiscoveryFragment { 605 private static final String TAG = "DiscoveryFragment"; 606 private Callback mCallback; 607 608 public DiscoveryFragment() { 609 mCallback = null; 610 } 611 612 public void setCallback(Callback cb) { 613 mCallback = cb; 614 } 615 616 @Override 617 public Callback onCreateCallback() { 618 return mCallback; 619 } 620 621 @Override 622 public int onPrepareCallbackFlags() { 623 // Add the CALLBACK_FLAG_UNFILTERED_EVENTS flag to ensure that we will 624 // observe and log all route events including those that are for routes 625 // that do not match our selector. This is only for demonstration purposes 626 // and should not be needed by most applications. 627 return super.onPrepareCallbackFlags() | MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS; 628 } 629 } 630 631 private static final class MediaItem { 632 public final String mName; 633 public final Uri mUri; 634 public final String mMime; 635 636 public MediaItem(String name, Uri uri, String mime) { 637 mName = name; 638 mUri = uri; 639 mMime = mime; 640 } 641 642 @Override 643 public String toString() { 644 return mName; 645 } 646 } 647 648 private final class LibraryAdapter extends ArrayAdapter<MediaItem> { 649 public LibraryAdapter() { 650 super(MainActivity.this, R.layout.media_item); 651 } 652 653 @Override 654 public View getView(int position, View convertView, ViewGroup parent) { 655 final View v; 656 if (convertView == null) { 657 v = getLayoutInflater().inflate(R.layout.media_item, null); 658 } else { 659 v = convertView; 660 } 661 662 final MediaItem item = getItem(position); 663 664 TextView tv = (TextView) v.findViewById(R.id.item_text); 665 tv.setText(item.mName); 666 667 ImageButton b = (ImageButton) v.findViewById(R.id.item_action); 668 b.setImageResource(R.drawable.ic_suggestions_add); 669 b.setTag(item); 670 b.setOnClickListener(new OnClickListener() { 671 @Override 672 public void onClick(View v) { 673 if (item != null) { 674 mSessionManager.add(item.mUri, item.mMime); 675 Toast.makeText(MainActivity.this, R.string.playlist_item_added_text, 676 Toast.LENGTH_SHORT).show(); 677 } 678 } 679 }); 680 681 return v; 682 } 683 } 684 685 private final class PlaylistAdapter extends ArrayAdapter<PlaylistItem> { 686 public PlaylistAdapter() { 687 super(MainActivity.this, R.layout.media_item); 688 } 689 690 @Override 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_suggestions_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 Toast.makeText(MainActivity.this, R.string.playlist_item_removed_text, 713 Toast.LENGTH_SHORT).show(); 714 } 715 } 716 }); 717 718 return v; 719 } 720 } 721 } 722