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.ActionBarActivity; 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 ActionBarActivity { 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(mMediaRouterCB); 227 fragment.setRouteSelector(mSelector); 228 fm.beginTransaction().add(fragment, DISCOVERY_FRAGMENT_TAG).commit(); 229 } else { 230 fragment.setCallback(mMediaRouterCB); 231 fragment.setRouteSelector(mSelector); 232 } 233 234 // Populate an array adapter with streaming media items. 235 String[] mediaNames = getResources().getStringArray(R.array.media_names); 236 String[] mediaUris = getResources().getStringArray(R.array.media_uris); 237 mLibraryItems = new LibraryAdapter(); 238 for (int i = 0; i < mediaNames.length; i++) { 239 mLibraryItems.add(new MediaItem( 240 "[streaming] " + mediaNames[i], Uri.parse(mediaUris[i]), "video/mp4")); 241 } 242 243 // Scan local external storage directory for media files. 244 File externalDir = Environment.getExternalStorageDirectory(); 245 if (externalDir != null) { 246 File list[] = externalDir.listFiles(); 247 if (list != null) { 248 for (int i = 0; i < list.length; i++) { 249 String filename = list[i].getName(); 250 if (filename.matches(".*\\.(m4v|mp4)")) { 251 mLibraryItems.add(new MediaItem( 252 "[local] " + filename, Uri.fromFile(list[i]), "video/mp4")); 253 } 254 } 255 } 256 } 257 258 mPlayListItems = new PlaylistAdapter(); 259 260 // Initialize the layout. 261 setContentView(R.layout.sample_media_router); 262 263 TabHost tabHost = (TabHost) findViewById(R.id.tabHost); 264 tabHost.setup(); 265 String tabName = getResources().getString(R.string.library_tab_text); 266 TabSpec spec1 = tabHost.newTabSpec(tabName); 267 spec1.setContent(R.id.tab1); 268 spec1.setIndicator(tabName); 269 270 tabName = getResources().getString(R.string.playlist_tab_text); 271 TabSpec spec2 = tabHost.newTabSpec(tabName); 272 spec2.setIndicator(tabName); 273 spec2.setContent(R.id.tab2); 274 275 tabName = getResources().getString(R.string.statistics_tab_text); 276 TabSpec spec3 = tabHost.newTabSpec(tabName); 277 spec3.setIndicator(tabName); 278 spec3.setContent(R.id.tab3); 279 280 tabHost.addTab(spec1); 281 tabHost.addTab(spec2); 282 tabHost.addTab(spec3); 283 tabHost.setOnTabChangedListener(new OnTabChangeListener() { 284 @Override 285 public void onTabChanged(String arg0) { 286 updateUi(); 287 } 288 }); 289 290 mLibraryView = (ListView) findViewById(R.id.media); 291 mLibraryView.setAdapter(mLibraryItems); 292 mLibraryView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 293 mLibraryView.setOnItemClickListener(new OnItemClickListener() { 294 @Override 295 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 296 updateButtons(); 297 } 298 }); 299 300 mPlayListView = (ListView) findViewById(R.id.playlist); 301 mPlayListView.setAdapter(mPlayListItems); 302 mPlayListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 303 mPlayListView.setOnItemClickListener(new OnItemClickListener() { 304 @Override 305 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 306 updateButtons(); 307 } 308 }); 309 310 mInfoTextView = (TextView) findViewById(R.id.info); 311 312 mPauseResumeButton = (ImageButton) findViewById(R.id.pause_resume_button); 313 mPauseResumeButton.setOnClickListener(new OnClickListener() { 314 @Override 315 public void onClick(View v) { 316 mPaused = !mPaused; 317 if (mPaused) { 318 mSessionManager.pause(); 319 } else { 320 mSessionManager.resume(); 321 } 322 } 323 }); 324 325 mStopButton = (ImageButton) findViewById(R.id.stop_button); 326 mStopButton.setOnClickListener(new OnClickListener() { 327 @Override 328 public void onClick(View v) { 329 mPaused = false; 330 mSessionManager.stop(); 331 } 332 }); 333 334 mSeekBar = (SeekBar) findViewById(R.id.seekbar); 335 mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { 336 @Override 337 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 338 PlaylistItem item = getCheckedPlaylistItem(); 339 if (fromUser && item != null && item.getDuration() > 0) { 340 long pos = progress * item.getDuration() / 100; 341 mSessionManager.seek(item.getItemId(), pos); 342 item.setPosition(pos); 343 item.setTimestamp(SystemClock.elapsedRealtime()); 344 } 345 } 346 347 @Override 348 public void onStartTrackingTouch(SeekBar seekBar) { 349 mSeeking = true; 350 } 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 = 365 new ComponentName(getPackageName(), 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 registerRemoteControlClient(); 372 373 // Set up playback manager and player 374 mPlayer = Player.create(MainActivity.this, mMediaRouter.getSelectedRoute()); 375 mSessionManager.setPlayer(mPlayer); 376 mSessionManager.setCallback(new SessionManager.Callback() { 377 @Override 378 public void onStatusChanged() { 379 updateUi(); 380 } 381 382 @Override 383 public void onItemChanged(PlaylistItem item) { 384 } 385 }); 386 387 updateUi(); 388 } 389 390 private void registerRemoteControlClient() { 391 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 392 // Create the RCC and register with AudioManager and MediaRouter 393 mAudioManager.requestAudioFocus(mAfChangeListener, AudioManager.STREAM_MUSIC, 394 AudioManager.AUDIOFOCUS_GAIN); 395 mAudioManager.registerMediaButtonEventReceiver(mEventReceiver); 396 mRemoteControlClient = new RemoteControlClient(mMediaPendingIntent); 397 mAudioManager.registerRemoteControlClient(mRemoteControlClient); 398 mMediaRouter.addRemoteControlClient(mRemoteControlClient); 399 SampleMediaButtonReceiver.setActivity(MainActivity.this); 400 mRemoteControlClient.setTransportControlFlags(RemoteControlClient 401 .FLAG_KEY_MEDIA_PLAY_PAUSE); 402 mRemoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); 403 } 404 } 405 406 private void unregisterRemoteControlClient() { 407 // Unregister the RCC with AudioManager and MediaRouter 408 if (mRemoteControlClient != null) { 409 mRemoteControlClient.setTransportControlFlags(0); 410 mAudioManager.abandonAudioFocus(mAfChangeListener); 411 mAudioManager.unregisterMediaButtonEventReceiver(mEventReceiver); 412 mAudioManager.unregisterRemoteControlClient(mRemoteControlClient); 413 mMediaRouter.removeRemoteControlClient(mRemoteControlClient); 414 SampleMediaButtonReceiver.setActivity(null); 415 mRemoteControlClient = null; 416 } 417 } 418 419 public boolean handleMediaKey(KeyEvent event) { 420 if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { 421 switch (event.getKeyCode()) { 422 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: { 423 Log.d(TAG, "Received Play/Pause event from RemoteControlClient"); 424 mPaused = !mPaused; 425 if (mPaused) { 426 mSessionManager.pause(); 427 } else { 428 mSessionManager.resume(); 429 } 430 return true; 431 } 432 case KeyEvent.KEYCODE_MEDIA_PLAY: { 433 Log.d(TAG, "Received Play event from RemoteControlClient"); 434 if (mPaused) { 435 mPaused = false; 436 mSessionManager.resume(); 437 } 438 return true; 439 } 440 case KeyEvent.KEYCODE_MEDIA_PAUSE: { 441 Log.d(TAG, "Received Pause event from RemoteControlClient"); 442 if (!mPaused) { 443 mPaused = true; 444 mSessionManager.pause(); 445 } 446 return true; 447 } 448 case KeyEvent.KEYCODE_MEDIA_STOP: { 449 Log.d(TAG, "Received Stop event from RemoteControlClient"); 450 mPaused = false; 451 mSessionManager.stop(); 452 return true; 453 } 454 default: 455 break; 456 } 457 } 458 return false; 459 } 460 461 @Override 462 public boolean onKeyDown(int keyCode, KeyEvent event) { 463 return handleMediaKey(event) || super.onKeyDown(keyCode, event); 464 } 465 466 @Override 467 public boolean onKeyUp(int keyCode, KeyEvent event) { 468 return handleMediaKey(event) || super.onKeyUp(keyCode, event); 469 } 470 471 @Override 472 public void onStart() { 473 // Be sure to call the super class. 474 super.onStart(); 475 } 476 477 @Override 478 public void onPause() { 479 // pause media player for local playback case only 480 if (!mPlayer.isRemotePlayback() && !mPaused) { 481 mNeedResume = true; 482 mSessionManager.pause(); 483 } 484 super.onPause(); 485 } 486 487 @Override 488 public void onResume() { 489 // resume media player for local playback case only 490 if (!mPlayer.isRemotePlayback() && mNeedResume) { 491 mSessionManager.resume(); 492 mNeedResume = false; 493 } 494 super.onResume(); 495 } 496 497 @Override 498 public void onDestroy() { 499 // Unregister the remote control client 500 unregisterRemoteControlClient(); 501 502 mPaused = false; 503 mSessionManager.stop(); 504 mPlayer.release(); 505 super.onDestroy(); 506 } 507 508 @Override 509 public boolean onCreateOptionsMenu(Menu menu) { 510 // Be sure to call the super class. 511 super.onCreateOptionsMenu(menu); 512 513 // Inflate the menu and configure the media router action provider. 514 getMenuInflater().inflate(R.menu.sample_media_router_menu, menu); 515 516 MenuItem mediaRouteMenuItem = menu.findItem(R.id.media_route_menu_item); 517 MediaRouteActionProvider mediaRouteActionProvider = 518 (MediaRouteActionProvider) MenuItemCompat.getActionProvider(mediaRouteMenuItem); 519 mediaRouteActionProvider.setRouteSelector(mSelector); 520 521 // Return true to show the menu. 522 return true; 523 } 524 525 private void updateProgress() { 526 // Estimate content position from last status time and elapsed time. 527 // (Note this might be slightly out of sync with remote side, however 528 // it avoids frequent polling the MRP.) 529 int progress = 0; 530 PlaylistItem item = getCheckedPlaylistItem(); 531 if (item != null) { 532 int state = item.getState(); 533 long duration = item.getDuration(); 534 if (duration <= 0) { 535 if (state == MediaItemStatus.PLAYBACK_STATE_PLAYING || 536 state == MediaItemStatus.PLAYBACK_STATE_PAUSED) { 537 mSessionManager.updateStatus(); 538 } 539 } else { 540 long position = item.getPosition(); 541 long timeDelta = 542 mPaused ? 0 : (SystemClock.elapsedRealtime() - item.getTimestamp()); 543 progress = (int) (100.0 * (position + timeDelta) / duration); 544 } 545 } 546 mSeekBar.setProgress(progress); 547 } 548 549 private void updateUi() { 550 updatePlaylist(); 551 updateRouteDescription(); 552 updateButtons(); 553 } 554 555 private void updatePlaylist() { 556 mPlayListItems.clear(); 557 for (PlaylistItem item : mSessionManager.getPlaylist()) { 558 mPlayListItems.add(item); 559 } 560 mPlayListView.invalidate(); 561 } 562 563 564 private void updateRouteDescription() { 565 RouteInfo route = mMediaRouter.getSelectedRoute(); 566 mInfoTextView.setText( 567 "Currently selected route:" + "\nName: " + route.getName() + "\nProvider: " + 568 route.getProvider().getPackageName() + "\nDescription: " + 569 route.getDescription() + "\nStatistics: " + 570 mSessionManager.getStatistics()); 571 } 572 573 private void updateButtons() { 574 MediaRouter.RouteInfo route = mMediaRouter.getSelectedRoute(); 575 // show pause or resume icon depending on current state 576 mPauseResumeButton.setImageResource( 577 mPaused ? R.drawable.ic_action_play : R.drawable.ic_action_pause); 578 // disable pause/resume/stop if no session 579 mPauseResumeButton.setEnabled(mSessionManager.hasSession()); 580 mStopButton.setEnabled(mSessionManager.hasSession()); 581 // only enable seek bar when duration is known 582 PlaylistItem item = getCheckedPlaylistItem(); 583 mSeekBar.setEnabled(item != null && item.getDuration() > 0); 584 if (mRemoteControlClient != null) { 585 mRemoteControlClient.setPlaybackState(mPaused ? RemoteControlClient.PLAYSTATE_PAUSED : 586 RemoteControlClient.PLAYSTATE_PLAYING); 587 } 588 } 589 590 private PlaylistItem getCheckedPlaylistItem() { 591 int count = mPlayListView.getCount(); 592 int index = mPlayListView.getCheckedItemPosition(); 593 if (count > 0) { 594 if (index < 0 || index >= count) { 595 index = 0; 596 mPlayListView.setItemChecked(0, true); 597 } 598 return mPlayListItems.getItem(index); 599 } 600 return null; 601 } 602 603 public static final class DiscoveryFragment extends MediaRouteDiscoveryFragment { 604 private static final String TAG = "DiscoveryFragment"; 605 private Callback mCallback; 606 607 public DiscoveryFragment() { 608 mCallback = null; 609 } 610 611 public DiscoveryFragment(Callback cb) { 612 mCallback = cb; 613 } 614 615 public void setCallback(Callback cb) { 616 mCallback = cb; 617 } 618 619 @Override 620 public Callback onCreateCallback() { 621 return mCallback; 622 } 623 624 @Override 625 public int onPrepareCallbackFlags() { 626 // Add the CALLBACK_FLAG_UNFILTERED_EVENTS flag to ensure that we will 627 // observe and log all route events including those that are for routes 628 // that do not match our selector. This is only for demonstration purposes 629 // and should not be needed by most applications. 630 return super.onPrepareCallbackFlags() | MediaRouter.CALLBACK_FLAG_UNFILTERED_EVENTS; 631 } 632 } 633 634 private static final class MediaItem { 635 public final String mName; 636 public final Uri mUri; 637 public final String mMime; 638 639 public MediaItem(String name, Uri uri, String mime) { 640 mName = name; 641 mUri = uri; 642 mMime = mime; 643 } 644 645 @Override 646 public String toString() { 647 return mName; 648 } 649 } 650 651 private final class LibraryAdapter extends ArrayAdapter<MediaItem> { 652 public LibraryAdapter() { 653 super(MainActivity.this, R.layout.media_item); 654 } 655 656 @Override 657 public View getView(int position, View convertView, ViewGroup parent) { 658 final View v; 659 if (convertView == null) { 660 v = getLayoutInflater().inflate(R.layout.media_item, null); 661 } else { 662 v = convertView; 663 } 664 665 final MediaItem item = getItem(position); 666 667 TextView tv = (TextView) v.findViewById(R.id.item_text); 668 tv.setText(item.mName); 669 670 ImageButton b = (ImageButton) v.findViewById(R.id.item_action); 671 b.setImageResource(R.drawable.ic_suggestions_add); 672 b.setTag(item); 673 b.setOnClickListener(new OnClickListener() { 674 @Override 675 public void onClick(View v) { 676 if (item != null) { 677 mSessionManager.add(item.mUri, item.mMime); 678 Toast.makeText(MainActivity.this, R.string.playlist_item_added_text, 679 Toast.LENGTH_SHORT).show(); 680 } 681 } 682 }); 683 684 return v; 685 } 686 } 687 688 private final class PlaylistAdapter extends ArrayAdapter<PlaylistItem> { 689 public PlaylistAdapter() { 690 super(MainActivity.this, R.layout.media_item); 691 } 692 693 @Override 694 public View getView(int position, View convertView, ViewGroup parent) { 695 final View v; 696 if (convertView == null) { 697 v = getLayoutInflater().inflate(R.layout.media_item, null); 698 } else { 699 v = convertView; 700 } 701 702 final PlaylistItem item = getItem(position); 703 704 TextView tv = (TextView) v.findViewById(R.id.item_text); 705 tv.setText(item.toString()); 706 707 ImageButton b = (ImageButton) v.findViewById(R.id.item_action); 708 b.setImageResource(R.drawable.ic_suggestions_delete); 709 b.setTag(item); 710 b.setOnClickListener(new OnClickListener() { 711 @Override 712 public void onClick(View v) { 713 if (item != null) { 714 mSessionManager.remove(item.getItemId()); 715 Toast.makeText(MainActivity.this, R.string.playlist_item_removed_text, 716 Toast.LENGTH_SHORT).show(); 717 } 718 } 719 }); 720 721 return v; 722 } 723 } 724 }