MediaPlaybackService.java revision 272eb78d8836f969f7480454167bdffc6a6f6dd7
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.NotificationManager;
21792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.app.PendingIntent;
22792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.app.Service;
23490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Projectimport android.appwidget.AppWidgetManager;
24792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ContentResolver;
25792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ContentUris;
26792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.ContentValues;
27792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.Context;
28792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.Intent;
29792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.IntentFilter;
30792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.BroadcastReceiver;
31792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.SharedPreferences;
32792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.content.SharedPreferences.Editor;
33792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.database.Cursor;
34792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.database.sqlite.SQLiteException;
35792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.AudioManager;
36792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.MediaFile;
37792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.MediaPlayer;
38792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.net.Uri;
39792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Environment;
40792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.FileUtils;
41792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Handler;
42792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.IBinder;
43792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Message;
44792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.PowerManager;
45792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.SystemClock;
46792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.PowerManager.WakeLock;
47792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.provider.MediaStore;
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 Projectimport com.android.internal.telephony.Phone;
52792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport com.android.internal.telephony.PhoneStateIntentReceiver;
53792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
54792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.io.IOException;
552b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissenimport java.lang.ref.WeakReference;
56792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.util.Random;
57792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.util.Vector;
58792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
59792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project/**
60792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Provides "background" audio playback capabilities, allowing the
61792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * user to switch between activities without stopping playback.
62792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */
63792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpublic class MediaPlaybackService extends Service {
64792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** used to specify whether enqueue() should start playing
65792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the new list of files right away, next or once all the currently
66792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * queued files have been played
67792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
68792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int NOW = 1;
69792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int NEXT = 2;
70792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int LAST = 3;
71792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int PLAYBACKSERVICE_STATUS = 1;
72792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
73792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_NONE = 0;
74792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_NORMAL = 1;
75792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_AUTO = 2;
76792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
77792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_NONE = 0;
78792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_CURRENT = 1;
79792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_ALL = 2;
80792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
81792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PLAYSTATE_CHANGED = "com.android.music.playstatechanged";
82792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String META_CHANGED = "com.android.music.metachanged";
83792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String QUEUE_CHANGED = "com.android.music.queuechanged";
84792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PLAYBACK_COMPLETE = "com.android.music.playbackcomplete";
85792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String ASYNC_OPEN_COMPLETE = "com.android.music.asyncopencomplete";
86792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
87792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String SERVICECMD = "com.android.music.musicservicecommand";
88792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDNAME = "command";
89792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDTOGGLEPAUSE = "togglepause";
90792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDSTOP = "stop";
91792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDPAUSE = "pause";
92792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDPREVIOUS = "previous";
93792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDNEXT = "next";
94792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
95792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String TOGGLEPAUSE_ACTION = "com.android.music.musicservicecommand.togglepause";
96792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PAUSE_ACTION = "com.android.music.musicservicecommand.pause";
97792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PREVIOUS_ACTION = "com.android.music.musicservicecommand.previous";
98792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String NEXT_ACTION = "com.android.music.musicservicecommand.next";
99792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int PHONE_CHANGED = 1;
101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int TRACK_ENDED = 1;
102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int RELEASE_WAKELOCK = 2;
103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int SERVER_DIED = 3;
104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int FADEIN = 4;
105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int MAX_HISTORY_SIZE = 10;
106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private MultiPlayer mPlayer;
108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private String mFileToPlay;
109792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private PhoneStateIntentReceiver mPsir;
110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mShuffleMode = SHUFFLE_NONE;
111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mRepeatMode = REPEAT_NONE;
112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mMediaMountedCount = 0;
113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int [] mAutoShuffleList = null;
114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mOneShot;
115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int [] mPlayList = null;
116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mPlayListLen = 0;
117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Vector<Integer> mHistory = new Vector<Integer>(MAX_HISTORY_SIZE);
118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Cursor mCursor;
119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mPlayPos = -1;
120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final String LOGTAG = "MediaPlaybackService";
121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final Shuffler mRand = new Shuffler();
122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mOpenFailedCounter = 0;
123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    String[] mCursorCols = new String[] {
124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            "audio._id AS _id",             // index must match IDCOLIDX below
125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST,
126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ALBUM,
127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.TITLE,
128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.DATA,
129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.MIME_TYPE,
130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ALBUM_ID,
131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST_ID,
132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.IS_PODCAST, // index must match PODCASTCOLIDX below
133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.BOOKMARK    // index must match BOOKMARKCOLIDX below
134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int IDCOLIDX = 0;
136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int PODCASTCOLIDX = 8;
137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int BOOKMARKCOLIDX = 9;
138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private BroadcastReceiver mUnmountReceiver = null;
139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private WakeLock mWakeLock;
140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mServiceStartId = -1;
141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mServiceInUse = false;
142792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mResumeAfterCall = false;
143c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen    private boolean mIsSupposedToBePlaying = false;
144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mQuietMode = false;
145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
146792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private SharedPreferences mPreferences;
147792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // We use this to distinguish between different cards when saving/restoring playlists.
148792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // This will have to change if we want to support multiple simultaneous cards.
149792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mCardId;
150792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
151490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project    private MediaAppWidgetProvider mAppWidgetProvider = MediaAppWidgetProvider.getInstance();
152792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // interval after which we stop the service when idle
154792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int IDLE_DELAY = 60000;
155792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
156792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Handler mPhoneHandler = new Handler() {
157792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
158792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void handleMessage(Message msg) {
159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            switch (msg.what) {
160792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case PHONE_CHANGED:
161792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    Phone.State state = mPsir.getPhoneState();
162792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (state == Phone.State.RINGING) {
163792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
164792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        int ringvolume = audioManager.getStreamVolume(AudioManager.STREAM_RING);
165792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (ringvolume > 0) {
166792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mResumeAfterCall = (isPlaying() || mResumeAfterCall) && (getAudioId() >= 0);
167792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            pause();
168792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
169792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (state == Phone.State.OFFHOOK) {
170792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // pause the music while a conversation is in progress
171792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mResumeAfterCall = (isPlaying() || mResumeAfterCall) && (getAudioId() >= 0);
172792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        pause();
173792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (state == Phone.State.IDLE) {
174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // start playing again
175792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (mResumeAfterCall) {
176792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            // resume playback only if music was playing
177792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            // when the call was answered
178792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            startAndFadeIn();
179792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mResumeAfterCall = false;
180792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
181792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
182792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
183792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                default:
184792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
185792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
187792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
189792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void startAndFadeIn() {
190792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mMediaplayerHandler.sendEmptyMessageDelayed(FADEIN, 10);
191792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Handler mMediaplayerHandler = new Handler() {
194792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        float mCurrentVolume = 1.0f;
195792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void handleMessage(Message msg) {
197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            switch (msg.what) {
198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case FADEIN:
199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (!isPlaying()) {
200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCurrentVolume = 0f;
201792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayer.setVolume(mCurrentVolume);
202792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
203792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mMediaplayerHandler.sendEmptyMessageDelayed(FADEIN, 10);
204792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
205792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCurrentVolume += 0.01f;
206792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (mCurrentVolume < 1.0f) {
207792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mMediaplayerHandler.sendEmptyMessageDelayed(FADEIN, 10);
208792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        } else {
209792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCurrentVolume = 1.0f;
210792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayer.setVolume(mCurrentVolume);
212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case SERVER_DIED:
215c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                    if (mIsSupposedToBePlaying) {
216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        next(true);
217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // the server died when we were idle, so just
219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // reopen the same song (it will start again
220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // from the beginning though when the user
221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // restarts)
222792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        openCurrent();
223792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
224792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case TRACK_ENDED:
226792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_CURRENT) {
227792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        seek(0);
228792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
229792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (!mOneShot) {
230792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        next(false);
231792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
232792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(PLAYBACK_COMPLETE);
233c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                        mIsSupposedToBePlaying = false;
234792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
235792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
236792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case RELEASE_WAKELOCK:
237792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mWakeLock.release();
238792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                default:
240792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
241792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
244792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
246792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
247792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void onReceive(Context context, Intent intent) {
248792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String action = intent.getAction();
249792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String cmd = intent.getStringExtra("command");
250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                next(true);
252792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
253792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                prev();
254792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
255792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (isPlaying()) {
256792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    pause();
257792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
258792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
259792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
260792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
261792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDSTOP.equals(cmd)) {
263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                seek(0);
265490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project            } else if (MediaAppWidgetProvider.CMDAPPWIDGETUPDATE.equals(cmd)) {
266490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                // Someone asked us to refresh a set of specific widgets, probably
267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // because they were just added.
268490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
269490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                mAppWidgetProvider.performUpdate(MediaPlaybackService.this, appWidgetIds);
270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public MediaPlaybackService() {
275792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPsir = new PhoneStateIntentReceiver(this, mPhoneHandler);
276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPsir.notifyPhoneCallState(PHONE_CHANGED);
277792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onCreate() {
281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onCreate();
282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPreferences = getSharedPreferences("Music", MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE);
284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mCardId = FileUtils.getFatVolumeId(Environment.getExternalStorageDirectory().getPath());
285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        registerExternalStorageListener();
287792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
288792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Needs to be done in this thread, since otherwise ApplicationContext.getPowerManager() crashes.
289792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayer = new MultiPlayer();
290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayer.setHandler(mMediaplayerHandler);
291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Clear leftover notification in case this service previously got killed while playing
293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        nm.cancel(PLAYBACKSERVICE_STATUS);
295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        reloadQueue();
297792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
298792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        IntentFilter commandFilter = new IntentFilter();
299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(SERVICECMD);
300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(TOGGLEPAUSE_ACTION);
301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(PAUSE_ACTION);
302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(NEXT_ACTION);
303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(PREVIOUS_ACTION);
304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        registerReceiver(mIntentReceiver, commandFilter);
305792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
306792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPsir.registerIntent();
307792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
308792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
309792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock.setReferenceCounted(false);
310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // If the service was idle, but got killed before it stopped itself, the
312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // system will relaunch it. Make sure it gets stopped again in that case.
313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
314792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
315792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
316792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
317792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
318792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onDestroy() {
319792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Check that we're not being destroyed while something is still playing.
320792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (isPlaying()) {
321792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Log.e("MediaPlaybackService", "Service being destroyed while still playing.");
322792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
3232b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        // release all MediaPlayer resources, including the native player and wakelocks
3242b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mPlayer.release();
3252b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mPlayer = null;
326792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
3272b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        // make sure there aren't any other messages coming
3282b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mDelayedStopHandler.removeCallbacksAndMessages(null);
32949e36ea916aefba042c6e927c771b10708b6891eMarco Nelissen        mMediaplayerHandler.removeCallbacksAndMessages(null);
33049e36ea916aefba042c6e927c771b10708b6891eMarco Nelissen        mPhoneHandler.removeCallbacksAndMessages(null);
3312b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
332792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mCursor != null) {
333792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor.close();
334792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
335792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
336792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        unregisterReceiver(mIntentReceiver);
338792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mUnmountReceiver != null) {
339792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            unregisterReceiver(mUnmountReceiver);
340792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnmountReceiver = null;
341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
342792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPsir.unregisterIntent();
343792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock.release();
344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onDestroy();
345792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
347792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final char hexdigits [] = new char [] {
348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '0', '1', '2', '3',
349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '4', '5', '6', '7',
350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '8', '9', 'a', 'b',
351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            'c', 'd', 'e', 'f'
352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void saveQueue(boolean full) {
355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mOneShot) {
356792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return;
357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Editor ed = mPreferences.edit();
359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        //long start = System.currentTimeMillis();
360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (full) {
361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            StringBuilder q = new StringBuilder();
362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // The current playlist is saved as a list of "reverse hexadecimal"
364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // numbers, which we can generate faster than normal decimal or
365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // hexadecimal numbers, which in turn allows us to save the playlist
366792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // more often without worrying too much about performance.
367792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // (saving the full state takes about 40 ms under no-load conditions
368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // on the phone)
369792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = mPlayListLen;
370792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
371792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int n = mPlayList[i];
372792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (n == 0) {
373792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    q.append("0;");
374792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
375792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    while (n != 0) {
376792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        int digit = n & 0xf;
377792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        n >>= 4;
378792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        q.append(hexdigits[digit]);
379792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
380792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    q.append(";");
381792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
382792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
383792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //Log.i("@@@@ service", "created queue string in " + (System.currentTimeMillis() - start) + " ms");
384792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putString("queue", q.toString());
385792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putInt("cardid", mCardId);
386792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
387792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("curpos", mPlayPos);
388792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
389792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putLong("seekpos", mPlayer.position());
390792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
391792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("repeatmode", mRepeatMode);
392792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("shufflemode", mShuffleMode);
393792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.commit();
394792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
395792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        //Log.i("@@@@ service", "saved state in " + (System.currentTimeMillis() - start) + " ms");
396792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
398792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void reloadQueue() {
399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String q = null;
400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
401792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        boolean newstyle = false;
402792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int id = mCardId;
403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPreferences.contains("cardid")) {
404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            newstyle = true;
405792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            id = mPreferences.getInt("cardid", ~mCardId);
406792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
407792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (id == mCardId) {
408792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Only restore the saved playlist if the card is still
409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // the same one as when the playlist was saved
410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            q = mPreferences.getString("queue", "");
411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
412792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (q != null && q.length() > 1) {
413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //Log.i("@@@@ service", "loaded queue: " + q);
414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String [] entries = q.split(";");
415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = entries.length;
416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ensurePlayListCapacity(len);
417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (newstyle) {
419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    String revhex = entries[i];
420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    int n = 0;
421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    for (int j = revhex.length() - 1; j >= 0 ; j--) {
422792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        n <<= 4;
423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        char c = revhex.charAt(j);
424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (c >= '0' && c <= '9') {
425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            n += (c - '0');
426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        } else if (c >= 'a' && c <= 'f') {
427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            n += (10 + c - 'a');
428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        } else {
429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            // bogus playlist data
430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            len = 0;
431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            break;
432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = n;
435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
436792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = Integer.parseInt(entries[i]);
437792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen = len;
440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int pos = mPreferences.getInt("curpos", 0);
442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (pos < 0 || pos >= len) {
443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // The saved playlist is bogus, discard it
444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 0;
445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
446792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
447792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = pos;
448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // When reloadQueue is called in response to a card-insertion,
450792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // we might not be able to query the media provider right away.
451792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // To deal with this, try querying for the current file, and if
452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // that fails, wait a while and try again. If that too fails,
453792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // assume there is a problem and don't restore the state.
454792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Cursor c = MusicUtils.query(this,
455792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
456792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        new String [] {"_id"}, "_id=" + mPlayList[mPlayPos] , null, null);
457792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c == null || c.getCount() == 0) {
458792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // wait a bit and try again
459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                SystemClock.sleep(3000);
460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c = getContentResolver().query(
461792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCursorCols, "_id=" + mPlayList[mPlayPos] , null, null);
463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c != null) {
465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.close();
466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Make sure we don't auto-skip to the next song, since that
469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // also starts playback. What could happen in that case is:
470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music is paused
471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - go to UMS and delete some files, including the currently playing one
472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - come back from UMS
473792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // (time passes)
474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music app is killed for some reason (out of memory)
475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music service is restarted, service restores state, doesn't find
476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //   the "current" file, goes to the next and: playback starts on its
477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //   own, potentially at some random inconvenient time.
478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mOpenFailedCounter = 20;
479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mQuietMode = true;
480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mQuietMode = false;
482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (!mPlayer.isInitialized()) {
483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // couldn't restore the saved state
484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 0;
485792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
486792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
487792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
488792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            long seekpos = mPreferences.getLong("seekpos", 0);
489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            seek(seekpos >= 0 && seekpos < duration() ? seekpos : 0);
490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
491792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int repmode = mPreferences.getInt("repeatmode", REPEAT_NONE);
492792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (repmode != REPEAT_ALL && repmode != REPEAT_CURRENT) {
493792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                repmode = REPEAT_NONE;
494792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
495792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = repmode;
496792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
497792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int shufmode = mPreferences.getInt("shufflemode", SHUFFLE_NONE);
498792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (shufmode != SHUFFLE_AUTO && shufmode != SHUFFLE_NORMAL) {
499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                shufmode = SHUFFLE_NONE;
500792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
501792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (shufmode == SHUFFLE_AUTO) {
502792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (! makeAutoShuffleList()) {
503792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    shufmode = SHUFFLE_NONE;
504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
506792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mShuffleMode = shufmode;
507792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
508792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
509792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public IBinder onBind(Intent intent) {
512792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
513792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = true;
514792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mBinder;
515792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onRebind(Intent intent) {
519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = true;
521792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onStart(Intent intent, int startId) {
525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceStartId = startId;
526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
527792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
528792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String action = intent.getAction();
529792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String cmd = intent.getStringExtra("command");
530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            next(true);
533792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            prev();
535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
536792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (isPlaying()) {
537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
539792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            pause();
543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else if (CMDSTOP.equals(cmd)) {
544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            pause();
545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            seek(0);
546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // make sure the service will shut down on its own if it was
549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // just started but not bound to and nothing is playing
550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean onUnbind(Intent intent) {
557792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = false;
558792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Take a snapshot of the current playlist
560792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        saveQueue(true);
561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (isPlaying() || mResumeAfterCall) {
563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // something is currently playing, or will be playing once
564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // an in-progress call ends, so don't stop the service now.
565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // If there is a playlist but playback is paused, then wait a while
569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // before stopping the service, so that pause/resume isn't slow.
570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Also delay stopping the service if we're transitioning between tracks.
571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayListLen > 0  || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Message msg = mDelayedStopHandler.obtainMessage();
573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
576792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // No active playlist, OK to stop the service right now
578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stopSelf(mServiceStartId);
579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return true;
580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Handler mDelayedStopHandler = new Handler() {
583792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
584792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void handleMessage(Message msg) {
585792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Check again to make sure nothing is playing right now
586792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (isPlaying() || mResumeAfterCall || mServiceInUse
587792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
588792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
589792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // save the queue again, because it might have changed
591792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // since the user exited the music app (because of
592792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // party-shuffle or because the play-position changed)
593792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(true);
594792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stopSelf(mServiceStartId);
595792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
596792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Called when we receive a ACTION_MEDIA_EJECT notification.
600792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
601792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param storagePath path to mount point for the removed media
602792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
603792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void closeExternalStorageFiles(String storagePath) {
604792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // stop playback and clean up if the SD card is going to be unmounted.
605792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stop(true);
606792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        notifyChange(QUEUE_CHANGED);
607792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        notifyChange(META_CHANGED);
608792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
609792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
610792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
611792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Registers an intent to listen for ACTION_MEDIA_EJECT notifications.
612792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent will call closeExternalStorageFiles() if the external media
613792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * is going to be ejected, so applications can clean up any files they have open.
614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
615792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void registerExternalStorageListener() {
616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mUnmountReceiver == null) {
617792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnmountReceiver = new BroadcastReceiver() {
618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                @Override
619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                public void onReceive(Context context, Intent intent) {
620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    String action = intent.getAction();
621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        saveQueue(true);
623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mOneShot = true; // This makes us not save the state again later,
624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                                         // which would be wrong because the song ids and
625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                                         // card id might not match.
626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        closeExternalStorageFiles(intent.getData().getPath());
627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mMediaMountedCount++;
629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCardId = FileUtils.getFatVolumeId(intent.getData().getPath());
630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        reloadQueue();
631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(QUEUE_CHANGED);
632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(META_CHANGED);
633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            };
636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            IntentFilter iFilter = new IntentFilter();
637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_EJECT);
638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addDataScheme("file");
640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            registerReceiver(mUnmountReceiver, iFilter);
641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Notify the change-receivers that something has changed.
646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent that is sent contains the following data
647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * for the currently playing track:
648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "id" - Integer: the database row ID
649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "artist" - String: the name of the artist
650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "album" - String: the name of the album
651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "track" - String: the name of the track
652792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent has an action that is one of
653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.metachanged"
654792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.queuechanged",
655792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.playbackcomplete"
656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.playstatechanged"
657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * respectively indicating that a new track has
658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * started playing, that the playback queue has
659792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * changed, that playback has stopped because
660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the last file in the list has been played,
661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * or that the play-state changed (paused/resumed).
662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void notifyChange(String what) {
664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Intent i = new Intent(what);
666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("id", Integer.valueOf(getAudioId()));
667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("artist", getArtistName());
668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("album",getAlbumName());
669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("track", getTrackName());
670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        sendBroadcast(i);
671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (what.equals(QUEUE_CHANGED)) {
673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(true);
674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
678490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project        // Share this notification directly with our widgets
679490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project        mAppWidgetProvider.notifyChange(this, what);
680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void ensurePlayListCapacity(int size) {
683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayList == null || size > mPlayList.length) {
684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // reallocate at 2x requested size so we don't
685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // need to grow and copy the array for every
686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // insert
687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int [] newlist = new int[size * 2];
688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = mPlayListLen;
689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                newlist[i] = mPlayList[i];
691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList = newlist;
693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // FIXME: shrink the array when the needed size is much smaller
695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // than the allocated size
696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // insert the list of songs at the specified position in the playlist
699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void addToPlayList(int [] list, int position) {
700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int addlen = list.length;
701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (position < 0) { // overwrite
702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen = 0;
703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            position = 0;
704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ensurePlayListCapacity(mPlayListLen + addlen);
706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (position > mPlayListLen) {
707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            position = mPlayListLen;
708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // move part of list after insertion point
711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int tailsize = mPlayListLen - position;
712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = tailsize ; i > 0 ; i--) {
713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[position + i] = mPlayList[position + i - addlen];
714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // copy list into playlist
717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < addlen; i++) {
718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[position + i] = list[i];
719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayListLen += addlen;
721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Appends a list of tracks to the current playlist.
725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * If nothing is playing currently, playback will be started at
726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the first track.
727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * If the action is NOW, playback will switch to the first of
728792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the new tracks immediately.
729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param list The list of tracks to append.
730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param action NOW, NEXT or LAST
731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void enqueue(int [] list, int action) {
733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (action == NEXT && mPlayPos + 1 < mPlayListLen) {
735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, mPlayPos + 1);
736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
738792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // action == LAST || action == NOW || mPlayPos + 1 == mPlayListLen
739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, Integer.MAX_VALUE);
740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
741792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (action == NOW) {
742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = mPlayListLen - list.length;
743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    notifyChange(META_CHANGED);
746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos < 0) {
750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = 0;
751792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                openCurrent();
752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(META_CHANGED);
754792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
759792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Replaces the current playlist with a new list,
760792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * and prepares for starting playback at the specified
761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * position in the list, or a random position if the
762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * specified position is 0.
763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param list The new list of tracks.
764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void open(int [] list, int position) {
766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_AUTO) {
768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mShuffleMode = SHUFFLE_NORMAL;
769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
770d8c696753687ddb0177f869fad5f709eadfe27afJeffrey Sharkey            int oldId = getAudioId();
771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int listlength = list.length;
772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            boolean newlist = true;
773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayListLen == listlength) {
774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // possible fast path: list might be the same
775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                newlist = false;
776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = 0; i < listlength; i++) {
777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (list[i] != mPlayList[i]) {
778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        newlist = true;
779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        break;
780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (newlist) {
784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, -1);
785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int oldpos = mPlayPos;
788792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (position >= 0) {
789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = position;
790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = mRand.nextInt(mPlayListLen);
792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mHistory.clear();
794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
796792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
797d8c696753687ddb0177f869fad5f709eadfe27afJeffrey Sharkey            if (oldId != getAudioId()) {
798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(META_CHANGED);
799792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
800792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
801792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
802792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
803792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
804792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Moves the item at index1 to index2.
805792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param index1
806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param index2
807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
808792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void moveQueueItem(int index1, int index2) {
809792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
810792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index1 >= mPlayListLen) {
811792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                index1 = mPlayListLen - 1;
812792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index2 >= mPlayListLen) {
814792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                index2 = mPlayListLen - 1;
815792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index1 < index2) {
817792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int tmp = mPlayList[index1];
818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = index1; i < index2; i++) {
819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = mPlayList[i+1];
820792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[index2] = tmp;
822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos == index1) {
823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = index2;
824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else if (mPlayPos >= index1 && mPlayPos <= index2) {
825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos--;
826792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (index2 < index1) {
828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int tmp = mPlayList[index1];
829792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = index1; i > index2; i--) {
830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = mPlayList[i-1];
831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
832792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[index2] = tmp;
833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos == index1) {
834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = index2;
835792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else if (mPlayPos >= index2 && mPlayPos <= index1) {
836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos++;
837792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
840792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
841792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
842792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
844792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the current play list
845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return An array of integers containing the IDs of the tracks in the play list
846792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
847792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int [] getQueue() {
848792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = mPlayListLen;
850792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int [] list = new int[len];
851792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                list[i] = mPlayList[i];
853792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return list;
855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
856792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
858792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void openCurrent() {
859792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
860792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor != null) {
861792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor.close();
862792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor = null;
863792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
864792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayListLen == 0) {
865792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
867792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
868792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
869792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String id = String.valueOf(mPlayList[mPlayPos]);
870792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
871792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = getContentResolver().query(
872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
873792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mCursorCols, "_id=" + id , null, null);
874792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor != null) {
875792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor.moveToFirst();
876792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                open(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + id, false);
877792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // go to bookmark if needed
878792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (isPodcast()) {
879792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    long bookmark = getBookmark();
880792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // Start playing a little bit before the bookmark,
881792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // so it's easier to get back in to the narrative.
882792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    seek(bookmark - 5000);
883792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
884792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
885792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
886792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
887792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void openAsync(String path) {
889792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (path == null) {
891792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
892792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
893792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
894792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = REPEAT_NONE;
895792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ensurePlayListCapacity(1);
896792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen = 1;
897792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = -1;
898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
899792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mFileToPlay = path;
900792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
901792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.setDataSourceAsync(mFileToPlay);
902792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mOneShot = true;
903792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
904792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
905792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
906792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
907792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Opens the specified file and readies it for playback.
908792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param path The full path of the file to be opened.
910792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param oneshot when set to true, playback will stop after this file completes, instead
911792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * of moving on to the next track in the list
912792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
913792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void open(String path, boolean oneshot) {
914792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
915792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (path == null) {
916792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
917792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
918792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
919792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (oneshot) {
920792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mRepeatMode = REPEAT_NONE;
921792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ensurePlayListCapacity(1);
922792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 1;
923792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = -1;
924792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
925792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
926792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // if mCursor is null, try to associate path with a database cursor
927792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
928792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
929792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ContentResolver resolver = getContentResolver();
930792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Uri uri;
931792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String where;
932792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String selectionArgs[];
933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (path.startsWith("content://media/")) {
934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    uri = Uri.parse(path);
935792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    where = null;
936792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    selectionArgs = null;
937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
938792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   uri = MediaStore.Audio.Media.getContentUriForPath(path);
939792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   where = MediaStore.Audio.Media.DATA + "=?";
940792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   selectionArgs = new String[] { path };
941792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
942792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
943792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                try {
944792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mCursor = resolver.query(uri, mCursorCols, where, selectionArgs, null);
945792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if  (mCursor != null) {
946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (mCursor.getCount() == 0) {
947792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor.close();
948792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor = null;
949792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        } else {
950792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor.moveToNext();
951792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            ensurePlayListCapacity(1);
952792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mPlayListLen = 1;
953792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mPlayList[0] = mCursor.getInt(IDCOLIDX);
954792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mPlayPos = 0;
955792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
956792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
957792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } catch (UnsupportedOperationException ex) {
958792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
959792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
960792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mFileToPlay = path;
961792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.setDataSource(mFileToPlay);
962792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mOneShot = oneshot;
963792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (! mPlayer.isInitialized()) {
964792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                stop(true);
965792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mOpenFailedCounter++ < 10 &&  mPlayListLen > 1) {
966792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // beware: this ends up being recursive because next() calls open() again.
967792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    next(false);
968792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
969792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (! mPlayer.isInitialized() && mOpenFailedCounter != 0) {
970792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // need to make sure we only shows this once
971792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mOpenFailedCounter = 0;
972792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (!mQuietMode) {
973792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        Toast.makeText(this, R.string.playback_failed, Toast.LENGTH_SHORT).show();
974792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
975792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
976792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
977792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mOpenFailedCounter = 0;
978792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
979792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
980792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
981792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
982792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
983792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Starts playback of a previously opened file.
984792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
985792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void play() {
986792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
987272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle            // if we are at the end of the song, go to the next song first
988272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle            if (mRepeatMode != REPEAT_CURRENT &&
989272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle                mPlayer.position() >= mPlayer.duration() - 2000) {
990272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle                next(true);
991272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle            }
992272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle
993792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.start();
994792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            setForeground(true);
995792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
996792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            NotificationManager nm = (NotificationManager)
997792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            getSystemService(Context.NOTIFICATION_SERVICE);
998792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
999792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            RemoteViews views = new RemoteViews(getPackageName(), R.layout.statusbar);
1000792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            views.setImageViewResource(R.id.icon, R.drawable.stat_notify_musicplayer);
1001792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (getAudioId() < 0) {
1002792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // streaming
1003792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.trackname, getPath());
1004792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.artistalbum, null);
1005792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1006792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String artist = getArtistName();
1007792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.trackname, getTrackName());
1008792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (artist == null || artist.equals(MediaFile.UNKNOWN_STRING)) {
1009792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    artist = getString(R.string.unknown_artist_name);
1010792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1011792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String album = getAlbumName();
1012792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (album == null || album.equals(MediaFile.UNKNOWN_STRING)) {
1013792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    album = getString(R.string.unknown_album_name);
1014792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1015792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1016792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.artistalbum,
1017792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        getString(R.string.notification_artist_album, artist, album)
1018792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        );
1019792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1020792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1021792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Notification status = new Notification();
1022792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.contentView = views;
1023792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.flags |= Notification.FLAG_ONGOING_EVENT;
1024792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.icon = R.drawable.stat_notify_musicplayer;
1025792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.contentIntent = PendingIntent.getActivity(this, 0,
1026792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    new Intent("com.android.music.PLAYBACK_VIEWER"), 0);
1027792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            nm.notify(PLAYBACKSERVICE_STATUS, status);
1028c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen            if (!mIsSupposedToBePlaying) {
1029792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(PLAYSTATE_CHANGED);
1030792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1031c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen            mIsSupposedToBePlaying = true;
1032792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else if (mPlayListLen <= 0) {
1033792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // This is mostly so that if you press 'play' on a bluetooth headset
1034792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // without every having played anything before, it will still play
1035792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // something.
1036792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            setShuffleMode(SHUFFLE_AUTO);
1037792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1038792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1039792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1040792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void stop(boolean remove_status_icon) {
1041792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1042792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.stop();
1043792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1044792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mFileToPlay = null;
1045792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mCursor != null) {
1046792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor.close();
1047792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
1048792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1049792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (remove_status_icon) {
1050792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            gotoIdleState();
1051792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1052792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        setForeground(false);
1053792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (remove_status_icon) {
1054c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen            mIsSupposedToBePlaying = false;
1055792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1056792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1057792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1058792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1059792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Stops playback.
1060792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1061792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void stop() {
1062792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stop(true);
1063792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1064792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1065792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1066792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Pauses playback (call play() to resume)
1067792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1068792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void pause() {
1069407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen        synchronized(this) {
1070407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen            if (isPlaying()) {
1071407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                mPlayer.pause();
1072407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                gotoIdleState();
1073407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                setForeground(false);
1074407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                mIsSupposedToBePlaying = false;
1075407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                notifyChange(PLAYSTATE_CHANGED);
1076407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                saveBookmarkIfNeeded();
1077407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen            }
1078792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1079792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1080792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1081b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen    /** Returns whether something is currently playing
1082792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
1083b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen     * @return true if something is playing (or will be playing shortly, in case
1084b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen     * we're currently transitioning between tracks), false if not.
1085792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1086792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean isPlaying() {
1087c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen        return mIsSupposedToBePlaying;
1088792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1089792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1090792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /*
1091792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      Desired behavior for prev/next/shuffle:
1092792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1093792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      - NEXT will move to the next track in the list when not shuffling, and to
1094792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        a track randomly picked from the not-yet-played tracks when shuffling.
1095792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        If all tracks have already been played, pick from the full set, but
1096792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        avoid picking the previously played track if possible.
1097792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      - when shuffling, PREV will go to the previously played track. Hitting PREV
1098792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        again will go to the track played before that, etc. When the start of the
1099792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        history has been reached, PREV is a no-op.
1100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When not shuffling, PREV will go to the sequentially previous track (the
1101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        difference with the shuffle-case is mainly that when not shuffling, the
1102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        user can back up to tracks that are not in the history).
1103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Example:
1105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When playing an album with 10 tracks from the start, and enabling shuffle
1106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        while playing track 5, the remaining tracks (6-10) will be shuffled, e.g.
1107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        the final play order might be 1-2-3-4-5-8-10-6-9-7.
1108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When hitting 'prev' 8 times while playing track 7 in this example, the
1109792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        user will go to tracks 9-6-10-8-5-4-3-2. If the user then hits 'next',
1110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        a random track will be picked again. If at any time user disables shuffling
1111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        the next/previous track will be picked in sequential order again.
1112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void prev() {
1115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mOneShot) {
1117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // we were playing a specific file not part of a playlist, so there is no 'previous'
1118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                seek(0);
1119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
1120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_NORMAL) {
1123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // go to previously-played track and remove it from the history
1124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int histsize = mHistory.size();
1125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (histsize == 0) {
1126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // prev is a no-op
1127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Integer pos = mHistory.remove(histsize - 1);
1130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = pos.intValue();
1131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos > 0) {
1133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos--;
1134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = mPlayListLen - 1;
1136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
1139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1142792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1146792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void next(boolean force) {
1147792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1148792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mOneShot) {
1149792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // we were playing a specific file not part of a playlist, so there is no 'next'
1150792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                seek(0);
1151792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
1152792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1154792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1155792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Store the current file in the history, but keep the history at a
1156792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // reasonable size
1157792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos >= 0) {
1158792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHistory.add(Integer.valueOf(mPlayPos));
1159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1160792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mHistory.size() > MAX_HISTORY_SIZE) {
1161792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHistory.removeElementAt(0);
1162792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1163792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1164792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_NORMAL) {
1165792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Pick random next track from the not-yet-played ones
1166792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: make it work right after adding/removing items in the queue.
1167792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1168792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numTracks = mPlayListLen;
1169792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int[] tracks = new int[numTracks];
1170792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i=0;i < numTracks; i++) {
1171792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    tracks[i] = i;
1172792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1173792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numHistory = mHistory.size();
1175792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numUnplayed = numTracks;
1176792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i=0;i < numHistory; i++) {
1177792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    int idx = mHistory.get(i).intValue();
1178792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (idx < numTracks && tracks[idx] >= 0) {
1179792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        numUnplayed--;
1180792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        tracks[idx] = -1;
1181792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1182792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1183792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1184792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // 'numUnplayed' now indicates how many tracks have not yet
1185792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // been played, and 'tracks' contains the indices of those
1186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // tracks.
1187792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (numUnplayed <=0) {
1188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // everything's already been played
1189792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_ALL || force) {
1190792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        //pick from full set
1191792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        numUnplayed = numTracks;
1192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        for (int i=0;i < numTracks; i++) {
1193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            tracks[i] = i;
1194792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
1195792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
1196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // all done
1197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        gotoIdleState();
1198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        return;
1199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1201792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int skip = mRand.nextInt(numUnplayed);
1202792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int cnt = -1;
1203792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                while (true) {
1204792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    while (tracks[++cnt] < 0)
1205792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        ;
1206792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    skip--;
1207792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (skip < 0) {
1208792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        break;
1209792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1210792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = cnt;
1212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (mShuffleMode == SHUFFLE_AUTO) {
1213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                doAutoShuffleUpdate();
1214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos++;
1215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos >= mPlayListLen - 1) {
1217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // we're at the end of the list
1218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_NONE && !force) {
1219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // all done
1220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        gotoIdleState();
1221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(PLAYBACK_COMPLETE);
1222c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                        mIsSupposedToBePlaying = false;
1223792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        return;
1224792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (mRepeatMode == REPEAT_ALL || force) {
1225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos = 0;
1226792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1227792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1228792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos++;
1229792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1230792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1231792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
1232792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1233792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1234792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1235792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1236792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1237792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1238792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void gotoIdleState() {
1240792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        NotificationManager nm =
1241792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
1242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        nm.cancel(PLAYBACKSERVICE_STATUS);
1243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
1244792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
1245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
1246792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1247792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1248792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void saveBookmarkIfNeeded() {
1249792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (isPodcast()) {
1251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long pos = position();
1252792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long bookmark = getBookmark();
1253792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long duration = duration();
1254792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if ((pos < bookmark && (pos + 10000) > bookmark) ||
1255792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        (pos > bookmark && (pos - 10000) < bookmark)) {
1256792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // The existing bookmark is close to the current
1257792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // position, so don't update it.
1258792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1259792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1260792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (pos < 15000 || (pos + 10000) > duration) {
1261792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // if we're near the start or end, clear the bookmark
1262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    pos = 0;
1263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // write 'pos' to the bookmark field
1266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ContentValues values = new ContentValues();
1267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                values.put(MediaStore.Audio.Media.BOOKMARK, pos);
1268792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Uri uri = ContentUris.withAppendedId(
1269792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursor.getLong(IDCOLIDX));
1270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                getContentResolver().update(uri, values, null, null);
1271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (SQLiteException ex) {
1273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1275792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // Make sure there are at least 5 items after the currently playing item
1277792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // and no more than 10 items before.
1278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void doAutoShuffleUpdate() {
1279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        boolean notify = false;
1280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // remove old entries
1281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayPos > 10) {
1282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            removeTracks(0, mPlayPos - 9);
1283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notify = true;
1284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // add new entries if needed
1286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int to_add = 7 - (mPlayListLen - (mPlayPos < 0 ? -1 : mPlayPos));
1287792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < to_add; i++) {
1288792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // pick something at random from the list
1289792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int idx = mRand.nextInt(mAutoShuffleList.length);
1290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Integer which = mAutoShuffleList[idx];
1291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ensurePlayListCapacity(mPlayListLen + 1);
1292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[mPlayListLen++] = which;
1293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notify = true;
1294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (notify) {
1296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1297792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1298792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // A simple variation of Random that makes sure that the
1301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // value it returns is not equal to the value it returned
1302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // previously, unless the interval is 1.
1303756c3f57f11a7bb3bf1cf1333ee8ffbc51039748Marco Nelissen    private static class Shuffler {
1304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private int mPrevious;
1305792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private Random mRandom = new Random();
1306792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int nextInt(int interval) {
1307792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int ret;
1308792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            do {
1309792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ret = mRandom.nextInt(interval);
1310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } while (ret == mPrevious && interval > 1);
1311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPrevious = ret;
1312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return ret;
1313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1314792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
1315792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1316792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean makeAutoShuffleList() {
1317792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ContentResolver res = getContentResolver();
1318792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor c = null;
1319792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1320792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            c = res.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1321792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    new String[] {MediaStore.Audio.Media._ID}, MediaStore.Audio.Media.IS_MUSIC + "=1",
1322792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    null, null);
1323792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c == null || c.getCount() == 0) {
1324792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1325792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1326792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = c.getCount();
1327792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int[] list = new int[len];
1328792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
1329792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.moveToNext();
1330792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                list[i] = c.getInt(0);
1331792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1332792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mAutoShuffleList = list;
1333792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
1334792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (RuntimeException ex) {
1335792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } finally {
1336792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c != null) {
1337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.close();
1338792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1339792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1340792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return false;
1341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1342792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1343792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Removes the range of tracks specified from the play list. If a file within the range is
1345792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the file currently being played, playback will move to the next file after the
1346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * range.
1347792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param first The first file to be removed
1348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param last The last file to be removed
1349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return the number of tracks deleted
1350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int removeTracks(int first, int last) {
1352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int numremoved = removeTracksInternal(first, last);
1353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (numremoved > 0) {
1354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1356792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return numremoved;
1357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int removeTracksInternal(int first, int last) {
1360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (last < first) return 0;
1362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (first < 0) first = 0;
1363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (last >= mPlayListLen) last = mPlayListLen - 1;
1364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            boolean gotonext = false;
1366792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (first <= mPlayPos && mPlayPos <= last) {
1367792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = first;
1368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                gotonext = true;
1369792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (mPlayPos > last) {
1370792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos -= (last - first + 1);
1371792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1372792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int num = mPlayListLen - last - 1;
1373792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < num; i++) {
1374792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[first + i] = mPlayList[last + 1 + i];
1375792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1376792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen -= last - first + 1;
1377792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1378792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (gotonext) {
1379792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayListLen == 0) {
1380792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    stop(true);
1381792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = -1;
1382792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1383792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mPlayPos >= mPlayListLen) {
1384792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos = 0;
1385792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1386792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    boolean wasPlaying = isPlaying();
1387792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    stop(false);
1388792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
1389792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (wasPlaying) {
1390792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
1391792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1392792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1393792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1394792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return last - first + 1;
1395792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1396792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1398792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Removes all instances of the track with the given id
1400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * from the playlist.
1401792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param id The id to be removed
1402792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return how many instances of the track were removed
1403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int removeTrack(int id) {
1405792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int numremoved = 0;
1406792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1407792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < mPlayListLen; i++) {
1408792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayList[i] == id) {
1409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    numremoved += removeTracksInternal(i, i);
1410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    i--;
1411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1412792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (numremoved > 0) {
1415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return numremoved;
1418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setShuffleMode(int shufflemode) {
1421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1422792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == shufflemode && mPlayListLen > 0) {
1423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mShuffleMode = shufflemode;
1426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_AUTO) {
1427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (makeAutoShuffleList()) {
1428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayListLen = 0;
1429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    doAutoShuffleUpdate();
1430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = 0;
1431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
1432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
1433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    notifyChange(META_CHANGED);
1434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1436792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // failed to build a list of files to shuffle
1437792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mShuffleMode = SHUFFLE_NONE;
1438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
1441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getShuffleMode() {
1444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mShuffleMode;
1445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1446792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1447792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setRepeatMode(int repeatmode) {
1448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = repeatmode;
1450792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
1451792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1453792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getRepeatMode() {
1454792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mRepeatMode;
1455792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1456792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1457792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getMediaMountedCount() {
1458792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mMediaMountedCount;
1459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1461792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the path of the currently playing file, or null if
1463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * no file is currently playing.
1464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getPath() {
1466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mFileToPlay;
1467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the rowid of the currently playing file, or -1 if
1471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * no file is currently playing.
1472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1473792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getAudioId() {
1474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos >= 0 && mPlayer.isInitialized()) {
1476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return mPlayList[mPlayPos];
1477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the position in the queue
1484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return the position in the queue
1485792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1486792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getQueuePosition() {
1487792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1488792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayPos;
1489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1491792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1492792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1493792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Starts playing the track at the given position in the queue.
1494792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param pos The position in the queue of the track that will be played.
1495792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1496792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setQueuePosition(int pos) {
1497792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1498792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = pos;
1500792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1501792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1502792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1503792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1506792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getArtistName() {
1507792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1508792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1509792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
1512792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1513792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1514792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1515792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getArtistId() {
1516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return -1;
1519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getInt(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID));
1521792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getAlbumName() {
1525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1527792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1528792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1529792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
1530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1533792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getAlbumId() {
1534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1536792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return -1;
1537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getInt(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
1539792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getTrackName() {
1543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
1548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean isPodcast() {
1552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return (mCursor.getInt(PODCASTCOLIDX) > 0);
1557792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1558792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1560792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private long getBookmark() {
1561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return 0;
1564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getLong(BOOKMARKCOLIDX);
1566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the duration of the file in milliseconds.
1571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Currently this method returns -1 for the duration of MIDI files.
1572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long duration() {
1574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.duration();
1576792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the current playback position in milliseconds
1582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1583792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long position() {
1584792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1585792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.position();
1586792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1587792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1588792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1589792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1591792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Seeks to the position specified.
1592792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
1593792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param pos The position to seek to, in milliseconds
1594792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1595792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long seek(long pos) {
1596792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (pos < 0) pos = 0;
1598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (pos > mPlayer.duration()) pos = mPlayer.duration();
1599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.seek(pos);
1600792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1601792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1602792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1603792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1604792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1605792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Provides a unified interface for dealing with midi files and
1606792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * other media files.
1607792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1608792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private class MultiPlayer {
1609792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private MediaPlayer mMediaPlayer = new MediaPlayer();
1610792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private Handler mHandler;
1611792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private boolean mIsInitialized = false;
1612792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1613792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public MultiPlayer() {
1614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK);
1615792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1617792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setDataSourceAsync(String path) {
1618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
1619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.reset();
1620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setDataSource(path);
1621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
1622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setOnPreparedListener(preparedlistener);
1623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.prepareAsync();
1624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IOException ex) {
1625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IllegalArgumentException ex) {
1629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnCompletionListener(listener);
1634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnErrorListener(errorListener);
1635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = true;
1637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setDataSource(String path) {
1640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
1641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.reset();
1642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setOnPreparedListener(null);
1643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (path.startsWith("content://")) {
1644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setDataSource(MediaPlaybackService.this, Uri.parse(path));
1645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setDataSource(path);
1647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
1649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.prepare();
1650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IOException ex) {
1651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1652792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1654792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IllegalArgumentException ex) {
1655792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1659792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnCompletionListener(listener);
1660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnErrorListener(errorListener);
1661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = true;
1663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public boolean isInitialized() {
1666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mIsInitialized;
1667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void start() {
1670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.start();
1671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void stop() {
1674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.reset();
1675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = false;
1676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
16782b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        /**
16792b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen         * You CANNOT use this player anymore after calling release()
16802b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen         */
16812b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        public void release() {
16822b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            stop();
16832b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mMediaPlayer.release();
16842b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        }
16852b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
1686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void pause() {
1687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.pause();
1688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setHandler(Handler handler) {
1691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mHandler = handler;
1692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnCompletionListener listener = new MediaPlayer.OnCompletionListener() {
1695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public void onCompletion(MediaPlayer mp) {
1696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Acquire a temporary wakelock, since when we return from
1697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // this callback the MediaPlayer will release its wakelock
1698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // and allow the device to go to sleep.
1699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // This temporary wakelock is released when the RELEASE_WAKELOCK
1700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // message is processed, but just in case, put a timeout on it.
1701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mWakeLock.acquire(30000);
1702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHandler.sendEmptyMessage(TRACK_ENDED);
1703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHandler.sendEmptyMessage(RELEASE_WAKELOCK);
1704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnPreparedListener preparedlistener = new MediaPlayer.OnPreparedListener() {
1708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public void onPrepared(MediaPlayer mp) {
1709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(ASYNC_OPEN_COMPLETE);
1710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnErrorListener errorListener = new MediaPlayer.OnErrorListener() {
1714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public boolean onError(MediaPlayer mp, int what, int extra) {
1715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                switch (what) {
1716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
1717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mIsInitialized = false;
1718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.release();
1719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // Creating a new MediaPlayer and settings its wakemode does not
1720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // require the media service, so it's OK to do this now, while the
1721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // service is still being restarted
1722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer = new MediaPlayer();
1723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK);
1724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mHandler.sendMessageDelayed(mHandler.obtainMessage(SERVER_DIED), 2000);
1725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return true;
1726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                default:
1727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
1728792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project           }
1731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long duration() {
1734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mMediaPlayer.getDuration();
1735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long position() {
1738792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mMediaPlayer.getCurrentPosition();
1739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1741792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long seek(long whereto) {
1742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.seekTo((int) whereto);
1743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return whereto;
1744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setVolume(float vol) {
1747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setVolume(vol, vol);
1748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
17512b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    /*
17522b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * By making this a static class with a WeakReference to the Service, we
17532b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * ensure that the Service can be GCd even when the system process still
17542b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * has a remote reference to the stub.
17552b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     */
17562b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    static class ServiceStub extends IMediaPlaybackService.Stub {
17572b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        WeakReference<MediaPlaybackService> mService;
17582b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
17592b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        ServiceStub(MediaPlaybackService service) {
17602b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService = new WeakReference<MediaPlaybackService>(service);
17612b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        }
17622b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
1763b7841acd23f0cf4fd8db604d73bdf14e57994fd9Marco Nelissen        public void openFileAsync(String path)
1764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        {
17652b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().openAsync(path);
1766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1767b7841acd23f0cf4fd8db604d73bdf14e57994fd9Marco Nelissen        public void openFile(String path, boolean oneShot)
1768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        {
17692b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().open(path, oneShot);
1770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void open(int [] list, int position) {
17722b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().open(list, position);
1773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getQueuePosition() {
17752b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getQueuePosition();
1776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setQueuePosition(int index) {
17782b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setQueuePosition(index);
1779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public boolean isPlaying() {
17812b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().isPlaying();
1782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void stop() {
17842b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().stop();
1785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void pause() {
17872b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().pause();
1788792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void play() {
17902b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().play();
1791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void prev() {
17932b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().prev();
1794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void next() {
17962b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().next(true);
1797792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getTrackName() {
17992b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getTrackName();
1800792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1801792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getAlbumName() {
18022b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAlbumName();
1803792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1804792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getAlbumId() {
18052b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAlbumId();
1806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getArtistName() {
18082b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getArtistName();
1809792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1810792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getArtistId() {
18112b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getArtistId();
1812792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void enqueue(int [] list , int action) {
18142b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().enqueue(list, action);
1815792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int [] getQueue() {
18172b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getQueue();
1818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void moveQueueItem(int from, int to) {
18202b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().moveQueueItem(from, to);
1821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getPath() {
18232b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getPath();
1824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getAudioId() {
18262b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAudioId();
1827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long position() {
18292b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().position();
1830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long duration() {
18322b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().duration();
1833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long seek(long pos) {
18352b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().seek(pos);
1836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1837792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setShuffleMode(int shufflemode) {
18382b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setShuffleMode(shufflemode);
1839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1840792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getShuffleMode() {
18412b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getShuffleMode();
1842792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int removeTracks(int first, int last) {
18442b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().removeTracks(first, last);
1845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1846792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int removeTrack(int id) {
18472b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().removeTrack(id);
1848792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setRepeatMode(int repeatmode) {
18502b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setRepeatMode(repeatmode);
1851792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getRepeatMode() {
18532b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getRepeatMode();
1854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getMediaMountedCount() {
18562b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getMediaMountedCount();
1857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
18582b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
18592b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    }
18602b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
18612b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    private final IBinder mBinder = new ServiceStub(this);
1862792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project}
1863