MediaPlaybackService.java revision aa331877dd1a0777042481e5c925cd951682588f
1792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project/*
2792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
4792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * you may not use this file except in compliance with the License.
6792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * You may obtain a copy of the License at
7792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
8792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project *
10792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * See the License for the specific language governing permissions and
14792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * limitations under the License.
15792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */
16792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
17792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpackage com.android.music;
18792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
19792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.app.Notification;
20792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.app.PendingIntent;
21792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.app.Service;
22490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Projectimport android.appwidget.AppWidgetManager;
233d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Triviimport android.content.ComponentName;
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;
36085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Triviimport android.media.AudioManager.OnAudioFocusChangeListener;
37792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.MediaPlayer;
38792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.net.Uri;
39792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Handler;
40792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.IBinder;
41792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Message;
42792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.PowerManager;
43792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.SystemClock;
44792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.PowerManager.WakeLock;
45792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.provider.MediaStore;
463d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissenimport android.telephony.PhoneStateListener;
473d54a51b3ce7f7121bcf4b8bd99510ac1cfbaa37Marco Nelissenimport android.telephony.TelephonyManager;
48792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.util.Log;
49792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.RemoteViews;
50792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.Toast;
51792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
523988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissenimport java.io.FileDescriptor;
53792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.io.IOException;
543988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissenimport java.io.PrintWriter;
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 TRACK_ENDED = 1;
101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int RELEASE_WAKELOCK = 2;
102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int SERVER_DIED = 3;
103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int FADEIN = 4;
1043ec2ad9c8758d300864be808e491ae933dc9cd6bMarco Nelissen    private static final int MAX_HISTORY_SIZE = 100;
105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private MultiPlayer mPlayer;
107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private String mFileToPlay;
108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mShuffleMode = SHUFFLE_NONE;
109792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mRepeatMode = REPEAT_NONE;
110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mMediaMountedCount = 0;
111bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private long [] mAutoShuffleList = null;
112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mOneShot;
113bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private long [] mPlayList = null;
114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mPlayListLen = 0;
115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Vector<Integer> mHistory = new Vector<Integer>(MAX_HISTORY_SIZE);
116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Cursor mCursor;
117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mPlayPos = -1;
118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final String LOGTAG = "MediaPlaybackService";
119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final Shuffler mRand = new Shuffler();
120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mOpenFailedCounter = 0;
121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    String[] mCursorCols = new String[] {
122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            "audio._id AS _id",             // index must match IDCOLIDX below
123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST,
124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ALBUM,
125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.TITLE,
126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.DATA,
127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.MIME_TYPE,
128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ALBUM_ID,
129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST_ID,
130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.IS_PODCAST, // index must match PODCASTCOLIDX below
131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.BOOKMARK    // index must match BOOKMARKCOLIDX below
132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int IDCOLIDX = 0;
134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int PODCASTCOLIDX = 8;
135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int BOOKMARKCOLIDX = 9;
136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private BroadcastReceiver mUnmountReceiver = null;
137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private WakeLock mWakeLock;
138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mServiceStartId = -1;
139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mServiceInUse = false;
140c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen    private boolean mIsSupposedToBePlaying = false;
141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mQuietMode = false;
142085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    private AudioManager mAudioManager;
143085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    // used to track what type of audio focus loss caused the playback to pause
144085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    private boolean mPausedByTransientLossOfFocus = false;
145085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
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
154aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi    private static final int IDLE_DELAY = 60000;
155792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
156792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void startAndFadeIn() {
157792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mMediaplayerHandler.sendEmptyMessageDelayed(FADEIN, 10);
158792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
160792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Handler mMediaplayerHandler = new Handler() {
161792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        float mCurrentVolume = 1.0f;
162792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
163792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void handleMessage(Message msg) {
1643988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog("mMediaplayerHandler.handleMessage " + msg.what);
165792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            switch (msg.what) {
166792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case FADEIN:
167792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (!isPlaying()) {
168792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCurrentVolume = 0f;
169792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayer.setVolume(mCurrentVolume);
170792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
171792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mMediaplayerHandler.sendEmptyMessageDelayed(FADEIN, 10);
172792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
173792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCurrentVolume += 0.01f;
174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (mCurrentVolume < 1.0f) {
175792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mMediaplayerHandler.sendEmptyMessageDelayed(FADEIN, 10);
176792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        } else {
177792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCurrentVolume = 1.0f;
178792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
179792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayer.setVolume(mCurrentVolume);
180792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
181792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
182792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case SERVER_DIED:
183c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                    if (mIsSupposedToBePlaying) {
184792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        next(true);
185792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // the server died when we were idle, so just
187792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // reopen the same song (it will start again
188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // from the beginning though when the user
189792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // restarts)
190792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        openCurrent();
191792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case TRACK_ENDED:
194792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_CURRENT) {
195792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        seek(0);
196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (!mOneShot) {
198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        next(false);
199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(PLAYBACK_COMPLETE);
201c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                        mIsSupposedToBePlaying = false;
202792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
203792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
204792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case RELEASE_WAKELOCK:
205792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mWakeLock.release();
206792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
207792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                default:
208792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
209792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
210792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void onReceive(Context context, Intent intent) {
216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String action = intent.getAction();
217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String cmd = intent.getStringExtra("command");
2183988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog("mIntentReceiver.onReceive " + action + " / " + cmd);
219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                next(true);
221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
222792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                prev();
223792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
224792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (isPlaying()) {
225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    pause();
226aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                    mPausedByTransientLossOfFocus = false;
227792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
228792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
229792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
230792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
231792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
232aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
233792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDSTOP.equals(cmd)) {
234792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
235aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
236792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                seek(0);
237490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project            } else if (MediaAppWidgetProvider.CMDAPPWIDGETUPDATE.equals(cmd)) {
238490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                // Someone asked us to refresh a set of specific widgets, probably
239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // because they were just added.
240490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
241490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                mAppWidgetProvider.performUpdate(MediaPlaybackService.this, appWidgetIds);
242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
244792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
246085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() {
247f4cfdfd4a99040be44a1ccd74edbde762edc845bJean-Michel Trivi        public void onAudioFocusChange(int focusChange) {
248085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi            // AudioFocus is a new feature: focus updates are made verbose on purpose
249085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi            switch (focusChange) {
250085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                case AudioManager.AUDIOFOCUS_LOSS:
251085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS");
252085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    if(isPlaying()) {
253085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                        mPausedByTransientLossOfFocus = false;
254085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                        pause();
255085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    }
256085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    break;
257085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
258302a7fdb1c1e8d771ed983de73283927d8184084Jean-Michel Trivi                case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
259085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS_TRANSIENT");
260085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    if(isPlaying()) {
261085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                        mPausedByTransientLossOfFocus = true;
262085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                        pause();
263085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    }
264085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    break;
265085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                case AudioManager.AUDIOFOCUS_GAIN:
266085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_GAIN");
267085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    if(!isPlaying() && mPausedByTransientLossOfFocus) {
268085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                        mPausedByTransientLossOfFocus = false;
269aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                        startAndFadeIn();
270085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    }
271085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    break;
272085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                default:
273085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                    Log.e(LOGTAG, "Unknown audio focus change code");
274085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi            }
275085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        }
276085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    };
277085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public MediaPlaybackService() {
279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onCreate() {
283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onCreate();
284085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
285085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
286085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        mAudioManager.registerAudioFocusListener(mAudioFocusListener);
2873d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi        mAudioManager.registerMediaButtonEventReceiver(new ComponentName(getPackageName(),
2883d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi                MediaButtonIntentReceiver.class.getName()));
289792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPreferences = getSharedPreferences("Music", MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE);
29187bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen        mCardId = MusicUtils.getCardId(this);
292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        registerExternalStorageListener();
294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Needs to be done in this thread, since otherwise ApplicationContext.getPowerManager() crashes.
296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayer = new MultiPlayer();
297792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayer.setHandler(mMediaplayerHandler);
298792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        reloadQueue();
300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        IntentFilter commandFilter = new IntentFilter();
302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(SERVICECMD);
303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(TOGGLEPAUSE_ACTION);
304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(PAUSE_ACTION);
305792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(NEXT_ACTION);
306792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(PREVIOUS_ACTION);
307792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        registerReceiver(mIntentReceiver, commandFilter);
308792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
309792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock.setReferenceCounted(false);
312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // If the service was idle, but got killed before it stopped itself, the
314792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // system will relaunch it. Make sure it gets stopped again in that case.
315792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
316792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
317792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
318792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
319792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
320792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onDestroy() {
321792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Check that we're not being destroyed while something is still playing.
322792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (isPlaying()) {
323e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen            Log.e(LOGTAG, "Service being destroyed while still playing.");
324792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
3252b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        // release all MediaPlayer resources, including the native player and wakelocks
3262b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mPlayer.release();
3272b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mPlayer = null;
328085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
329085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        mAudioManager.abandonAudioFocus(mAudioFocusListener);
330085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        mAudioManager.unregisterAudioFocusListener(mAudioFocusListener);
331792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
3322b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        // make sure there aren't any other messages coming
3332b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mDelayedStopHandler.removeCallbacksAndMessages(null);
33449e36ea916aefba042c6e927c771b10708b6891eMarco Nelissen        mMediaplayerHandler.removeCallbacksAndMessages(null);
3352b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
336792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mCursor != null) {
337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor.close();
338792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
339792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
340792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        unregisterReceiver(mIntentReceiver);
342792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mUnmountReceiver != null) {
343792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            unregisterReceiver(mUnmountReceiver);
344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnmountReceiver = null;
345792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock.release();
347792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onDestroy();
348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final char hexdigits [] = new char [] {
351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '0', '1', '2', '3',
352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '4', '5', '6', '7',
353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '8', '9', 'a', 'b',
354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            'c', 'd', 'e', 'f'
355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
356792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void saveQueue(boolean full) {
358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mOneShot) {
359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return;
360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Editor ed = mPreferences.edit();
362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        //long start = System.currentTimeMillis();
363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (full) {
364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            StringBuilder q = new StringBuilder();
365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
366792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // The current playlist is saved as a list of "reverse hexadecimal"
367792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // numbers, which we can generate faster than normal decimal or
368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // hexadecimal numbers, which in turn allows us to save the playlist
369792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // more often without worrying too much about performance.
370792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // (saving the full state takes about 40 ms under no-load conditions
371792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // on the phone)
372792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = mPlayListLen;
373792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
374bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long n = mPlayList[i];
375792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (n == 0) {
376792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    q.append("0;");
377792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
378792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    while (n != 0) {
379bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                        int digit = (int)(n & 0xf);
380792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        n >>= 4;
381792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        q.append(hexdigits[digit]);
382792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
383792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    q.append(";");
384792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
385792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
386792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //Log.i("@@@@ service", "created queue string in " + (System.currentTimeMillis() - start) + " ms");
387792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putString("queue", q.toString());
388792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putInt("cardid", mCardId);
38963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (mShuffleMode != SHUFFLE_NONE) {
39063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                // In shuffle mode we need to save the history too
39163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                len = mHistory.size();
39263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                q.setLength(0);
39363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                for (int i = 0; i < len; i++) {
39463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    int n = mHistory.get(i);
39563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    if (n == 0) {
39663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        q.append("0;");
39763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    } else {
39863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        while (n != 0) {
39963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            int digit = (n & 0xf);
40063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            n >>= 4;
40163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            q.append(hexdigits[digit]);
40263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        }
40363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        q.append(";");
40463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    }
40563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                }
40663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                ed.putString("history", q.toString());
40763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            }
408792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("curpos", mPlayPos);
410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putLong("seekpos", mPlayer.position());
412792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("repeatmode", mRepeatMode);
414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("shufflemode", mShuffleMode);
415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.commit();
416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        //Log.i("@@@@ service", "saved state in " + (System.currentTimeMillis() - start) + " ms");
418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void reloadQueue() {
421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String q = null;
422792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        boolean newstyle = false;
424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int id = mCardId;
425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPreferences.contains("cardid")) {
426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            newstyle = true;
427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            id = mPreferences.getInt("cardid", ~mCardId);
428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (id == mCardId) {
430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Only restore the saved playlist if the card is still
431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // the same one as when the playlist was saved
432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            q = mPreferences.getString("queue", "");
433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
4346c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen        int qlen = q != null ? q.length() : 0;
4356c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen        if (qlen > 1) {
436792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //Log.i("@@@@ service", "loaded queue: " + q);
437bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int plen = 0;
438bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int n = 0;
439bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int shift = 0;
440bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            for (int i = 0; i < qlen; i++) {
441bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                char c = q.charAt(i);
442bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                if (c == ';') {
443bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    ensurePlayListCapacity(plen + 1);
444bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    mPlayList[plen] = n;
445bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    plen++;
446bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    n = 0;
447bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    shift = 0;
448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
449bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    if (c >= '0' && c <= '9') {
450bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        n += ((c - '0') << shift);
451bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    } else if (c >= 'a' && c <= 'f') {
452bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        n += ((10 + c - 'a') << shift);
453bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    } else {
454bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        // bogus playlist data
455bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        plen = 0;
456bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        break;
457bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    }
458bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    shift += 4;
459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
461bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            mPlayListLen = plen;
462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int pos = mPreferences.getInt("curpos", 0);
464bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            if (pos < 0 || pos >= mPlayListLen) {
465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // The saved playlist is bogus, discard it
466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 0;
467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = pos;
470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // When reloadQueue is called in response to a card-insertion,
472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // we might not be able to query the media provider right away.
473792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // To deal with this, try querying for the current file, and if
474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // that fails, wait a while and try again. If that too fails,
475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // assume there is a problem and don't restore the state.
47663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            Cursor crsr = MusicUtils.query(this,
477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        new String [] {"_id"}, "_id=" + mPlayList[mPlayPos] , null, null);
47963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (crsr == null || crsr.getCount() == 0) {
480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // wait a bit and try again
481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                SystemClock.sleep(3000);
48263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                crsr = getContentResolver().query(
483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCursorCols, "_id=" + mPlayList[mPlayPos] , null, null);
485792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
48663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (crsr != null) {
48763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                crsr.close();
488792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Make sure we don't auto-skip to the next song, since that
491792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // also starts playback. What could happen in that case is:
492792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music is paused
493792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - go to UMS and delete some files, including the currently playing one
494792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - come back from UMS
495792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // (time passes)
496792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music app is killed for some reason (out of memory)
497792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music service is restarted, service restores state, doesn't find
498792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //   the "current" file, goes to the next and: playback starts on its
499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //   own, potentially at some random inconvenient time.
500792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mOpenFailedCounter = 20;
501792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mQuietMode = true;
502792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
503792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mQuietMode = false;
504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (!mPlayer.isInitialized()) {
505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // couldn't restore the saved state
506792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 0;
507792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
508792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
509792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            long seekpos = mPreferences.getLong("seekpos", 0);
511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            seek(seekpos >= 0 && seekpos < duration() ? seekpos : 0);
512e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen            Log.d(LOGTAG, "restored queue, currently at position "
513e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    + position() + "/" + duration()
514e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    + " (requested " + seekpos + ")");
515792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int repmode = mPreferences.getInt("repeatmode", REPEAT_NONE);
517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (repmode != REPEAT_ALL && repmode != REPEAT_CURRENT) {
518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                repmode = REPEAT_NONE;
519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = repmode;
521792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int shufmode = mPreferences.getInt("shufflemode", SHUFFLE_NONE);
523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (shufmode != SHUFFLE_AUTO && shufmode != SHUFFLE_NORMAL) {
524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                shufmode = SHUFFLE_NONE;
525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
52663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (shufmode != SHUFFLE_NONE) {
52763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                // in shuffle mode we need to restore the history too
52863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                q = mPreferences.getString("history", "");
52963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                qlen = q != null ? q.length() : 0;
53063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                if (qlen > 1) {
53163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    plen = 0;
53263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    n = 0;
53363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    shift = 0;
53463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    mHistory.clear();
53563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    for (int i = 0; i < qlen; i++) {
53663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        char c = q.charAt(i);
53763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        if (c == ';') {
53863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            if (n >= mPlayListLen) {
53963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                // bogus history data
54063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                mHistory.clear();
54163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                break;
54263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            }
54363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            mHistory.add(n);
54463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            n = 0;
54563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            shift = 0;
54663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        } else {
54763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            if (c >= '0' && c <= '9') {
54863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                n += ((c - '0') << shift);
54963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            } else if (c >= 'a' && c <= 'f') {
55063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                n += ((10 + c - 'a') << shift);
55163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            } else {
55263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                // bogus history data
55363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                mHistory.clear();
55463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                break;
55563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            }
55663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            shift += 4;
55763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        }
55863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    }
55963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                }
56063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            }
561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (shufmode == SHUFFLE_AUTO) {
562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (! makeAutoShuffleList()) {
563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    shufmode = SHUFFLE_NONE;
564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mShuffleMode = shufmode;
567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public IBinder onBind(Intent intent) {
572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = true;
574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mBinder;
575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
576792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onRebind(Intent intent) {
579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = true;
581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
583792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
584c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen    public int onStartCommand(Intent intent, int flags, int startId) {
585792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceStartId = startId;
586792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
587c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen
588c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen        if (intent != null) {
589c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            String action = intent.getAction();
590c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            String cmd = intent.getStringExtra("command");
5913988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog("onStartCommand " + action + " / " + cmd);
592c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen
593c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
594c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                next(true);
595c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
596b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                if (position() < 2000) {
597b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    prev();
598b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                } else {
599b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    seek(0);
600b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    play();
601b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                }
602c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
603c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                if (isPlaying()) {
604c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                    pause();
605aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                    mPausedByTransientLossOfFocus = false;
606c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                } else {
607c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                    play();
608c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                }
609c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
610792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
611aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
612c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDSTOP.equals(cmd)) {
613c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                pause();
614aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
615c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                seek(0);
616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
617792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // make sure the service will shut down on its own if it was
620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // just started but not bound to and nothing is playing
621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
624c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen        return START_STICKY;
625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean onUnbind(Intent intent) {
629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = false;
630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Take a snapshot of the current playlist
632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        saveQueue(true);
633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
634aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi        if (isPlaying() || mPausedByTransientLossOfFocus) {
635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // something is currently playing, or will be playing once
636aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi            // an in-progress action requesting audio focus ends, so don't stop the service now.
637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // If there is a playlist but playback is paused, then wait a while
641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // before stopping the service, so that pause/resume isn't slow.
642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Also delay stopping the service if we're transitioning between tracks.
643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayListLen > 0  || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Message msg = mDelayedStopHandler.obtainMessage();
645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // No active playlist, OK to stop the service right now
650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stopSelf(mServiceStartId);
651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return true;
652792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
654792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Handler mDelayedStopHandler = new Handler() {
655792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void handleMessage(Message msg) {
657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Check again to make sure nothing is playing right now
658aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi            if (isPlaying() || mPausedByTransientLossOfFocus || mServiceInUse
659792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // save the queue again, because it might have changed
663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // since the user exited the music app (because of
664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // party-shuffle or because the play-position changed)
665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(true);
666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stopSelf(mServiceStartId);
667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Called when we receive a ACTION_MEDIA_EJECT notification.
672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param storagePath path to mount point for the removed media
674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void closeExternalStorageFiles(String storagePath) {
676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // stop playback and clean up if the SD card is going to be unmounted.
677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stop(true);
678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        notifyChange(QUEUE_CHANGED);
679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        notifyChange(META_CHANGED);
680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Registers an intent to listen for ACTION_MEDIA_EJECT notifications.
684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent will call closeExternalStorageFiles() if the external media
685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * is going to be ejected, so applications can clean up any files they have open.
686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void registerExternalStorageListener() {
688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mUnmountReceiver == null) {
689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnmountReceiver = new BroadcastReceiver() {
690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                @Override
691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                public void onReceive(Context context, Intent intent) {
692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    String action = intent.getAction();
693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        saveQueue(true);
695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mOneShot = true; // This makes us not save the state again later,
696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                                         // which would be wrong because the song ids and
697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                                         // card id might not match.
698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        closeExternalStorageFiles(intent.getData().getPath());
699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mMediaMountedCount++;
70187bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen                        mCardId = MusicUtils.getCardId(MediaPlaybackService.this);
702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        reloadQueue();
703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(QUEUE_CHANGED);
704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(META_CHANGED);
705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            };
708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            IntentFilter iFilter = new IntentFilter();
709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_EJECT);
710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addDataScheme("file");
712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            registerReceiver(mUnmountReceiver, iFilter);
713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Notify the change-receivers that something has changed.
718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent that is sent contains the following data
719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * for the currently playing track:
720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "id" - Integer: the database row ID
721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "artist" - String: the name of the artist
722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "album" - String: the name of the album
723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "track" - String: the name of the track
724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent has an action that is one of
725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.metachanged"
726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.queuechanged",
727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.playbackcomplete"
728792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.playstatechanged"
729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * respectively indicating that a new track has
730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * started playing, that the playback queue has
731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * changed, that playback has stopped because
732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the last file in the list has been played,
733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * or that the play-state changed (paused/resumed).
734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void notifyChange(String what) {
736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Intent i = new Intent(what);
738bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        i.putExtra("id", Long.valueOf(getAudioId()));
739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("artist", getArtistName());
740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("album",getAlbumName());
741792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("track", getTrackName());
742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        sendBroadcast(i);
743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (what.equals(QUEUE_CHANGED)) {
745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(true);
746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
750490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project        // Share this notification directly with our widgets
751490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project        mAppWidgetProvider.notifyChange(this, what);
752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
754792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void ensurePlayListCapacity(int size) {
755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayList == null || size > mPlayList.length) {
756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // reallocate at 2x requested size so we don't
757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // need to grow and copy the array for every
758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // insert
759bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] newlist = new long[size * 2];
760bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int len = mPlayList != null ? mPlayList.length : mPlayListLen;
761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                newlist[i] = mPlayList[i];
763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList = newlist;
765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // FIXME: shrink the array when the needed size is much smaller
767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // than the allocated size
768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // insert the list of songs at the specified position in the playlist
771bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private void addToPlayList(long [] list, int position) {
772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int addlen = list.length;
773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (position < 0) { // overwrite
774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen = 0;
775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            position = 0;
776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ensurePlayListCapacity(mPlayListLen + addlen);
778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (position > mPlayListLen) {
779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            position = mPlayListLen;
780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // move part of list after insertion point
783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int tailsize = mPlayListLen - position;
784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = tailsize ; i > 0 ; i--) {
785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[position + i] = mPlayList[position + i - addlen];
786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
788792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // copy list into playlist
789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < addlen; i++) {
790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[position + i] = list[i];
791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayListLen += addlen;
793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
796792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Appends a list of tracks to the current playlist.
797792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * If nothing is playing currently, playback will be started at
798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the first track.
799792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * If the action is NOW, playback will switch to the first of
800792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the new tracks immediately.
801792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param list The list of tracks to append.
802792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param action NOW, NEXT or LAST
803792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
804bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public void enqueue(long [] list, int action) {
805792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (action == NEXT && mPlayPos + 1 < mPlayListLen) {
807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, mPlayPos + 1);
808792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
809792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
810792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // action == LAST || action == NOW || mPlayPos + 1 == mPlayListLen
811792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, Integer.MAX_VALUE);
812792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (action == NOW) {
814792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = mPlayListLen - list.length;
815792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
817792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    notifyChange(META_CHANGED);
818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
820792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos < 0) {
822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = 0;
823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                openCurrent();
824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(META_CHANGED);
826792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
829792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Replaces the current playlist with a new list,
832792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * and prepares for starting playback at the specified
833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * position in the list, or a random position if the
834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * specified position is 0.
835792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param list The new list of tracks.
836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
837bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public void open(long [] list, int position) {
838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_AUTO) {
840792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mShuffleMode = SHUFFLE_NORMAL;
841792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
842bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long oldId = getAudioId();
843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int listlength = list.length;
844792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            boolean newlist = true;
845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayListLen == listlength) {
846792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // possible fast path: list might be the same
847792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                newlist = false;
848792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = 0; i < listlength; i++) {
849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (list[i] != mPlayList[i]) {
850792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        newlist = true;
851792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        break;
852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
853792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (newlist) {
856792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, -1);
857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
858792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
859792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int oldpos = mPlayPos;
860792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (position >= 0) {
861792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = position;
862792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
863792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = mRand.nextInt(mPlayListLen);
864792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
865792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mHistory.clear();
866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
867792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
868792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
869d8c696753687ddb0177f869fad5f709eadfe27afJeffrey Sharkey            if (oldId != getAudioId()) {
870792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(META_CHANGED);
871792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
873792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
874792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
875792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
876792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Moves the item at index1 to index2.
877792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param index1
878792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param index2
879792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
880792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void moveQueueItem(int index1, int index2) {
881792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
882792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index1 >= mPlayListLen) {
883792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                index1 = mPlayListLen - 1;
884792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
885792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index2 >= mPlayListLen) {
886792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                index2 = mPlayListLen - 1;
887792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index1 < index2) {
889bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long tmp = mPlayList[index1];
890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = index1; i < index2; i++) {
891792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = mPlayList[i+1];
892792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
893792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[index2] = tmp;
894792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos == index1) {
895792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = index2;
896792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else if (mPlayPos >= index1 && mPlayPos <= index2) {
897792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos--;
898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
899792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (index2 < index1) {
900bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long tmp = mPlayList[index1];
901792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = index1; i > index2; i--) {
902792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = mPlayList[i-1];
903792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
904792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[index2] = tmp;
905792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos == index1) {
906792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = index2;
907792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else if (mPlayPos >= index2 && mPlayPos <= index1) {
908792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos++;
909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
910792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
911792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
912792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
913792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
914792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
915792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
916792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the current play list
917792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return An array of integers containing the IDs of the tracks in the play list
918792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
919bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long [] getQueue() {
920792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
921792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = mPlayListLen;
922bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = new long[len];
923792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
924792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                list[i] = mPlayList[i];
925792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
926792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return list;
927792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
928792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
929792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
930792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void openCurrent() {
931792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
932792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor != null) {
933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor.close();
934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor = null;
935792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
936792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayListLen == 0) {
937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
938792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
939792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
940792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
941792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String id = String.valueOf(mPlayList[mPlayPos]);
942792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
943792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = getContentResolver().query(
944792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
945792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mCursorCols, "_id=" + id , null, null);
946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor != null) {
947792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor.moveToFirst();
948792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                open(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + id, false);
949792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // go to bookmark if needed
950792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (isPodcast()) {
951792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    long bookmark = getBookmark();
952792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // Start playing a little bit before the bookmark,
953792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // so it's easier to get back in to the narrative.
954792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    seek(bookmark - 5000);
955792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
956792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
957792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
958792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
959792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
960792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void openAsync(String path) {
961792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
962792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (path == null) {
963792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
964792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
965792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
966792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = REPEAT_NONE;
967792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ensurePlayListCapacity(1);
968792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen = 1;
969792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = -1;
970792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
971792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mFileToPlay = path;
972792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
973792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.setDataSourceAsync(mFileToPlay);
974792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mOneShot = true;
975792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
976792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
977792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
978792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
979792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Opens the specified file and readies it for playback.
980792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
981792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param path The full path of the file to be opened.
982792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param oneshot when set to true, playback will stop after this file completes, instead
983792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * of moving on to the next track in the list
984792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
985792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void open(String path, boolean oneshot) {
986792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
987792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (path == null) {
988792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
989792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
990792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
991792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (oneshot) {
992792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mRepeatMode = REPEAT_NONE;
993792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ensurePlayListCapacity(1);
994792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 1;
995792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = -1;
996792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
997792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
998792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // if mCursor is null, try to associate path with a database cursor
999792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1000792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1001792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ContentResolver resolver = getContentResolver();
1002792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Uri uri;
1003792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String where;
1004792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String selectionArgs[];
1005792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (path.startsWith("content://media/")) {
1006792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    uri = Uri.parse(path);
1007792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    where = null;
1008792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    selectionArgs = null;
1009792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1010792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   uri = MediaStore.Audio.Media.getContentUriForPath(path);
1011792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   where = MediaStore.Audio.Media.DATA + "=?";
1012792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   selectionArgs = new String[] { path };
1013792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1014792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1015792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                try {
1016792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mCursor = resolver.query(uri, mCursorCols, where, selectionArgs, null);
1017792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if  (mCursor != null) {
1018792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (mCursor.getCount() == 0) {
1019792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor.close();
1020792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor = null;
1021792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        } else {
1022792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor.moveToNext();
1023792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            ensurePlayListCapacity(1);
1024792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mPlayListLen = 1;
1025bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                            mPlayList[0] = mCursor.getLong(IDCOLIDX);
1026792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mPlayPos = 0;
1027792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
1028792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1029792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } catch (UnsupportedOperationException ex) {
1030792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1031792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1032792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mFileToPlay = path;
1033792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.setDataSource(mFileToPlay);
1034792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mOneShot = oneshot;
1035792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (! mPlayer.isInitialized()) {
1036792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                stop(true);
1037792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mOpenFailedCounter++ < 10 &&  mPlayListLen > 1) {
1038792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // beware: this ends up being recursive because next() calls open() again.
1039792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    next(false);
1040792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1041792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (! mPlayer.isInitialized() && mOpenFailedCounter != 0) {
1042792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // need to make sure we only shows this once
1043792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mOpenFailedCounter = 0;
1044792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (!mQuietMode) {
1045792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        Toast.makeText(this, R.string.playback_failed, Toast.LENGTH_SHORT).show();
1046792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1047e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    Log.d(LOGTAG, "Failed to open file for playback");
1048792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1049792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1050792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mOpenFailedCounter = 0;
1051792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1052792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1053792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1054792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1055792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1056792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Starts playback of a previously opened file.
1057792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1058792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void play() {
1059085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
1060085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                AudioManager.AUDIOFOCUS_GAIN);
10613d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi        mAudioManager.registerMediaButtonEventReceiver(new ComponentName(this.getPackageName(),
10623d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi                MediaButtonIntentReceiver.class.getName()));
1063085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
1064792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1065272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle            // if we are at the end of the song, go to the next song first
10662f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen            long duration = mPlayer.duration();
10672f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen            if (mRepeatMode != REPEAT_CURRENT && duration > 2000 &&
10682f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen                mPlayer.position() >= duration - 2000) {
1069272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle                next(true);
1070272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle            }
1071272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle
1072792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.start();
1073792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1074792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            RemoteViews views = new RemoteViews(getPackageName(), R.layout.statusbar);
1075792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            views.setImageViewResource(R.id.icon, R.drawable.stat_notify_musicplayer);
1076792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (getAudioId() < 0) {
1077792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // streaming
1078792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.trackname, getPath());
1079792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.artistalbum, null);
1080792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1081792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String artist = getArtistName();
1082792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.trackname, getTrackName());
1083f4d4b342061ade12eb7903f454df62814179906fMarco Nelissen                if (artist == null || artist.equals(MediaStore.UNKNOWN_STRING)) {
1084792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    artist = getString(R.string.unknown_artist_name);
1085792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1086792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String album = getAlbumName();
1087f4d4b342061ade12eb7903f454df62814179906fMarco Nelissen                if (album == null || album.equals(MediaStore.UNKNOWN_STRING)) {
1088792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    album = getString(R.string.unknown_album_name);
1089792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1090792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1091792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                views.setTextViewText(R.id.artistalbum,
1092792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        getString(R.string.notification_artist_album, artist, album)
1093792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        );
1094792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1095792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1096792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Notification status = new Notification();
1097792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.contentView = views;
1098792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.flags |= Notification.FLAG_ONGOING_EVENT;
1099792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.icon = R.drawable.stat_notify_musicplayer;
1100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            status.contentIntent = PendingIntent.getActivity(this, 0,
1101ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    new Intent("com.android.music.PLAYBACK_VIEWER")
1102ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0);
1103d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn            startForeground(PLAYBACKSERVICE_STATUS, status);
1104c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen            if (!mIsSupposedToBePlaying) {
1105347fe57e4c8a860dfbad6f0ec1991171bfa69d77Mike Cleron                mIsSupposedToBePlaying = true;
1106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(PLAYSTATE_CHANGED);
1107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1108347fe57e4c8a860dfbad6f0ec1991171bfa69d77Mike Cleron
1109792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else if (mPlayListLen <= 0) {
1110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // This is mostly so that if you press 'play' on a bluetooth headset
1111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // without every having played anything before, it will still play
1112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // something.
1113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            setShuffleMode(SHUFFLE_AUTO);
1114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void stop(boolean remove_status_icon) {
1118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.stop();
1120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mFileToPlay = null;
1122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mCursor != null) {
1123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor.close();
1124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
1125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (remove_status_icon) {
1127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            gotoIdleState();
1128d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn        } else {
1129d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn            stopForeground(false);
1130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (remove_status_icon) {
1132c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen            mIsSupposedToBePlaying = false;
1133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Stops playback.
1138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void stop() {
1140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stop(true);
1141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1142792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Pauses playback (call play() to resume)
1145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1146792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void pause() {
1147407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen        synchronized(this) {
1148407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen            if (isPlaying()) {
1149407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                mPlayer.pause();
1150407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                gotoIdleState();
1151407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                mIsSupposedToBePlaying = false;
1152407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                notifyChange(PLAYSTATE_CHANGED);
1153407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                saveBookmarkIfNeeded();
1154407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen            }
1155792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1156792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1157792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1158b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen    /** Returns whether something is currently playing
1159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
1160b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen     * @return true if something is playing (or will be playing shortly, in case
1161b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen     * we're currently transitioning between tracks), false if not.
1162792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1163792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean isPlaying() {
1164c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen        return mIsSupposedToBePlaying;
1165792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1166792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1167792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /*
1168792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      Desired behavior for prev/next/shuffle:
1169792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1170792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      - NEXT will move to the next track in the list when not shuffling, and to
1171792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        a track randomly picked from the not-yet-played tracks when shuffling.
1172792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        If all tracks have already been played, pick from the full set, but
1173792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        avoid picking the previously played track if possible.
1174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      - when shuffling, PREV will go to the previously played track. Hitting PREV
1175792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        again will go to the track played before that, etc. When the start of the
1176792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        history has been reached, PREV is a no-op.
1177792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When not shuffling, PREV will go to the sequentially previous track (the
1178792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        difference with the shuffle-case is mainly that when not shuffling, the
1179792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        user can back up to tracks that are not in the history).
1180792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1181792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Example:
1182792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When playing an album with 10 tracks from the start, and enabling shuffle
1183792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        while playing track 5, the remaining tracks (6-10) will be shuffled, e.g.
1184792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        the final play order might be 1-2-3-4-5-8-10-6-9-7.
1185792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When hitting 'prev' 8 times while playing track 7 in this example, the
1186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        user will go to tracks 9-6-10-8-5-4-3-2. If the user then hits 'next',
1187792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        a random track will be picked again. If at any time user disables shuffling
1188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        the next/previous track will be picked in sequential order again.
1189792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1190792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1191792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void prev() {
1192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mOneShot) {
1194792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // we were playing a specific file not part of a playlist, so there is no 'previous'
1195792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                seek(0);
1196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
1197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_NORMAL) {
1200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // go to previously-played track and remove it from the history
1201792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int histsize = mHistory.size();
1202792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (histsize == 0) {
1203792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // prev is a no-op
1204792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1205792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1206792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Integer pos = mHistory.remove(histsize - 1);
1207792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = pos.intValue();
1208792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1209792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos > 0) {
1210792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos--;
1211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = mPlayListLen - 1;
1213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
1216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1222792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1223792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void next(boolean force) {
1224792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mOneShot) {
1226792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // we were playing a specific file not part of a playlist, so there is no 'next'
1227792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                seek(0);
1228792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
1229792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1230792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1231792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1232663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen            if (mPlayListLen <= 0) {
1233e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                Log.d(LOGTAG, "No play queue");
1234663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen                return;
1235663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen            }
1236663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen
1237792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Store the current file in the history, but keep the history at a
1238792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // reasonable size
1239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos >= 0) {
1240792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHistory.add(Integer.valueOf(mPlayPos));
1241792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mHistory.size() > MAX_HISTORY_SIZE) {
1243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHistory.removeElementAt(0);
1244792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1246792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_NORMAL) {
1247792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Pick random next track from the not-yet-played ones
1248792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: make it work right after adding/removing items in the queue.
1249792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numTracks = mPlayListLen;
1251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int[] tracks = new int[numTracks];
1252792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i=0;i < numTracks; i++) {
1253792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    tracks[i] = i;
1254792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1255792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1256792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numHistory = mHistory.size();
1257792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numUnplayed = numTracks;
1258792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i=0;i < numHistory; i++) {
1259792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    int idx = mHistory.get(i).intValue();
1260792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (idx < numTracks && tracks[idx] >= 0) {
1261792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        numUnplayed--;
1262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        tracks[idx] = -1;
1263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // 'numUnplayed' now indicates how many tracks have not yet
1267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // been played, and 'tracks' contains the indices of those
1268792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // tracks.
1269792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (numUnplayed <=0) {
1270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // everything's already been played
1271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_ALL || force) {
1272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        //pick from full set
1273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        numUnplayed = numTracks;
1274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        for (int i=0;i < numTracks; i++) {
1275792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            tracks[i] = i;
1276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
1277792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
1278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // all done
1279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        gotoIdleState();
1280ab893d7a8067b9c45eda455b38f3b064e82dcb91Marco Nelissen                        if (mIsSupposedToBePlaying) {
1281ab893d7a8067b9c45eda455b38f3b064e82dcb91Marco Nelissen                            mIsSupposedToBePlaying = false;
1282ab893d7a8067b9c45eda455b38f3b064e82dcb91Marco Nelissen                            notifyChange(PLAYSTATE_CHANGED);
1283ab893d7a8067b9c45eda455b38f3b064e82dcb91Marco Nelissen                        }
1284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        return;
1285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1287792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int skip = mRand.nextInt(numUnplayed);
1288792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int cnt = -1;
1289792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                while (true) {
1290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    while (tracks[++cnt] < 0)
1291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        ;
1292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    skip--;
1293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (skip < 0) {
1294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        break;
1295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1297792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = cnt;
1298792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (mShuffleMode == SHUFFLE_AUTO) {
1299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                doAutoShuffleUpdate();
1300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos++;
1301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos >= mPlayListLen - 1) {
1303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // we're at the end of the list
1304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_NONE && !force) {
1305792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // all done
1306792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        gotoIdleState();
1307792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(PLAYBACK_COMPLETE);
1308c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                        mIsSupposedToBePlaying = false;
1309792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        return;
1310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (mRepeatMode == REPEAT_ALL || force) {
1311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos = 0;
1312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1314792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos++;
1315792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1316792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1317792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
1318792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1319792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1320792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1321792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1322792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1323792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1324792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1325792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void gotoIdleState() {
1326792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
1327792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
1328792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
1329d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn        stopForeground(true);
1330792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1331792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1332792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void saveBookmarkIfNeeded() {
1333792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1334792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (isPodcast()) {
1335792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long pos = position();
1336792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long bookmark = getBookmark();
1337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long duration = duration();
1338792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if ((pos < bookmark && (pos + 10000) > bookmark) ||
1339792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        (pos > bookmark && (pos - 10000) < bookmark)) {
1340792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // The existing bookmark is close to the current
1341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // position, so don't update it.
1342792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1343792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (pos < 15000 || (pos + 10000) > duration) {
1345792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // if we're near the start or end, clear the bookmark
1346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    pos = 0;
1347792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // write 'pos' to the bookmark field
1350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ContentValues values = new ContentValues();
1351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                values.put(MediaStore.Audio.Media.BOOKMARK, pos);
1352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Uri uri = ContentUris.withAppendedId(
1353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursor.getLong(IDCOLIDX));
1354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                getContentResolver().update(uri, values, null, null);
1355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1356792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (SQLiteException ex) {
1357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // Make sure there are at least 5 items after the currently playing item
1361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // and no more than 10 items before.
1362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void doAutoShuffleUpdate() {
1363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        boolean notify = false;
1364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // remove old entries
1365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayPos > 10) {
1366792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            removeTracks(0, mPlayPos - 9);
1367792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notify = true;
1368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1369792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // add new entries if needed
1370792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int to_add = 7 - (mPlayListLen - (mPlayPos < 0 ? -1 : mPlayPos));
1371792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < to_add; i++) {
1372792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // pick something at random from the list
1373792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int idx = mRand.nextInt(mAutoShuffleList.length);
1374bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long which = mAutoShuffleList[idx];
1375792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ensurePlayListCapacity(mPlayListLen + 1);
1376792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[mPlayListLen++] = which;
1377792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notify = true;
1378792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1379792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (notify) {
1380792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1381792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1382792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1383792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1384792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // A simple variation of Random that makes sure that the
1385792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // value it returns is not equal to the value it returned
1386792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // previously, unless the interval is 1.
1387756c3f57f11a7bb3bf1cf1333ee8ffbc51039748Marco Nelissen    private static class Shuffler {
1388792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private int mPrevious;
1389792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private Random mRandom = new Random();
1390792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int nextInt(int interval) {
1391792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int ret;
1392792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            do {
1393792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ret = mRandom.nextInt(interval);
1394792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } while (ret == mPrevious && interval > 1);
1395792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPrevious = ret;
1396792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return ret;
1397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1398792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
1399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean makeAutoShuffleList() {
1401792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ContentResolver res = getContentResolver();
1402792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor c = null;
1403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            c = res.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1405792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    new String[] {MediaStore.Audio.Media._ID}, MediaStore.Audio.Media.IS_MUSIC + "=1",
1406792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    null, null);
1407792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c == null || c.getCount() == 0) {
1408792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = c.getCount();
1411bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = new long[len];
1412792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
1413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.moveToNext();
1414bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                list[i] = c.getLong(0);
1415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mAutoShuffleList = list;
1417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
1418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (RuntimeException ex) {
1419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } finally {
1420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c != null) {
1421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.close();
1422792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return false;
1425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Removes the range of tracks specified from the play list. If a file within the range is
1429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the file currently being played, playback will move to the next file after the
1430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * range.
1431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param first The first file to be removed
1432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param last The last file to be removed
1433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return the number of tracks deleted
1434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int removeTracks(int first, int last) {
1436792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int numremoved = removeTracksInternal(first, last);
1437792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (numremoved > 0) {
1438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return numremoved;
1441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int removeTracksInternal(int first, int last) {
1444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (last < first) return 0;
1446792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (first < 0) first = 0;
1447792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (last >= mPlayListLen) last = mPlayListLen - 1;
1448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            boolean gotonext = false;
1450792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (first <= mPlayPos && mPlayPos <= last) {
1451792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = first;
1452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                gotonext = true;
1453792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (mPlayPos > last) {
1454792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos -= (last - first + 1);
1455792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1456792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int num = mPlayListLen - last - 1;
1457792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < num; i++) {
1458792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[first + i] = mPlayList[last + 1 + i];
1459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen -= last - first + 1;
1461792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (gotonext) {
1463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayListLen == 0) {
1464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    stop(true);
1465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = -1;
1466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mPlayPos >= mPlayListLen) {
1468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos = 0;
1469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    boolean wasPlaying = isPlaying();
1471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    stop(false);
1472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
1473792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (wasPlaying) {
1474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
1475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return last - first + 1;
1479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Removes all instances of the track with the given id
1484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * from the playlist.
1485792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param id The id to be removed
1486792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return how many instances of the track were removed
1487792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1488bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public int removeTrack(long id) {
1489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int numremoved = 0;
1490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1491792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < mPlayListLen; i++) {
1492792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayList[i] == id) {
1493792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    numremoved += removeTracksInternal(i, i);
1494792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    i--;
1495792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1496792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1497792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1498792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (numremoved > 0) {
1499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1500792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1501792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return numremoved;
1502792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1503792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setShuffleMode(int shufflemode) {
1505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1506792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == shufflemode && mPlayListLen > 0) {
1507792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1508792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1509792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mShuffleMode = shufflemode;
1510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_AUTO) {
1511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (makeAutoShuffleList()) {
1512792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayListLen = 0;
1513792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    doAutoShuffleUpdate();
1514792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = 0;
1515792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
1516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
1517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    notifyChange(META_CHANGED);
1518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // failed to build a list of files to shuffle
1521792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mShuffleMode = SHUFFLE_NONE;
1522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
1525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1527792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getShuffleMode() {
1528792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mShuffleMode;
1529792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setRepeatMode(int repeatmode) {
1532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1533792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = repeatmode;
1534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
1535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1536792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getRepeatMode() {
1538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mRepeatMode;
1539792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getMediaMountedCount() {
1542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mMediaMountedCount;
1543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the path of the currently playing file, or null if
1547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * no file is currently playing.
1548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getPath() {
1550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mFileToPlay;
1551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the rowid of the currently playing file, or -1 if
1555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * no file is currently playing.
1556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1557bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getAudioId() {
1558792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos >= 0 && mPlayer.isInitialized()) {
1560792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return mPlayList[mPlayPos];
1561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the position in the queue
1568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return the position in the queue
1569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getQueuePosition() {
1571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayPos;
1573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1576792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Starts playing the track at the given position in the queue.
1578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param pos The position in the queue of the track that will be played.
1579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setQueuePosition(int pos) {
1581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1583792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = pos;
1584792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1585792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1586792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1587ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            if (mShuffleMode == SHUFFLE_AUTO) {
1588ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                doAutoShuffleUpdate();
1589ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            }
1590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1591792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1592792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1593792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getArtistName() {
1594792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1595792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1596792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
1599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1600792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1601792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1602bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getArtistId() {
1603792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1604792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1605792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return -1;
1606792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1607bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID));
1608792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1609792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1610792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1611792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getAlbumName() {
1612792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1613792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1615792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
1617792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1620bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getAlbumId() {
1621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return -1;
1624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1625bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
1626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getTrackName() {
1630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
1635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean isPodcast() {
1639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return (mCursor.getInt(PODCASTCOLIDX) > 0);
1644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private long getBookmark() {
1648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return 0;
1651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1652792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getLong(BOOKMARKCOLIDX);
1653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1654792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1655792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the duration of the file in milliseconds.
1658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Currently this method returns -1 for the duration of MIDI files.
1659792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long duration() {
1661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.duration();
1663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the current playback position in milliseconds
1669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long position() {
1671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.position();
1673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Seeks to the position specified.
1679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
1680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param pos The position to seek to, in milliseconds
1681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long seek(long pos) {
1683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (pos < 0) pos = 0;
1685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (pos > mPlayer.duration()) pos = mPlayer.duration();
1686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.seek(pos);
1687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Provides a unified interface for dealing with midi files and
1693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * other media files.
1694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private class MultiPlayer {
1696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private MediaPlayer mMediaPlayer = new MediaPlayer();
1697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private Handler mHandler;
1698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private boolean mIsInitialized = false;
1699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public MultiPlayer() {
1701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK);
1702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setDataSourceAsync(String path) {
1705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
1706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.reset();
1707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setDataSource(path);
1708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
1709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setOnPreparedListener(preparedlistener);
1710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.prepareAsync();
1711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IOException ex) {
1712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IllegalArgumentException ex) {
1716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnCompletionListener(listener);
1721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnErrorListener(errorListener);
1722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = true;
1724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setDataSource(String path) {
1727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
1728792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.reset();
1729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setOnPreparedListener(null);
1730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (path.startsWith("content://")) {
1731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setDataSource(MediaPlaybackService.this, Uri.parse(path));
1732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setDataSource(path);
1734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
1736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.prepare();
1737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IOException ex) {
1738792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1741792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IllegalArgumentException ex) {
1742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnCompletionListener(listener);
1747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnErrorListener(errorListener);
1748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = true;
1750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1751792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public boolean isInitialized() {
1753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mIsInitialized;
1754792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void start() {
17573988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog(new Exception("MultiPlayer.start called"));
1758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.start();
1759792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1760792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void stop() {
1762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.reset();
1763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = false;
1764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
17662b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        /**
17672b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen         * You CANNOT use this player anymore after calling release()
17682b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen         */
17692b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        public void release() {
17702b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            stop();
17712b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mMediaPlayer.release();
17722b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        }
17732b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
1774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void pause() {
1775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.pause();
1776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setHandler(Handler handler) {
1779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mHandler = handler;
1780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnCompletionListener listener = new MediaPlayer.OnCompletionListener() {
1783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public void onCompletion(MediaPlayer mp) {
1784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Acquire a temporary wakelock, since when we return from
1785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // this callback the MediaPlayer will release its wakelock
1786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // and allow the device to go to sleep.
1787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // This temporary wakelock is released when the RELEASE_WAKELOCK
1788792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // message is processed, but just in case, put a timeout on it.
1789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mWakeLock.acquire(30000);
1790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHandler.sendEmptyMessage(TRACK_ENDED);
1791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHandler.sendEmptyMessage(RELEASE_WAKELOCK);
1792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnPreparedListener preparedlistener = new MediaPlayer.OnPreparedListener() {
1796792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public void onPrepared(MediaPlayer mp) {
1797792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(ASYNC_OPEN_COMPLETE);
1798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1799792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1800792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1801792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnErrorListener errorListener = new MediaPlayer.OnErrorListener() {
1802792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public boolean onError(MediaPlayer mp, int what, int extra) {
1803792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                switch (what) {
1804792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
1805792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mIsInitialized = false;
1806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.release();
1807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // Creating a new MediaPlayer and settings its wakemode does not
1808792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // require the media service, so it's OK to do this now, while the
1809792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // service is still being restarted
1810792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer = new MediaPlayer();
1811792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK);
1812792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mHandler.sendMessageDelayed(mHandler.obtainMessage(SERVER_DIED), 2000);
1813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return true;
1814792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                default:
1815e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    Log.d("MultiPlayer", "Error: " + what + "," + extra);
1816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
1817792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project           }
1820792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long duration() {
1823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mMediaPlayer.getDuration();
1824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1826792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long position() {
1827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mMediaPlayer.getCurrentPosition();
1828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1829792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long seek(long whereto) {
1831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.seekTo((int) whereto);
1832792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return whereto;
1833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1835792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setVolume(float vol) {
1836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setVolume(vol, vol);
1837792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
18402b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    /*
18412b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * By making this a static class with a WeakReference to the Service, we
18422b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * ensure that the Service can be GCd even when the system process still
18432b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * has a remote reference to the stub.
18442b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     */
18452b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    static class ServiceStub extends IMediaPlaybackService.Stub {
18462b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        WeakReference<MediaPlaybackService> mService;
18472b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
18482b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        ServiceStub(MediaPlaybackService service) {
18492b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService = new WeakReference<MediaPlaybackService>(service);
18502b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        }
18512b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
1852b7841acd23f0cf4fd8db604d73bdf14e57994fd9Marco Nelissen        public void openFileAsync(String path)
1853792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        {
18542b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().openAsync(path);
1855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1856b7841acd23f0cf4fd8db604d73bdf14e57994fd9Marco Nelissen        public void openFile(String path, boolean oneShot)
1857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        {
18582b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().open(path, oneShot);
1859792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1860bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public void open(long [] list, int position) {
18612b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().open(list, position);
1862792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1863792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getQueuePosition() {
18642b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getQueuePosition();
1865792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setQueuePosition(int index) {
18672b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setQueuePosition(index);
1868792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1869792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public boolean isPlaying() {
18702b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().isPlaying();
1871792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void stop() {
18732b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().stop();
1874792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1875792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void pause() {
18762b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().pause();
1877792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1878792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void play() {
18792b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().play();
1880792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1881792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void prev() {
18822b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().prev();
1883792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1884792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void next() {
18852b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().next(true);
1886792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1887792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getTrackName() {
18882b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getTrackName();
1889792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getAlbumName() {
18912b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAlbumName();
1892792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1893bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getAlbumId() {
18942b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAlbumId();
1895792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1896792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getArtistName() {
18972b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getArtistName();
1898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1899bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getArtistId() {
19002b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getArtistId();
1901792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1902bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public void enqueue(long [] list , int action) {
19032b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().enqueue(list, action);
1904792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1905bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long [] getQueue() {
19062b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getQueue();
1907792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1908792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void moveQueueItem(int from, int to) {
19092b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().moveQueueItem(from, to);
1910792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1911792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getPath() {
19122b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getPath();
1913792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1914bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getAudioId() {
19152b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAudioId();
1916792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1917792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long position() {
19182b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().position();
1919792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1920792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long duration() {
19212b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().duration();
1922792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1923792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long seek(long pos) {
19242b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().seek(pos);
1925792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1926792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setShuffleMode(int shufflemode) {
19272b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setShuffleMode(shufflemode);
1928792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1929792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getShuffleMode() {
19302b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getShuffleMode();
1931792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1932792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int removeTracks(int first, int last) {
19332b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().removeTracks(first, last);
1934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1935bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public int removeTrack(long id) {
19362b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().removeTrack(id);
1937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1938792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setRepeatMode(int repeatmode) {
19392b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setRepeatMode(repeatmode);
1940792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1941792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getRepeatMode() {
19422b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getRepeatMode();
1943792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1944792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getMediaMountedCount() {
19452b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getMediaMountedCount();
1946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
19472b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
19482b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    }
19493988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
19503988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    @Override
19513988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1952bf555cee7a01aed223b05144d1cec0cffdd9a6aeMarco Nelissen        writer.println("" + mPlayListLen + " items in queue, currently at index " + mPlayPos);
19533988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println("Currently loaded:");
19543988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getArtistName());
19553988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getAlbumName());
19563988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getTrackName());
19573988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getPath());
19583988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println("playing: " + mIsSupposedToBePlaying);
19593988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println("actual: " + mPlayer.mMediaPlayer.isPlaying());
1960bf555cee7a01aed223b05144d1cec0cffdd9a6aeMarco Nelissen        writer.println("shuffle mode: " + mShuffleMode);
19613988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        MusicUtils.debugDump(writer);
19623988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    }
19633988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
19642b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    private final IBinder mBinder = new ServiceStub(this);
1965792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project}
1966