mediaplaybackservice.java

来自「Android平台上的media player, iPhone风格」· Java 代码 · 共 1,619 行 · 第 1/4 页

JAVA
1,619
字号
                    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(0);                            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;                    Toast.makeText(this, R.string.playback_failed, Toast.LENGTH_SHORT).show();                }            } else {                mOpenFailedCounter = 0;            }        }    }    /**     * Starts playback of a previously opened file.     */    public void play() {        if (mPlayer.isInitialized()) {            mPlayer.start();            setForeground(true);            mWasPlaying = 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);            views.setTextViewText(R.id.trackname, getTrackName());            String artist = getArtistName();            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.imusic.playing");            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.imusic.playing"), 0);            nm.notify(PLAYBACKSERVICE_STATUS, status);            notifyChange(PLAYSTATE_CHANGED);        }    }    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);        mWasPlaying = false;    }    /**     * Stops playback.     */    public void stop() {        stop(true);    }    /**     * Pauses playback (call play() to resume)     */    public void pause() {        if (isPlaying()) {            mPlayer.pause();            gotoIdleState();            setForeground(false);            mWasPlaying = false;            notifyChange(PLAYSTATE_CHANGED);        }    }    /** Returns whether playback is currently paused     *     * @return true if playback is paused, false if not     */    public boolean isPlaying() {        if (mPlayer.isInitialized()) {            return mPlayer.isPlaying();        }        return false;    }    /*      Desired behavior for prev/next/shuffle:      - NEXT will move to the next track in the list when not shuffling, and to        a track randomly picked from the not-yet-played tracks when shuffling.        If all tracks have already been played, pick from the full set, but        avoid picking the previously played track if possible.      - when shuffling, PREV will go to the previously played track. Hitting PREV        again will go to the track played before that, etc. When the start of the        history has been reached, PREV is a no-op.        When not shuffling, PREV will go to the sequentially previous track (the        difference with the shuffle-case is mainly that when not shuffling, the        user can back up to tracks that are not in the history).        Example:        When playing an album with 10 tracks from the start, and enabling shuffle        while playing track 5, the remaining tracks (6-10) will be shuffled, e.g.        the final play order might be 1-2-3-4-5-8-10-6-9-7.        When hitting 'prev' 8 times while playing track 7 in this example, the        user will go to tracks 9-6-10-8-5-4-3-2. If the user then hits 'next',        a random track will be picked again. If at any time user disables shuffling        the next/previous track will be picked in sequential order again.     */    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;                }            }            stop(false);            openCurrent();            play();            notifyChange(META_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            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++;                }            }            stop(false);            openCurrent();            play();            notifyChange(META_CHANGED);        }    }        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);    }        // Make sure there are at least 5 items after the currently playing item    // and no more than 10 items before.    private void doAutoShuffleUpdate() {        // remove old entries        if (mPlayPos > 10) {            removeTracks(0, mPlayPos - 9);        }        // add new entries if needed        int to_add = 7 - (mPlayListLen - (mPlayPos < 0 ? -1 : mPlayPos));        if (to_add > 0) {            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];                addToPlayList(which);            }            notifyChange(QUEUE_CHANGED);        }    }    // A simple variation of Random that makes sure that the    // value it returns is not equal to the value it returned    // previously, unless the interval is 1.    private class Shuffler {        private int mPrevious;        private Random mRandom = new Random();        public int nextInt(int interval) {            int ret;            do {                ret = mRandom.nextInt(interval);            } while (ret == mPrevious && interval > 1);            mPrevious = ret;            return ret;        }    };    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;    }        /**     * 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.      * @param first The first file to be removed     * @param last The last file to be removed     * @return the number of tracks deleted     */    public int removeTracks(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;                    }                    stop(false);                    openCurrent();                    play();                }            }            notifyChange(QUEUE_CHANGED);            return last - first + 1;        }    }        /**     * Removes all instances of the track with the given id     * from the playlist.     * @param id The id to be removed     * @return how many instances of the track were removed     */    public int removeTrack(int id) {        int numremoved = 0;        synchronized (this) {            for (int i = 0; i < mPlayListLen; i++) {                if (mPlayList[i] == id) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?