• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
onCreate(Bundle icicle)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 
textViewForContainer(View v)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 
onTouch(View v, MotionEvent event)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 
onLongClick(View view)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
onStart()518     public void onStart() {
519         LogHelper.d(TAG, "onStart()");
520         super.onStart();
521         mMediaBrowser.connect();
522     }
523 
524     @Override
onStop()525     public void onStop() {
526         LogHelper.d(TAG, "onStop()");
527         mMediaBrowser.disconnect();
528         super.onStop();
529     }
530 
531     @Override
onResume()532     public void onResume() {
533         LogHelper.d(TAG, "onResume()");
534         super.onResume();
535         updateTrackInfo();
536         setPauseButtonImage();
537     }
538 
539     @Override
onDestroy()540     public void onDestroy() {
541         LogHelper.d(TAG, "onDestroy()");
542         super.onDestroy();
543     }
544 
scanBackward(int repcnt, long delta)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 
scanForward(int repcnt, long delta)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 
toggleShuffle()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 
setRepeatMode(MediaPlaybackService.RepeatMode repeatMode)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 
setRepeatButtonImage(MediaPlaybackService.RepeatMode repeatMode)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 
showToast(int resid)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 
setShuffleButtonImage()648     private void setShuffleButtonImage() {
649         if (getMediaController() == null) return;
650         mShuffleButton.setImageResource(R.drawable.ic_mp_shuffle_off_btn);
651     }
652 
setPauseButtonImage()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 
updateProgressBar()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 
updateTrackInfo()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