1 /* 2 * Copyright (C) 2007 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.android.music; 18 19 import android.app.Activity; 20 import android.app.SearchManager; 21 import android.content.ComponentName; 22 import android.content.Intent; 23 import android.graphics.Bitmap; 24 import android.graphics.BitmapFactory; 25 import android.graphics.drawable.BitmapDrawable; 26 import android.media.AudioManager; 27 import android.media.MediaDescription; 28 import android.media.MediaMetadata; 29 import android.media.browse.MediaBrowser; 30 import android.media.session.MediaController; 31 import android.media.session.PlaybackState; 32 import android.net.Uri; 33 import android.os.Bundle; 34 import android.os.Handler; 35 import android.os.Message; 36 import android.os.SystemClock; 37 import android.provider.MediaStore; 38 import android.text.Layout; 39 import android.text.TextUtils.TruncateAt; 40 import android.util.Log; 41 import android.view.MotionEvent; 42 import android.view.View; 43 import android.view.ViewConfiguration; 44 import android.view.Window; 45 import android.widget.ImageButton; 46 import android.widget.ImageView; 47 import android.widget.LinearLayout; 48 import android.widget.ProgressBar; 49 import android.widget.SeekBar; 50 import android.widget.SeekBar.OnSeekBarChangeListener; 51 import android.widget.TextView; 52 import android.widget.Toast; 53 54 import com.android.music.utils.LogHelper; 55 import com.android.music.utils.MediaIDHelper; 56 import com.android.music.utils.MusicProvider; 57 58 /* 59 This is the Now Playing Activity 60 */ 61 public class MediaPlaybackActivity 62 extends Activity implements View.OnTouchListener, View.OnLongClickListener { 63 private static final String TAG = LogHelper.makeLogTag(MediaPlaybackActivity.class); 64 65 private long mStartSeekPos = 0; 66 private long mLastSeekEventTime; 67 private RepeatingImageButton mPrevButton; 68 private ImageButton mPlayPauseButton; 69 private RepeatingImageButton mNextButton; 70 private ImageButton mRepeatButton; 71 private ImageButton mShuffleButton; 72 private ImageButton mQueueButton; 73 private int mTouchSlop; 74 75 private ImageView mAlbumArt; 76 private TextView mCurrentTime; 77 private TextView mTotalTime; 78 private TextView mArtistName; 79 private TextView mAlbumName; 80 private TextView mTrackName; 81 private LinearLayout mTrackInfo; 82 private ProgressBar mProgress; 83 private BitmapDrawable mDefaultAlbumArt; 84 private Toast mToast; 85 86 private MediaBrowser mMediaBrowser; 87 private final Handler mHandler = new Handler(); 88 89 /** Called when the activity is first created. */ 90 @Override 91 public void onCreate(Bundle icicle) { 92 LogHelper.d(TAG, "onCreate()"); 93 super.onCreate(icicle); 94 setVolumeControlStream(AudioManager.STREAM_MUSIC); 95 96 requestWindowFeature(Window.FEATURE_NO_TITLE); 97 setContentView(R.layout.audio_player); 98 99 mCurrentTime = (TextView) findViewById(R.id.currenttime); 100 mTotalTime = (TextView) findViewById(R.id.totaltime); 101 mProgress = (ProgressBar) findViewById(android.R.id.progress); 102 mAlbumArt = (ImageView) findViewById(R.id.album); 103 mArtistName = (TextView) findViewById(R.id.artistname); 104 mAlbumName = (TextView) findViewById(R.id.albumname); 105 mTrackName = (TextView) findViewById(R.id.trackname); 106 mTrackInfo = (LinearLayout) findViewById(R.id.trackinfo); 107 108 Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.albumart_mp_unknown); 109 mDefaultAlbumArt = new BitmapDrawable(getResources(), b); 110 // no filter or dither, it's a lot faster and we can't tell the difference 111 mDefaultAlbumArt.setFilterBitmap(false); 112 mDefaultAlbumArt.setDither(false); 113 114 /* Set metadata listeners */ 115 View v = (View) mArtistName.getParent(); 116 v.setOnTouchListener(this); 117 v.setOnLongClickListener(this); 118 v = (View) mAlbumName.getParent(); 119 v.setOnTouchListener(this); 120 v.setOnLongClickListener(this); 121 v = (View) mTrackName.getParent(); 122 v.setOnTouchListener(this); 123 v.setOnLongClickListener(this); 124 125 /* Set button listeners */ 126 mPrevButton = (RepeatingImageButton) findViewById(R.id.prev); 127 mPrevButton.setOnClickListener(new View.OnClickListener() { 128 public void onClick(View v) { 129 if (getMediaController() == null) return; 130 if (getMediaController().getPlaybackState().getPosition() < 2000) { 131 getMediaController().getTransportControls().skipToPrevious(); 132 } else { 133 getMediaController().getTransportControls().seekTo(0); 134 getMediaController().getTransportControls().play(); 135 } 136 } 137 }); 138 mPrevButton.setRepeatListener(new RepeatingImageButton.RepeatListener() { 139 public void onRepeat(View v, long howlong, int repcnt) { 140 scanBackward(repcnt, howlong); 141 } 142 }, 260); 143 mPlayPauseButton = (ImageButton) findViewById(R.id.pause); 144 mPlayPauseButton.requestFocus(); 145 mPlayPauseButton.setOnClickListener(new View.OnClickListener() { 146 public void onClick(View v) { 147 if (getMediaController() != null) { 148 if (getMediaController().getPlaybackState().getState() 149 != PlaybackState.STATE_PLAYING) { 150 getMediaController().getTransportControls().play(); 151 } else { 152 getMediaController().getTransportControls().pause(); 153 } 154 } 155 } 156 }); 157 mNextButton = (RepeatingImageButton) findViewById(R.id.next); 158 mNextButton.setOnClickListener(new View.OnClickListener() { 159 public void onClick(View v) { 160 if (getMediaController() == null) return; 161 getMediaController().getTransportControls().skipToNext(); 162 } 163 }); 164 mNextButton.setRepeatListener(new RepeatingImageButton.RepeatListener() { 165 public void onRepeat(View v, long howlong, int repcnt) { 166 scanForward(repcnt, howlong); 167 } 168 }, 260); 169 mQueueButton = (ImageButton) findViewById(R.id.curplaylist); 170 mQueueButton.setOnClickListener(new View.OnClickListener() { 171 public void onClick(View v) { 172 LogHelper.d(TAG, "mQueueButton onClick"); 173 MediaBrowser.MediaItem parentItem = new MediaBrowser.MediaItem( 174 new MediaDescription.Builder() 175 .setMediaId(MediaIDHelper.createBrowseCategoryMediaID( 176 MediaIDHelper.MEDIA_ID_MUSICS_BY_PLAYLIST, 177 MediaIDHelper.MEDIA_ID_NOW_PLAYING)) 178 .setTitle("Now Playing") 179 .build(), 180 MediaBrowser.MediaItem.FLAG_BROWSABLE); 181 Intent intent = new Intent(Intent.ACTION_PICK) 182 .setDataAndType(Uri.EMPTY, "vnd.android.cursor.dir/track") 183 .putExtra(MusicUtils.TAG_WITH_TABS, false) 184 .putExtra(MusicUtils.TAG_PARENT_ITEM, parentItem); 185 startActivity(intent); 186 } 187 }); 188 mShuffleButton = ((ImageButton) findViewById(R.id.shuffle)); 189 mShuffleButton.setOnClickListener(new View.OnClickListener() { 190 public void onClick(View v) { 191 toggleShuffle(); 192 } 193 }); 194 mRepeatButton = ((ImageButton) findViewById(R.id.repeat)); 195 mRepeatButton.setOnClickListener(new View.OnClickListener() { 196 public void onClick(View v) { 197 LogHelper.d(TAG, "Repeat button clicked"); 198 if (getMediaController() == null) return; 199 Bundle extras = getMediaController().getExtras(); 200 if (extras == null) return; 201 MediaPlaybackService.RepeatMode repeatMode = 202 MediaPlaybackService.RepeatMode 203 .values()[extras.getInt(MediaPlaybackService.REPEAT_MODE)]; 204 MediaPlaybackService.RepeatMode nextRepeatMode; 205 switch (repeatMode) { 206 case REPEAT_NONE: 207 nextRepeatMode = MediaPlaybackService.RepeatMode.REPEAT_ALL; 208 showToast(R.string.repeat_all_notif); 209 break; 210 case REPEAT_ALL: 211 nextRepeatMode = MediaPlaybackService.RepeatMode.REPEAT_CURRENT; 212 showToast(R.string.repeat_current_notif); 213 break; 214 case REPEAT_CURRENT: 215 default: 216 nextRepeatMode = MediaPlaybackService.RepeatMode.REPEAT_NONE; 217 showToast(R.string.repeat_off_notif); 218 break; 219 } 220 setRepeatMode(nextRepeatMode); 221 // TODO(siyuanh): Should use a callback to register changes on service side 222 setRepeatButtonImage(nextRepeatMode); 223 } 224 }); 225 226 if (mProgress instanceof SeekBar) { 227 SeekBar seeker = (SeekBar) mProgress; 228 seeker.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { 229 boolean mmFromTouch = false; 230 public void onStartTrackingTouch(SeekBar bar) { 231 mLastSeekEventTime = 0; 232 mmFromTouch = true; 233 } 234 public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) { 235 if (!fromuser || (getMediaController() == null)) return; 236 long now = SystemClock.elapsedRealtime(); 237 if ((now - mLastSeekEventTime) > 250) { 238 mLastSeekEventTime = now; 239 long duration = getMediaController().getMetadata().getLong( 240 MediaMetadata.METADATA_KEY_DURATION); 241 long position = duration * progress / 1000; 242 getMediaController().getTransportControls().seekTo(position); 243 // trackball event, allow progress updates 244 if (!mmFromTouch) { 245 updateProgressBar(); 246 } 247 } 248 } 249 public void onStopTrackingTouch(SeekBar bar) { 250 mmFromTouch = false; 251 } 252 }); 253 } else { 254 LogHelper.d(TAG, "Seeking not supported"); 255 } 256 mProgress.setMax(1000); 257 258 mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop(); 259 260 Log.d(TAG, "Creating MediaBrowser"); 261 mMediaBrowser = new MediaBrowser(this, new ComponentName(this, MediaPlaybackService.class), 262 mConnectionCallback, null); 263 } 264 265 // Receive callbacks from the MediaController. Here we update our state such as which queue 266 // is being shown, the current title and description and the PlaybackState. 267 private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() { 268 269 @Override 270 public void onSessionDestroyed() { 271 LogHelper.d(TAG, "Session destroyed. Need to fetch a new Media Session"); 272 } 273 274 @Override 275 public void onPlaybackStateChanged(PlaybackState state) { 276 if (state == null) { 277 return; 278 } 279 LogHelper.d(TAG, "Received playback state change to state ", state.toString()); 280 updateProgressBar(); 281 setPauseButtonImage(); 282 } 283 284 @Override 285 public void onMetadataChanged(MediaMetadata metadata) { 286 if (metadata == null) { 287 return; 288 } 289 LogHelper.d(TAG, "Received updated metadata: ", metadata); 290 updateTrackInfo(); 291 } 292 }; 293 294 private MediaBrowser.ConnectionCallback mConnectionCallback = 295 new MediaBrowser.ConnectionCallback() { 296 @Override 297 public void onConnected() { 298 Log.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken()); 299 if (mMediaBrowser.getSessionToken() == null) { 300 throw new IllegalArgumentException("No Session token"); 301 } 302 MediaController mediaController = new MediaController( 303 MediaPlaybackActivity.this, mMediaBrowser.getSessionToken()); 304 mediaController.registerCallback(mMediaControllerCallback); 305 MediaPlaybackActivity.this.setMediaController(mediaController); 306 mRepeatButton.setVisibility(View.VISIBLE); 307 mShuffleButton.setVisibility(View.VISIBLE); 308 mQueueButton.setVisibility(View.VISIBLE); 309 setRepeatButtonImage(null); 310 setShuffleButtonImage(); 311 setPauseButtonImage(); 312 updateTrackInfo(); 313 mHandler.post(new Runnable() { 314 @Override 315 public void run() { 316 long delay = updateProgressBar(); 317 mHandler.postDelayed(this, delay); 318 } 319 }); 320 } 321 322 @Override 323 public void onConnectionFailed() { 324 Log.d(TAG, "onConnectionFailed"); 325 } 326 327 @Override 328 public void onConnectionSuspended() { 329 Log.d(TAG, "onConnectionSuspended"); 330 mHandler.removeCallbacksAndMessages(null); 331 MediaPlaybackActivity.this.setMediaController(null); 332 } 333 }; 334 335 int mInitialX = -1; 336 int mLastX = -1; 337 int mTextWidth = 0; 338 int mViewWidth = 0; 339 boolean mDraggingLabel = false; 340 341 TextView textViewForContainer(View v) { 342 View vv = v.findViewById(R.id.artistname); 343 if (vv != null) return (TextView) vv; 344 vv = v.findViewById(R.id.albumname); 345 if (vv != null) return (TextView) vv; 346 vv = v.findViewById(R.id.trackname); 347 if (vv != null) return (TextView) vv; 348 return null; 349 } 350 351 public boolean onTouch(View v, MotionEvent event) { 352 int action = event.getAction(); 353 TextView tv = textViewForContainer(v); 354 if (tv == null) { 355 return false; 356 } 357 if (action == MotionEvent.ACTION_DOWN) { 358 v.setBackgroundColor(0xff606060); 359 mInitialX = mLastX = (int) event.getX(); 360 mDraggingLabel = false; 361 } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { 362 v.setBackgroundColor(0); 363 if (mDraggingLabel) { 364 Message msg = mLabelScroller.obtainMessage(0, tv); 365 mLabelScroller.sendMessageDelayed(msg, 1000); 366 } 367 } else if (action == MotionEvent.ACTION_MOVE) { 368 if (mDraggingLabel) { 369 int scrollx = tv.getScrollX(); 370 int x = (int) event.getX(); 371 int delta = mLastX - x; 372 if (delta != 0) { 373 mLastX = x; 374 scrollx += delta; 375 if (scrollx > mTextWidth) { 376 // scrolled the text completely off the view to the left 377 scrollx -= mTextWidth; 378 scrollx -= mViewWidth; 379 } 380 if (scrollx < -mViewWidth) { 381 // scrolled the text completely off the view to the right 382 scrollx += mViewWidth; 383 scrollx += mTextWidth; 384 } 385 tv.scrollTo(scrollx, 0); 386 } 387 return true; 388 } 389 int delta = mInitialX - (int) event.getX(); 390 if (Math.abs(delta) > mTouchSlop) { 391 // start moving 392 mLabelScroller.removeMessages(0, tv); 393 394 // Only turn ellipsizing off when it's not already off, because it 395 // causes the scroll position to be reset to 0. 396 if (tv.getEllipsize() != null) { 397 tv.setEllipsize(null); 398 } 399 Layout ll = tv.getLayout(); 400 // layout might be null if the text just changed, or ellipsizing 401 // was just turned off 402 if (ll == null) { 403 return false; 404 } 405 // get the non-ellipsized line width, to determine whether scrolling 406 // should even be allowed 407 mTextWidth = (int) tv.getLayout().getLineWidth(0); 408 mViewWidth = tv.getWidth(); 409 if (mViewWidth > mTextWidth) { 410 tv.setEllipsize(TruncateAt.END); 411 v.cancelLongPress(); 412 return false; 413 } 414 mDraggingLabel = true; 415 tv.setHorizontalFadingEdgeEnabled(true); 416 v.cancelLongPress(); 417 return true; 418 } 419 } 420 return false; 421 } 422 423 Handler mLabelScroller = new Handler() { 424 @Override 425 public void handleMessage(Message msg) { 426 TextView tv = (TextView) msg.obj; 427 int x = tv.getScrollX(); 428 x = x * 3 / 4; 429 tv.scrollTo(x, 0); 430 if (x == 0) { 431 tv.setEllipsize(TruncateAt.END); 432 } else { 433 Message newmsg = obtainMessage(0, tv); 434 mLabelScroller.sendMessageDelayed(newmsg, 15); 435 } 436 } 437 }; 438 439 public boolean onLongClick(View view) { 440 CharSequence title = null; 441 String mime = null; 442 String query = null; 443 if (getMediaController() == null) { 444 LogHelper.d(TAG, "No media controller avalable yet"); 445 return true; 446 } 447 MediaMetadata metadata = getMediaController().getMetadata(); 448 if (metadata == null) { 449 LogHelper.d(TAG, "No metadata avalable yet"); 450 return true; 451 } 452 String artist = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST); 453 String album = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM); 454 String song = metadata.getString(MediaMetadata.METADATA_KEY_TITLE); 455 long audioid = metadata.getLong(MediaMetadata.METADATA_KEY_MEDIA_ID); 456 457 if (album == null && artist == null && song != null && song.startsWith("recording")) { 458 LogHelper.d(TAG, "Item is not music"); 459 return false; 460 } 461 462 if (audioid < 0) { 463 return false; 464 } 465 466 boolean knownartist = (artist != null) && !MediaStore.UNKNOWN_STRING.equals(artist); 467 boolean knownalbum = (album != null) && !MediaStore.UNKNOWN_STRING.equals(album); 468 469 if (knownartist && view.equals(mArtistName.getParent())) { 470 title = artist; 471 query = artist; 472 mime = MediaStore.Audio.Artists.ENTRY_CONTENT_TYPE; 473 } else if (knownalbum && view.equals(mAlbumName.getParent())) { 474 title = album; 475 if (knownartist) { 476 query = artist + " " + album; 477 } else { 478 query = album; 479 } 480 mime = MediaStore.Audio.Albums.ENTRY_CONTENT_TYPE; 481 } else if (view.equals(mTrackName.getParent()) || !knownartist || !knownalbum) { 482 if ((song == null) || MediaStore.UNKNOWN_STRING.equals(song)) { 483 // A popup of the form "Search for null/'' using ..." is pretty 484 // unhelpful, plus, we won't find any way to buy it anyway. 485 return true; 486 } 487 488 title = song; 489 if (knownartist) { 490 query = artist + " " + song; 491 } else { 492 query = song; 493 } 494 mime = "audio/*"; // the specific type doesn't matter, so don't bother retrieving it 495 } else { 496 throw new RuntimeException("shouldn't be here"); 497 } 498 title = getString(R.string.mediasearch, title); 499 500 Intent i = new Intent(); 501 i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 502 i.setAction(MediaStore.INTENT_ACTION_MEDIA_SEARCH); 503 i.putExtra(SearchManager.QUERY, query); 504 if (knownartist) { 505 i.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, artist); 506 } 507 if (knownalbum) { 508 i.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, album); 509 } 510 i.putExtra(MediaStore.EXTRA_MEDIA_TITLE, song); 511 i.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, mime); 512 513 startActivity(Intent.createChooser(i, title)); 514 return true; 515 } 516 517 @Override 518 public void onStart() { 519 LogHelper.d(TAG, "onStart()"); 520 super.onStart(); 521 mMediaBrowser.connect(); 522 } 523 524 @Override 525 public void onStop() { 526 LogHelper.d(TAG, "onStop()"); 527 mMediaBrowser.disconnect(); 528 super.onStop(); 529 } 530 531 @Override 532 public void onResume() { 533 LogHelper.d(TAG, "onResume()"); 534 super.onResume(); 535 updateTrackInfo(); 536 setPauseButtonImage(); 537 } 538 539 @Override 540 public void onDestroy() { 541 LogHelper.d(TAG, "onDestroy()"); 542 super.onDestroy(); 543 } 544 545 private void scanBackward(int repcnt, long delta) { 546 if (getMediaController() == null) return; 547 if (repcnt == 0) { 548 mStartSeekPos = getMediaController().getPlaybackState().getPosition(); 549 mLastSeekEventTime = 0; 550 } else { 551 if (delta < 5000) { 552 // seek at 10x speed for the first 5 seconds 553 delta = delta * 10; 554 } else { 555 // seek at 40x after that 556 delta = 50000 + (delta - 5000) * 40; 557 } 558 long newpos = mStartSeekPos - delta; 559 if (newpos < 0) { 560 // move to previous track 561 getMediaController().getTransportControls().skipToPrevious(); 562 long duration = getMediaController().getMetadata().getLong( 563 MediaMetadata.METADATA_KEY_DURATION); 564 mStartSeekPos += duration; 565 newpos += duration; 566 } 567 if (((delta - mLastSeekEventTime) > 250) || repcnt < 0) { 568 getMediaController().getTransportControls().seekTo(newpos); 569 mLastSeekEventTime = delta; 570 } 571 updateProgressBar(); 572 } 573 } 574 575 private void scanForward(int repcnt, long delta) { 576 if (getMediaController() == null) return; 577 if (repcnt == 0) { 578 mStartSeekPos = getMediaController().getPlaybackState().getPosition(); 579 mLastSeekEventTime = 0; 580 } else { 581 if (delta < 5000) { 582 // seek at 10x speed for the first 5 seconds 583 delta = delta * 10; 584 } else { 585 // seek at 40x after that 586 delta = 50000 + (delta - 5000) * 40; 587 } 588 long newpos = mStartSeekPos + delta; 589 long duration = 590 getMediaController().getMetadata().getLong(MediaMetadata.METADATA_KEY_DURATION); 591 if (newpos >= duration) { 592 // move to next track 593 getMediaController().getTransportControls().skipToNext(); 594 mStartSeekPos -= duration; // is OK to go negative 595 newpos -= duration; 596 } 597 if (((delta - mLastSeekEventTime) > 250) || repcnt < 0) { 598 getMediaController().getTransportControls().seekTo(newpos); 599 mLastSeekEventTime = delta; 600 } 601 updateProgressBar(); 602 } 603 } 604 605 private void toggleShuffle() { 606 // TODO(b/36371715): Implement shuffle for SHUFFLE_NORMAL, SHUFFLE_AUTO, SHUFFLE_NONE 607 LogHelper.d(TAG, "Shuffle not implemented yet"); 608 Toast.makeText(this, "Shuffle not implemented yet", Toast.LENGTH_SHORT).show(); 609 } 610 611 private void setRepeatMode(MediaPlaybackService.RepeatMode repeatMode) { 612 Bundle extras = new Bundle(); 613 extras.putInt(MediaPlaybackService.REPEAT_MODE, repeatMode.ordinal()); 614 getMediaController().getTransportControls().sendCustomAction( 615 MediaPlaybackService.CMD_REPEAT, extras); 616 } 617 618 private void setRepeatButtonImage(MediaPlaybackService.RepeatMode repeatMode) { 619 if (getMediaController() == null) return; 620 Bundle extras = getMediaController().getExtras(); 621 if (extras == null) return; 622 if (repeatMode == null) { 623 repeatMode = MediaPlaybackService.RepeatMode 624 .values()[extras.getInt(MediaPlaybackService.REPEAT_MODE)]; 625 } 626 switch (repeatMode) { 627 case REPEAT_CURRENT: 628 mRepeatButton.setImageResource(R.drawable.ic_mp_repeat_once_btn); 629 break; 630 case REPEAT_ALL: 631 mRepeatButton.setImageResource(R.drawable.ic_mp_repeat_all_btn); 632 break; 633 case REPEAT_NONE: 634 default: 635 mRepeatButton.setImageResource(R.drawable.ic_mp_repeat_off_btn); 636 break; 637 } 638 } 639 640 private void showToast(int resid) { 641 if (mToast == null) { 642 mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT); 643 } 644 mToast.setText(resid); 645 mToast.show(); 646 } 647 648 private void setShuffleButtonImage() { 649 if (getMediaController() == null) return; 650 mShuffleButton.setImageResource(R.drawable.ic_mp_shuffle_off_btn); 651 } 652 653 private void setPauseButtonImage() { 654 if (getMediaController() == null) { 655 return; 656 } 657 if (getMediaController().getPlaybackState().getState() != PlaybackState.STATE_PLAYING) { 658 mPlayPauseButton.setImageResource(android.R.drawable.ic_media_play); 659 } else { 660 mPlayPauseButton.setImageResource(android.R.drawable.ic_media_pause); 661 } 662 } 663 664 private long updateProgressBar() { 665 MediaController mediaController = getMediaController(); 666 if (mediaController == null || mediaController.getMetadata() == null 667 || mediaController.getPlaybackState() == null) { 668 return 500; 669 } 670 long duration = mediaController.getMetadata().getLong(MediaMetadata.METADATA_KEY_DURATION); 671 long pos = mediaController.getPlaybackState().getPosition(); 672 if ((pos >= 0) && (duration > 0)) { 673 mCurrentTime.setText(MusicUtils.makeTimeString(this, pos / 1000)); 674 int progress = (int) (1000 * pos / duration); 675 mProgress.setProgress(progress); 676 677 if (mediaController.getPlaybackState().getState() == PlaybackState.STATE_PLAYING) { 678 mCurrentTime.setVisibility(View.VISIBLE); 679 } else { 680 // blink the counter 681 int vis = mCurrentTime.getVisibility(); 682 mCurrentTime.setVisibility(vis == View.INVISIBLE ? View.VISIBLE : View.INVISIBLE); 683 return 500; 684 } 685 } else { 686 mCurrentTime.setText("--:--"); 687 mProgress.setProgress(1000); 688 } 689 // calculate the number of milliseconds until the next full second, so 690 // the counter can be updated at just the right time 691 long remaining = 1000 - (pos % 1000); 692 693 // approximate how often we would need to refresh the slider to 694 // move it smoothly 695 int width = mProgress.getWidth(); 696 if (width == 0) width = 320; 697 long smoothrefreshtime = duration / width; 698 699 if (smoothrefreshtime > remaining) return remaining; 700 if (smoothrefreshtime < 20) return 20; 701 return smoothrefreshtime; 702 } 703 704 private void updateTrackInfo() { 705 LogHelper.d(TAG, "updateTrackInfo()"); 706 if (getMediaController() == null) { 707 return; 708 } 709 MediaMetadata metadata = getMediaController().getMetadata(); 710 if (metadata == null) { 711 return; 712 } 713 mTrackInfo.setVisibility(View.VISIBLE); 714 mTrackName.setText(metadata.getString(MediaMetadata.METADATA_KEY_TITLE)); 715 LogHelper.d(TAG, "Track Name: ", mTrackName.getText()); 716 String artistName = metadata.getString(MediaMetadata.METADATA_KEY_ARTIST); 717 if (artistName.equals(MusicProvider.UNKOWN)) { 718 artistName = getString(R.string.unknown_artist_name); 719 } 720 mArtistName.setText(artistName); 721 String albumName = metadata.getString(MediaMetadata.METADATA_KEY_ALBUM); 722 if (albumName.equals(MusicProvider.UNKOWN)) { 723 albumName = getString(R.string.unknown_album_name); 724 } 725 mAlbumName.setText(albumName); 726 Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART); 727 if (albumArt != null) { 728 mAlbumArt.setImageBitmap(albumArt); 729 } else { 730 mAlbumArt.setImageDrawable(mDefaultAlbumArt); 731 } 732 mAlbumArt.setVisibility(View.VISIBLE); 733 734 long duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION); 735 mTotalTime.setText(MusicUtils.makeTimeString(this, duration / 1000)); 736 } 737 } 738