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 + -
显示快捷键?