mediaplaybackservice.java
来自「Android平台上的media player, iPhone风格」· Java 代码 · 共 1,619 行 · 第 1/4 页
JAVA
1,619 行
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; } } @Override public IBinder onBind(Intent intent) { mDelayedStopHandler.removeCallbacksAndMessages(null); mServiceInUse = true; return mBinder; } @Override public void onRebind(Intent intent) { mDelayedStopHandler.removeCallbacksAndMessages(null); mServiceInUse = true; } @Override public void onStart(Intent intent, int startId) { mServiceStartId = startId; mDelayedStopHandler.removeCallbacksAndMessages(null); String cmd = intent.getStringExtra("command"); if (CMDNEXT.equals(cmd)) { next(true); } else if (CMDTOGGLEPAUSE.equals(cmd)) { if (isPlaying()) { pause(); } else { play(); } } else if (CMDPAUSE.equals(cmd)) { pause(); } // 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); } @Override public boolean onUnbind(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; } private Handler mDelayedStopHandler = new Handler() { @Override public void handleMessage(Message msg) { // Check again to make sure nothing is playing right now if (isPlaying() || mResumeAfterCall || mServiceInUse || mMediaplayerHandler.hasMessages(TRACK_ENDED)) { return; } // save the queue again, because it might have change // since the user exited the music app (because of // party-shuffle or because the play-position changed) saveQueue(true); stopSelf(mServiceStartId); } }; /** * Called when we receive a ACTION_MEDIA_EJECT notification. * * @param storagePath path to mount point for the removed media */ public void closeExternalStorageFiles(String storagePath) { // stop playback and clean up if the SD card is going to be unmounted. stop(true); notifyChange(QUEUE_CHANGED); notifyChange(META_CHANGED); } /** * 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. */ public void registerExternalStorageListener() { 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); } } /** * 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.imusic.metachanged" * "com.android.imusic.queuechanged", * "com.android.imusic.playbackcomplete" * "com.android.imusic.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). */ private void notifyChange(String what) { 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); } } 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 } private void addToPlayList(int id) { synchronized(this) { ensurePlayListCapacity(mPlayListLen + 1); mPlayList[mPlayListLen++] = id; } } 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; } /** * 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. * @param list The list of tracks to append. * @param action NOW, NEXT or LAST */ public void enqueue(int [] list, int action) { 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); } } } /** * Replaces the current playlist with a new list, * and prepares for starting playback at the specified * position in the list. * @param list The new list of tracks. */ public void open(int [] list, int position) { synchronized (this) { if (mShuffleMode == SHUFFLE_AUTO) { mShuffleMode = SHUFFLE_NORMAL; } addToPlayList(list, -1); mPlayPos = position; mHistory.clear(); openCurrent(); } } /** * Moves the item at index1 to index2. * @param index1 * @param index2 */ public void moveQueueItem(int index1, int 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); } } /** * Returns the current play list * @return An array of integers containing the IDs of the tracks in the play list */ public int [] getQueue() { synchronized (this) { int len = mPlayListLen; int [] list = new int[len]; for (int i = 0; i < len; i++) { list[i] = mPlayList[i]; } return list; } } 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); } } } public void openAsync(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; } } /** * Opens the specified file and readies it for playback. * * @param path The full path of the file to be opened. * @param oneshot when set to true, playback will stop after this file completes, instead * of moving on to the next track in the list */ public void open(String path, boolean oneshot) { 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?