MediaPlaybackService.java revision f4d4b342061ade12eb7903f454df62814179906f
1792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project/*
2792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
4792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * you may not use this file except in compliance with the License.
6792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * You may obtain a copy of the License at
7792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
8792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
10792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * See the License for the specific language governing permissions and
14792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * limitations under the License.
15792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */
16792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
17792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpackage com.android.music;
18792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
19792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.app.Notification;
20792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.app.PendingIntent;
21792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.app.Service;
22490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Projectimport android.appwidget.AppWidgetManager;
23792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ContentResolver;
24792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ContentUris;
25792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ContentValues;
26792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.Context;
27792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.Intent;
28792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.IntentFilter;
29792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.BroadcastReceiver;
30792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.SharedPreferences;
31792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.SharedPreferences.Editor;
32792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.database.Cursor;
33792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.database.sqlite.SQLiteException;
34792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.AudioManager;
35792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.MediaPlayer;
36792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.net.Uri;
37792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Environment;
38792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.FileUtils;
39792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Handler;
40792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.IBinder;
41792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Message;
42792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.PowerManager;
43792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.SystemClock;
44792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.PowerManager.WakeLock;
45792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.provider.MediaStore;
463d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissenimport android.telephony.PhoneStateListener;
473d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissenimport android.telephony.TelephonyManager;
48792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.util.Log;
49792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.RemoteViews;
50792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.Toast;
51792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
52792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.io.IOException;
532b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissenimport java.lang.ref.WeakReference;
54792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.util.Random;
55792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.util.Vector;
56792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
57792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project/**
58792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Provides "background" audio playback capabilities, allowing the
59792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * user to switch between activities without stopping playback.
60792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */
61792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpublic class MediaPlaybackService extends Service {
62792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** used to specify whether enqueue() should start playing
63792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the new list of files right away, next or once all the currently
64792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * queued files have been played
65792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
66792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int NOW = 1;
67792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int NEXT = 2;
68792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int LAST = 3;
69792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int PLAYBACKSERVICE_STATUS = 1;
70792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
71792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_NONE = 0;
72792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_NORMAL = 1;
73792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_AUTO = 2;
74792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
75792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_NONE = 0;
76792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_CURRENT = 1;
77792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_ALL = 2;
78792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
79792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PLAYSTATE_CHANGED = "com.android.music.playstatechanged";
80792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String META_CHANGED = "com.android.music.metachanged";
81792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String QUEUE_CHANGED = "com.android.music.queuechanged";
82792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PLAYBACK_COMPLETE = "com.android.music.playbackcomplete";
83792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String ASYNC_OPEN_COMPLETE = "com.android.music.asyncopencomplete";
84792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
85792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String SERVICECMD = "com.android.music.musicservicecommand";
86792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDNAME = "command";
87792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDTOGGLEPAUSE = "togglepause";
88792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDSTOP = "stop";
89792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDPAUSE = "pause";
90792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDPREVIOUS = "previous";
91792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDNEXT = "next";
92792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
93792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String TOGGLEPAUSE_ACTION = "com.android.music.musicservicecommand.togglepause";
94792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PAUSE_ACTION = "com.android.music.musicservicecommand.pause";
95792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PREVIOUS_ACTION = "com.android.music.musicservicecommand.previous";
96792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String NEXT_ACTION = "com.android.music.musicservicecommand.next";
97792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
98792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int TRACK_ENDED = 1;
99792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int RELEASE_WAKELOCK = 2;
100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int SERVER_DIED = 3;
101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int FADEIN = 4;
1023ec2ad9c8758d300864be808e491ae933dc9cd6bMarco Nelissen    private static final int MAX_HISTORY_SIZE = 100;
103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private MultiPlayer mPlayer;
105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private String mFileToPlay;
106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mShuffleMode = SHUFFLE_NONE;
107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mRepeatMode = REPEAT_NONE;
108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mMediaMountedCount = 0;
109bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private long [] mAutoShuffleList = null;
110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mOneShot;
111bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private long [] mPlayList = null;
112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mPlayListLen = 0;
113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Vector<Integer> mHistory = new Vector<Integer>(MAX_HISTORY_SIZE);
114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Cursor mCursor;
115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mPlayPos = -1;
116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final String LOGTAG = "MediaPlaybackService";
117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final Shuffler mRand = new Shuffler();
118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mOpenFailedCounter = 0;
119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    String[] mCursorCols = new String[] {
120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            "audio._id AS _id",             // index must match IDCOLIDX below
121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST,
122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ALBUM,
123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.TITLE,
124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.DATA,
125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.MIME_TYPE,
126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ALBUM_ID,
127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST_ID,
128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.IS_PODCAST, // index must match PODCASTCOLIDX below
129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.BOOKMARK    // index must match BOOKMARKCOLIDX below
130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int IDCOLIDX = 0;
132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int PODCASTCOLIDX = 8;
133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int BOOKMARKCOLIDX = 9;
134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private BroadcastReceiver mUnmountReceiver = null;
135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private WakeLock mWakeLock;
136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mServiceStartId = -1;
137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mServiceInUse = false;
138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mResumeAfterCall = false;
139c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen    private boolean mIsSupposedToBePlaying = false;
140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mQuietMode = false;
141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
142792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private SharedPreferences mPreferences;
143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // We use this to distinguish between different cards when saving/restoring playlists.
144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // This will have to change if we want to support multiple simultaneous cards.
145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mCardId;
146792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
147490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project    private MediaAppWidgetProvider mAppWidgetProvider = MediaAppWidgetProvider.getInstance();
148792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
149792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // interval after which we stop the service when idle
150792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int IDLE_DELAY = 60000;
151792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1523d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
1543d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen        public void onCallStateChanged(int state, String incomingNumber) {
1553d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen            if (state == TelephonyManager.CALL_STATE_RINGING) {
1563d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
1573d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                int ringvolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
1583d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                if (ringvolume > 0) {
1593d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                    mResumeAfterCall = (isPlaying() || mResumeAfterCall) && (getAudioId() >= 0);
1603d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                    pause();
1613d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                }
1623d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen            } else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
1633d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                // pause the music while a conversation is in progress
1643d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                mResumeAfterCall = (isPlaying() || mResumeAfterCall) && (getAudioId() >= 0);
1653d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                pause();
1663d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen            } else if (state == TelephonyManager.CALL_STATE_IDLE) {
1673d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                // start playing again
1683d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                if (mResumeAfterCall) {
1693d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                    // resume playback only if music was playing
1703d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                    // when the call was answered
1713d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                    startAndFadeIn();
1723d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                    mResumeAfterCall = false;
1733d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen                }
174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
175792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
176792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
177792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
178792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void startAndFadeIn() {
179792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mMediaplayerHandler.sendEmptyMessageDelayed(FADEIN, 10);
180792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
181792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
182792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Handler mMediaplayerHandler = new Handler() {
183792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        float mCurrentVolume = 1.0f;
184792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
185792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void handleMessage(Message msg) {
186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            switch (msg.what) {
187792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case FADEIN:
188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (!isPlaying()) {
189792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCurrentVolume = 0f;
190792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayer.setVolume(mCurrentVolume);
191792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mMediaplayerHandler.sendEmptyMessageDelayed(FADEIN, 10);
193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
194792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCurrentVolume += 0.01f;
195792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (mCurrentVolume < 1.0f) {
196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mMediaplayerHandler.sendEmptyMessageDelayed(FADEIN, 10);
197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        } else {
198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCurrentVolume = 1.0f;
199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayer.setVolume(mCurrentVolume);
201792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
202792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
203792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case SERVER_DIED:
204c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                    if (mIsSupposedToBePlaying) {
205792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        next(true);
206792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
207792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // the server died when we were idle, so just
208792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // reopen the same song (it will start again
209792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // from the beginning though when the user
210792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // restarts)
211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        openCurrent();
212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case TRACK_ENDED:
215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_CURRENT) {
216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        seek(0);
217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (!mOneShot) {
219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        next(false);
220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(PLAYBACK_COMPLETE);
222c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                        mIsSupposedToBePlaying = false;
223792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
224792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case RELEASE_WAKELOCK:
226792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mWakeLock.release();
227792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
228792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                default:
229792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
230792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
231792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
232792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
233792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
234792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
235792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
236792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void onReceive(Context context, Intent intent) {
237792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String action = intent.getAction();
238792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String cmd = intent.getStringExtra("command");
239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
240792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                next(true);
241792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                prev();
243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
244792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (isPlaying()) {
245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    pause();
246792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
247792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
248792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
249792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDSTOP.equals(cmd)) {
252792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
253792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                seek(0);
254490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project            } else if (MediaAppWidgetProvider.CMDAPPWIDGETUPDATE.equals(cmd)) {
255490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                // Someone asked us to refresh a set of specific widgets, probably
256792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // because they were just added.
257490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
258490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                mAppWidgetProvider.performUpdate(MediaPlaybackService.this, appWidgetIds);
259792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
260792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
261792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public MediaPlaybackService() {
264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onCreate() {
268792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onCreate();
269792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPreferences = getSharedPreferences("Music", MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE);
271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mCardId = FileUtils.getFatVolumeId(Environment.getExternalStorageDirectory().getPath());
272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        registerExternalStorageListener();
274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
275792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Needs to be done in this thread, since otherwise ApplicationContext.getPowerManager() crashes.
276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayer = new MultiPlayer();
277792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayer.setHandler(mMediaplayerHandler);
278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        reloadQueue();
280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        IntentFilter commandFilter = new IntentFilter();
282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(SERVICECMD);
283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(TOGGLEPAUSE_ACTION);
284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(PAUSE_ACTION);
285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(NEXT_ACTION);
286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(PREVIOUS_ACTION);
287792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        registerReceiver(mIntentReceiver, commandFilter);
288792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
2893d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen        TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
2903d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock.setReferenceCounted(false);
294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // If the service was idle, but got killed before it stopped itself, the
296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // system will relaunch it. Make sure it gets stopped again in that case.
297792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
298792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onDestroy() {
303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Check that we're not being destroyed while something is still playing.
304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (isPlaying()) {
305e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen            Log.e(LOGTAG, "Service being destroyed while still playing.");
306792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
3072b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        // release all MediaPlayer resources, including the native player and wakelocks
3082b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mPlayer.release();
3092b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mPlayer = null;
310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
3112b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        // make sure there aren't any other messages coming
3122b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mDelayedStopHandler.removeCallbacksAndMessages(null);
31349e36ea916aefba042c6e927c771b10708b6891eMarco Nelissen        mMediaplayerHandler.removeCallbacksAndMessages(null);
3142b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
315792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mCursor != null) {
316792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor.close();
317792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
318792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
319792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
3203d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen        TelephonyManager tmgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
3213d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen        tmgr.listen(mPhoneStateListener, 0);
3223d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissen
323792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        unregisterReceiver(mIntentReceiver);
324792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mUnmountReceiver != null) {
325792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            unregisterReceiver(mUnmountReceiver);
326792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnmountReceiver = null;
327792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
328792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock.release();
329792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onDestroy();
330792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
331792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
332792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final char hexdigits [] = new char [] {
333792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '0', '1', '2', '3',
334792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '4', '5', '6', '7',
335792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '8', '9', 'a', 'b',
336792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            'c', 'd', 'e', 'f'
337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
338792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
339792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void saveQueue(boolean full) {
340792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mOneShot) {
341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return;
342792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
343792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Editor ed = mPreferences.edit();
344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        //long start = System.currentTimeMillis();
345792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (full) {
346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            StringBuilder q = new StringBuilder();
347792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // The current playlist is saved as a list of "reverse hexadecimal"
349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // numbers, which we can generate faster than normal decimal or
350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // hexadecimal numbers, which in turn allows us to save the playlist
351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // more often without worrying too much about performance.
352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // (saving the full state takes about 40 ms under no-load conditions
353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // on the phone)
354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = mPlayListLen;
355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
356bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long n = mPlayList[i];
357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (n == 0) {
358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    q.append("0;");
359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    while (n != 0) {
361bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                        int digit = (int)(n & 0xf);
362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        n >>= 4;
363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        q.append(hexdigits[digit]);
364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    q.append(";");
366792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
367792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //Log.i("@@@@ service", "created queue string in " + (System.currentTimeMillis() - start) + " ms");
369792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putString("queue", q.toString());
370792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putInt("cardid", mCardId);
37163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (mShuffleMode != SHUFFLE_NONE) {
37263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                // In shuffle mode we need to save the history too
37363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                len = mHistory.size();
37463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                q.setLength(0);
37563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                for (int i = 0; i < len; i++) {
37663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    int n = mHistory.get(i);
37763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    if (n == 0) {
37863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        q.append("0;");
37963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    } else {
38063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        while (n != 0) {
38163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            int digit = (n & 0xf);
38263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            n >>= 4;
38363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            q.append(hexdigits[digit]);
38463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        }
38563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        q.append(";");
38663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    }
38763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                }
38863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                ed.putString("history", q.toString());
38963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            }
390792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
391792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("curpos", mPlayPos);
392792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
393792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putLong("seekpos", mPlayer.position());
394792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
395792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("repeatmode", mRepeatMode);
396792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("shufflemode", mShuffleMode);
397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.commit();
398792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        //Log.i("@@@@ service", "saved state in " + (System.currentTimeMillis() - start) + " ms");
400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
401792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
402792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void reloadQueue() {
403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String q = null;
404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
405792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        boolean newstyle = false;
406792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int id = mCardId;
407792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPreferences.contains("cardid")) {
408792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            newstyle = true;
409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            id = mPreferences.getInt("cardid", ~mCardId);
410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (id == mCardId) {
412792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Only restore the saved playlist if the card is still
413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // the same one as when the playlist was saved
414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            q = mPreferences.getString("queue", "");
415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
4166c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen        int qlen = q != null ? q.length() : 0;
4176c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen        if (qlen > 1) {
418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //Log.i("@@@@ service", "loaded queue: " + q);
419bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int plen = 0;
420bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int n = 0;
421bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int shift = 0;
422bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            for (int i = 0; i < qlen; i++) {
423bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                char c = q.charAt(i);
424bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                if (c == ';') {
425bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    ensurePlayListCapacity(plen + 1);
426bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    mPlayList[plen] = n;
427bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    plen++;
428bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    n = 0;
429bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    shift = 0;
430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
431bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    if (c >= '0' && c <= '9') {
432bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        n += ((c - '0') << shift);
433bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    } else if (c >= 'a' && c <= 'f') {
434bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        n += ((10 + c - 'a') << shift);
435bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    } else {
436bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        // bogus playlist data
437bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        plen = 0;
438bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        break;
439bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    }
440bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    shift += 4;
441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
443bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            mPlayListLen = plen;
444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int pos = mPreferences.getInt("curpos", 0);
446bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            if (pos < 0 || pos >= mPlayListLen) {
447792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // The saved playlist is bogus, discard it
448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 0;
449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
450792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
451792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = pos;
452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
453792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // When reloadQueue is called in response to a card-insertion,
454792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // we might not be able to query the media provider right away.
455792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // To deal with this, try querying for the current file, and if
456792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // that fails, wait a while and try again. If that too fails,
457792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // assume there is a problem and don't restore the state.
45863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            Cursor crsr = MusicUtils.query(this,
459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        new String [] {"_id"}, "_id=" + mPlayList[mPlayPos] , null, null);
46163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (crsr == null || crsr.getCount() == 0) {
462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // wait a bit and try again
463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                SystemClock.sleep(3000);
46463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                crsr = getContentResolver().query(
465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCursorCols, "_id=" + mPlayList[mPlayPos] , null, null);
467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
46863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (crsr != null) {
46963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                crsr.close();
470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Make sure we don't auto-skip to the next song, since that
473792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // also starts playback. What could happen in that case is:
474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music is paused
475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - go to UMS and delete some files, including the currently playing one
476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - come back from UMS
477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // (time passes)
478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music app is killed for some reason (out of memory)
479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music service is restarted, service restores state, doesn't find
480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //   the "current" file, goes to the next and: playback starts on its
481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //   own, potentially at some random inconvenient time.
482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mOpenFailedCounter = 20;
483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mQuietMode = true;
484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
485792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mQuietMode = false;
486792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (!mPlayer.isInitialized()) {
487792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // couldn't restore the saved state
488792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 0;
489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
491792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
492792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            long seekpos = mPreferences.getLong("seekpos", 0);
493792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            seek(seekpos >= 0 && seekpos < duration() ? seekpos : 0);
494e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen            Log.d(LOGTAG, "restored queue, currently at position "
495e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    + position() + "/" + duration()
496e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    + " (requested " + seekpos + ")");
497792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
498792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int repmode = mPreferences.getInt("repeatmode", REPEAT_NONE);
499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (repmode != REPEAT_ALL && repmode != REPEAT_CURRENT) {
500792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                repmode = REPEAT_NONE;
501792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
502792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = repmode;
503792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int shufmode = mPreferences.getInt("shufflemode", SHUFFLE_NONE);
505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (shufmode != SHUFFLE_AUTO && shufmode != SHUFFLE_NORMAL) {
506792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                shufmode = SHUFFLE_NONE;
507792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
50863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (shufmode != SHUFFLE_NONE) {
50963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                // in shuffle mode we need to restore the history too
51063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                q = mPreferences.getString("history", "");
51163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                qlen = q != null ? q.length() : 0;
51263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                if (qlen > 1) {
51363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    plen = 0;
51463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    n = 0;
51563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    shift = 0;
51663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    mHistory.clear();
51763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    for (int i = 0; i < qlen; i++) {
51863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        char c = q.charAt(i);
51963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        if (c == ';') {
52063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            if (n >= mPlayListLen) {
52163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                // bogus history data
52263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                mHistory.clear();
52363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                break;
52463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            }
52563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            mHistory.add(n);
52663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            n = 0;
52763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            shift = 0;
52863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        } else {
52963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            if (c >= '0' && c <= '9') {
53063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                n += ((c - '0') << shift);
53163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            } else if (c >= 'a' && c <= 'f') {
53263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                n += ((10 + c - 'a') << shift);
53363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            } else {
53463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                // bogus history data
53563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                mHistory.clear();
53663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                break;
53763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            }
53863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            shift += 4;
53963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        }
54063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    }
54163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                }
54263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            }
543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (shufmode == SHUFFLE_AUTO) {
544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (! makeAutoShuffleList()) {
545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    shufmode = SHUFFLE_NONE;
546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mShuffleMode = shufmode;
549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public IBinder onBind(Intent intent) {
554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = true;
556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mBinder;
557792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
558792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
560792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onRebind(Intent intent) {
561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = true;
563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
566c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen    public int onStartCommand(Intent intent, int flags, int startId) {
567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceStartId = startId;
568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
569c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen
570c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen        if (intent != null) {
571c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            String action = intent.getAction();
572c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            String cmd = intent.getStringExtra("command");
573c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen
574c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
575c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                next(true);
576c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
577b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                if (position() < 2000) {
578b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    prev();
579b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                } else {
580b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    seek(0);
581b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    play();
582b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                }
583c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
584c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                if (isPlaying()) {
585c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                    pause();
586c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                } else {
587c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                    play();
588c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                }
589c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
591c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDSTOP.equals(cmd)) {
592c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                pause();
593c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                seek(0);
594792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
595792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
596792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // make sure the service will shut down on its own if it was
598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // just started but not bound to and nothing is playing
599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
600792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
601792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
602c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen        return START_STICKY;
603792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
604792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
605792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
606792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean onUnbind(Intent intent) {
607792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = false;
608792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
609792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Take a snapshot of the current playlist
610792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        saveQueue(true);
611792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
612792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (isPlaying() || mResumeAfterCall) {
613792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // something is currently playing, or will be playing once
614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // an in-progress call ends, so don't stop the service now.
615792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
617792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // If there is a playlist but playback is paused, then wait a while
619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // before stopping the service, so that pause/resume isn't slow.
620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Also delay stopping the service if we're transitioning between tracks.
621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayListLen > 0  || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Message msg = mDelayedStopHandler.obtainMessage();
623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // No active playlist, OK to stop the service right now
628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stopSelf(mServiceStartId);
629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return true;
630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Handler mDelayedStopHandler = new Handler() {
633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void handleMessage(Message msg) {
635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Check again to make sure nothing is playing right now
636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (isPlaying() || mResumeAfterCall || mServiceInUse
637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // save the queue again, because it might have changed
641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // since the user exited the music app (because of
642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // party-shuffle or because the play-position changed)
643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(true);
644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stopSelf(mServiceStartId);
645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Called when we receive a ACTION_MEDIA_EJECT notification.
650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param storagePath path to mount point for the removed media
652792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void closeExternalStorageFiles(String storagePath) {
654792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // stop playback and clean up if the SD card is going to be unmounted.
655792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stop(true);
656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        notifyChange(QUEUE_CHANGED);
657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        notifyChange(META_CHANGED);
658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
659792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Registers an intent to listen for ACTION_MEDIA_EJECT notifications.
662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent will call closeExternalStorageFiles() if the external media
663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * is going to be ejected, so applications can clean up any files they have open.
664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void registerExternalStorageListener() {
666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mUnmountReceiver == null) {
667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnmountReceiver = new BroadcastReceiver() {
668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                @Override
669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                public void onReceive(Context context, Intent intent) {
670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    String action = intent.getAction();
671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        saveQueue(true);
673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mOneShot = true; // This makes us not save the state again later,
674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                                         // which would be wrong because the song ids and
675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                                         // card id might not match.
676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        closeExternalStorageFiles(intent.getData().getPath());
677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mMediaMountedCount++;
679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCardId = FileUtils.getFatVolumeId(intent.getData().getPath());
680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        reloadQueue();
681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(QUEUE_CHANGED);
682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(META_CHANGED);
683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            };
686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            IntentFilter iFilter = new IntentFilter();
687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_EJECT);
688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addDataScheme("file");
690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            registerReceiver(mUnmountReceiver, iFilter);
691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Notify the change-receivers that something has changed.
696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent that is sent contains the following data
697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * for the currently playing track:
698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "id" - Integer: the database row ID
699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "artist" - String: the name of the artist
700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "album" - String: the name of the album
701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "track" - String: the name of the track
702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent has an action that is one of
703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.metachanged"
704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.queuechanged",
705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.playbackcomplete"
706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.playstatechanged"
707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * respectively indicating that a new track has
708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * started playing, that the playback queue has
709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * changed, that playback has stopped because
710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the last file in the list has been played,
711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * or that the play-state changed (paused/resumed).
712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void notifyChange(String what) {
714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Intent i = new Intent(what);
716bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        i.putExtra("id", Long.valueOf(getAudioId()));
717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("artist", getArtistName());
718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("album",getAlbumName());
719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("track", getTrackName());
720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        sendBroadcast(i);
721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (what.equals(QUEUE_CHANGED)) {
723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(true);
724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
728490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project        // Share this notification directly with our widgets
729490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project        mAppWidgetProvider.notifyChange(this, what);
730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void ensurePlayListCapacity(int size) {
733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayList == null || size > mPlayList.length) {
734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // reallocate at 2x requested size so we don't
735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // need to grow and copy the array for every
736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // insert
737bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] newlist = new long[size * 2];
738bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int len = mPlayList != null ? mPlayList.length : mPlayListLen;
739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                newlist[i] = mPlayList[i];
741792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList = newlist;
743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // FIXME: shrink the array when the needed size is much smaller
745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // than the allocated size
746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // insert the list of songs at the specified position in the playlist
749bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private void addToPlayList(long [] list, int position) {
750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int addlen = list.length;
751792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (position < 0) { // overwrite
752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen = 0;
753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            position = 0;
754792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ensurePlayListCapacity(mPlayListLen + addlen);
756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (position > mPlayListLen) {
757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            position = mPlayListLen;
758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
759792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
760792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // move part of list after insertion point
761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int tailsize = mPlayListLen - position;
762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = tailsize ; i > 0 ; i--) {
763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[position + i] = mPlayList[position + i - addlen];
764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // copy list into playlist
767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < addlen; i++) {
768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[position + i] = list[i];
769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayListLen += addlen;
771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Appends a list of tracks to the current playlist.
775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * If nothing is playing currently, playback will be started at
776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the first track.
777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * If the action is NOW, playback will switch to the first of
778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the new tracks immediately.
779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param list The list of tracks to append.
780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param action NOW, NEXT or LAST
781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
782bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public void enqueue(long [] list, int action) {
783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (action == NEXT && mPlayPos + 1 < mPlayListLen) {
785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, mPlayPos + 1);
786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
788792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // action == LAST || action == NOW || mPlayPos + 1 == mPlayListLen
789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, Integer.MAX_VALUE);
790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (action == NOW) {
792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = mPlayListLen - list.length;
793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    notifyChange(META_CHANGED);
796792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
797792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
799792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos < 0) {
800792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = 0;
801792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                openCurrent();
802792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
803792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(META_CHANGED);
804792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
805792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
808792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
809792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Replaces the current playlist with a new list,
810792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * and prepares for starting playback at the specified
811792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * position in the list, or a random position if the
812792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * specified position is 0.
813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param list The new list of tracks.
814792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
815bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public void open(long [] list, int position) {
816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
817792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_AUTO) {
818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mShuffleMode = SHUFFLE_NORMAL;
819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
820bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long oldId = getAudioId();
821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int listlength = list.length;
822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            boolean newlist = true;
823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayListLen == listlength) {
824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // possible fast path: list might be the same
825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                newlist = false;
826792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = 0; i < listlength; i++) {
827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (list[i] != mPlayList[i]) {
828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        newlist = true;
829792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        break;
830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
832792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (newlist) {
834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, -1);
835792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
837792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int oldpos = mPlayPos;
838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (position >= 0) {
839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = position;
840792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
841792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = mRand.nextInt(mPlayListLen);
842792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mHistory.clear();
844792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
846792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
847d8c696753687ddb0177f869fad5f709eadfe27afJeffrey Sharkey            if (oldId != getAudioId()) {
848792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(META_CHANGED);
849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
850792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
851792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
853792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Moves the item at index1 to index2.
855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param index1
856792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param index2
857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
858792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void moveQueueItem(int index1, int index2) {
859792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
860792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index1 >= mPlayListLen) {
861792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                index1 = mPlayListLen - 1;
862792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
863792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index2 >= mPlayListLen) {
864792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                index2 = mPlayListLen - 1;
865792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index1 < index2) {
867bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long tmp = mPlayList[index1];
868792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = index1; i < index2; i++) {
869792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = mPlayList[i+1];
870792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
871792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[index2] = tmp;
872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos == index1) {
873792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = index2;
874792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else if (mPlayPos >= index1 && mPlayPos <= index2) {
875792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos--;
876792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
877792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (index2 < index1) {
878bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long tmp = mPlayList[index1];
879792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = index1; i > index2; i--) {
880792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = mPlayList[i-1];
881792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
882792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[index2] = tmp;
883792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos == index1) {
884792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = index2;
885792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else if (mPlayPos >= index2 && mPlayPos <= index1) {
886792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos++;
887792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
889792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
891792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
892792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
893792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
894792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the current play list
895792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return An array of integers containing the IDs of the tracks in the play list
896792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
897bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long [] getQueue() {
898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
899792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = mPlayListLen;
900bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = new long[len];
901792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
902792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                list[i] = mPlayList[i];
903792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
904792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return list;
905792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
906792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
907792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
908792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void openCurrent() {
909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
910792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor != null) {
911792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor.close();
912792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor = null;
913792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
914792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayListLen == 0) {
915792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
916792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
917792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
918792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
919792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String id = String.valueOf(mPlayList[mPlayPos]);
920792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
921792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = getContentResolver().query(
922792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
923792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mCursorCols, "_id=" + id , null, null);
924792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor != null) {
925792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor.moveToFirst();
926792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                open(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + id, false);
927792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // go to bookmark if needed
928792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (isPodcast()) {
929792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    long bookmark = getBookmark();
930792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // Start playing a little bit before the bookmark,
931792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // so it's easier to get back in to the narrative.
932792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    seek(bookmark - 5000);
933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
935792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
936792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
938792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void openAsync(String path) {
939792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
940792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (path == null) {
941792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
942792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
943792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
944792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = REPEAT_NONE;
945792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ensurePlayListCapacity(1);
946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen = 1;
947792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = -1;
948792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
949792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mFileToPlay = path;
950792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
951792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.setDataSourceAsync(mFileToPlay);
952792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mOneShot = true;
953792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
954792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
955792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
956792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
957792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Opens the specified file and readies it for playback.
958792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
959792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param path The full path of the file to be opened.
960792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param oneshot when set to true, playback will stop after this file completes, instead
961792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * of moving on to the next track in the list
962792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
963792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void open(String path, boolean oneshot) {
964792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
965792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (path == null) {
966792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
967792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
968792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
969792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (oneshot) {
970792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mRepeatMode = REPEAT_NONE;
971792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ensurePlayListCapacity(1);
972792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 1;
973792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = -1;
974792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
975792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
976792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // if mCursor is null, try to associate path with a database cursor
977792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
978792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
979792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ContentResolver resolver = getContentResolver();
980792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Uri uri;
981792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String where;
982792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String selectionArgs[];
983792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (path.startsWith("content://media/")) {
984792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    uri = Uri.parse(path);
985792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    where = null;
986792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    selectionArgs = null;
987792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
988792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   uri = MediaStore.Audio.Media.getContentUriForPath(path);
989792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   where = MediaStore.Audio.Media.DATA + "=?";
990792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   selectionArgs = new String[] { path };
991792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
992792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
993792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                try {
994792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mCursor = resolver.query(uri, mCursorCols, where, selectionArgs, null);
995792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if  (mCursor != null) {
996792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (mCursor.getCount() == 0) {
997792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor.close();
998792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor = null;
999792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        } else {
1000792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor.moveToNext();
1001792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            ensurePlayListCapacity(1);
1002792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mPlayListLen = 1;
1003bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                            mPlayList[0] = mCursor.getLong(IDCOLIDX);
1004792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mPlayPos = 0;
1005792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
1006792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1007792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } catch (UnsupportedOperationException ex) {
1008792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1009792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1010792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mFileToPlay = path;
1011792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.setDataSource(mFileToPlay);
1012792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mOneShot = oneshot;
1013792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (! mPlayer.isInitialized()) {
1014792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                stop(true);
1015792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mOpenFailedCounter++ < 10 &&  mPlayListLen > 1) {
1016792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // beware: this ends up being recursive because next() calls open() again.
1017792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    next(false);
1018792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1019792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (! mPlayer.isInitialized() && mOpenFailedCounter != 0) {
1020792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // need to make sure we only shows this once
1021792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mOpenFailedCounter = 0;
1022792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (!mQuietMode) {
1023792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        Toast.makeText(this, R.string.playback_failed, Toast.LENGTH_SHORT).show();
1024792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1025e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    Log.d(LOGTAG, "Failed to open file for playback");
1026792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1027792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1028792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mOpenFailedCounter = 0;
1029792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1030792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1031792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1032792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1033792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1034792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Starts playback of a previously opened file.
1035792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1036792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void play() {
1037792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1038272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle            // if we are at the end of the song, go to the next song first
10392f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen            long duration = mPlayer.duration();
10402f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen            if (mRepeatMode != REPEAT_CURRENT && duration > 2000 &&
10412f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen                mPlayer.position() >= duration - 2000) {
1042272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle                next(true);
1043272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle            }
1044272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle
1045792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.start();
1046792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1047792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            RemoteViews views = new RemoteViews(getPackageName(), R.layout.statusbar);
1048792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            views.setImageViewResource(R.id.icon, R.drawable.stat_notify_musicplayer);
1049792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (getAudioId() < 0) {
1050792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // streaming
1051792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.trackname, getPath());
1052792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.artistalbum, null);
1053792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1054792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String artist = getArtistName();
1055792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.trackname, getTrackName());
1056f4d4b342061ade12eb7903f454df62814179906fMarco Nelissen                if (artist == null || artist.equals(MediaStore.UNKNOWN_STRING)) {
1057792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    artist = getString(R.string.unknown_artist_name);
1058792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1059792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String album = getAlbumName();
1060f4d4b342061ade12eb7903f454df62814179906fMarco Nelissen                if (album == null || album.equals(MediaStore.UNKNOWN_STRING)) {
1061792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    album = getString(R.string.unknown_album_name);
1062792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1063792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1064792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.artistalbum,
1065792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        getString(R.string.notification_artist_album, artist, album)
1066792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        );
1067792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1068792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1069792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Notification status = new Notification();
1070792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.contentView = views;
1071792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.flags |= Notification.FLAG_ONGOING_EVENT;
1072792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.icon = R.drawable.stat_notify_musicplayer;
1073792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.contentIntent = PendingIntent.getActivity(this, 0,
1074ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    new Intent("com.android.music.PLAYBACK_VIEWER")
1075ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0);
1076d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn            startForeground(PLAYBACKSERVICE_STATUS, status);
1077c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen            if (!mIsSupposedToBePlaying) {
1078347fe57e4c8a860dfbad6f0ec1991171bfa69d77Mike Cleron                mIsSupposedToBePlaying = true;
1079792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(PLAYSTATE_CHANGED);
1080792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1081347fe57e4c8a860dfbad6f0ec1991171bfa69d77Mike Cleron
1082792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else if (mPlayListLen <= 0) {
1083792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // This is mostly so that if you press 'play' on a bluetooth headset
1084792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // without every having played anything before, it will still play
1085792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // something.
1086792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            setShuffleMode(SHUFFLE_AUTO);
1087792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1088792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1089792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1090792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void stop(boolean remove_status_icon) {
1091792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1092792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.stop();
1093792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1094792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mFileToPlay = null;
1095792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mCursor != null) {
1096792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor.close();
1097792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
1098792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1099792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (remove_status_icon) {
1100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            gotoIdleState();
1101d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn        } else {
1102d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn            stopForeground(false);
1103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (remove_status_icon) {
1105c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen            mIsSupposedToBePlaying = false;
1106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1109792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Stops playback.
1111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void stop() {
1113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stop(true);
1114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Pauses playback (call play() to resume)
1118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void pause() {
1120407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen        synchronized(this) {
1121407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen            if (isPlaying()) {
1122407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                mPlayer.pause();
1123407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                gotoIdleState();
1124407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                mIsSupposedToBePlaying = false;
1125407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                notifyChange(PLAYSTATE_CHANGED);
1126407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                saveBookmarkIfNeeded();
1127407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen            }
1128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1131b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen    /** Returns whether something is currently playing
1132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
1133b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen     * @return true if something is playing (or will be playing shortly, in case
1134b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen     * we're currently transitioning between tracks), false if not.
1135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean isPlaying() {
1137c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen        return mIsSupposedToBePlaying;
1138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /*
1141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      Desired behavior for prev/next/shuffle:
1142792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      - NEXT will move to the next track in the list when not shuffling, and to
1144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        a track randomly picked from the not-yet-played tracks when shuffling.
1145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        If all tracks have already been played, pick from the full set, but
1146792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        avoid picking the previously played track if possible.
1147792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      - when shuffling, PREV will go to the previously played track. Hitting PREV
1148792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        again will go to the track played before that, etc. When the start of the
1149792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        history has been reached, PREV is a no-op.
1150792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When not shuffling, PREV will go to the sequentially previous track (the
1151792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        difference with the shuffle-case is mainly that when not shuffling, the
1152792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        user can back up to tracks that are not in the history).
1153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1154792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Example:
1155792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When playing an album with 10 tracks from the start, and enabling shuffle
1156792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        while playing track 5, the remaining tracks (6-10) will be shuffled, e.g.
1157792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        the final play order might be 1-2-3-4-5-8-10-6-9-7.
1158792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When hitting 'prev' 8 times while playing track 7 in this example, the
1159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        user will go to tracks 9-6-10-8-5-4-3-2. If the user then hits 'next',
1160792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        a random track will be picked again. If at any time user disables shuffling
1161792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        the next/previous track will be picked in sequential order again.
1162792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1163792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1164792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void prev() {
1165792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1166792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mOneShot) {
1167792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // we were playing a specific file not part of a playlist, so there is no 'previous'
1168792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                seek(0);
1169792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
1170792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1171792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1172792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_NORMAL) {
1173792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // go to previously-played track and remove it from the history
1174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int histsize = mHistory.size();
1175792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (histsize == 0) {
1176792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // prev is a no-op
1177792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1178792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1179792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Integer pos = mHistory.remove(histsize - 1);
1180792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = pos.intValue();
1181792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1182792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos > 0) {
1183792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos--;
1184792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1185792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = mPlayListLen - 1;
1186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1187792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
1189792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1190792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1191792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1194792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1195792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void next(boolean force) {
1197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mOneShot) {
1199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // we were playing a specific file not part of a playlist, so there is no 'next'
1200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                seek(0);
1201792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
1202792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1203792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1204792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1205663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen            if (mPlayListLen <= 0) {
1206e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                Log.d(LOGTAG, "No play queue");
1207663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen                return;
1208663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen            }
1209663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen
1210792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Store the current file in the history, but keep the history at a
1211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // reasonable size
1212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos >= 0) {
1213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHistory.add(Integer.valueOf(mPlayPos));
1214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mHistory.size() > MAX_HISTORY_SIZE) {
1216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHistory.removeElementAt(0);
1217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_NORMAL) {
1220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Pick random next track from the not-yet-played ones
1221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: make it work right after adding/removing items in the queue.
1222792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1223792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numTracks = mPlayListLen;
1224792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int[] tracks = new int[numTracks];
1225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i=0;i < numTracks; i++) {
1226792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    tracks[i] = i;
1227792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1228792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1229792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numHistory = mHistory.size();
1230792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numUnplayed = numTracks;
1231792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i=0;i < numHistory; i++) {
1232792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    int idx = mHistory.get(i).intValue();
1233792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (idx < numTracks && tracks[idx] >= 0) {
1234792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        numUnplayed--;
1235792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        tracks[idx] = -1;
1236792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1237792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1238792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // 'numUnplayed' now indicates how many tracks have not yet
1240792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // been played, and 'tracks' contains the indices of those
1241792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // tracks.
1242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (numUnplayed <=0) {
1243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // everything's already been played
1244792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_ALL || force) {
1245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        //pick from full set
1246792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        numUnplayed = numTracks;
1247792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        for (int i=0;i < numTracks; i++) {
1248792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            tracks[i] = i;
1249792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
1250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
1251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // all done
1252792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        gotoIdleState();
1253792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        return;
1254792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1255792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1256792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int skip = mRand.nextInt(numUnplayed);
1257792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int cnt = -1;
1258792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                while (true) {
1259792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    while (tracks[++cnt] < 0)
1260792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        ;
1261792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    skip--;
1262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (skip < 0) {
1263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        break;
1264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = cnt;
1267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (mShuffleMode == SHUFFLE_AUTO) {
1268792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                doAutoShuffleUpdate();
1269792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos++;
1270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos >= mPlayListLen - 1) {
1272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // we're at the end of the list
1273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_NONE && !force) {
1274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // all done
1275792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        gotoIdleState();
1276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(PLAYBACK_COMPLETE);
1277c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                        mIsSupposedToBePlaying = false;
1278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        return;
1279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (mRepeatMode == REPEAT_ALL || force) {
1280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos = 0;
1281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos++;
1284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
1287792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1288792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1289792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void gotoIdleState() {
1295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
1296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
1297792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
1298d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn        stopForeground(true);
1299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void saveBookmarkIfNeeded() {
1302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (isPodcast()) {
1304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long pos = position();
1305792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long bookmark = getBookmark();
1306792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long duration = duration();
1307792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if ((pos < bookmark && (pos + 10000) > bookmark) ||
1308792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        (pos > bookmark && (pos - 10000) < bookmark)) {
1309792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // The existing bookmark is close to the current
1310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // position, so don't update it.
1311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (pos < 15000 || (pos + 10000) > duration) {
1314792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // if we're near the start or end, clear the bookmark
1315792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    pos = 0;
1316792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1317792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1318792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // write 'pos' to the bookmark field
1319792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ContentValues values = new ContentValues();
1320792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                values.put(MediaStore.Audio.Media.BOOKMARK, pos);
1321792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Uri uri = ContentUris.withAppendedId(
1322792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursor.getLong(IDCOLIDX));
1323792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                getContentResolver().update(uri, values, null, null);
1324792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1325792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (SQLiteException ex) {
1326792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1327792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1328792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1329792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // Make sure there are at least 5 items after the currently playing item
1330792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // and no more than 10 items before.
1331792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void doAutoShuffleUpdate() {
1332792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        boolean notify = false;
1333792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // remove old entries
1334792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayPos > 10) {
1335792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            removeTracks(0, mPlayPos - 9);
1336792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notify = true;
1337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1338792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // add new entries if needed
1339792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int to_add = 7 - (mPlayListLen - (mPlayPos < 0 ? -1 : mPlayPos));
1340792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < to_add; i++) {
1341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // pick something at random from the list
1342792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int idx = mRand.nextInt(mAutoShuffleList.length);
1343bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long which = mAutoShuffleList[idx];
1344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ensurePlayListCapacity(mPlayListLen + 1);
1345792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[mPlayListLen++] = which;
1346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notify = true;
1347792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (notify) {
1349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // A simple variation of Random that makes sure that the
1354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // value it returns is not equal to the value it returned
1355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // previously, unless the interval is 1.
1356756c3f57f11a7bb3bf1cf1333ee8ffbc51039748Marco Nelissen    private static class Shuffler {
1357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private int mPrevious;
1358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private Random mRandom = new Random();
1359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int nextInt(int interval) {
1360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int ret;
1361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            do {
1362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ret = mRandom.nextInt(interval);
1363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } while (ret == mPrevious && interval > 1);
1364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPrevious = ret;
1365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return ret;
1366792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1367792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
1368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1369792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean makeAutoShuffleList() {
1370792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ContentResolver res = getContentResolver();
1371792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor c = null;
1372792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1373792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            c = res.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1374792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    new String[] {MediaStore.Audio.Media._ID}, MediaStore.Audio.Media.IS_MUSIC + "=1",
1375792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    null, null);
1376792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c == null || c.getCount() == 0) {
1377792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1378792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1379792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = c.getCount();
1380bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = new long[len];
1381792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
1382792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.moveToNext();
1383bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                list[i] = c.getLong(0);
1384792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1385792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mAutoShuffleList = list;
1386792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
1387792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (RuntimeException ex) {
1388792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } finally {
1389792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c != null) {
1390792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.close();
1391792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1392792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1393792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return false;
1394792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1395792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1396792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Removes the range of tracks specified from the play list. If a file within the range is
1398792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the file currently being played, playback will move to the next file after the
1399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * range.
1400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param first The first file to be removed
1401792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param last The last file to be removed
1402792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return the number of tracks deleted
1403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int removeTracks(int first, int last) {
1405792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int numremoved = removeTracksInternal(first, last);
1406792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (numremoved > 0) {
1407792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1408792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return numremoved;
1410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1412792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int removeTracksInternal(int first, int last) {
1413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (last < first) return 0;
1415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (first < 0) first = 0;
1416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (last >= mPlayListLen) last = mPlayListLen - 1;
1417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            boolean gotonext = false;
1419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (first <= mPlayPos && mPlayPos <= last) {
1420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = first;
1421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                gotonext = true;
1422792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (mPlayPos > last) {
1423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos -= (last - first + 1);
1424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int num = mPlayListLen - last - 1;
1426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < num; i++) {
1427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[first + i] = mPlayList[last + 1 + i];
1428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen -= last - first + 1;
1430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (gotonext) {
1432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayListLen == 0) {
1433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    stop(true);
1434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = -1;
1435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1436792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mPlayPos >= mPlayListLen) {
1437792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos = 0;
1438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    boolean wasPlaying = isPlaying();
1440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    stop(false);
1441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
1442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (wasPlaying) {
1443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
1444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1446792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1447792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return last - first + 1;
1448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1450792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1451792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Removes all instances of the track with the given id
1453792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * from the playlist.
1454792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param id The id to be removed
1455792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return how many instances of the track were removed
1456792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1457bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public int removeTrack(long id) {
1458792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int numremoved = 0;
1459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < mPlayListLen; i++) {
1461792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayList[i] == id) {
1462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    numremoved += removeTracksInternal(i, i);
1463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    i--;
1464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (numremoved > 0) {
1468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return numremoved;
1471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1473792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setShuffleMode(int shufflemode) {
1474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == shufflemode && mPlayListLen > 0) {
1476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mShuffleMode = shufflemode;
1479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_AUTO) {
1480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (makeAutoShuffleList()) {
1481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayListLen = 0;
1482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    doAutoShuffleUpdate();
1483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = 0;
1484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
1485792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
1486792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    notifyChange(META_CHANGED);
1487792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1488792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // failed to build a list of files to shuffle
1490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mShuffleMode = SHUFFLE_NONE;
1491792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1492792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1493792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
1494792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1495792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1496792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getShuffleMode() {
1497792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mShuffleMode;
1498792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1500792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setRepeatMode(int repeatmode) {
1501792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1502792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = repeatmode;
1503792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
1504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1506792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getRepeatMode() {
1507792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mRepeatMode;
1508792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1509792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getMediaMountedCount() {
1511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mMediaMountedCount;
1512792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1513792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1514792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1515792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the path of the currently playing file, or null if
1516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * no file is currently playing.
1517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getPath() {
1519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mFileToPlay;
1520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1521792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the rowid of the currently playing file, or -1 if
1524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * no file is currently playing.
1525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1526bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getAudioId() {
1527792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1528792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos >= 0 && mPlayer.isInitialized()) {
1529792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return mPlayList[mPlayPos];
1530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1533792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1536792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the position in the queue
1537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return the position in the queue
1538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1539792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getQueuePosition() {
1540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayPos;
1542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Starts playing the track at the given position in the queue.
1547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param pos The position in the queue of the track that will be played.
1548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setQueuePosition(int pos) {
1550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = pos;
1553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1556ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            if (mShuffleMode == SHUFFLE_AUTO) {
1557ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                doAutoShuffleUpdate();
1558ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            }
1559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1560792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getArtistName() {
1563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
1568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1571bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getArtistId() {
1572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return -1;
1575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1576bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID));
1577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getAlbumName() {
1581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1583792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1584792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1585792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
1586792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1587792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1588792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1589bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getAlbumId() {
1590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1591792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1592792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return -1;
1593792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1594bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
1595792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1596792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getTrackName() {
1599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1600792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1601792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1602792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1603792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
1604792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1605792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1606792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1607792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean isPodcast() {
1608792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1609792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1610792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1611792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1612792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return (mCursor.getInt(PODCASTCOLIDX) > 0);
1613792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1615792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private long getBookmark() {
1617792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return 0;
1620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getLong(BOOKMARKCOLIDX);
1622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the duration of the file in milliseconds.
1627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Currently this method returns -1 for the duration of MIDI files.
1628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long duration() {
1630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.duration();
1632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the current playback position in milliseconds
1638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long position() {
1640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.position();
1642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Seeks to the position specified.
1648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
1649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param pos The position to seek to, in milliseconds
1650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long seek(long pos) {
1652792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (pos < 0) pos = 0;
1654792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (pos > mPlayer.duration()) pos = mPlayer.duration();
1655792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.seek(pos);
1656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1659792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Provides a unified interface for dealing with midi files and
1662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * other media files.
1663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private class MultiPlayer {
1665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private MediaPlayer mMediaPlayer = new MediaPlayer();
1666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private Handler mHandler;
1667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private boolean mIsInitialized = false;
1668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public MultiPlayer() {
1670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK);
1671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setDataSourceAsync(String path) {
1674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
1675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.reset();
1676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setDataSource(path);
1677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
1678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setOnPreparedListener(preparedlistener);
1679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.prepareAsync();
1680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IOException ex) {
1681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IllegalArgumentException ex) {
1685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnCompletionListener(listener);
1690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnErrorListener(errorListener);
1691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = true;
1693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setDataSource(String path) {
1696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
1697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.reset();
1698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setOnPreparedListener(null);
1699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (path.startsWith("content://")) {
1700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setDataSource(MediaPlaybackService.this, Uri.parse(path));
1701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setDataSource(path);
1703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
1705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.prepare();
1706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IOException ex) {
1707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IllegalArgumentException ex) {
1711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnCompletionListener(listener);
1716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnErrorListener(errorListener);
1717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = true;
1719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public boolean isInitialized() {
1722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mIsInitialized;
1723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void start() {
1726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.start();
1727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1728792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void stop() {
1730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.reset();
1731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = false;
1732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
17342b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        /**
17352b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen         * You CANNOT use this player anymore after calling release()
17362b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen         */
17372b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        public void release() {
17382b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            stop();
17392b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mMediaPlayer.release();
17402b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        }
17412b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
1742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void pause() {
1743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.pause();
1744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setHandler(Handler handler) {
1747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mHandler = handler;
1748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnCompletionListener listener = new MediaPlayer.OnCompletionListener() {
1751792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public void onCompletion(MediaPlayer mp) {
1752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Acquire a temporary wakelock, since when we return from
1753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // this callback the MediaPlayer will release its wakelock
1754792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // and allow the device to go to sleep.
1755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // This temporary wakelock is released when the RELEASE_WAKELOCK
1756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // message is processed, but just in case, put a timeout on it.
1757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mWakeLock.acquire(30000);
1758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHandler.sendEmptyMessage(TRACK_ENDED);
1759792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHandler.sendEmptyMessage(RELEASE_WAKELOCK);
1760792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnPreparedListener preparedlistener = new MediaPlayer.OnPreparedListener() {
1764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public void onPrepared(MediaPlayer mp) {
1765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(ASYNC_OPEN_COMPLETE);
1766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnErrorListener errorListener = new MediaPlayer.OnErrorListener() {
1770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public boolean onError(MediaPlayer mp, int what, int extra) {
1771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                switch (what) {
1772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
1773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mIsInitialized = false;
1774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.release();
1775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // Creating a new MediaPlayer and settings its wakemode does not
1776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // require the media service, so it's OK to do this now, while the
1777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // service is still being restarted
1778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer = new MediaPlayer();
1779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK);
1780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mHandler.sendMessageDelayed(mHandler.obtainMessage(SERVER_DIED), 2000);
1781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return true;
1782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                default:
1783e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    Log.d("MultiPlayer", "Error: " + what + "," + extra);
1784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
1785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project           }
1788792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long duration() {
1791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mMediaPlayer.getDuration();
1792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long position() {
1795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mMediaPlayer.getCurrentPosition();
1796792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1797792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long seek(long whereto) {
1799792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.seekTo((int) whereto);
1800792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return whereto;
1801792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1802792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1803792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setVolume(float vol) {
1804792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setVolume(vol, vol);
1805792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
18082b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    /*
18092b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * By making this a static class with a WeakReference to the Service, we
18102b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * ensure that the Service can be GCd even when the system process still
18112b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * has a remote reference to the stub.
18122b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     */
18132b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    static class ServiceStub extends IMediaPlaybackService.Stub {
18142b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        WeakReference<MediaPlaybackService> mService;
18152b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
18162b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        ServiceStub(MediaPlaybackService service) {
18172b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService = new WeakReference<MediaPlaybackService>(service);
18182b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        }
18192b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
1820b7841acd23f0cf4fd8db604d73bdf14e57994fd9Marco Nelissen        public void openFileAsync(String path)
1821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        {
18222b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().openAsync(path);
1823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1824b7841acd23f0cf4fd8db604d73bdf14e57994fd9Marco Nelissen        public void openFile(String path, boolean oneShot)
1825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        {
18262b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().open(path, oneShot);
1827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1828bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public void open(long [] list, int position) {
18292b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().open(list, position);
1830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getQueuePosition() {
18322b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getQueuePosition();
1833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setQueuePosition(int index) {
18352b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setQueuePosition(index);
1836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1837792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public boolean isPlaying() {
18382b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().isPlaying();
1839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1840792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void stop() {
18412b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().stop();
1842792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void pause() {
18442b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().pause();
1845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1846792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void play() {
18472b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().play();
1848792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void prev() {
18502b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().prev();
1851792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void next() {
18532b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().next(true);
1854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getTrackName() {
18562b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getTrackName();
1857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1858792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getAlbumName() {
18592b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAlbumName();
1860792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1861bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getAlbumId() {
18622b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAlbumId();
1863792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1864792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getArtistName() {
18652b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getArtistName();
1866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1867bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getArtistId() {
18682b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getArtistId();
1869792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1870bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public void enqueue(long [] list , int action) {
18712b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().enqueue(list, action);
1872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1873bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long [] getQueue() {
18742b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getQueue();
1875792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1876792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void moveQueueItem(int from, int to) {
18772b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().moveQueueItem(from, to);
1878792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1879792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getPath() {
18802b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getPath();
1881792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1882bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getAudioId() {
18832b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAudioId();
1884792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1885792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long position() {
18862b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().position();
1887792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long duration() {
18892b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().duration();
1890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1891792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long seek(long pos) {
18922b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().seek(pos);
1893792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1894792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setShuffleMode(int shufflemode) {
18952b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setShuffleMode(shufflemode);
1896792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1897792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getShuffleMode() {
18982b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getShuffleMode();
1899792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1900792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int removeTracks(int first, int last) {
19012b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().removeTracks(first, last);
1902792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1903bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public int removeTrack(long id) {
19042b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().removeTrack(id);
1905792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1906792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setRepeatMode(int repeatmode) {
19072b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setRepeatMode(repeatmode);
1908792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getRepeatMode() {
19102b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getRepeatMode();
1911792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1912792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getMediaMountedCount() {
19132b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getMediaMountedCount();
1914792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
19152b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
19162b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    }
19172b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
19182b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    private final IBinder mBinder = new ServiceStub(this);
1919792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project}
1920