MediaPlaybackService.java revision 47dd847ba35375d95c15bc1ee141d638f03ec82e
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;
35f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissenimport android.media.audiofx.AudioEffect;
36792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.AudioManager;
37085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Triviimport android.media.AudioManager.OnAudioFocusChangeListener;
38792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.MediaPlayer;
39792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.net.Uri;
40792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Handler;
41792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.IBinder;
42792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Message;
43792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.PowerManager;
44792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.SystemClock;
45792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.PowerManager.WakeLock;
46792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.provider.MediaStore;
47792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.util.Log;
48792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.RemoteViews;
49792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.Toast;
50792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
513988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissenimport java.io.FileDescriptor;
52792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.io.IOException;
533988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissenimport java.io.PrintWriter;
542b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissenimport java.lang.ref.WeakReference;
55792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.util.Random;
56792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.util.Vector;
57792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
58792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project/**
59792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Provides "background" audio playback capabilities, allowing the
60792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * user to switch between activities without stopping playback.
61792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */
62792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpublic class MediaPlaybackService extends Service {
63792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** used to specify whether enqueue() should start playing
64792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the new list of files right away, next or once all the currently
65792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * queued files have been played
66792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
67792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int NOW = 1;
68792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int NEXT = 2;
69792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int LAST = 3;
70792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int PLAYBACKSERVICE_STATUS = 1;
71792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
72792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_NONE = 0;
73792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_NORMAL = 1;
74792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_AUTO = 2;
75792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
76792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_NONE = 0;
77792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_CURRENT = 1;
78792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_ALL = 2;
79792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
80792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PLAYSTATE_CHANGED = "com.android.music.playstatechanged";
81792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String META_CHANGED = "com.android.music.metachanged";
82792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String QUEUE_CHANGED = "com.android.music.queuechanged";
83792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
84792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String SERVICECMD = "com.android.music.musicservicecommand";
85792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDNAME = "command";
86792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDTOGGLEPAUSE = "togglepause";
87792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDSTOP = "stop";
88792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDPAUSE = "pause";
89fc1c0dc301b5cae2e8c5661e7a217dc57dacac1eMarco Nelissen    public static final String CMDPLAY = "play";
90792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDPREVIOUS = "previous";
91792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDNEXT = "next";
92792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
93792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String TOGGLEPAUSE_ACTION = "com.android.music.musicservicecommand.togglepause";
94792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PAUSE_ACTION = "com.android.music.musicservicecommand.pause";
95792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PREVIOUS_ACTION = "com.android.music.musicservicecommand.previous";
96792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String NEXT_ACTION = "com.android.music.musicservicecommand.next";
97792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
98792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int TRACK_ENDED = 1;
99792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int RELEASE_WAKELOCK = 2;
100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int SERVER_DIED = 3;
1017181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen    private static final int FOCUSCHANGE = 4;
1022da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen    private static final int FADEDOWN = 5;
1032da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen    private static final int FADEUP = 6;
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;
112bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private long [] mPlayList = null;
113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mPlayListLen = 0;
114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Vector<Integer> mHistory = new Vector<Integer>(MAX_HISTORY_SIZE);
115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Cursor mCursor;
116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mPlayPos = -1;
117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final String LOGTAG = "MediaPlaybackService";
118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final Shuffler mRand = new Shuffler();
119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mOpenFailedCounter = 0;
120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    String[] mCursorCols = new String[] {
121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            "audio._id AS _id",             // index must match IDCOLIDX below
122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST,
123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ALBUM,
124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.TITLE,
125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.DATA,
126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.MIME_TYPE,
127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ALBUM_ID,
128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST_ID,
129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.IS_PODCAST, // index must match PODCASTCOLIDX below
130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.BOOKMARK    // index must match BOOKMARKCOLIDX below
131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int IDCOLIDX = 0;
133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int PODCASTCOLIDX = 8;
134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int BOOKMARKCOLIDX = 9;
135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private BroadcastReceiver mUnmountReceiver = null;
136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private WakeLock mWakeLock;
137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mServiceStartId = -1;
138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mServiceInUse = false;
139c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen    private boolean mIsSupposedToBePlaying = false;
140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mQuietMode = false;
141085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    private AudioManager mAudioManager;
1428d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen    private boolean mQueueIsSaveable = true;
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 Handler mMediaplayerHandler = new Handler() {
157792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        float mCurrentVolume = 1.0f;
158792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void handleMessage(Message msg) {
1603988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog("mMediaplayerHandler.handleMessage " + msg.what);
161792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            switch (msg.what) {
1622da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                case FADEDOWN:
1632da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    mCurrentVolume -= .05f;
1642da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    if (mCurrentVolume > .2f) {
1652da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                        mMediaplayerHandler.sendEmptyMessageDelayed(FADEDOWN, 10);
166792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
1672da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                        mCurrentVolume = .2f;
1682da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    }
1692da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    mPlayer.setVolume(mCurrentVolume);
1702da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    break;
1712da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                case FADEUP:
1722da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    mCurrentVolume += .01f;
1732da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    if (mCurrentVolume < 1.0f) {
1742da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                        mMediaplayerHandler.sendEmptyMessageDelayed(FADEUP, 10);
1752da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    } else {
1762da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                        mCurrentVolume = 1.0f;
177792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1782da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    mPlayer.setVolume(mCurrentVolume);
179792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
180792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case SERVER_DIED:
181c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                    if (mIsSupposedToBePlaying) {
182792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        next(true);
183792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
184792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // the server died when we were idle, so just
185792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // reopen the same song (it will start again
186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // from the beginning though when the user
187792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // restarts)
188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        openCurrent();
189792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
190792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
191792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case TRACK_ENDED:
192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_CURRENT) {
193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        seek(0);
194792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
195792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
1968d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen                        next(false);
197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case RELEASE_WAKELOCK:
200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mWakeLock.release();
201792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
2027181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen
2037181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                case FOCUSCHANGE:
2047181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                    // This code is here so we can better synchronize it with the code that
2057181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                    // handles fade-in
2067181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                    switch (msg.arg1) {
2077181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                        case AudioManager.AUDIOFOCUS_LOSS:
2087181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS");
2097181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            if(isPlaying()) {
2107181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mPausedByTransientLossOfFocus = false;
2117181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            }
2127181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            pause();
2137181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            break;
2147181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
2157bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen                            mMediaplayerHandler.removeMessages(FADEUP);
2167bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen                            mMediaplayerHandler.sendEmptyMessage(FADEDOWN);
2177bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen                            break;
2187bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
2197181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS_TRANSIENT");
2207181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            if(isPlaying()) {
2217181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mPausedByTransientLossOfFocus = true;
2227181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            }
2237181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            pause();
2247181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            break;
2257181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                        case AudioManager.AUDIOFOCUS_GAIN:
2267181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_GAIN");
2277181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            if(!isPlaying() && mPausedByTransientLossOfFocus) {
2287181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mPausedByTransientLossOfFocus = false;
2297181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mCurrentVolume = 0f;
2307181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mPlayer.setVolume(mCurrentVolume);
2317181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                play(); // also queues a fade-in
2327181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            } else {
2337bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen                                mMediaplayerHandler.removeMessages(FADEDOWN);
2347181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mMediaplayerHandler.sendEmptyMessage(FADEUP);
2357181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            }
2367181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            break;
2377181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                        default:
2387181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            Log.e(LOGTAG, "Unknown audio focus change code");
2397181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                    }
2407181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                    break;
2417181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen
242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                default:
243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
244792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
246792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
247792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
248792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
249792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void onReceive(Context context, Intent intent) {
251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String action = intent.getAction();
252792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String cmd = intent.getStringExtra("command");
2533988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog("mIntentReceiver.onReceive " + action + " / " + cmd);
254792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
255792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                next(true);
256792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
257792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                prev();
258792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
259792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (isPlaying()) {
260792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    pause();
261aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                    mPausedByTransientLossOfFocus = false;
262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
267aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
268fc1c0dc301b5cae2e8c5661e7a217dc57dacac1eMarco Nelissen            } else if (CMDPLAY.equals(cmd)) {
269fc1c0dc301b5cae2e8c5661e7a217dc57dacac1eMarco Nelissen                play();
270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDSTOP.equals(cmd)) {
271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
272aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                seek(0);
274490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project            } else if (MediaAppWidgetProvider.CMDAPPWIDGETUPDATE.equals(cmd)) {
275490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                // Someone asked us to refresh a set of specific widgets, probably
276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // because they were just added.
277490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
278490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                mAppWidgetProvider.performUpdate(MediaPlaybackService.this, appWidgetIds);
279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
283085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() {
284f4cfdfd4a99040be44a1ccd74edbde762edc845bJean-Michel Trivi        public void onAudioFocusChange(int focusChange) {
2857181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen            mMediaplayerHandler.obtainMessage(FOCUSCHANGE, focusChange, 0).sendToTarget();
286085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        }
287085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    };
288085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
289792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public MediaPlaybackService() {
290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onCreate() {
294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onCreate();
295085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
296085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
2973d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi        mAudioManager.registerMediaButtonEventReceiver(new ComponentName(getPackageName(),
2983d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi                MediaButtonIntentReceiver.class.getName()));
299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPreferences = getSharedPreferences("Music", MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE);
30187bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen        mCardId = MusicUtils.getCardId(this);
302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        registerExternalStorageListener();
304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
305792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Needs to be done in this thread, since otherwise ApplicationContext.getPowerManager() crashes.
306792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayer = new MultiPlayer();
307792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayer.setHandler(mMediaplayerHandler);
308792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
309792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        reloadQueue();
310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        IntentFilter commandFilter = new IntentFilter();
312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(SERVICECMD);
313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(TOGGLEPAUSE_ACTION);
314792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(PAUSE_ACTION);
315792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(NEXT_ACTION);
316792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(PREVIOUS_ACTION);
317792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        registerReceiver(mIntentReceiver, commandFilter);
318792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
319792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
320792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
321792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock.setReferenceCounted(false);
322792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
323792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // If the service was idle, but got killed before it stopped itself, the
324792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // system will relaunch it. Make sure it gets stopped again in that case.
325792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
326792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
327792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
328792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
329792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
330792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onDestroy() {
331792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Check that we're not being destroyed while something is still playing.
332792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (isPlaying()) {
333e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen            Log.e(LOGTAG, "Service being destroyed while still playing.");
334792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
3352b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        // release all MediaPlayer resources, including the native player and wakelocks
336f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen        Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
337f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen        i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId());
338f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen        i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
339f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen        sendBroadcast(i);
3402b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mPlayer.release();
3412b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mPlayer = null;
342085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
343085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        mAudioManager.abandonAudioFocus(mAudioFocusListener);
344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
3452b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        // make sure there aren't any other messages coming
3462b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mDelayedStopHandler.removeCallbacksAndMessages(null);
34749e36ea916aefba042c6e927c771b10708b6891eMarco Nelissen        mMediaplayerHandler.removeCallbacksAndMessages(null);
3482b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mCursor != null) {
350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor.close();
351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        unregisterReceiver(mIntentReceiver);
355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mUnmountReceiver != null) {
356792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            unregisterReceiver(mUnmountReceiver);
357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnmountReceiver = null;
358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock.release();
360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onDestroy();
361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final char hexdigits [] = new char [] {
364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '0', '1', '2', '3',
365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '4', '5', '6', '7',
366792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '8', '9', 'a', 'b',
367792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            'c', 'd', 'e', 'f'
368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
369792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
370792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void saveQueue(boolean full) {
3718d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen        if (!mQueueIsSaveable) {
372792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return;
373792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
3748d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen
375792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Editor ed = mPreferences.edit();
376792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        //long start = System.currentTimeMillis();
377792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (full) {
378792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            StringBuilder q = new StringBuilder();
379792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
380792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // The current playlist is saved as a list of "reverse hexadecimal"
381792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // numbers, which we can generate faster than normal decimal or
382792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // hexadecimal numbers, which in turn allows us to save the playlist
383792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // more often without worrying too much about performance.
384792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // (saving the full state takes about 40 ms under no-load conditions
385792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // on the phone)
386792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = mPlayListLen;
387792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
388bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long n = mPlayList[i];
389133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen                if (n < 0) {
390133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen                    continue;
391133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen                } else if (n == 0) {
392792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    q.append("0;");
393792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
394792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    while (n != 0) {
395bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                        int digit = (int)(n & 0xf);
396133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen                        n >>>= 4;
397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        q.append(hexdigits[digit]);
398792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    q.append(";");
400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
401792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
402792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //Log.i("@@@@ service", "created queue string in " + (System.currentTimeMillis() - start) + " ms");
403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putString("queue", q.toString());
404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putInt("cardid", mCardId);
40563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (mShuffleMode != SHUFFLE_NONE) {
40663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                // In shuffle mode we need to save the history too
40763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                len = mHistory.size();
40863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                q.setLength(0);
40963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                for (int i = 0; i < len; i++) {
41063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    int n = mHistory.get(i);
41163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    if (n == 0) {
41263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        q.append("0;");
41363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    } else {
41463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        while (n != 0) {
41563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            int digit = (n & 0xf);
416133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen                            n >>>= 4;
41763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            q.append(hexdigits[digit]);
41863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        }
41963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        q.append(";");
42063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    }
42163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                }
42263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                ed.putString("history", q.toString());
42363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            }
424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("curpos", mPlayPos);
426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putLong("seekpos", mPlayer.position());
428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("repeatmode", mRepeatMode);
430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("shufflemode", mShuffleMode);
43114c3caeb7bc2de0dd7abbb1e5f217dbb6367afbaBrad Fitzpatrick        SharedPreferencesCompat.apply(ed);
43214c3caeb7bc2de0dd7abbb1e5f217dbb6367afbaBrad Fitzpatrick
433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        //Log.i("@@@@ service", "saved state in " + (System.currentTimeMillis() - start) + " ms");
434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
436792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void reloadQueue() {
437792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String q = null;
438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        boolean newstyle = false;
440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int id = mCardId;
441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPreferences.contains("cardid")) {
442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            newstyle = true;
443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            id = mPreferences.getInt("cardid", ~mCardId);
444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (id == mCardId) {
446792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Only restore the saved playlist if the card is still
447792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // the same one as when the playlist was saved
448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            q = mPreferences.getString("queue", "");
449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
4506c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen        int qlen = q != null ? q.length() : 0;
4516c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen        if (qlen > 1) {
452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //Log.i("@@@@ service", "loaded queue: " + q);
453bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int plen = 0;
454bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int n = 0;
455bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int shift = 0;
456bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            for (int i = 0; i < qlen; i++) {
457bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                char c = q.charAt(i);
458bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                if (c == ';') {
459bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    ensurePlayListCapacity(plen + 1);
460bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    mPlayList[plen] = n;
461bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    plen++;
462bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    n = 0;
463bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    shift = 0;
464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
465bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    if (c >= '0' && c <= '9') {
466bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        n += ((c - '0') << shift);
467bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    } else if (c >= 'a' && c <= 'f') {
468bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        n += ((10 + c - 'a') << shift);
469bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    } else {
470bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        // bogus playlist data
471bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        plen = 0;
472bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        break;
473bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    }
474bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    shift += 4;
475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
477bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            mPlayListLen = plen;
478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int pos = mPreferences.getInt("curpos", 0);
480bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            if (pos < 0 || pos >= mPlayListLen) {
481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // The saved playlist is bogus, discard it
482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 0;
483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
485792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = pos;
486792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
487792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // When reloadQueue is called in response to a card-insertion,
488792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // we might not be able to query the media provider right away.
489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // To deal with this, try querying for the current file, and if
490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // that fails, wait a while and try again. If that too fails,
491792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // assume there is a problem and don't restore the state.
49263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            Cursor crsr = MusicUtils.query(this,
493792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
494792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        new String [] {"_id"}, "_id=" + mPlayList[mPlayPos] , null, null);
49563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (crsr == null || crsr.getCount() == 0) {
496792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // wait a bit and try again
497792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                SystemClock.sleep(3000);
49863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                crsr = getContentResolver().query(
499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
500792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCursorCols, "_id=" + mPlayList[mPlayPos] , null, null);
501792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
50263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (crsr != null) {
50363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                crsr.close();
504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
506792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Make sure we don't auto-skip to the next song, since that
507792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // also starts playback. What could happen in that case is:
508792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music is paused
509792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - go to UMS and delete some files, including the currently playing one
510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - come back from UMS
511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // (time passes)
512792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music app is killed for some reason (out of memory)
513792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music service is restarted, service restores state, doesn't find
514792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //   the "current" file, goes to the next and: playback starts on its
515792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //   own, potentially at some random inconvenient time.
516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mOpenFailedCounter = 20;
517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mQuietMode = true;
518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mQuietMode = false;
520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (!mPlayer.isInitialized()) {
521792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // couldn't restore the saved state
522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 0;
523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            long seekpos = mPreferences.getLong("seekpos", 0);
527792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            seek(seekpos >= 0 && seekpos < duration() ? seekpos : 0);
528e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen            Log.d(LOGTAG, "restored queue, currently at position "
529e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    + position() + "/" + duration()
530e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    + " (requested " + seekpos + ")");
531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int repmode = mPreferences.getInt("repeatmode", REPEAT_NONE);
533792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (repmode != REPEAT_ALL && repmode != REPEAT_CURRENT) {
534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                repmode = REPEAT_NONE;
535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
536792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = repmode;
537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int shufmode = mPreferences.getInt("shufflemode", SHUFFLE_NONE);
539792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (shufmode != SHUFFLE_AUTO && shufmode != SHUFFLE_NORMAL) {
540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                shufmode = SHUFFLE_NONE;
541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
54263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (shufmode != SHUFFLE_NONE) {
54363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                // in shuffle mode we need to restore the history too
54463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                q = mPreferences.getString("history", "");
54563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                qlen = q != null ? q.length() : 0;
54663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                if (qlen > 1) {
54763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    plen = 0;
54863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    n = 0;
54963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    shift = 0;
55063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    mHistory.clear();
55163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    for (int i = 0; i < qlen; i++) {
55263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        char c = q.charAt(i);
55363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        if (c == ';') {
55463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            if (n >= mPlayListLen) {
55563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                // bogus history data
55663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                mHistory.clear();
55763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                break;
55863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            }
55963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            mHistory.add(n);
56063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            n = 0;
56163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            shift = 0;
56263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        } else {
56363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            if (c >= '0' && c <= '9') {
56463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                n += ((c - '0') << shift);
56563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            } else if (c >= 'a' && c <= 'f') {
56663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                n += ((10 + c - 'a') << shift);
56763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            } else {
56863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                // bogus history data
56963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                mHistory.clear();
57063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                break;
57163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            }
57263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            shift += 4;
57363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        }
57463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    }
57563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                }
57663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            }
577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (shufmode == SHUFFLE_AUTO) {
578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (! makeAutoShuffleList()) {
579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    shufmode = SHUFFLE_NONE;
580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mShuffleMode = shufmode;
583792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
584792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
585792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
586792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
587792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public IBinder onBind(Intent intent) {
588792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
589792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = true;
590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mBinder;
591792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
592792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
593792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
594792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onRebind(Intent intent) {
595792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
596792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = true;
597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
600c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen    public int onStartCommand(Intent intent, int flags, int startId) {
601792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceStartId = startId;
602792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
603c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen
604c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen        if (intent != null) {
605c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            String action = intent.getAction();
606c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            String cmd = intent.getStringExtra("command");
6073988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog("onStartCommand " + action + " / " + cmd);
608c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen
609c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
610c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                next(true);
611c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
612b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                if (position() < 2000) {
613b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    prev();
614b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                } else {
615b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    seek(0);
616b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    play();
617b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                }
618c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
619c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                if (isPlaying()) {
620c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                    pause();
621aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                    mPausedByTransientLossOfFocus = false;
622c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                } else {
623c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                    play();
624c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                }
625c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
627aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
62847dd847ba35375d95c15bc1ee141d638f03ec82eJaikumar Ganesh            } else if (CMDPLAY.equals(cmd)) {
62947dd847ba35375d95c15bc1ee141d638f03ec82eJaikumar Ganesh                play();
630c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDSTOP.equals(cmd)) {
631c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                pause();
632aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
633c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                seek(0);
634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // make sure the service will shut down on its own if it was
638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // just started but not bound to and nothing is playing
639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
642c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen        return START_STICKY;
643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean onUnbind(Intent intent) {
647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = false;
648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Take a snapshot of the current playlist
650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        saveQueue(true);
651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
652aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi        if (isPlaying() || mPausedByTransientLossOfFocus) {
653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // something is currently playing, or will be playing once
654aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi            // an in-progress action requesting audio focus ends, so don't stop the service now.
655792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // If there is a playlist but playback is paused, then wait a while
659792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // before stopping the service, so that pause/resume isn't slow.
660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Also delay stopping the service if we're transitioning between tracks.
661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayListLen > 0  || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Message msg = mDelayedStopHandler.obtainMessage();
663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // No active playlist, OK to stop the service right now
668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stopSelf(mServiceStartId);
669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return true;
670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Handler mDelayedStopHandler = new Handler() {
673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void handleMessage(Message msg) {
675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Check again to make sure nothing is playing right now
676aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi            if (isPlaying() || mPausedByTransientLossOfFocus || mServiceInUse
677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // save the queue again, because it might have changed
681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // since the user exited the music app (because of
682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // party-shuffle or because the play-position changed)
683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(true);
684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stopSelf(mServiceStartId);
685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
687f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen
688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Called when we receive a ACTION_MEDIA_EJECT notification.
690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param storagePath path to mount point for the removed media
692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void closeExternalStorageFiles(String storagePath) {
694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // stop playback and clean up if the SD card is going to be unmounted.
695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stop(true);
696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        notifyChange(QUEUE_CHANGED);
697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        notifyChange(META_CHANGED);
698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Registers an intent to listen for ACTION_MEDIA_EJECT notifications.
702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent will call closeExternalStorageFiles() if the external media
703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * is going to be ejected, so applications can clean up any files they have open.
704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void registerExternalStorageListener() {
706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mUnmountReceiver == null) {
707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnmountReceiver = new BroadcastReceiver() {
708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                @Override
709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                public void onReceive(Context context, Intent intent) {
710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    String action = intent.getAction();
711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        saveQueue(true);
7138d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen                        mQueueIsSaveable = false;
714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        closeExternalStorageFiles(intent.getData().getPath());
715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mMediaMountedCount++;
71787bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen                        mCardId = MusicUtils.getCardId(MediaPlaybackService.this);
718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        reloadQueue();
7198d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen                        mQueueIsSaveable = true;
720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(QUEUE_CHANGED);
721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(META_CHANGED);
722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            };
725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            IntentFilter iFilter = new IntentFilter();
726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_EJECT);
727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
728792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addDataScheme("file");
729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            registerReceiver(mUnmountReceiver, iFilter);
730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Notify the change-receivers that something has changed.
735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent that is sent contains the following data
736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * for the currently playing track:
737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "id" - Integer: the database row ID
738792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "artist" - String: the name of the artist
739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "album" - String: the name of the album
740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "track" - String: the name of the track
741792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent has an action that is one of
742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.metachanged"
743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.queuechanged",
744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.playbackcomplete"
745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.playstatechanged"
746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * respectively indicating that a new track has
747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * started playing, that the playback queue has
748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * changed, that playback has stopped because
749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the last file in the list has been played,
750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * or that the play-state changed (paused/resumed).
751792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void notifyChange(String what) {
753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
754792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Intent i = new Intent(what);
755bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        i.putExtra("id", Long.valueOf(getAudioId()));
756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("artist", getArtistName());
757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("album",getAlbumName());
758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("track", getTrackName());
7596b507de7beda7f4a8b969b437dfbf81f5ecd5e5eMarco Nelissen        i.putExtra("playing", isPlaying());
7606b507de7beda7f4a8b969b437dfbf81f5ecd5e5eMarco Nelissen        sendStickyBroadcast(i);
761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (what.equals(QUEUE_CHANGED)) {
763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(true);
764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
768490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project        // Share this notification directly with our widgets
769490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project        mAppWidgetProvider.notifyChange(this, what);
770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void ensurePlayListCapacity(int size) {
773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayList == null || size > mPlayList.length) {
774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // reallocate at 2x requested size so we don't
775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // need to grow and copy the array for every
776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // insert
777bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] newlist = new long[size * 2];
778bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int len = mPlayList != null ? mPlayList.length : mPlayListLen;
779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                newlist[i] = mPlayList[i];
781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList = newlist;
783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // FIXME: shrink the array when the needed size is much smaller
785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // than the allocated size
786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
788792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // insert the list of songs at the specified position in the playlist
789bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private void addToPlayList(long [] list, int position) {
790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int addlen = list.length;
791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (position < 0) { // overwrite
792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen = 0;
793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            position = 0;
794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ensurePlayListCapacity(mPlayListLen + addlen);
796792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (position > mPlayListLen) {
797792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            position = mPlayListLen;
798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
799792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
800792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // move part of list after insertion point
801792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int tailsize = mPlayListLen - position;
802792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = tailsize ; i > 0 ; i--) {
803792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[position + i] = mPlayList[position + i - addlen];
804792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
805792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // copy list into playlist
807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < addlen; i++) {
808792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[position + i] = list[i];
809792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
810792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayListLen += addlen;
8113aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen        if (mPlayListLen == 0) {
8123aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen            mCursor.close();
8133aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen            mCursor = null;
8143aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen            notifyChange(META_CHANGED);
8153aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen        }
816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
817792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Appends a list of tracks to the current playlist.
820792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * If nothing is playing currently, playback will be started at
821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the first track.
822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * If the action is NOW, playback will switch to the first of
823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the new tracks immediately.
824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param list The list of tracks to append.
825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param action NOW, NEXT or LAST
826792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
827bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public void enqueue(long [] list, int action) {
828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
829792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (action == NEXT && mPlayPos + 1 < mPlayListLen) {
830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, mPlayPos + 1);
831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
832792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // action == LAST || action == NOW || mPlayPos + 1 == mPlayListLen
834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, Integer.MAX_VALUE);
835792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (action == NOW) {
837792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = mPlayListLen - list.length;
838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
840792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    notifyChange(META_CHANGED);
841792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
842792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
844792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos < 0) {
845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = 0;
846792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                openCurrent();
847792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
848792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(META_CHANGED);
849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
850792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
851792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
853792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Replaces the current playlist with a new list,
855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * and prepares for starting playback at the specified
856792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * position in the list, or a random position if the
857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * specified position is 0.
858792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param list The new list of tracks.
859792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
860bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public void open(long [] list, int position) {
861792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
862792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_AUTO) {
863792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mShuffleMode = SHUFFLE_NORMAL;
864792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
865bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long oldId = getAudioId();
866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int listlength = list.length;
867792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            boolean newlist = true;
868792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayListLen == listlength) {
869792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // possible fast path: list might be the same
870792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                newlist = false;
871792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = 0; i < listlength; i++) {
872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (list[i] != mPlayList[i]) {
873792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        newlist = true;
874792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        break;
875792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
876792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
877792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
878792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (newlist) {
879792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, -1);
880792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
881792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
882792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int oldpos = mPlayPos;
883792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (position >= 0) {
884792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = position;
885792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
886792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = mRand.nextInt(mPlayListLen);
887792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mHistory.clear();
889792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
891792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
892d8c696753687ddb0177f869fad5f709eadfe27afJeffrey Sharkey            if (oldId != getAudioId()) {
893792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(META_CHANGED);
894792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
895792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
896792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
897792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
899792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Moves the item at index1 to index2.
900792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param index1
901792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param index2
902792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
903792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void moveQueueItem(int index1, int index2) {
904792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
905792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index1 >= mPlayListLen) {
906792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                index1 = mPlayListLen - 1;
907792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
908792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index2 >= mPlayListLen) {
909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                index2 = mPlayListLen - 1;
910792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
911792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index1 < index2) {
912bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long tmp = mPlayList[index1];
913792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = index1; i < index2; i++) {
914792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = mPlayList[i+1];
915792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
916792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[index2] = tmp;
917792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos == index1) {
918792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = index2;
919792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else if (mPlayPos >= index1 && mPlayPos <= index2) {
920792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos--;
921792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
922792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (index2 < index1) {
923bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long tmp = mPlayList[index1];
924792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = index1; i > index2; i--) {
925792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = mPlayList[i-1];
926792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
927792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[index2] = tmp;
928792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos == index1) {
929792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = index2;
930792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else if (mPlayPos >= index2 && mPlayPos <= index1) {
931792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos++;
932792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
935792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
936792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
938792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
939792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the current play list
940792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return An array of integers containing the IDs of the tracks in the play list
941792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
942bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long [] getQueue() {
943792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
944792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = mPlayListLen;
945bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = new long[len];
946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
947792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                list[i] = mPlayList[i];
948792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
949792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return list;
950792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
951792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
952792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
953792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void openCurrent() {
954792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
955792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor != null) {
956792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor.close();
957792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor = null;
958792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
9598d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen
960792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayListLen == 0) {
961792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
962792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
963792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
964792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
965792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String id = String.valueOf(mPlayList[mPlayPos]);
966792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
967792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = getContentResolver().query(
968792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
969792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mCursorCols, "_id=" + id , null, null);
970792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor != null) {
971792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor.moveToFirst();
9728d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen                open(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + id);
973792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // go to bookmark if needed
974792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (isPodcast()) {
975792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    long bookmark = getBookmark();
976792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // Start playing a little bit before the bookmark,
977792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // so it's easier to get back in to the narrative.
978792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    seek(bookmark - 5000);
979792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
980792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
981792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
982792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
983792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
984792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
985792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Opens the specified file and readies it for playback.
986792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
987792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param path The full path of the file to be opened.
988792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
9898d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen    public void open(String path) {
990792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
991792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (path == null) {
992792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
993792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
994792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
995792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // if mCursor is null, try to associate path with a database cursor
996792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
997792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
998792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ContentResolver resolver = getContentResolver();
999792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Uri uri;
1000792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String where;
1001792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String selectionArgs[];
1002792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (path.startsWith("content://media/")) {
1003792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    uri = Uri.parse(path);
1004792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    where = null;
1005792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    selectionArgs = null;
1006792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1007792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   uri = MediaStore.Audio.Media.getContentUriForPath(path);
1008792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   where = MediaStore.Audio.Media.DATA + "=?";
1009792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   selectionArgs = new String[] { path };
1010792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1011792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1012792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                try {
1013792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mCursor = resolver.query(uri, mCursorCols, where, selectionArgs, null);
1014792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if  (mCursor != null) {
1015792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (mCursor.getCount() == 0) {
1016792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor.close();
1017792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor = null;
1018792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        } else {
1019792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor.moveToNext();
1020792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            ensurePlayListCapacity(1);
1021792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mPlayListLen = 1;
1022bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                            mPlayList[0] = mCursor.getLong(IDCOLIDX);
1023792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mPlayPos = 0;
1024792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
1025792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1026792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } catch (UnsupportedOperationException ex) {
1027792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1028792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1029792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mFileToPlay = path;
1030792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.setDataSource(mFileToPlay);
1031792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (! mPlayer.isInitialized()) {
1032792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                stop(true);
1033792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mOpenFailedCounter++ < 10 &&  mPlayListLen > 1) {
1034792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // beware: this ends up being recursive because next() calls open() again.
1035792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    next(false);
1036792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1037792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (! mPlayer.isInitialized() && mOpenFailedCounter != 0) {
1038792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // need to make sure we only shows this once
1039792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mOpenFailedCounter = 0;
1040792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (!mQuietMode) {
1041792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        Toast.makeText(this, R.string.playback_failed, Toast.LENGTH_SHORT).show();
1042792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1043e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    Log.d(LOGTAG, "Failed to open file for playback");
1044792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1045792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1046792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mOpenFailedCounter = 0;
1047792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1048792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1049792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1050792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1051792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1052792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Starts playback of a previously opened file.
1053792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1054792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void play() {
1055085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
1056085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                AudioManager.AUDIOFOCUS_GAIN);
10573d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi        mAudioManager.registerMediaButtonEventReceiver(new ComponentName(this.getPackageName(),
10583d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi                MediaButtonIntentReceiver.class.getName()));
1059085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
1060792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1061272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle            // if we are at the end of the song, go to the next song first
10622f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen            long duration = mPlayer.duration();
10632f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen            if (mRepeatMode != REPEAT_CURRENT && duration > 2000 &&
10642f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen                mPlayer.position() >= duration - 2000) {
1065272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle                next(true);
1066272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle            }
1067272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle
1068792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.start();
10697181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen            // make sure we fade in, in case a previous fadein was stopped because
10707181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen            // of another focus loss
10717bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen            mMediaplayerHandler.removeMessages(FADEDOWN);
10727181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen            mMediaplayerHandler.sendEmptyMessage(FADEUP);
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) {
11487181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen            mMediaplayerHandler.removeMessages(FADEUP);
1149407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen            if (isPlaying()) {
1150407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                mPlayer.pause();
1151407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                gotoIdleState();
1152407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                mIsSupposedToBePlaying = false;
1153407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                notifyChange(PLAYSTATE_CHANGED);
1154407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                saveBookmarkIfNeeded();
1155407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen            }
1156792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1157792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1158792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1159b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen    /** Returns whether something is currently playing
1160792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
1161b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen     * @return true if something is playing (or will be playing shortly, in case
1162b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen     * we're currently transitioning between tracks), false if not.
1163792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1164792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean isPlaying() {
1165c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen        return mIsSupposedToBePlaying;
1166792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1167792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1168792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /*
1169792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      Desired behavior for prev/next/shuffle:
1170792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1171792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      - NEXT will move to the next track in the list when not shuffling, and to
1172792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        a track randomly picked from the not-yet-played tracks when shuffling.
1173792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        If all tracks have already been played, pick from the full set, but
1174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        avoid picking the previously played track if possible.
1175792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      - when shuffling, PREV will go to the previously played track. Hitting PREV
1176792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        again will go to the track played before that, etc. When the start of the
1177792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        history has been reached, PREV is a no-op.
1178792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When not shuffling, PREV will go to the sequentially previous track (the
1179792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        difference with the shuffle-case is mainly that when not shuffling, the
1180792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        user can back up to tracks that are not in the history).
1181792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1182792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Example:
1183792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When playing an album with 10 tracks from the start, and enabling shuffle
1184792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        while playing track 5, the remaining tracks (6-10) will be shuffled, e.g.
1185792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        the final play order might be 1-2-3-4-5-8-10-6-9-7.
1186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When hitting 'prev' 8 times while playing track 7 in this example, the
1187792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        user will go to tracks 9-6-10-8-5-4-3-2. If the user then hits 'next',
1188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        a random track will be picked again. If at any time user disables shuffling
1189792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        the next/previous track will be picked in sequential order again.
1190792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1191792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void prev() {
1193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1194792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_NORMAL) {
1195792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // go to previously-played track and remove it from the history
1196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int histsize = mHistory.size();
1197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (histsize == 0) {
1198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // prev is a no-op
1199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1201792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Integer pos = mHistory.remove(histsize - 1);
1202792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = pos.intValue();
1203792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1204792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos > 0) {
1205792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos--;
1206792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1207792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = mPlayListLen - 1;
1208792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1209792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1210792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
1211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void next(boolean force) {
1219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1220663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen            if (mPlayListLen <= 0) {
1221e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                Log.d(LOGTAG, "No play queue");
1222663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen                return;
1223663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen            }
1224663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen
1225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_NORMAL) {
1226792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Pick random next track from the not-yet-played ones
1227792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: make it work right after adding/removing items in the queue.
1228792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
12293f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                // Store the current file in the history, but keep the history at a
12303f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                // reasonable size
12313f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                if (mPlayPos >= 0) {
12323f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                    mHistory.add(mPlayPos);
12333f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                }
12343f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                if (mHistory.size() > MAX_HISTORY_SIZE) {
12353f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                    mHistory.removeElementAt(0);
12363f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                }
12373f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
1238792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numTracks = mPlayListLen;
1239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int[] tracks = new int[numTracks];
1240792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i=0;i < numTracks; i++) {
1241792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    tracks[i] = i;
1242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1244792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numHistory = mHistory.size();
1245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int numUnplayed = numTracks;
1246792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i=0;i < numHistory; i++) {
1247792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    int idx = mHistory.get(i).intValue();
1248792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (idx < numTracks && tracks[idx] >= 0) {
1249792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        numUnplayed--;
1250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        tracks[idx] = -1;
1251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1252792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1253792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1254792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // 'numUnplayed' now indicates how many tracks have not yet
1255792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // been played, and 'tracks' contains the indices of those
1256792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // tracks.
1257792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (numUnplayed <=0) {
1258792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // everything's already been played
1259792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_ALL || force) {
1260792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        //pick from full set
1261792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        numUnplayed = numTracks;
1262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        for (int i=0;i < numTracks; i++) {
1263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            tracks[i] = i;
1264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
1265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
1266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // all done
1267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        gotoIdleState();
1268ab893d7a8067b9c45eda455b38f3b064e82dcb91Marco Nelissen                        if (mIsSupposedToBePlaying) {
1269ab893d7a8067b9c45eda455b38f3b064e82dcb91Marco Nelissen                            mIsSupposedToBePlaying = false;
1270ab893d7a8067b9c45eda455b38f3b064e82dcb91Marco Nelissen                            notifyChange(PLAYSTATE_CHANGED);
1271ab893d7a8067b9c45eda455b38f3b064e82dcb91Marco Nelissen                        }
1272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        return;
1273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1275792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int skip = mRand.nextInt(numUnplayed);
1276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int cnt = -1;
1277792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                while (true) {
1278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    while (tracks[++cnt] < 0)
1279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        ;
1280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    skip--;
1281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (skip < 0) {
1282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        break;
1283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = cnt;
1286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (mShuffleMode == SHUFFLE_AUTO) {
1287792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                doAutoShuffleUpdate();
1288792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos++;
1289792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos >= mPlayListLen - 1) {
1291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // we're at the end of the list
1292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_NONE && !force) {
1293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // all done
1294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        gotoIdleState();
1295c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                        mIsSupposedToBePlaying = false;
12966b507de7beda7f4a8b969b437dfbf81f5ecd5e5eMarco Nelissen                        notifyChange(PLAYSTATE_CHANGED);
1297792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        return;
1298792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (mRepeatMode == REPEAT_ALL || force) {
1299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos = 0;
1300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos++;
1303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1305792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
1306792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1307792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1308792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1309792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void gotoIdleState() {
1314792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
1315792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
1316792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
1317d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn        stopForeground(true);
1318792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1319792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1320792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void saveBookmarkIfNeeded() {
1321792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1322792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (isPodcast()) {
1323792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long pos = position();
1324792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long bookmark = getBookmark();
1325792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long duration = duration();
1326792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if ((pos < bookmark && (pos + 10000) > bookmark) ||
1327792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        (pos > bookmark && (pos - 10000) < bookmark)) {
1328792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // The existing bookmark is close to the current
1329792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // position, so don't update it.
1330792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1331792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1332792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (pos < 15000 || (pos + 10000) > duration) {
1333792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // if we're near the start or end, clear the bookmark
1334792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    pos = 0;
1335792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1336792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // write 'pos' to the bookmark field
1338792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ContentValues values = new ContentValues();
1339792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                values.put(MediaStore.Audio.Media.BOOKMARK, pos);
1340792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Uri uri = ContentUris.withAppendedId(
1341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursor.getLong(IDCOLIDX));
1342792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                getContentResolver().update(uri, values, null, null);
1343792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (SQLiteException ex) {
1345792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1347792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // Make sure there are at least 5 items after the currently playing item
1349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // and no more than 10 items before.
1350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void doAutoShuffleUpdate() {
1351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        boolean notify = false;
13523f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
1353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // remove old entries
1354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayPos > 10) {
1355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            removeTracks(0, mPlayPos - 9);
1356792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notify = true;
1357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // add new entries if needed
1359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int to_add = 7 - (mPlayListLen - (mPlayPos < 0 ? -1 : mPlayPos));
1360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < to_add; i++) {
1361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // pick something at random from the list
13623f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
13633f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            int lookback = mHistory.size();
13643f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            int idx = -1;
13653f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            while(true) {
13663f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                idx = mRand.nextInt(mAutoShuffleList.length);
13673f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                if (!wasRecentlyUsed(idx, lookback)) {
13683f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                    break;
13693f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                }
13703f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                lookback /= 2;
13713f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            }
13723f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            mHistory.add(idx);
13733f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            if (mHistory.size() > MAX_HISTORY_SIZE) {
13743f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                mHistory.remove(0);
13753f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            }
1376792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ensurePlayListCapacity(mPlayListLen + 1);
13773f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            mPlayList[mPlayListLen++] = mAutoShuffleList[idx];
1378792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notify = true;
1379792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1380792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (notify) {
1381792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1382792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1383792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1384792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
13853f502de8e8963224054a97730d132f82ac87d522Marco Nelissen    // check that the specified idx is not in the history (but only look at at
13863f502de8e8963224054a97730d132f82ac87d522Marco Nelissen    // most lookbacksize entries in the history)
13873f502de8e8963224054a97730d132f82ac87d522Marco Nelissen    private boolean wasRecentlyUsed(int idx, int lookbacksize) {
13883f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
13893f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        // early exit to prevent infinite loops in case idx == mPlayPos
13903f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        if (lookbacksize == 0) {
13913f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            return false;
13923f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        }
13933f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
13943f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        int histsize = mHistory.size();
13953f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        if (histsize < lookbacksize) {
13963f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            Log.d(LOGTAG, "lookback too big");
13973f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            lookbacksize = histsize;
13983f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        }
13993f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        int maxidx = histsize - 1;
14003f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        for (int i = 0; i < lookbacksize; i++) {
14013f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            long entry = mHistory.get(maxidx - i);
14023f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            if (entry == idx) {
14033f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                return true;
14043f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            }
14053f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        }
14063f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        return false;
14073f502de8e8963224054a97730d132f82ac87d522Marco Nelissen    }
14083f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
1409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // A simple variation of Random that makes sure that the
1410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // value it returns is not equal to the value it returned
1411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // previously, unless the interval is 1.
1412756c3f57f11a7bb3bf1cf1333ee8ffbc51039748Marco Nelissen    private static class Shuffler {
1413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private int mPrevious;
1414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private Random mRandom = new Random();
1415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int nextInt(int interval) {
1416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int ret;
1417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            do {
1418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ret = mRandom.nextInt(interval);
1419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } while (ret == mPrevious && interval > 1);
1420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPrevious = ret;
1421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return ret;
1422792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
1424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean makeAutoShuffleList() {
1426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ContentResolver res = getContentResolver();
1427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor c = null;
1428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            c = res.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    new String[] {MediaStore.Audio.Media._ID}, MediaStore.Audio.Media.IS_MUSIC + "=1",
1431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    null, null);
1432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c == null || c.getCount() == 0) {
1433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = c.getCount();
1436bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = new long[len];
1437792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
1438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.moveToNext();
1439bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                list[i] = c.getLong(0);
1440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mAutoShuffleList = list;
1442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
1443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (RuntimeException ex) {
1444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } finally {
1445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c != null) {
1446792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.close();
1447792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return false;
1450792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1451792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1453792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Removes the range of tracks specified from the play list. If a file within the range is
1454792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the file currently being played, playback will move to the next file after the
1455792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * range.
1456792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param first The first file to be removed
1457792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param last The last file to be removed
1458792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return the number of tracks deleted
1459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int removeTracks(int first, int last) {
1461792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int numremoved = removeTracksInternal(first, last);
1462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (numremoved > 0) {
1463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return numremoved;
1466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int removeTracksInternal(int first, int last) {
1469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (last < first) return 0;
1471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (first < 0) first = 0;
1472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (last >= mPlayListLen) last = mPlayListLen - 1;
1473792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            boolean gotonext = false;
1475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (first <= mPlayPos && mPlayPos <= last) {
1476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = first;
1477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                gotonext = true;
1478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (mPlayPos > last) {
1479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos -= (last - first + 1);
1480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int num = mPlayListLen - last - 1;
1482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < num; i++) {
1483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[first + i] = mPlayList[last + 1 + i];
1484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1485792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen -= last - first + 1;
1486792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1487792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (gotonext) {
1488792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayListLen == 0) {
1489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    stop(true);
1490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = -1;
14913aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen                    if (mCursor != null) {
14923aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen                        mCursor.close();
14933aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen                        mCursor = null;
14943aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen                    }
1495792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1496792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mPlayPos >= mPlayListLen) {
1497792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos = 0;
1498792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    boolean wasPlaying = isPlaying();
1500792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    stop(false);
1501792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
1502792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (wasPlaying) {
1503792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
1504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
15063aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen                notifyChange(META_CHANGED);
1507792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1508792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return last - first + 1;
1509792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1512792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1513792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Removes all instances of the track with the given id
1514792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * from the playlist.
1515792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param id The id to be removed
1516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return how many instances of the track were removed
1517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1518bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public int removeTrack(long id) {
1519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int numremoved = 0;
1520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1521792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < mPlayListLen; i++) {
1522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayList[i] == id) {
1523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    numremoved += removeTracksInternal(i, i);
1524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    i--;
1525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1527792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1528792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (numremoved > 0) {
1529792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return numremoved;
1532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1533792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setShuffleMode(int shufflemode) {
1535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1536792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == shufflemode && mPlayListLen > 0) {
1537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1539792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mShuffleMode = shufflemode;
1540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_AUTO) {
1541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (makeAutoShuffleList()) {
1542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayListLen = 0;
1543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    doAutoShuffleUpdate();
1544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = 0;
1545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    openCurrent();
1546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
1547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    notifyChange(META_CHANGED);
1548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // failed to build a list of files to shuffle
1551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mShuffleMode = SHUFFLE_NONE;
1552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
1555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1557792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getShuffleMode() {
1558792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mShuffleMode;
1559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1560792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setRepeatMode(int repeatmode) {
1562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = repeatmode;
1564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
1565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getRepeatMode() {
1568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mRepeatMode;
1569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getMediaMountedCount() {
1572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mMediaMountedCount;
1573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1576792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the path of the currently playing file, or null if
1577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * no file is currently playing.
1578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getPath() {
1580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mFileToPlay;
1581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1583792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1584792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the rowid of the currently playing file, or -1 if
1585792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * no file is currently playing.
1586792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1587bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getAudioId() {
1588792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1589792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos >= 0 && mPlayer.isInitialized()) {
1590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return mPlayList[mPlayPos];
1591792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1592792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1593792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1594792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1595792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1596792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the position in the queue
1598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return the position in the queue
1599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1600792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getQueuePosition() {
1601792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1602792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayPos;
1603792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1604792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1605792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1606792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1607792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Starts playing the track at the given position in the queue.
1608792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param pos The position in the queue of the track that will be played.
1609792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1610792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setQueuePosition(int pos) {
1611792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1612792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1613792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = pos;
1614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            openCurrent();
1615792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1617ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            if (mShuffleMode == SHUFFLE_AUTO) {
1618ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                doAutoShuffleUpdate();
1619ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            }
1620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getArtistName() {
1624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
1629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1632bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getArtistId() {
1633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return -1;
1636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1637bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID));
1638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getAlbumName() {
1642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
1647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1650bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getAlbumId() {
1651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1652792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return -1;
1654792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1655bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
1656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1659792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getTrackName() {
1660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
1665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean isPodcast() {
1669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return (mCursor.getInt(PODCASTCOLIDX) > 0);
1674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private long getBookmark() {
1678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return 0;
1681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getLong(BOOKMARKCOLIDX);
1683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the duration of the file in milliseconds.
1688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Currently this method returns -1 for the duration of MIDI files.
1689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long duration() {
1691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.duration();
1693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the current playback position in milliseconds
1699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long position() {
1701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.position();
1703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Seeks to the position specified.
1709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
1710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param pos The position to seek to, in milliseconds
1711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long seek(long pos) {
1713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (pos < 0) pos = 0;
1715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (pos > mPlayer.duration()) pos = mPlayer.duration();
1716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.seek(pos);
1717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
17221cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     * Sets the audio session ID.
17231cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     *
17241cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     * @param sessionId: the audio session ID.
17251cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     */
17261cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    public void setAudioSessionId(int sessionId) {
17271cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        synchronized (this) {
17281cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent            mPlayer.setAudioSessionId(sessionId);
17291cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        }
17301cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    }
17311cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent
17321cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    /**
17331cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     * Returns the audio session ID.
17341cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     */
17351cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    public int getAudioSessionId() {
17361cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        synchronized (this) {
17371cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent            return mPlayer.getAudioSessionId();
17381cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        }
17391cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    }
17401cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent
17411cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    /**
1742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Provides a unified interface for dealing with midi files and
1743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * other media files.
1744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private class MultiPlayer {
1746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private MediaPlayer mMediaPlayer = new MediaPlayer();
1747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private Handler mHandler;
1748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private boolean mIsInitialized = false;
1749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public MultiPlayer() {
1751792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK);
1752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1754792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setDataSource(String path) {
1755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
1756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.reset();
1757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setOnPreparedListener(null);
1758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (path.startsWith("content://")) {
1759792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setDataSource(MediaPlaybackService.this, Uri.parse(path));
1760792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setDataSource(path);
1762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
1764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mMediaPlayer.prepare();
1765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IOException ex) {
1766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IllegalArgumentException ex) {
1770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
1771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mIsInitialized = false;
1772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnCompletionListener(listener);
1775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setOnErrorListener(errorListener);
1776f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen            Intent i = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
1777f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen            i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId());
1778f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen            i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
1779f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen            sendBroadcast(i);
1780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = true;
1781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public boolean isInitialized() {
1784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mIsInitialized;
1785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void start() {
17883988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog(new Exception("MultiPlayer.start called"));
1789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.start();
1790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void stop() {
1793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.reset();
1794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = false;
1795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1796792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
17972b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        /**
17982b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen         * You CANNOT use this player anymore after calling release()
17992b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen         */
18002b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        public void release() {
18012b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            stop();
18022b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mMediaPlayer.release();
18032b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        }
18042b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
1805792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void pause() {
1806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.pause();
1807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1808792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1809792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setHandler(Handler handler) {
1810792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mHandler = handler;
1811792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1812792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnCompletionListener listener = new MediaPlayer.OnCompletionListener() {
1814792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public void onCompletion(MediaPlayer mp) {
1815792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // Acquire a temporary wakelock, since when we return from
1816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // this callback the MediaPlayer will release its wakelock
1817792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // and allow the device to go to sleep.
1818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // This temporary wakelock is released when the RELEASE_WAKELOCK
1819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // message is processed, but just in case, put a timeout on it.
1820792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mWakeLock.acquire(30000);
1821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHandler.sendEmptyMessage(TRACK_ENDED);
1822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mHandler.sendEmptyMessage(RELEASE_WAKELOCK);
1823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1826792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnErrorListener errorListener = new MediaPlayer.OnErrorListener() {
1827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public boolean onError(MediaPlayer mp, int what, int extra) {
1828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                switch (what) {
1829792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
1830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mIsInitialized = false;
1831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.release();
1832792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // Creating a new MediaPlayer and settings its wakemode does not
1833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // require the media service, so it's OK to do this now, while the
1834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // service is still being restarted
1835792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer = new MediaPlayer();
1836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK);
1837792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mHandler.sendMessageDelayed(mHandler.obtainMessage(SERVER_DIED), 2000);
1838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return true;
1839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                default:
1840e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    Log.d("MultiPlayer", "Error: " + what + "," + extra);
1841792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
1842792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1844792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project           }
1845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1846792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1847792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long duration() {
1848792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mMediaPlayer.getDuration();
1849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1850792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1851792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long position() {
1852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mMediaPlayer.getCurrentPosition();
1853792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long seek(long whereto) {
1856792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.seekTo((int) whereto);
1857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return whereto;
1858792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1859792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1860792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setVolume(float vol) {
1861792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mMediaPlayer.setVolume(vol, vol);
1862792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
18631cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent
18641cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        public void setAudioSessionId(int sessionId) {
18651cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent            mMediaPlayer.setAudioSessionId(sessionId);
18661cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        }
18671cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent
18681cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        public int getAudioSessionId() {
18691cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent            return mMediaPlayer.getAudioSessionId();
18701cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        }
1871792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
18732b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    /*
18742b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * By making this a static class with a WeakReference to the Service, we
18752b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * ensure that the Service can be GCd even when the system process still
18762b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * has a remote reference to the stub.
18772b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     */
18782b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    static class ServiceStub extends IMediaPlaybackService.Stub {
18792b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        WeakReference<MediaPlaybackService> mService;
18802b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
18812b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        ServiceStub(MediaPlaybackService service) {
18822b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService = new WeakReference<MediaPlaybackService>(service);
18832b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        }
18842b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
18858d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen        public void openFile(String path)
1886792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        {
18878d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen            mService.get().open(path);
1888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1889bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public void open(long [] list, int position) {
18902b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().open(list, position);
1891792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1892792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getQueuePosition() {
18932b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getQueuePosition();
1894792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1895792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setQueuePosition(int index) {
18962b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setQueuePosition(index);
1897792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public boolean isPlaying() {
18992b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().isPlaying();
1900792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1901792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void stop() {
19022b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().stop();
1903792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1904792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void pause() {
19052b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().pause();
1906792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1907792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void play() {
19082b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().play();
1909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1910792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void prev() {
19112b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().prev();
1912792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1913792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void next() {
19142b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().next(true);
1915792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1916792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getTrackName() {
19172b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getTrackName();
1918792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1919792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getAlbumName() {
19202b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAlbumName();
1921792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1922bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getAlbumId() {
19232b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAlbumId();
1924792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1925792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getArtistName() {
19262b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getArtistName();
1927792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1928bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getArtistId() {
19292b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getArtistId();
1930792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1931bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public void enqueue(long [] list , int action) {
19322b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().enqueue(list, action);
1933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1934bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long [] getQueue() {
19352b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getQueue();
1936792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void moveQueueItem(int from, int to) {
19382b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().moveQueueItem(from, to);
1939792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1940792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getPath() {
19412b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getPath();
1942792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1943bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getAudioId() {
19442b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAudioId();
1945792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long position() {
19472b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().position();
1948792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1949792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long duration() {
19502b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().duration();
1951792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1952792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long seek(long pos) {
19532b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().seek(pos);
1954792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1955792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setShuffleMode(int shufflemode) {
19562b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setShuffleMode(shufflemode);
1957792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1958792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getShuffleMode() {
19592b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getShuffleMode();
1960792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1961792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int removeTracks(int first, int last) {
19622b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().removeTracks(first, last);
1963792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1964bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public int removeTrack(long id) {
19652b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().removeTrack(id);
1966792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1967792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setRepeatMode(int repeatmode) {
19682b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setRepeatMode(repeatmode);
1969792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1970792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getRepeatMode() {
19712b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getRepeatMode();
1972792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1973792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getMediaMountedCount() {
19742b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getMediaMountedCount();
1975792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
19761cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        public int getAudioSessionId() {
19771cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent            return mService.get().getAudioSessionId();
19781cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        }
19792b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    }
19803988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
19813988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    @Override
19823988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1983bf555cee7a01aed223b05144d1cec0cffdd9a6aeMarco Nelissen        writer.println("" + mPlayListLen + " items in queue, currently at index " + mPlayPos);
19843988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println("Currently loaded:");
19853988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getArtistName());
19863988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getAlbumName());
19873988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getTrackName());
19883988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getPath());
19893988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println("playing: " + mIsSupposedToBePlaying);
19903988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println("actual: " + mPlayer.mMediaPlayer.isPlaying());
1991bf555cee7a01aed223b05144d1cec0cffdd9a6aeMarco Nelissen        writer.println("shuffle mode: " + mShuffleMode);
19923988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        MusicUtils.debugDump(writer);
19933988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    }
19943988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
19952b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    private final IBinder mBinder = new ServiceStub(this);
1996792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project}
1997