Methods Summary |
---|
private void | addToPlayList(int[] list, int position)
int addlen = list.length;
if (position < 0) { // overwrite
mPlayListLen = 0;
position = 0;
}
ensurePlayListCapacity(mPlayListLen + addlen);
if (position > mPlayListLen) {
position = mPlayListLen;
}
// move part of list after insertion point
int tailsize = mPlayListLen - position;
for (int i = tailsize ; i > 0 ; i--) {
mPlayList[position + i] = mPlayList[position + i - addlen];
}
// copy list into playlist
for (int i = 0; i < addlen; i++) {
mPlayList[position + i] = list[i];
}
mPlayListLen += addlen;
|
public void | closeExternalStorageFiles(java.lang.String storagePath)Called when we receive a ACTION_MEDIA_EJECT notification.
// stop playback and clean up if the SD card is going to be unmounted.
stop(true);
notifyChange(QUEUE_CHANGED);
notifyChange(META_CHANGED);
|
private void | doAutoShuffleUpdate()
boolean notify = false;
// remove old entries
if (mPlayPos > 10) {
removeTracks(0, mPlayPos - 9);
notify = true;
}
// add new entries if needed
int to_add = 7 - (mPlayListLen - (mPlayPos < 0 ? -1 : mPlayPos));
for (int i = 0; i < to_add; i++) {
// pick something at random from the list
int idx = mRand.nextInt(mAutoShuffleList.length);
Integer which = mAutoShuffleList[idx];
ensurePlayListCapacity(mPlayListLen + 1);
mPlayList[mPlayListLen++] = which;
notify = true;
}
if (notify) {
notifyChange(QUEUE_CHANGED);
}
|
public long | duration()Returns the duration of the file in milliseconds.
Currently this method returns -1 for the duration of MIDI files.
if (mPlayer.isInitialized()) {
return mPlayer.duration();
}
return -1;
|
public void | enqueue(int[] list, int action)Appends a list of tracks to the current playlist.
If nothing is playing currently, playback will be started at
the first track.
If the action is NOW, playback will switch to the first of
the new tracks immediately.
synchronized(this) {
if (action == NEXT && mPlayPos + 1 < mPlayListLen) {
addToPlayList(list, mPlayPos + 1);
notifyChange(QUEUE_CHANGED);
} else {
// action == LAST || action == NOW || mPlayPos + 1 == mPlayListLen
addToPlayList(list, Integer.MAX_VALUE);
notifyChange(QUEUE_CHANGED);
if (action == NOW) {
mPlayPos = mPlayListLen - list.length;
openCurrent();
play();
notifyChange(META_CHANGED);
return;
}
}
if (mPlayPos < 0) {
mPlayPos = 0;
openCurrent();
play();
notifyChange(META_CHANGED);
}
}
|
private void | ensurePlayListCapacity(int size)
if (mPlayList == null || size > mPlayList.length) {
// reallocate at 2x requested size so we don't
// need to grow and copy the array for every
// insert
int [] newlist = new int[size * 2];
int len = mPlayListLen;
for (int i = 0; i < len; i++) {
newlist[i] = mPlayList[i];
}
mPlayList = newlist;
}
// FIXME: shrink the array when the needed size is much smaller
// than the allocated size
|
public int | getAlbumId()
synchronized (this) {
if (mCursor == null) {
return -1;
}
return mCursor.getInt(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
}
|
public java.lang.String | getAlbumName()
synchronized (this) {
if (mCursor == null) {
return null;
}
return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
}
|
public int | getArtistId()
synchronized (this) {
if (mCursor == null) {
return -1;
}
return mCursor.getInt(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID));
}
|
public java.lang.String | getArtistName()
synchronized(this) {
if (mCursor == null) {
return null;
}
return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
}
|
public int | getAudioId()Returns the rowid of the currently playing file, or -1 if
no file is currently playing.
synchronized (this) {
if (mPlayPos >= 0 && mPlayer.isInitialized()) {
return mPlayList[mPlayPos];
}
}
return -1;
|
private long | getBookmark()
synchronized (this) {
if (mCursor == null) {
return 0;
}
return mCursor.getLong(BOOKMARKCOLIDX);
}
|
public int | getMediaMountedCount()
return mMediaMountedCount;
|
public java.lang.String | getPath()Returns the path of the currently playing file, or null if
no file is currently playing.
return mFileToPlay;
|
public int[] | getQueue()Returns the current play list
synchronized (this) {
int len = mPlayListLen;
int [] list = new int[len];
for (int i = 0; i < len; i++) {
list[i] = mPlayList[i];
}
return list;
}
|
public int | getQueuePosition()Returns the position in the queue
synchronized(this) {
return mPlayPos;
}
|
public int | getRepeatMode()
return mRepeatMode;
|
public int | getShuffleMode()
return mShuffleMode;
|
public java.lang.String | getTrackName()
synchronized (this) {
if (mCursor == null) {
return null;
}
return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
}
|
private void | gotoIdleState()
NotificationManager nm =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel(PLAYBACKSERVICE_STATUS);
mDelayedStopHandler.removeCallbacksAndMessages(null);
Message msg = mDelayedStopHandler.obtainMessage();
mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
|
public boolean | isPlaying()Returns whether playback is currently paused
if (mPlayer.isInitialized()) {
return mPlayer.isPlaying();
}
return false;
|
private boolean | isPodcast()
synchronized (this) {
if (mCursor == null) {
return false;
}
return (mCursor.getInt(PODCASTCOLIDX) > 0);
}
|
private boolean | makeAutoShuffleList()
ContentResolver res = getContentResolver();
Cursor c = null;
try {
c = res.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[] {MediaStore.Audio.Media._ID}, MediaStore.Audio.Media.IS_MUSIC + "=1",
null, null);
if (c == null || c.getCount() == 0) {
return false;
}
int len = c.getCount();
int[] list = new int[len];
for (int i = 0; i < len; i++) {
c.moveToNext();
list[i] = c.getInt(0);
}
mAutoShuffleList = list;
return true;
} catch (RuntimeException ex) {
} finally {
if (c != null) {
c.close();
}
}
return false;
|
public void | moveQueueItem(int index1, int index2)Moves the item at index1 to index2.
synchronized (this) {
if (index1 >= mPlayListLen) {
index1 = mPlayListLen - 1;
}
if (index2 >= mPlayListLen) {
index2 = mPlayListLen - 1;
}
if (index1 < index2) {
int tmp = mPlayList[index1];
for (int i = index1; i < index2; i++) {
mPlayList[i] = mPlayList[i+1];
}
mPlayList[index2] = tmp;
if (mPlayPos == index1) {
mPlayPos = index2;
} else if (mPlayPos >= index1 && mPlayPos <= index2) {
mPlayPos--;
}
} else if (index2 < index1) {
int tmp = mPlayList[index1];
for (int i = index1; i > index2; i--) {
mPlayList[i] = mPlayList[i-1];
}
mPlayList[index2] = tmp;
if (mPlayPos == index1) {
mPlayPos = index2;
} else if (mPlayPos >= index2 && mPlayPos <= index1) {
mPlayPos++;
}
}
notifyChange(QUEUE_CHANGED);
}
|
public void | next(boolean force)
synchronized (this) {
if (mOneShot) {
// we were playing a specific file not part of a playlist, so there is no 'next'
seek(0);
play();
return;
}
// Store the current file in the history, but keep the history at a
// reasonable size
if (mPlayPos >= 0) {
mHistory.add(Integer.valueOf(mPlayPos));
}
if (mHistory.size() > MAX_HISTORY_SIZE) {
mHistory.removeElementAt(0);
}
if (mShuffleMode == SHUFFLE_NORMAL) {
// Pick random next track from the not-yet-played ones
// TODO: make it work right after adding/removing items in the queue.
int numTracks = mPlayListLen;
int[] tracks = new int[numTracks];
for (int i=0;i < numTracks; i++) {
tracks[i] = i;
}
int numHistory = mHistory.size();
int numUnplayed = numTracks;
for (int i=0;i < numHistory; i++) {
int idx = mHistory.get(i).intValue();
if (idx < numTracks && tracks[idx] >= 0) {
numUnplayed--;
tracks[idx] = -1;
}
}
// 'numUnplayed' now indicates how many tracks have not yet
// been played, and 'tracks' contains the indices of those
// tracks.
if (numUnplayed <=0) {
// everything's already been played
if (mRepeatMode == REPEAT_ALL || force) {
//pick from full set
numUnplayed = numTracks;
for (int i=0;i < numTracks; i++) {
tracks[i] = i;
}
} else {
// all done
gotoIdleState();
return;
}
}
int skip = mRand.nextInt(numUnplayed);
int cnt = -1;
while (true) {
while (tracks[++cnt] < 0)
;
skip--;
if (skip < 0) {
break;
}
}
mPlayPos = cnt;
} else if (mShuffleMode == SHUFFLE_AUTO) {
doAutoShuffleUpdate();
mPlayPos++;
} else {
if (mPlayPos >= mPlayListLen - 1) {
// we're at the end of the list
if (mRepeatMode == REPEAT_NONE && !force) {
// all done
gotoIdleState();
notifyChange(PLAYBACK_COMPLETE);
return;
} else if (mRepeatMode == REPEAT_ALL || force) {
mPlayPos = 0;
}
} else {
mPlayPos++;
}
}
saveBookmarkIfNeeded();
stop(false);
openCurrent();
play();
notifyChange(META_CHANGED);
}
|
private void | notifyChange(java.lang.String what)Notify the change-receivers that something has changed.
The intent that is sent contains the following data
for the currently playing track:
"id" - Integer: the database row ID
"artist" - String: the name of the artist
"album" - String: the name of the album
"track" - String: the name of the track
The intent has an action that is one of
"com.android.music.metachanged"
"com.android.music.queuechanged",
"com.android.music.playbackcomplete"
"com.android.music.playstatechanged"
respectively indicating that a new track has
started playing, that the playback queue has
changed, that playback has stopped because
the last file in the list has been played,
or that the play-state changed (paused/resumed).
Intent i = new Intent(what);
i.putExtra("id", Integer.valueOf(getAudioId()));
i.putExtra("artist", getArtistName());
i.putExtra("album",getAlbumName());
i.putExtra("track", getTrackName());
sendBroadcast(i);
if (what.equals(QUEUE_CHANGED)) {
saveQueue(true);
} else {
saveQueue(false);
}
// Share this notification directly with our widgets
mAppWidgetProvider.notifyChange(this, what);
|
public android.os.IBinder | onBind(android.content.Intent intent)
mDelayedStopHandler.removeCallbacksAndMessages(null);
mServiceInUse = true;
return mBinder;
|
public void | onCreate()
super.onCreate();
mPreferences = getSharedPreferences("Music", MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE);
mCardId = FileUtils.getFatVolumeId(Environment.getExternalStorageDirectory().getPath());
registerExternalStorageListener();
// Needs to be done in this thread, since otherwise ApplicationContext.getPowerManager() crashes.
mPlayer = new MultiPlayer();
mPlayer.setHandler(mMediaplayerHandler);
// Clear leftover notification in case this service previously got killed while playing
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel(PLAYBACKSERVICE_STATUS);
reloadQueue();
IntentFilter commandFilter = new IntentFilter();
commandFilter.addAction(SERVICECMD);
commandFilter.addAction(TOGGLEPAUSE_ACTION);
commandFilter.addAction(PAUSE_ACTION);
commandFilter.addAction(NEXT_ACTION);
commandFilter.addAction(PREVIOUS_ACTION);
registerReceiver(mIntentReceiver, commandFilter);
mPsir.registerIntent();
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
mWakeLock.setReferenceCounted(false);
// If the service was idle, but got killed before it stopped itself, the
// system will relaunch it. Make sure it gets stopped again in that case.
Message msg = mDelayedStopHandler.obtainMessage();
mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
|
public void | onDestroy()
// Check that we're not being destroyed while something is still playing.
if (isPlaying()) {
Log.e("MediaPlaybackService", "Service being destroyed while still playing.");
}
// and for good measure, call mPlayer.stop(), which calls MediaPlayer.reset(), which
// releases the MediaPlayer's wake lock, if any.
mPlayer.stop();
if (mCursor != null) {
mCursor.close();
mCursor = null;
}
unregisterReceiver(mIntentReceiver);
if (mUnmountReceiver != null) {
unregisterReceiver(mUnmountReceiver);
mUnmountReceiver = null;
}
mPsir.unregisterIntent();
mWakeLock.release();
super.onDestroy();
|
public void | onRebind(android.content.Intent intent)
mDelayedStopHandler.removeCallbacksAndMessages(null);
mServiceInUse = true;
|
public void | onStart(android.content.Intent intent, int startId)
mServiceStartId = startId;
mDelayedStopHandler.removeCallbacksAndMessages(null);
String action = intent.getAction();
String cmd = intent.getStringExtra("command");
if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
next(true);
} else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
prev();
} else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
if (isPlaying()) {
pause();
} else {
play();
}
} else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
pause();
} else if (CMDSTOP.equals(cmd)) {
pause();
seek(0);
}
// make sure the service will shut down on its own if it was
// just started but not bound to and nothing is playing
mDelayedStopHandler.removeCallbacksAndMessages(null);
Message msg = mDelayedStopHandler.obtainMessage();
mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
|
public boolean | onUnbind(android.content.Intent intent)
mServiceInUse = false;
// Take a snapshot of the current playlist
saveQueue(true);
if (isPlaying() || mResumeAfterCall) {
// something is currently playing, or will be playing once
// an in-progress call ends, so don't stop the service now.
return true;
}
// If there is a playlist but playback is paused, then wait a while
// before stopping the service, so that pause/resume isn't slow.
// Also delay stopping the service if we're transitioning between tracks.
if (mPlayListLen > 0 || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
Message msg = mDelayedStopHandler.obtainMessage();
mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
return true;
}
// No active playlist, OK to stop the service right now
stopSelf(mServiceStartId);
return true;
|
public void | open(int[] list, int position)Replaces the current playlist with a new list,
and prepares for starting playback at the specified
position in the list, or a random position if the
specified position is 0.
synchronized (this) {
if (mShuffleMode == SHUFFLE_AUTO) {
mShuffleMode = SHUFFLE_NORMAL;
}
int oldId = getAudioId();
int listlength = list.length;
boolean newlist = true;
if (mPlayListLen == listlength) {
// possible fast path: list might be the same
newlist = false;
for (int i = 0; i < listlength; i++) {
if (list[i] != mPlayList[i]) {
newlist = true;
break;
}
}
}
if (newlist) {
addToPlayList(list, -1);
notifyChange(QUEUE_CHANGED);
}
int oldpos = mPlayPos;
if (position >= 0) {
mPlayPos = position;
} else {
mPlayPos = mRand.nextInt(mPlayListLen);
}
mHistory.clear();
saveBookmarkIfNeeded();
openCurrent();
if (oldId != getAudioId()) {
notifyChange(META_CHANGED);
}
}
|
public void | open(java.lang.String path, boolean oneshot)Opens the specified file and readies it for playback.
synchronized (this) {
if (path == null) {
return;
}
if (oneshot) {
mRepeatMode = REPEAT_NONE;
ensurePlayListCapacity(1);
mPlayListLen = 1;
mPlayPos = -1;
}
// if mCursor is null, try to associate path with a database cursor
if (mCursor == null) {
ContentResolver resolver = getContentResolver();
Uri uri;
String where;
String selectionArgs[];
if (path.startsWith("content://media/")) {
uri = Uri.parse(path);
where = null;
selectionArgs = null;
} else {
uri = MediaStore.Audio.Media.getContentUriForPath(path);
where = MediaStore.Audio.Media.DATA + "=?";
selectionArgs = new String[] { path };
}
try {
mCursor = resolver.query(uri, mCursorCols, where, selectionArgs, null);
if (mCursor != null) {
if (mCursor.getCount() == 0) {
mCursor.close();
mCursor = null;
} else {
mCursor.moveToNext();
ensurePlayListCapacity(1);
mPlayListLen = 1;
mPlayList[0] = mCursor.getInt(IDCOLIDX);
mPlayPos = 0;
}
}
} catch (UnsupportedOperationException ex) {
}
}
mFileToPlay = path;
mPlayer.setDataSource(mFileToPlay);
mOneShot = oneshot;
if (! mPlayer.isInitialized()) {
stop(true);
if (mOpenFailedCounter++ < 10 && mPlayListLen > 1) {
// beware: this ends up being recursive because next() calls open() again.
next(false);
}
if (! mPlayer.isInitialized() && mOpenFailedCounter != 0) {
// need to make sure we only shows this once
mOpenFailedCounter = 0;
if (!mQuietMode) {
Toast.makeText(this, R.string.playback_failed, Toast.LENGTH_SHORT).show();
}
}
} else {
mOpenFailedCounter = 0;
}
}
|
public void | openAsync(java.lang.String path)
synchronized (this) {
if (path == null) {
return;
}
mRepeatMode = REPEAT_NONE;
ensurePlayListCapacity(1);
mPlayListLen = 1;
mPlayPos = -1;
mFileToPlay = path;
mCursor = null;
mPlayer.setDataSourceAsync(mFileToPlay);
mOneShot = true;
}
|
private void | openCurrent()
synchronized (this) {
if (mCursor != null) {
mCursor.close();
mCursor = null;
}
if (mPlayListLen == 0) {
return;
}
stop(false);
String id = String.valueOf(mPlayList[mPlayPos]);
mCursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
mCursorCols, "_id=" + id , null, null);
if (mCursor != null) {
mCursor.moveToFirst();
open(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + id, false);
// go to bookmark if needed
if (isPodcast()) {
long bookmark = getBookmark();
// Start playing a little bit before the bookmark,
// so it's easier to get back in to the narrative.
seek(bookmark - 5000);
}
}
}
|
public void | pause()Pauses playback (call play() to resume)
if (isPlaying()) {
mPlayer.pause();
gotoIdleState();
setForeground(false);
mWasPlaying = false;
notifyChange(PLAYSTATE_CHANGED);
saveBookmarkIfNeeded();
}
|
public void | play()Starts playback of a previously opened file.
if (mPlayer.isInitialized()) {
mPlayer.start();
setForeground(true);
NotificationManager nm = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
RemoteViews views = new RemoteViews(getPackageName(), R.layout.statusbar);
views.setImageViewResource(R.id.icon, R.drawable.stat_notify_musicplayer);
if (getAudioId() < 0) {
// streaming
views.setTextViewText(R.id.trackname, getPath());
views.setTextViewText(R.id.artistalbum, null);
} else {
String artist = getArtistName();
views.setTextViewText(R.id.trackname, getTrackName());
if (artist == null || artist.equals(MediaFile.UNKNOWN_STRING)) {
artist = getString(R.string.unknown_artist_name);
}
String album = getAlbumName();
if (album == null || album.equals(MediaFile.UNKNOWN_STRING)) {
album = getString(R.string.unknown_album_name);
}
views.setTextViewText(R.id.artistalbum,
getString(R.string.notification_artist_album, artist, album)
);
}
Intent statusintent = new Intent("com.android.music.PLAYBACK_VIEWER");
statusintent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Notification status = new Notification();
status.contentView = views;
status.flags |= Notification.FLAG_ONGOING_EVENT;
status.icon = R.drawable.stat_notify_musicplayer;
status.contentIntent = PendingIntent.getActivity(this, 0,
new Intent("com.android.music.PLAYBACK_VIEWER"), 0);
nm.notify(PLAYBACKSERVICE_STATUS, status);
if (!mWasPlaying) {
notifyChange(PLAYSTATE_CHANGED);
}
mWasPlaying = true;
} else if (mPlayListLen <= 0) {
// This is mostly so that if you press 'play' on a bluetooth headset
// without every having played anything before, it will still play
// something.
setShuffleMode(SHUFFLE_AUTO);
}
|
public long | position()Returns the current playback position in milliseconds
if (mPlayer.isInitialized()) {
return mPlayer.position();
}
return -1;
|
public void | prev()
synchronized (this) {
if (mOneShot) {
// we were playing a specific file not part of a playlist, so there is no 'previous'
seek(0);
play();
return;
}
if (mShuffleMode == SHUFFLE_NORMAL) {
// go to previously-played track and remove it from the history
int histsize = mHistory.size();
if (histsize == 0) {
// prev is a no-op
return;
}
Integer pos = mHistory.remove(histsize - 1);
mPlayPos = pos.intValue();
} else {
if (mPlayPos > 0) {
mPlayPos--;
} else {
mPlayPos = mPlayListLen - 1;
}
}
saveBookmarkIfNeeded();
stop(false);
openCurrent();
play();
notifyChange(META_CHANGED);
}
|
public void | registerExternalStorageListener()Registers an intent to listen for ACTION_MEDIA_EJECT notifications.
The intent will call closeExternalStorageFiles() if the external media
is going to be ejected, so applications can clean up any files they have open.
if (mUnmountReceiver == null) {
mUnmountReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
saveQueue(true);
mOneShot = true; // This makes us not save the state again later,
// which would be wrong because the song ids and
// card id might not match.
closeExternalStorageFiles(intent.getData().getPath());
} else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
mMediaMountedCount++;
mCardId = FileUtils.getFatVolumeId(intent.getData().getPath());
reloadQueue();
notifyChange(QUEUE_CHANGED);
notifyChange(META_CHANGED);
}
}
};
IntentFilter iFilter = new IntentFilter();
iFilter.addAction(Intent.ACTION_MEDIA_EJECT);
iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
iFilter.addDataScheme("file");
registerReceiver(mUnmountReceiver, iFilter);
}
|
private void | reloadQueue()
String q = null;
boolean newstyle = false;
int id = mCardId;
if (mPreferences.contains("cardid")) {
newstyle = true;
id = mPreferences.getInt("cardid", ~mCardId);
}
if (id == mCardId) {
// Only restore the saved playlist if the card is still
// the same one as when the playlist was saved
q = mPreferences.getString("queue", "");
}
if (q != null && q.length() > 1) {
//Log.i("@@@@ service", "loaded queue: " + q);
String [] entries = q.split(";");
int len = entries.length;
ensurePlayListCapacity(len);
for (int i = 0; i < len; i++) {
if (newstyle) {
String revhex = entries[i];
int n = 0;
for (int j = revhex.length() - 1; j >= 0 ; j--) {
n <<= 4;
char c = revhex.charAt(j);
if (c >= '0" && c <= '9") {
n += (c - '0");
} else if (c >= 'a" && c <= 'f") {
n += (10 + c - 'a");
} else {
// bogus playlist data
len = 0;
break;
}
}
mPlayList[i] = n;
} else {
mPlayList[i] = Integer.parseInt(entries[i]);
}
}
mPlayListLen = len;
int pos = mPreferences.getInt("curpos", 0);
if (pos < 0 || pos >= len) {
// The saved playlist is bogus, discard it
mPlayListLen = 0;
return;
}
mPlayPos = pos;
// When reloadQueue is called in response to a card-insertion,
// we might not be able to query the media provider right away.
// To deal with this, try querying for the current file, and if
// that fails, wait a while and try again. If that too fails,
// assume there is a problem and don't restore the state.
Cursor c = MusicUtils.query(this,
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String [] {"_id"}, "_id=" + mPlayList[mPlayPos] , null, null);
if (c == null || c.getCount() == 0) {
// wait a bit and try again
SystemClock.sleep(3000);
c = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
mCursorCols, "_id=" + mPlayList[mPlayPos] , null, null);
}
if (c != null) {
c.close();
}
// Make sure we don't auto-skip to the next song, since that
// also starts playback. What could happen in that case is:
// - music is paused
// - go to UMS and delete some files, including the currently playing one
// - come back from UMS
// (time passes)
// - music app is killed for some reason (out of memory)
// - music service is restarted, service restores state, doesn't find
// the "current" file, goes to the next and: playback starts on its
// own, potentially at some random inconvenient time.
mOpenFailedCounter = 20;
mQuietMode = true;
openCurrent();
mQuietMode = false;
if (!mPlayer.isInitialized()) {
// couldn't restore the saved state
mPlayListLen = 0;
return;
}
long seekpos = mPreferences.getLong("seekpos", 0);
seek(seekpos >= 0 && seekpos < duration() ? seekpos : 0);
int repmode = mPreferences.getInt("repeatmode", REPEAT_NONE);
if (repmode != REPEAT_ALL && repmode != REPEAT_CURRENT) {
repmode = REPEAT_NONE;
}
mRepeatMode = repmode;
int shufmode = mPreferences.getInt("shufflemode", SHUFFLE_NONE);
if (shufmode != SHUFFLE_AUTO && shufmode != SHUFFLE_NORMAL) {
shufmode = SHUFFLE_NONE;
}
if (shufmode == SHUFFLE_AUTO) {
if (! makeAutoShuffleList()) {
shufmode = SHUFFLE_NONE;
}
}
mShuffleMode = shufmode;
}
|
public int | removeTrack(int id)Removes all instances of the track with the given id
from the playlist.
int numremoved = 0;
synchronized (this) {
for (int i = 0; i < mPlayListLen; i++) {
if (mPlayList[i] == id) {
numremoved += removeTracksInternal(i, i);
i--;
}
}
}
if (numremoved > 0) {
notifyChange(QUEUE_CHANGED);
}
return numremoved;
|
public int | removeTracks(int first, int last)Removes the range of tracks specified from the play list. If a file within the range is
the file currently being played, playback will move to the next file after the
range.
int numremoved = removeTracksInternal(first, last);
if (numremoved > 0) {
notifyChange(QUEUE_CHANGED);
}
return numremoved;
|
private int | removeTracksInternal(int first, int last)
synchronized (this) {
if (last < first) return 0;
if (first < 0) first = 0;
if (last >= mPlayListLen) last = mPlayListLen - 1;
boolean gotonext = false;
if (first <= mPlayPos && mPlayPos <= last) {
mPlayPos = first;
gotonext = true;
} else if (mPlayPos > last) {
mPlayPos -= (last - first + 1);
}
int num = mPlayListLen - last - 1;
for (int i = 0; i < num; i++) {
mPlayList[first + i] = mPlayList[last + 1 + i];
}
mPlayListLen -= last - first + 1;
if (gotonext) {
if (mPlayListLen == 0) {
stop(true);
mPlayPos = -1;
} else {
if (mPlayPos >= mPlayListLen) {
mPlayPos = 0;
}
boolean wasPlaying = isPlaying();
stop(false);
openCurrent();
if (wasPlaying) {
play();
}
}
}
return last - first + 1;
}
|
private void | saveBookmarkIfNeeded()
try {
if (isPodcast()) {
long pos = position();
long bookmark = getBookmark();
long duration = duration();
if ((pos < bookmark && (pos + 10000) > bookmark) ||
(pos > bookmark && (pos - 10000) < bookmark)) {
// The existing bookmark is close to the current
// position, so don't update it.
return;
}
if (pos < 15000 || (pos + 10000) > duration) {
// if we're near the start or end, clear the bookmark
pos = 0;
}
// write 'pos' to the bookmark field
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.Media.BOOKMARK, pos);
Uri uri = ContentUris.withAppendedId(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursor.getLong(IDCOLIDX));
getContentResolver().update(uri, values, null, null);
}
} catch (SQLiteException ex) {
}
|
private void | saveQueue(boolean full)
if (mOneShot) {
return;
}
Editor ed = mPreferences.edit();
//long start = System.currentTimeMillis();
if (full) {
StringBuilder q = new StringBuilder();
// The current playlist is saved as a list of "reverse hexadecimal"
// numbers, which we can generate faster than normal decimal or
// hexadecimal numbers, which in turn allows us to save the playlist
// more often without worrying too much about performance.
// (saving the full state takes about 40 ms under no-load conditions
// on the phone)
int len = mPlayListLen;
for (int i = 0; i < len; i++) {
int n = mPlayList[i];
if (n == 0) {
q.append("0;");
} else {
while (n != 0) {
int digit = n & 0xf;
n >>= 4;
q.append(hexdigits[digit]);
}
q.append(";");
}
}
//Log.i("@@@@ service", "created queue string in " + (System.currentTimeMillis() - start) + " ms");
ed.putString("queue", q.toString());
ed.putInt("cardid", mCardId);
}
ed.putInt("curpos", mPlayPos);
if (mPlayer.isInitialized()) {
ed.putLong("seekpos", mPlayer.position());
}
ed.putInt("repeatmode", mRepeatMode);
ed.putInt("shufflemode", mShuffleMode);
ed.commit();
//Log.i("@@@@ service", "saved state in " + (System.currentTimeMillis() - start) + " ms");
|
public long | seek(long pos)Seeks to the position specified.
if (mPlayer.isInitialized()) {
if (pos < 0) pos = 0;
if (pos > mPlayer.duration()) pos = mPlayer.duration();
return mPlayer.seek(pos);
}
return -1;
|
public void | setQueuePosition(int pos)Starts playing the track at the given position in the queue.
synchronized(this) {
stop(false);
mPlayPos = pos;
openCurrent();
play();
notifyChange(META_CHANGED);
}
|
public void | setRepeatMode(int repeatmode)
synchronized(this) {
mRepeatMode = repeatmode;
saveQueue(false);
}
|
public void | setShuffleMode(int shufflemode)
synchronized(this) {
if (mShuffleMode == shufflemode && mPlayListLen > 0) {
return;
}
mShuffleMode = shufflemode;
if (mShuffleMode == SHUFFLE_AUTO) {
if (makeAutoShuffleList()) {
mPlayListLen = 0;
doAutoShuffleUpdate();
mPlayPos = 0;
openCurrent();
play();
notifyChange(META_CHANGED);
return;
} else {
// failed to build a list of files to shuffle
mShuffleMode = SHUFFLE_NONE;
}
}
saveQueue(false);
}
|
private void | startAndFadeIn()
mMediaplayerHandler.sendEmptyMessageDelayed(FADEIN, 10);
|
private void | stop(boolean remove_status_icon)
if (mPlayer.isInitialized()) {
mPlayer.stop();
}
mFileToPlay = null;
if (mCursor != null) {
mCursor.close();
mCursor = null;
}
if (remove_status_icon) {
gotoIdleState();
}
setForeground(false);
if (remove_status_icon) {
mWasPlaying = false;
}
|
public void | stop()Stops playback.
stop(true);
|