MediaPlaybackService.java revision 90d1f62b8edbc03a0d0b2b42217e9004e7d658d8
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;
358717d3490e179e9591eac98a91a14995d98291adMarco Nelissenimport android.graphics.Bitmap;
36f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissenimport android.media.audiofx.AudioEffect;
37792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.AudioManager;
38085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Triviimport android.media.AudioManager.OnAudioFocusChangeListener;
398717d3490e179e9591eac98a91a14995d98291adMarco Nelissenimport android.media.MediaMetadataRetriever;
40792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.media.MediaPlayer;
41308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissenimport android.media.MediaPlayer.OnCompletionListener;
428717d3490e179e9591eac98a91a14995d98291adMarco Nelissenimport android.media.RemoteControlClient;
438717d3490e179e9591eac98a91a14995d98291adMarco Nelissenimport android.media.RemoteControlClient.MetadataEditor;
44792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.net.Uri;
45792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Handler;
46792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.IBinder;
47792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.Message;
48792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.PowerManager;
49792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.SystemClock;
50792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.os.PowerManager.WakeLock;
51792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.provider.MediaStore;
52792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.util.Log;
53792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.RemoteViews;
54792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport android.widget.Toast;
55792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
563988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissenimport java.io.FileDescriptor;
57792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.io.IOException;
583988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissenimport java.io.PrintWriter;
592b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissenimport java.lang.ref.WeakReference;
60792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.util.Random;
61792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectimport java.util.Vector;
62792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
63792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project/**
64792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Provides "background" audio playback capabilities, allowing the
65792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * user to switch between activities without stopping playback.
66792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */
67792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Projectpublic class MediaPlaybackService extends Service {
68792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /** used to specify whether enqueue() should start playing
69792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the new list of files right away, next or once all the currently
70792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * queued files have been played
71792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
72792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int NOW = 1;
73792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int NEXT = 2;
74792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int LAST = 3;
75792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int PLAYBACKSERVICE_STATUS = 1;
76792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
77792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_NONE = 0;
78792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_NORMAL = 1;
79792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int SHUFFLE_AUTO = 2;
80792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
81792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_NONE = 0;
82792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_CURRENT = 1;
83792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final int REPEAT_ALL = 2;
84792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
85792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PLAYSTATE_CHANGED = "com.android.music.playstatechanged";
86792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String META_CHANGED = "com.android.music.metachanged";
87792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String QUEUE_CHANGED = "com.android.music.queuechanged";
88792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
89792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String SERVICECMD = "com.android.music.musicservicecommand";
90792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDNAME = "command";
91792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDTOGGLEPAUSE = "togglepause";
92792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDSTOP = "stop";
93792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDPAUSE = "pause";
94fc1c0dc301b5cae2e8c5661e7a217dc57dacac1eMarco Nelissen    public static final String CMDPLAY = "play";
95792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDPREVIOUS = "previous";
96792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String CMDNEXT = "next";
97792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
98792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String TOGGLEPAUSE_ACTION = "com.android.music.musicservicecommand.togglepause";
99792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PAUSE_ACTION = "com.android.music.musicservicecommand.pause";
100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String PREVIOUS_ACTION = "com.android.music.musicservicecommand.previous";
101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public static final String NEXT_ACTION = "com.android.music.musicservicecommand.next";
102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int TRACK_ENDED = 1;
104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int RELEASE_WAKELOCK = 2;
105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final int SERVER_DIED = 3;
1067181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen    private static final int FOCUSCHANGE = 4;
1072da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen    private static final int FADEDOWN = 5;
1082da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen    private static final int FADEUP = 6;
109e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen    private static final int TRACK_WENT_TO_NEXT = 7;
1103ec2ad9c8758d300864be808e491ae933dc9cd6bMarco Nelissen    private static final int MAX_HISTORY_SIZE = 100;
111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private MultiPlayer mPlayer;
113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private String mFileToPlay;
114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mShuffleMode = SHUFFLE_NONE;
115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mRepeatMode = REPEAT_NONE;
116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mMediaMountedCount = 0;
117bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private long [] mAutoShuffleList = null;
118bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private long [] mPlayList = null;
119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mPlayListLen = 0;
120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Vector<Integer> mHistory = new Vector<Integer>(MAX_HISTORY_SIZE);
121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Cursor mCursor;
122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mPlayPos = -1;
123e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen    private int mNextPlayPos = -1;
124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private static final String LOGTAG = "MediaPlaybackService";
125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final Shuffler mRand = new Shuffler();
126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mOpenFailedCounter = 0;
127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    String[] mCursorCols = new String[] {
128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            "audio._id AS _id",             // index must match IDCOLIDX below
129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST,
130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ALBUM,
131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.TITLE,
132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.DATA,
133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.MIME_TYPE,
134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ALBUM_ID,
135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.ARTIST_ID,
136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.IS_PODCAST, // index must match PODCASTCOLIDX below
137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            MediaStore.Audio.Media.BOOKMARK    // index must match BOOKMARKCOLIDX below
138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int IDCOLIDX = 0;
140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int PODCASTCOLIDX = 8;
141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final static int BOOKMARKCOLIDX = 9;
142792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private BroadcastReceiver mUnmountReceiver = null;
143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private WakeLock mWakeLock;
144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mServiceStartId = -1;
145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mServiceInUse = false;
146c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen    private boolean mIsSupposedToBePlaying = false;
147792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean mQuietMode = false;
148085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    private AudioManager mAudioManager;
1498d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen    private boolean mQueueIsSaveable = true;
150085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    // used to track what type of audio focus loss caused the playback to pause
151085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    private boolean mPausedByTransientLossOfFocus = false;
152085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private SharedPreferences mPreferences;
154792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // We use this to distinguish between different cards when saving/restoring playlists.
155792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // This will have to change if we want to support multiple simultaneous cards.
156792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int mCardId;
157792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
158490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project    private MediaAppWidgetProvider mAppWidgetProvider = MediaAppWidgetProvider.getInstance();
159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
160792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // interval after which we stop the service when idle
161aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi    private static final int IDLE_DELAY = 60000;
1628717d3490e179e9591eac98a91a14995d98291adMarco Nelissen
1638717d3490e179e9591eac98a91a14995d98291adMarco Nelissen    private RemoteControlClient mRemoteControlClient;
1648717d3490e179e9591eac98a91a14995d98291adMarco Nelissen
165792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Handler mMediaplayerHandler = new Handler() {
166792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        float mCurrentVolume = 1.0f;
167792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
168792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void handleMessage(Message msg) {
1693988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog("mMediaplayerHandler.handleMessage " + msg.what);
170792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            switch (msg.what) {
1712da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                case FADEDOWN:
1722da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    mCurrentVolume -= .05f;
1732da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    if (mCurrentVolume > .2f) {
1742da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                        mMediaplayerHandler.sendEmptyMessageDelayed(FADEDOWN, 10);
175792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
1762da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                        mCurrentVolume = .2f;
1772da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    }
1782da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    mPlayer.setVolume(mCurrentVolume);
1792da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    break;
1802da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                case FADEUP:
1812da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    mCurrentVolume += .01f;
1822da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    if (mCurrentVolume < 1.0f) {
1832da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                        mMediaplayerHandler.sendEmptyMessageDelayed(FADEUP, 10);
1842da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    } else {
1852da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                        mCurrentVolume = 1.0f;
186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1872da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen                    mPlayer.setVolume(mCurrentVolume);
188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
189792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case SERVER_DIED:
190c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen                    if (mIsSupposedToBePlaying) {
191bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                        gotoNext(true);
192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // the server died when we were idle, so just
194792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // reopen the same song (it will start again
195792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // from the beginning though when the user
196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        // restarts)
197e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                        openCurrentAndNext();
198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
200e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                case TRACK_WENT_TO_NEXT:
201e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    mPlayPos = mNextPlayPos;
202e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    if (mCursor != null) {
203e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                        mCursor.close();
204e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                        mCursor = null;
205e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    }
206e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    mCursor = getCursorForId(mPlayList[mPlayPos]);
207e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    notifyChange(META_CHANGED);
208e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    updateNotification();
209e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    setNextTrack();
210e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    break;
211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case TRACK_ENDED:
212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mRepeatMode == REPEAT_CURRENT) {
213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        seek(0);
214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else {
216bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                        gotoNext(false);
217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case RELEASE_WAKELOCK:
220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mWakeLock.release();
221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
2227181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen
2237181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                case FOCUSCHANGE:
2247181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                    // This code is here so we can better synchronize it with the code that
2257181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                    // handles fade-in
2267181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                    switch (msg.arg1) {
2277181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                        case AudioManager.AUDIOFOCUS_LOSS:
2287181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS");
2297181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            if(isPlaying()) {
2307181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mPausedByTransientLossOfFocus = false;
2317181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            }
2327181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            pause();
2337181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            break;
2347181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
2357bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen                            mMediaplayerHandler.removeMessages(FADEUP);
2367bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen                            mMediaplayerHandler.sendEmptyMessage(FADEDOWN);
2377bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen                            break;
2387bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
2397181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS_TRANSIENT");
2407181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            if(isPlaying()) {
2417181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mPausedByTransientLossOfFocus = true;
2427181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            }
2437181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            pause();
2447181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            break;
2457181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                        case AudioManager.AUDIOFOCUS_GAIN:
2467181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_GAIN");
2477181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            if(!isPlaying() && mPausedByTransientLossOfFocus) {
2487181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mPausedByTransientLossOfFocus = false;
2497181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mCurrentVolume = 0f;
2507181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mPlayer.setVolume(mCurrentVolume);
2517181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                play(); // also queues a fade-in
2527181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            } else {
2537bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen                                mMediaplayerHandler.removeMessages(FADEDOWN);
2547181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                                mMediaplayerHandler.sendEmptyMessage(FADEUP);
2557181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            }
2567181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            break;
2577181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                        default:
2587181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                            Log.e(LOGTAG, "Unknown audio focus change code");
2597181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                    }
2607181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen                    break;
2617181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen
262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                default:
263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
268792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
269792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void onReceive(Context context, Intent intent) {
271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String action = intent.getAction();
272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            String cmd = intent.getStringExtra("command");
2733988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog("mIntentReceiver.onReceive " + action + " / " + cmd);
274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
275bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                gotoNext(true);
276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
277792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                prev();
278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (isPlaying()) {
280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    pause();
281aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                    mPausedByTransientLossOfFocus = false;
282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
287aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
288fc1c0dc301b5cae2e8c5661e7a217dc57dacac1eMarco Nelissen            } else if (CMDPLAY.equals(cmd)) {
289fc1c0dc301b5cae2e8c5661e7a217dc57dacac1eMarco Nelissen                play();
290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (CMDSTOP.equals(cmd)) {
291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
292aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                seek(0);
294490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project            } else if (MediaAppWidgetProvider.CMDAPPWIDGETUPDATE.equals(cmd)) {
295490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                // Someone asked us to refresh a set of specific widgets, probably
296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // because they were just added.
297490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
298490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project                mAppWidgetProvider.performUpdate(MediaPlaybackService.this, appWidgetIds);
299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
303085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() {
304f4cfdfd4a99040be44a1ccd74edbde762edc845bJean-Michel Trivi        public void onAudioFocusChange(int focusChange) {
3057181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen            mMediaplayerHandler.obtainMessage(FOCUSCHANGE, focusChange, 0).sendToTarget();
306085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        }
307085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi    };
308085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
309792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public MediaPlaybackService() {
310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onCreate() {
314792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onCreate();
315085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
316085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
3178717d3490e179e9591eac98a91a14995d98291adMarco Nelissen        ComponentName rec = new ComponentName(getPackageName(),
3188717d3490e179e9591eac98a91a14995d98291adMarco Nelissen                MediaButtonIntentReceiver.class.getName());
3198717d3490e179e9591eac98a91a14995d98291adMarco Nelissen        mAudioManager.registerMediaButtonEventReceiver(rec);
32094ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi        // TODO update to new constructor
32194ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//        mRemoteControlClient = new RemoteControlClient(rec);
32294ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//        mAudioManager.registerRemoteControlClient(mRemoteControlClient);
32394ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//
32494ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//        int flags = RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS
32594ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//                | RemoteControlClient.FLAG_KEY_MEDIA_NEXT
32694ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//                | RemoteControlClient.FLAG_KEY_MEDIA_PLAY
32794ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//                | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE
32894ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//                | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE
32994ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//                | RemoteControlClient.FLAG_KEY_MEDIA_STOP;
33094ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//        mRemoteControlClient.setTransportControlFlags(flags);
331792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
332792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPreferences = getSharedPreferences("Music", MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE);
33387bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen        mCardId = MusicUtils.getCardId(this);
334792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
335792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        registerExternalStorageListener();
336792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Needs to be done in this thread, since otherwise ApplicationContext.getPowerManager() crashes.
338792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayer = new MultiPlayer();
339792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayer.setHandler(mMediaplayerHandler);
340792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        reloadQueue();
3428717d3490e179e9591eac98a91a14995d98291adMarco Nelissen        notifyChange(QUEUE_CHANGED);
3438717d3490e179e9591eac98a91a14995d98291adMarco Nelissen        notifyChange(META_CHANGED);
3448717d3490e179e9591eac98a91a14995d98291adMarco Nelissen
345792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        IntentFilter commandFilter = new IntentFilter();
346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(SERVICECMD);
347792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(TOGGLEPAUSE_ACTION);
348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(PAUSE_ACTION);
349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(NEXT_ACTION);
350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        commandFilter.addAction(PREVIOUS_ACTION);
351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        registerReceiver(mIntentReceiver, commandFilter);
352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName());
355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock.setReferenceCounted(false);
356792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // If the service was idle, but got killed before it stopped itself, the
358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // system will relaunch it. Make sure it gets stopped again in that case.
359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onDestroy() {
365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Check that we're not being destroyed while something is still playing.
366792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (isPlaying()) {
367e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen            Log.e(LOGTAG, "Service being destroyed while still playing.");
368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
3692b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        // release all MediaPlayer resources, including the native player and wakelocks
370f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen        Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
371f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen        i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId());
372f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen        i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
373f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen        sendBroadcast(i);
3742b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mPlayer.release();
3752b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mPlayer = null;
376085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
377085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        mAudioManager.abandonAudioFocus(mAudioFocusListener);
37894ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi        //mAudioManager.unregisterRemoteControlClient(mRemoteControlClient);
379792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
3802b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        // make sure there aren't any other messages coming
3812b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        mDelayedStopHandler.removeCallbacksAndMessages(null);
38249e36ea916aefba042c6e927c771b10708b6891eMarco Nelissen        mMediaplayerHandler.removeCallbacksAndMessages(null);
3832b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
384792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mCursor != null) {
385792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor.close();
386792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
387792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
388792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
389792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        unregisterReceiver(mIntentReceiver);
390792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mUnmountReceiver != null) {
391792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            unregisterReceiver(mUnmountReceiver);
392792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnmountReceiver = null;
393792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
394792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mWakeLock.release();
395792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        super.onDestroy();
396792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
398792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private final char hexdigits [] = new char [] {
399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '0', '1', '2', '3',
400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '4', '5', '6', '7',
401792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            '8', '9', 'a', 'b',
402792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            'c', 'd', 'e', 'f'
403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
405792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void saveQueue(boolean full) {
4068d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen        if (!mQueueIsSaveable) {
407792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return;
408792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
4098d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen
410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Editor ed = mPreferences.edit();
411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        //long start = System.currentTimeMillis();
412792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (full) {
413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            StringBuilder q = new StringBuilder();
414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // The current playlist is saved as a list of "reverse hexadecimal"
416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // numbers, which we can generate faster than normal decimal or
417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // hexadecimal numbers, which in turn allows us to save the playlist
418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // more often without worrying too much about performance.
419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // (saving the full state takes about 40 ms under no-load conditions
420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // on the phone)
421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = mPlayListLen;
422792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
423bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long n = mPlayList[i];
424133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen                if (n < 0) {
425133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen                    continue;
426133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen                } else if (n == 0) {
427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    q.append("0;");
428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    while (n != 0) {
430bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                        int digit = (int)(n & 0xf);
431133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen                        n >>>= 4;
432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        q.append(hexdigits[digit]);
433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    q.append(";");
435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
436792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
437792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //Log.i("@@@@ service", "created queue string in " + (System.currentTimeMillis() - start) + " ms");
438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putString("queue", q.toString());
439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putInt("cardid", mCardId);
44063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (mShuffleMode != SHUFFLE_NONE) {
44163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                // In shuffle mode we need to save the history too
44263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                len = mHistory.size();
44363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                q.setLength(0);
44463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                for (int i = 0; i < len; i++) {
44563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    int n = mHistory.get(i);
44663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    if (n == 0) {
44763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        q.append("0;");
44863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    } else {
44963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        while (n != 0) {
45063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            int digit = (n & 0xf);
451133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen                            n >>>= 4;
45263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            q.append(hexdigits[digit]);
45363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        }
45463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        q.append(";");
45563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    }
45663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                }
45763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                ed.putString("history", q.toString());
45863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            }
459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("curpos", mPlayPos);
461792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ed.putLong("seekpos", mPlayer.position());
463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("repeatmode", mRepeatMode);
465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ed.putInt("shufflemode", mShuffleMode);
46614c3caeb7bc2de0dd7abbb1e5f217dbb6367afbaBrad Fitzpatrick        SharedPreferencesCompat.apply(ed);
46714c3caeb7bc2de0dd7abbb1e5f217dbb6367afbaBrad Fitzpatrick
468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        //Log.i("@@@@ service", "saved state in " + (System.currentTimeMillis() - start) + " ms");
469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void reloadQueue() {
472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        String q = null;
473792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        boolean newstyle = false;
475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int id = mCardId;
476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPreferences.contains("cardid")) {
477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            newstyle = true;
478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            id = mPreferences.getInt("cardid", ~mCardId);
479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (id == mCardId) {
481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Only restore the saved playlist if the card is still
482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // the same one as when the playlist was saved
483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            q = mPreferences.getString("queue", "");
484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
4856c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen        int qlen = q != null ? q.length() : 0;
4866c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen        if (qlen > 1) {
487792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //Log.i("@@@@ service", "loaded queue: " + q);
488bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int plen = 0;
489bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int n = 0;
490bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int shift = 0;
491bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            for (int i = 0; i < qlen; i++) {
492bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                char c = q.charAt(i);
493bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                if (c == ';') {
494bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    ensurePlayListCapacity(plen + 1);
495bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    mPlayList[plen] = n;
496bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    plen++;
497bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    n = 0;
498bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    shift = 0;
499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
500bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    if (c >= '0' && c <= '9') {
501bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        n += ((c - '0') << shift);
502bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    } else if (c >= 'a' && c <= 'f') {
503bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        n += ((10 + c - 'a') << shift);
504bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    } else {
505bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        // bogus playlist data
506bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        plen = 0;
507bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                        break;
508bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    }
509bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen                    shift += 4;
510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
512bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            mPlayListLen = plen;
513792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
514792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int pos = mPreferences.getInt("curpos", 0);
515bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            if (pos < 0 || pos >= mPlayListLen) {
516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // The saved playlist is bogus, discard it
517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 0;
518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = pos;
521792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // When reloadQueue is called in response to a card-insertion,
523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // we might not be able to query the media provider right away.
524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // To deal with this, try querying for the current file, and if
525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // that fails, wait a while and try again. If that too fails,
526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // assume there is a problem and don't restore the state.
52763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            Cursor crsr = MusicUtils.query(this,
528792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
529792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        new String [] {"_id"}, "_id=" + mPlayList[mPlayPos] , null, null);
53063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (crsr == null || crsr.getCount() == 0) {
531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // wait a bit and try again
532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                SystemClock.sleep(3000);
53363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                crsr = getContentResolver().query(
534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mCursorCols, "_id=" + mPlayList[mPlayPos] , null, null);
536792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
53763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (crsr != null) {
53863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                crsr.close();
539792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Make sure we don't auto-skip to the next song, since that
542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // also starts playback. What could happen in that case is:
543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music is paused
544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - go to UMS and delete some files, including the currently playing one
545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - come back from UMS
546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // (time passes)
547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music app is killed for some reason (out of memory)
548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // - music service is restarted, service restores state, doesn't find
549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //   the "current" file, goes to the next and: playback starts on its
550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            //   own, potentially at some random inconvenient time.
551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mOpenFailedCounter = 20;
552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mQuietMode = true;
553e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            openCurrentAndNext();
554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mQuietMode = false;
555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (!mPlayer.isInitialized()) {
556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // couldn't restore the saved state
557792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayListLen = 0;
558792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
560792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            long seekpos = mPreferences.getLong("seekpos", 0);
562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            seek(seekpos >= 0 && seekpos < duration() ? seekpos : 0);
563e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen            Log.d(LOGTAG, "restored queue, currently at position "
564e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    + position() + "/" + duration()
565e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    + " (requested " + seekpos + ")");
566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int repmode = mPreferences.getInt("repeatmode", REPEAT_NONE);
568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (repmode != REPEAT_ALL && repmode != REPEAT_CURRENT) {
569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                repmode = REPEAT_NONE;
570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = repmode;
572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int shufmode = mPreferences.getInt("shufflemode", SHUFFLE_NONE);
574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (shufmode != SHUFFLE_AUTO && shufmode != SHUFFLE_NORMAL) {
575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                shufmode = SHUFFLE_NONE;
576792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
57763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            if (shufmode != SHUFFLE_NONE) {
57863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                // in shuffle mode we need to restore the history too
57963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                q = mPreferences.getString("history", "");
58063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                qlen = q != null ? q.length() : 0;
58163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                if (qlen > 1) {
58263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    plen = 0;
58363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    n = 0;
58463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    shift = 0;
58563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    mHistory.clear();
58663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    for (int i = 0; i < qlen; i++) {
58763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        char c = q.charAt(i);
58863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        if (c == ';') {
58963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            if (n >= mPlayListLen) {
59063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                // bogus history data
59163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                mHistory.clear();
59263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                break;
59363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            }
59463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            mHistory.add(n);
59563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            n = 0;
59663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            shift = 0;
59763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        } else {
59863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            if (c >= '0' && c <= '9') {
59963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                n += ((c - '0') << shift);
60063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            } else if (c >= 'a' && c <= 'f') {
60163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                n += ((10 + c - 'a') << shift);
60263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            } else {
60363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                // bogus history data
60463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                mHistory.clear();
60563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                                break;
60663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            }
60763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                            shift += 4;
60863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                        }
60963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                    }
61063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen                }
61163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen            }
612792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (shufmode == SHUFFLE_AUTO) {
613792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (! makeAutoShuffleList()) {
614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    shufmode = SHUFFLE_NONE;
615792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
617792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mShuffleMode = shufmode;
618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public IBinder onBind(Intent intent) {
623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = true;
625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mBinder;
626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void onRebind(Intent intent) {
630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = true;
632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
635c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen    public int onStartCommand(Intent intent, int flags, int startId) {
636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceStartId = startId;
637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
638c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen
639c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen        if (intent != null) {
640c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            String action = intent.getAction();
641c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            String cmd = intent.getStringExtra("command");
6423988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog("onStartCommand " + action + " / " + cmd);
643c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen
644c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) {
645bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                gotoNext(true);
646c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) {
647b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                if (position() < 2000) {
648b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    prev();
649b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                } else {
650b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    seek(0);
651b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                    play();
652b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen                }
653c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) {
654c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                if (isPlaying()) {
655c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                    pause();
656aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                    mPausedByTransientLossOfFocus = false;
657c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                } else {
658c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                    play();
659c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                }
660c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) {
661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                pause();
662aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
66347dd847ba35375d95c15bc1ee141d638f03ec82eJaikumar Ganesh            } else if (CMDPLAY.equals(cmd)) {
66447dd847ba35375d95c15bc1ee141d638f03ec82eJaikumar Ganesh                play();
665c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen            } else if (CMDSTOP.equals(cmd)) {
666c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                pause();
667aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi                mPausedByTransientLossOfFocus = false;
668c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen                seek(0);
669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // make sure the service will shut down on its own if it was
673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // just started but not bound to and nothing is playing
674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
677c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen        return START_STICKY;
678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    @Override
681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean onUnbind(Intent intent) {
682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mServiceInUse = false;
683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Take a snapshot of the current playlist
685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        saveQueue(true);
686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
687aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi        if (isPlaying() || mPausedByTransientLossOfFocus) {
688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // something is currently playing, or will be playing once
689aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi            // an in-progress action requesting audio focus ends, so don't stop the service now.
690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // If there is a playlist but playback is paused, then wait a while
694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // before stopping the service, so that pause/resume isn't slow.
695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // Also delay stopping the service if we're transitioning between tracks.
696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayListLen > 0  || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            Message msg = mDelayedStopHandler.obtainMessage();
698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // No active playlist, OK to stop the service right now
703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stopSelf(mServiceStartId);
704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return true;
705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private Handler mDelayedStopHandler = new Handler() {
708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        @Override
709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void handleMessage(Message msg) {
710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // Check again to make sure nothing is playing right now
711aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi            if (isPlaying() || mPausedByTransientLossOfFocus || mServiceInUse
712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    || mMediaplayerHandler.hasMessages(TRACK_ENDED)) {
713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // save the queue again, because it might have changed
716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // since the user exited the music app (because of
717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // party-shuffle or because the play-position changed)
718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(true);
719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stopSelf(mServiceStartId);
720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
722f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen
723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Called when we receive a ACTION_MEDIA_EJECT notification.
725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param storagePath path to mount point for the removed media
727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
728792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void closeExternalStorageFiles(String storagePath) {
729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // stop playback and clean up if the SD card is going to be unmounted.
730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stop(true);
731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        notifyChange(QUEUE_CHANGED);
732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        notifyChange(META_CHANGED);
733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Registers an intent to listen for ACTION_MEDIA_EJECT notifications.
737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent will call closeExternalStorageFiles() if the external media
738792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * is going to be ejected, so applications can clean up any files they have open.
739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void registerExternalStorageListener() {
741792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mUnmountReceiver == null) {
742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mUnmountReceiver = new BroadcastReceiver() {
743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                @Override
744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                public void onReceive(Context context, Intent intent) {
745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    String action = intent.getAction();
746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        saveQueue(true);
7488d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen                        mQueueIsSaveable = false;
749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        closeExternalStorageFiles(intent.getData().getPath());
750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
751792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mMediaMountedCount++;
75287bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen                        mCardId = MusicUtils.getCardId(MediaPlaybackService.this);
753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        reloadQueue();
7548d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen                        mQueueIsSaveable = true;
755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(QUEUE_CHANGED);
756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        notifyChange(META_CHANGED);
757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
759792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            };
760792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            IntentFilter iFilter = new IntentFilter();
761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_EJECT);
762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            iFilter.addDataScheme("file");
764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            registerReceiver(mUnmountReceiver, iFilter);
765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Notify the change-receivers that something has changed.
770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent that is sent contains the following data
771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * for the currently playing track:
772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "id" - Integer: the database row ID
773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "artist" - String: the name of the artist
774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "album" - String: the name of the album
775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "track" - String: the name of the track
776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * The intent has an action that is one of
777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.metachanged"
778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.queuechanged",
779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.playbackcomplete"
780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * "com.android.music.playstatechanged"
781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * respectively indicating that a new track has
782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * started playing, that the playback queue has
783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * changed, that playback has stopped because
784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the last file in the list has been played,
785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * or that the play-state changed (paused/resumed).
786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void notifyChange(String what) {
7888717d3490e179e9591eac98a91a14995d98291adMarco Nelissen
789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Intent i = new Intent(what);
790bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        i.putExtra("id", Long.valueOf(getAudioId()));
791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("artist", getArtistName());
792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("album",getAlbumName());
793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        i.putExtra("track", getTrackName());
7946b507de7beda7f4a8b969b437dfbf81f5ecd5e5eMarco Nelissen        i.putExtra("playing", isPlaying());
7956b507de7beda7f4a8b969b437dfbf81f5ecd5e5eMarco Nelissen        sendStickyBroadcast(i);
7968717d3490e179e9591eac98a91a14995d98291adMarco Nelissen
7978717d3490e179e9591eac98a91a14995d98291adMarco Nelissen        if (what.equals(PLAYSTATE_CHANGED)) {
79894ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//            mRemoteControlClient.setPlaybackState(isPlaying() ?
79994ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//                    RemoteControlClient.PLAYSTATE_PLAYING : RemoteControlClient.PLAYSTATE_PAUSED);
8008717d3490e179e9591eac98a91a14995d98291adMarco Nelissen        } else if (what.equals(META_CHANGED)) {
80194ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//            RemoteControlClient.MetadataEditor ed = mRemoteControlClient.editMetadata(true);
80294ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//            ed.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, getTrackName());
80394ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//            ed.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, getAlbumName());
80494ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//            ed.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, getArtistName());
80594ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//            ed.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, duration());
80694ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//            Bitmap b = MusicUtils.getArtwork(this, getAudioId(), getAlbumId(), false);
80794ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//            if (b != null) {
80894ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//                ed.putBitmap(MetadataEditor.BITMAP_KEY_ARTWORK, b);
80994ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//            }
81094ed2422b691e1822783d696bc5acdecf222fe12Jean-Michel Trivi//            ed.apply();
8118717d3490e179e9591eac98a91a14995d98291adMarco Nelissen        }
8128717d3490e179e9591eac98a91a14995d98291adMarco Nelissen
813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (what.equals(QUEUE_CHANGED)) {
814792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(true);
815792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else {
816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
817792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
819490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project        // Share this notification directly with our widgets
820490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project        mAppWidgetProvider.notifyChange(this, what);
821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void ensurePlayListCapacity(int size) {
824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayList == null || size > mPlayList.length) {
825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // reallocate at 2x requested size so we don't
826792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // need to grow and copy the array for every
827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // insert
828bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] newlist = new long[size * 2];
829bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen            int len = mPlayList != null ? mPlayList.length : mPlayListLen;
830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                newlist[i] = mPlayList[i];
832792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList = newlist;
834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
835792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // FIXME: shrink the array when the needed size is much smaller
836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // than the allocated size
837792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // insert the list of songs at the specified position in the playlist
840bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    private void addToPlayList(long [] list, int position) {
841792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int addlen = list.length;
842792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (position < 0) { // overwrite
843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen = 0;
844792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            position = 0;
845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
846792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ensurePlayListCapacity(mPlayListLen + addlen);
847792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (position > mPlayListLen) {
848792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            position = mPlayListLen;
849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
850792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
851792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // move part of list after insertion point
852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int tailsize = mPlayListLen - position;
853792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = tailsize ; i > 0 ; i--) {
854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[position + i] = mPlayList[position + i - addlen];
855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
856792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // copy list into playlist
858792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < addlen; i++) {
859792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayList[position + i] = list[i];
860792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
861792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mPlayListLen += addlen;
8623aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen        if (mPlayListLen == 0) {
8633aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen            mCursor.close();
8643aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen            mCursor = null;
8653aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen            notifyChange(META_CHANGED);
8663aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen        }
867792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
868792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
869792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
870792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Appends a list of tracks to the current playlist.
871792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * If nothing is playing currently, playback will be started at
872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the first track.
873792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * If the action is NOW, playback will switch to the first of
874792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the new tracks immediately.
875792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param list The list of tracks to append.
876792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param action NOW, NEXT or LAST
877792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
878bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public void enqueue(long [] list, int action) {
879792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
880792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (action == NEXT && mPlayPos + 1 < mPlayListLen) {
881792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, mPlayPos + 1);
882792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
883792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
884792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // action == LAST || action == NOW || mPlayPos + 1 == mPlayListLen
885792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, Integer.MAX_VALUE);
886792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
887792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (action == NOW) {
888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = mPlayListLen - list.length;
889e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    openCurrentAndNext();
890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
891792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    notifyChange(META_CHANGED);
892792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
893792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
894792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
895792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos < 0) {
896792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = 0;
897e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                openCurrentAndNext();
898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                play();
899792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(META_CHANGED);
900792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
901792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
902792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
903792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
904792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
905792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Replaces the current playlist with a new list,
906792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * and prepares for starting playback at the specified
907792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * position in the list, or a random position if the
908792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * specified position is 0.
909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param list The new list of tracks.
910792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
911bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public void open(long [] list, int position) {
912792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
913792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_AUTO) {
914792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mShuffleMode = SHUFFLE_NORMAL;
915792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
916bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long oldId = getAudioId();
917792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int listlength = list.length;
918792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            boolean newlist = true;
919792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayListLen == listlength) {
920792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // possible fast path: list might be the same
921792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                newlist = false;
922792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = 0; i < listlength; i++) {
923792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (list[i] != mPlayList[i]) {
924792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        newlist = true;
925792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        break;
926792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
927792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
928792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
929792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (newlist) {
930792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                addToPlayList(list, -1);
931792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(QUEUE_CHANGED);
932792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int oldpos = mPlayPos;
934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (position >= 0) {
935792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = position;
936792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = mRand.nextInt(mPlayListLen);
938792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
939792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mHistory.clear();
940792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
941792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
942e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            openCurrentAndNext();
943d8c696753687ddb0177f869fad5f709eadfe27afJeffrey Sharkey            if (oldId != getAudioId()) {
944792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(META_CHANGED);
945792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
947792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
948792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
949792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
950792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Moves the item at index1 to index2.
951792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param index1
952792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param index2
953792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
954792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void moveQueueItem(int index1, int index2) {
955792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
956792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index1 >= mPlayListLen) {
957792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                index1 = mPlayListLen - 1;
958792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
959792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index2 >= mPlayListLen) {
960792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                index2 = mPlayListLen - 1;
961792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
962792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (index1 < index2) {
963bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long tmp = mPlayList[index1];
964792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = index1; i < index2; i++) {
965792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = mPlayList[i+1];
966792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
967792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[index2] = tmp;
968792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos == index1) {
969792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = index2;
970792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else if (mPlayPos >= index1 && mPlayPos <= index2) {
971792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos--;
972792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
973792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (index2 < index1) {
974bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                long tmp = mPlayList[index1];
975792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                for (int i = index1; i > index2; i--) {
976792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayList[i] = mPlayList[i-1];
977792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
978792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[index2] = tmp;
979792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos == index1) {
980792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = index2;
981792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else if (mPlayPos >= index2 && mPlayPos <= index1) {
982792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos++;
983792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
984792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
985792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
986792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
987792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
988792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
989792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
990792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the current play list
991792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return An array of integers containing the IDs of the tracks in the play list
992792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
993bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long [] getQueue() {
994792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
995792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = mPlayListLen;
996bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = new long[len];
997792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
998792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                list[i] = mPlayList[i];
999792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1000792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return list;
1001792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1002792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1003792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1004e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen    private Cursor getCursorForId(long lid) {
1005e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        String id = String.valueOf(lid);
1006e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen
1007e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        Cursor c = getContentResolver().query(
1008e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1009e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                mCursorCols, "_id=" + id , null, null);
1010e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        c.moveToFirst();
1011e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        return c;
1012e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen    }
1013e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen
1014e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen    private void openCurrentAndNext() {
1015792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1016792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor != null) {
1017792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor.close();
1018792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mCursor = null;
1019792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
10208d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen
1021792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayListLen == 0) {
1022792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1023792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1024792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1025792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
102690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            mCursor = getCursorForId(mPlayList[mPlayPos]);
102790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            while(!open(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + mCursor.getLong(IDCOLIDX))) {
102890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                if (mOpenFailedCounter++ < 10 &&  mPlayListLen > 1) {
102990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    int pos = getNextPosition(false);
103090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    if (pos < 0) {
103190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                        gotoIdleState();
103290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                        if (mIsSupposedToBePlaying) {
103390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                            mIsSupposedToBePlaying = false;
103490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                            notifyChange(PLAYSTATE_CHANGED);
103590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                        }
103690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                        return;
103790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    }
103890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    mPlayPos = pos;
103990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    stop(false);
104090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    mPlayPos = pos;
104190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    mCursor = getCursorForId(mPlayList[mPlayPos]);
104290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                } else {
104390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    mOpenFailedCounter = 0;
104490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    if (!mQuietMode) {
104590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                        Toast.makeText(this, R.string.playback_failed, Toast.LENGTH_SHORT).show();
104690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    }
104790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    Log.d(LOGTAG, "Failed to open file for playback");
104890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                    return;
1049e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                }
1050792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
105190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen
105290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            // go to bookmark if needed
105390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            if (isPodcast()) {
105490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                long bookmark = getBookmark();
105590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                // Start playing a little bit before the bookmark,
105690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                // so it's easier to get back in to the narrative.
105790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                seek(bookmark - 5000);
105890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            }
105990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            setNextTrack();
1060792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1061792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1062792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1063e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen    private void setNextTrack() {
1064e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        mNextPlayPos = getNextPosition(false);
1065e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        if (mNextPlayPos >= 0) {
1066e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            long id = mPlayList[mNextPlayPos];
1067e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mPlayer.setNextDataSource(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + id);
1068e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        }
1069e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen    }
1070e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen
1071792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1072792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Opens the specified file and readies it for playback.
1073792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
1074792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param path The full path of the file to be opened.
1075792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
107690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen    public boolean open(String path) {
1077792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1078792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (path == null) {
107990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                return false;
1080792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1081792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1082792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // if mCursor is null, try to associate path with a database cursor
1083792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1084792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1085792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ContentResolver resolver = getContentResolver();
1086792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Uri uri;
1087792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String where;
1088792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                String selectionArgs[];
1089792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (path.startsWith("content://media/")) {
1090792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    uri = Uri.parse(path);
1091792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    where = null;
1092792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    selectionArgs = null;
1093792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1094792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   uri = MediaStore.Audio.Media.getContentUriForPath(path);
1095792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   where = MediaStore.Audio.Media.DATA + "=?";
1096792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                   selectionArgs = new String[] { path };
1097792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1098792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1099792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                try {
1100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mCursor = resolver.query(uri, mCursorCols, where, selectionArgs, null);
1101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if  (mCursor != null) {
1102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        if (mCursor.getCount() == 0) {
1103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor.close();
1104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor = null;
1105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        } else {
1106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mCursor.moveToNext();
1107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            ensurePlayListCapacity(1);
1108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mPlayListLen = 1;
1109bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                            mPlayList[0] = mCursor.getLong(IDCOLIDX);
1110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                            mPlayPos = 0;
1111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        }
1112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } catch (UnsupportedOperationException ex) {
1114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mFileToPlay = path;
1117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.setDataSource(mFileToPlay);
111890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            if (mPlayer.isInitialized()) {
1119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mOpenFailedCounter = 0;
112090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                return true;
1121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
112290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            stop(true);
112390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            return false;
1124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Starts playback of a previously opened file.
1129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void play() {
1131085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi        mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC,
1132085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi                AudioManager.AUDIOFOCUS_GAIN);
11333d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi        mAudioManager.registerMediaButtonEventReceiver(new ComponentName(this.getPackageName(),
11343d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi                MediaButtonIntentReceiver.class.getName()));
1135085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi
1136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1137272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle            // if we are at the end of the song, go to the next song first
11382f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen            long duration = mPlayer.duration();
11392f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen            if (mRepeatMode != REPEAT_CURRENT && duration > 2000 &&
11402f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen                mPlayer.position() >= duration - 2000) {
1141bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                gotoNext(true);
1142272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle            }
1143272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle
1144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.start();
11457181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen            // make sure we fade in, in case a previous fadein was stopped because
11467181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen            // of another focus loss
11477bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen            mMediaplayerHandler.removeMessages(FADEDOWN);
11487181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen            mMediaplayerHandler.sendEmptyMessage(FADEUP);
1149792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1150e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            updateNotification();
1151c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen            if (!mIsSupposedToBePlaying) {
1152347fe57e4c8a860dfbad6f0ec1991171bfa69d77Mike Cleron                mIsSupposedToBePlaying = true;
1153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                notifyChange(PLAYSTATE_CHANGED);
1154792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1155347fe57e4c8a860dfbad6f0ec1991171bfa69d77Mike Cleron
1156792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } else if (mPlayListLen <= 0) {
1157792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // This is mostly so that if you press 'play' on a bluetooth headset
1158792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // without every having played anything before, it will still play
1159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // something.
1160792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            setShuffleMode(SHUFFLE_AUTO);
1161792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1162792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1163e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen
1164e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen    private void updateNotification() {
1165e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        RemoteViews views = new RemoteViews(getPackageName(), R.layout.statusbar);
1166e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        views.setImageViewResource(R.id.icon, R.drawable.stat_notify_musicplayer);
1167e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        if (getAudioId() < 0) {
1168e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            // streaming
1169e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            views.setTextViewText(R.id.trackname, getPath());
1170e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            views.setTextViewText(R.id.artistalbum, null);
1171e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        } else {
1172e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            String artist = getArtistName();
1173e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            views.setTextViewText(R.id.trackname, getTrackName());
1174e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            if (artist == null || artist.equals(MediaStore.UNKNOWN_STRING)) {
1175e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                artist = getString(R.string.unknown_artist_name);
1176e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            }
1177e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            String album = getAlbumName();
1178e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            if (album == null || album.equals(MediaStore.UNKNOWN_STRING)) {
1179e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                album = getString(R.string.unknown_album_name);
1180e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            }
1181e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen
1182e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            views.setTextViewText(R.id.artistalbum,
1183e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    getString(R.string.notification_artist_album, artist, album)
1184e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    );
1185e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        }
1186e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        Notification status = new Notification();
1187e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        status.contentView = views;
1188e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        status.flags |= Notification.FLAG_ONGOING_EVENT;
1189e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        status.icon = R.drawable.stat_notify_musicplayer;
1190e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        status.contentIntent = PendingIntent.getActivity(this, 0,
1191e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                new Intent("com.android.music.PLAYBACK_VIEWER")
1192e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0);
1193e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        startForeground(PLAYBACKSERVICE_STATUS, status);
1194e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen    }
1195e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen
1196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void stop(boolean remove_status_icon) {
1197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1198792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayer.stop();
1199792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mFileToPlay = null;
1201792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mCursor != null) {
1202792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor.close();
1203792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mCursor = null;
1204792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1205792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (remove_status_icon) {
1206792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            gotoIdleState();
1207d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn        } else {
1208d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn            stopForeground(false);
1209792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1210792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (remove_status_icon) {
1211c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen            mIsSupposedToBePlaying = false;
1212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Stops playback.
1217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void stop() {
1219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        stop(true);
1220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1222792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1223792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Pauses playback (call play() to resume)
1224792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void pause() {
1226407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen        synchronized(this) {
12277181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen            mMediaplayerHandler.removeMessages(FADEUP);
1228407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen            if (isPlaying()) {
1229407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                mPlayer.pause();
1230407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                gotoIdleState();
1231407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                mIsSupposedToBePlaying = false;
1232407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                notifyChange(PLAYSTATE_CHANGED);
1233407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen                saveBookmarkIfNeeded();
1234407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen            }
1235792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1236792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1237792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1238b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen    /** Returns whether something is currently playing
1239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
1240b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen     * @return true if something is playing (or will be playing shortly, in case
1241b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen     * we're currently transitioning between tracks), false if not.
1242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public boolean isPlaying() {
1244c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen        return mIsSupposedToBePlaying;
1245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1246792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1247792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /*
1248792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      Desired behavior for prev/next/shuffle:
1249792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      - NEXT will move to the next track in the list when not shuffling, and to
1251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        a track randomly picked from the not-yet-played tracks when shuffling.
1252792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        If all tracks have already been played, pick from the full set, but
1253792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        avoid picking the previously played track if possible.
1254792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project      - when shuffling, PREV will go to the previously played track. Hitting PREV
1255792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        again will go to the track played before that, etc. When the start of the
1256792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        history has been reached, PREV is a no-op.
1257792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When not shuffling, PREV will go to the sequentially previous track (the
1258792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        difference with the shuffle-case is mainly that when not shuffling, the
1259792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        user can back up to tracks that are not in the history).
1260792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1261792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Example:
1262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When playing an album with 10 tracks from the start, and enabling shuffle
1263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        while playing track 5, the remaining tracks (6-10) will be shuffled, e.g.
1264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        the final play order might be 1-2-3-4-5-8-10-6-9-7.
1265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        When hitting 'prev' 8 times while playing track 7 in this example, the
1266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        user will go to tracks 9-6-10-8-5-4-3-2. If the user then hits 'next',
1267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        a random track will be picked again. If at any time user disables shuffling
1268792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        the next/previous track will be picked in sequential order again.
1269792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void prev() {
1272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_NORMAL) {
1274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // go to previously-played track and remove it from the history
1275792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                int histsize = mHistory.size();
1276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (histsize == 0) {
1277792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // prev is a no-op
1278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Integer pos = mHistory.remove(histsize - 1);
1281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = pos.intValue();
1282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayPos > 0) {
1284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos--;
1285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = mPlayListLen - 1;
1287792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1288792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1289792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
1290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1291e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            openCurrentAndNext();
1292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1297bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen    /**
1298bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen     * Get the next position to play. Note that this may actually modify mPlayPos
1299bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen     * if playback is in SHUFFLE_AUTO mode and the shuffle list window needed to
1300bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen     * be adjusted. Either way, the return value is the next value that should be
1301bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen     * assigned to mPlayPos;
1302bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen     */
1303bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen    private int getNextPosition(boolean force) {
1304e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        if (mRepeatMode == REPEAT_CURRENT) {
1305e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            if (mPlayPos < 0) return 0;
1306e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            return mPlayPos;
1307e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        } else if (mShuffleMode == SHUFFLE_NORMAL) {
1308bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            // Pick random next track from the not-yet-played ones
1309bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            // TODO: make it work right after adding/removing items in the queue.
1310663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen
1311bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            // Store the current file in the history, but keep the history at a
1312bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            // reasonable size
1313bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            if (mPlayPos >= 0) {
1314bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                mHistory.add(mPlayPos);
1315bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            }
1316bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            if (mHistory.size() > MAX_HISTORY_SIZE) {
1317bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                mHistory.removeElementAt(0);
1318bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            }
1319792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1320bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            int numTracks = mPlayListLen;
1321bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            int[] tracks = new int[numTracks];
1322bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            for (int i=0;i < numTracks; i++) {
1323bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                tracks[i] = i;
1324bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            }
13253f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
1326bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            int numHistory = mHistory.size();
1327bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            int numUnplayed = numTracks;
1328bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            for (int i=0;i < numHistory; i++) {
1329bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                int idx = mHistory.get(i).intValue();
1330bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                if (idx < numTracks && tracks[idx] >= 0) {
1331bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    numUnplayed--;
1332bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    tracks[idx] = -1;
1333792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1334bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            }
1335792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1336bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            // 'numUnplayed' now indicates how many tracks have not yet
1337bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            // been played, and 'tracks' contains the indices of those
1338bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            // tracks.
1339bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            if (numUnplayed <=0) {
1340bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                // everything's already been played
1341bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                if (mRepeatMode == REPEAT_ALL || force) {
1342bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    //pick from full set
1343bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    numUnplayed = numTracks;
1344bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    for (int i=0;i < numTracks; i++) {
1345bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                        tracks[i] = i;
1346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1347bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                } else {
1348bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    // all done
1349bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    return -1;
1350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1351bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            }
1352bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            int skip = mRand.nextInt(numUnplayed);
1353bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            int cnt = -1;
1354bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            while (true) {
1355bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                while (tracks[++cnt] < 0)
1356bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    ;
1357bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                skip--;
1358bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                if (skip < 0) {
1359bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    break;
1360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1361bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            }
1362bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            return cnt;
1363bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen        } else if (mShuffleMode == SHUFFLE_AUTO) {
1364bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            doAutoShuffleUpdate();
1365bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            return mPlayPos + 1;
1366bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen        } else {
1367bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            if (mPlayPos >= mPlayListLen - 1) {
1368bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                // we're at the end of the list
1369bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                if (mRepeatMode == REPEAT_NONE && !force) {
1370bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    // all done
1371bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    return -1;
1372bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                } else if (mRepeatMode == REPEAT_ALL || force) {
1373bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    return 0;
1374792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1375bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                return -1;
1376792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else {
1377bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                return mPlayPos + 1;
1378bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            }
1379bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen        }
1380bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen    }
1381bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen
1382bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen    public void gotoNext(boolean force) {
1383bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen        synchronized (this) {
1384bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            if (mPlayListLen <= 0) {
1385bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                Log.d(LOGTAG, "No play queue");
1386bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                return;
1387bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            }
1388bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen
1389bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            int pos = getNextPosition(force);
1390bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            if (pos < 0) {
1391bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                gotoIdleState();
1392bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                if (mIsSupposedToBePlaying) {
1393bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    mIsSupposedToBePlaying = false;
1394bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                    notifyChange(PLAYSTATE_CHANGED);
1395792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1396bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen                return;
1397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1398bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            mPlayPos = pos;
1399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveBookmarkIfNeeded();
1400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1401e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mPlayPos = pos;
1402e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            openCurrentAndNext();
1403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1405792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1406792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1407792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1408792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void gotoIdleState() {
1409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.removeCallbacksAndMessages(null);
1410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Message msg = mDelayedStopHandler.obtainMessage();
1411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY);
1412d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn        stopForeground(true);
1413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void saveBookmarkIfNeeded() {
1416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (isPodcast()) {
1418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long pos = position();
1419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long bookmark = getBookmark();
1420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                long duration = duration();
1421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if ((pos < bookmark && (pos + 10000) > bookmark) ||
1422792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        (pos > bookmark && (pos - 10000) < bookmark)) {
1423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // The existing bookmark is close to the current
1424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // position, so don't update it.
1425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (pos < 15000 || (pos + 10000) > duration) {
1428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // if we're near the start or end, clear the bookmark
1429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    pos = 0;
1430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // write 'pos' to the bookmark field
1433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ContentValues values = new ContentValues();
1434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                values.put(MediaStore.Audio.Media.BOOKMARK, pos);
1435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                Uri uri = ContentUris.withAppendedId(
1436792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursor.getLong(IDCOLIDX));
1437792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                getContentResolver().update(uri, values, null, null);
1438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (SQLiteException ex) {
1440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // Make sure there are at least 5 items after the currently playing item
1444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // and no more than 10 items before.
1445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private void doAutoShuffleUpdate() {
1446792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        boolean notify = false;
14473f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
1448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // remove old entries
1449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayPos > 10) {
1450792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            removeTracks(0, mPlayPos - 9);
1451792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notify = true;
1452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1453792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        // add new entries if needed
1454792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int to_add = 7 - (mPlayListLen - (mPlayPos < 0 ? -1 : mPlayPos));
1455792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        for (int i = 0; i < to_add; i++) {
1456792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            // pick something at random from the list
14573f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
14583f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            int lookback = mHistory.size();
14593f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            int idx = -1;
14603f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            while(true) {
14613f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                idx = mRand.nextInt(mAutoShuffleList.length);
14623f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                if (!wasRecentlyUsed(idx, lookback)) {
14633f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                    break;
14643f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                }
14653f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                lookback /= 2;
14663f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            }
14673f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            mHistory.add(idx);
14683f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            if (mHistory.size() > MAX_HISTORY_SIZE) {
14693f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                mHistory.remove(0);
14703f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            }
1471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            ensurePlayListCapacity(mPlayListLen + 1);
14723f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            mPlayList[mPlayListLen++] = mAutoShuffleList[idx];
1473792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notify = true;
1474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (notify) {
1476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
14803f502de8e8963224054a97730d132f82ac87d522Marco Nelissen    // check that the specified idx is not in the history (but only look at at
14813f502de8e8963224054a97730d132f82ac87d522Marco Nelissen    // most lookbacksize entries in the history)
14823f502de8e8963224054a97730d132f82ac87d522Marco Nelissen    private boolean wasRecentlyUsed(int idx, int lookbacksize) {
14833f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
14843f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        // early exit to prevent infinite loops in case idx == mPlayPos
14853f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        if (lookbacksize == 0) {
14863f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            return false;
14873f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        }
14883f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
14893f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        int histsize = mHistory.size();
14903f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        if (histsize < lookbacksize) {
14913f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            Log.d(LOGTAG, "lookback too big");
14923f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            lookbacksize = histsize;
14933f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        }
14943f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        int maxidx = histsize - 1;
14953f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        for (int i = 0; i < lookbacksize; i++) {
14963f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            long entry = mHistory.get(maxidx - i);
14973f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            if (entry == idx) {
14983f502de8e8963224054a97730d132f82ac87d522Marco Nelissen                return true;
14993f502de8e8963224054a97730d132f82ac87d522Marco Nelissen            }
15003f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        }
15013f502de8e8963224054a97730d132f82ac87d522Marco Nelissen        return false;
15023f502de8e8963224054a97730d132f82ac87d522Marco Nelissen    }
15033f502de8e8963224054a97730d132f82ac87d522Marco Nelissen
1504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // A simple variation of Random that makes sure that the
1505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // value it returns is not equal to the value it returned
1506792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    // previously, unless the interval is 1.
1507756c3f57f11a7bb3bf1cf1333ee8ffbc51039748Marco Nelissen    private static class Shuffler {
1508792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private int mPrevious;
1509792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private Random mRandom = new Random();
1510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int nextInt(int interval) {
1511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int ret;
1512792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            do {
1513792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                ret = mRandom.nextInt(interval);
1514792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } while (ret == mPrevious && interval > 1);
1515792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPrevious = ret;
1516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return ret;
1517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    };
1519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean makeAutoShuffleList() {
1521792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        ContentResolver res = getContentResolver();
1522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        Cursor c = null;
1523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        try {
1524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            c = res.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
1525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    new String[] {MediaStore.Audio.Media._ID}, MediaStore.Audio.Media.IS_MUSIC + "=1",
1526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    null, null);
1527792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c == null || c.getCount() == 0) {
1528792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1529792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int len = c.getCount();
1531bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            long [] list = new long[len];
1532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < len; i++) {
1533792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.moveToNext();
1534bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen                list[i] = c.getLong(0);
1535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1536792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mAutoShuffleList = list;
1537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return true;
1538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } catch (RuntimeException ex) {
1539792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        } finally {
1540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (c != null) {
1541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                c.close();
1542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return false;
1545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Removes the range of tracks specified from the play list. If a file within the range is
1549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * the file currently being played, playback will move to the next file after the
1550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * range.
1551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param first The first file to be removed
1552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param last The last file to be removed
1553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return the number of tracks deleted
1554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int removeTracks(int first, int last) {
1556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int numremoved = removeTracksInternal(first, last);
1557792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (numremoved > 0) {
1558792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1560792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return numremoved;
1561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private int removeTracksInternal(int first, int last) {
1564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (last < first) return 0;
1566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (first < 0) first = 0;
1567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (last >= mPlayListLen) last = mPlayListLen - 1;
1568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            boolean gotonext = false;
1570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (first <= mPlayPos && mPlayPos <= last) {
1571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos = first;
1572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                gotonext = true;
1573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } else if (mPlayPos > last) {
1574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayPos -= (last - first + 1);
1575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1576792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            int num = mPlayListLen - last - 1;
1577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < num; i++) {
1578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                mPlayList[first + i] = mPlayList[last + 1 + i];
1579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayListLen -= last - first + 1;
1581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (gotonext) {
1583792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayListLen == 0) {
1584792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    stop(true);
1585792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = -1;
15863aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen                    if (mCursor != null) {
15873aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen                        mCursor.close();
15883aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen                        mCursor = null;
15893aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen                    }
1590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1591792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (mPlayPos >= mPlayListLen) {
1592792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        mPlayPos = 0;
1593792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1594792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    boolean wasPlaying = isPlaying();
1595792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    stop(false);
1596e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    openCurrentAndNext();
1597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    if (wasPlaying) {
1598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                        play();
1599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    }
1600792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
16013aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen                notifyChange(META_CHANGED);
1602792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1603792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return last - first + 1;
1604792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1605792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1606792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1607792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1608792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Removes all instances of the track with the given id
1609792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * from the playlist.
1610792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param id The id to be removed
1611792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return how many instances of the track were removed
1612792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1613bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public int removeTrack(long id) {
1614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        int numremoved = 0;
1615792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            for (int i = 0; i < mPlayListLen; i++) {
1617792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (mPlayList[i] == id) {
1618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    numremoved += removeTracksInternal(i, i);
1619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    i--;
1620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (numremoved > 0) {
1624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(QUEUE_CHANGED);
1625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return numremoved;
1627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setShuffleMode(int shufflemode) {
1630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == shufflemode && mPlayListLen > 0) {
1632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return;
1633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mShuffleMode = shufflemode;
1635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mShuffleMode == SHUFFLE_AUTO) {
1636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (makeAutoShuffleList()) {
1637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayListLen = 0;
1638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    doAutoShuffleUpdate();
1639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mPlayPos = 0;
1640e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    openCurrentAndNext();
1641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    play();
1642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    notifyChange(META_CHANGED);
1643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return;
1644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // failed to build a list of files to shuffle
1646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mShuffleMode = SHUFFLE_NONE;
1647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
1650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1652792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getShuffleMode() {
1653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mShuffleMode;
1654792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1655792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setRepeatMode(int repeatmode) {
1657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mRepeatMode = repeatmode;
1659e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            setNextTrack();
1660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            saveQueue(false);
1661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getRepeatMode() {
1664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mRepeatMode;
1665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getMediaMountedCount() {
1668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mMediaMountedCount;
1669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the path of the currently playing file, or null if
1673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * no file is currently playing.
1674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getPath() {
1676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return mFileToPlay;
1677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the rowid of the currently playing file, or -1 if
1681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * no file is currently playing.
1682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1683bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getAudioId() {
1684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mPlayPos >= 0 && mPlayer.isInitialized()) {
1686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return mPlayList[mPlayPos];
1687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the position in the queue
1694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @return the position in the queue
1695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public int getQueuePosition() {
1697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayPos;
1699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Starts playing the track at the given position in the queue.
1704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param pos The position in the queue of the track that will be played.
1705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public void setQueuePosition(int pos) {
1707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            stop(false);
1709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mPlayPos = pos;
1710e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            openCurrentAndNext();
1711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            play();
1712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            notifyChange(META_CHANGED);
1713ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            if (mShuffleMode == SHUFFLE_AUTO) {
1714ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen                doAutoShuffleUpdate();
1715ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen            }
1716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getArtistName() {
1720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized(this) {
1721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
1725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1728bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getArtistId() {
1729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return -1;
1732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1733bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID));
1734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getAlbumName() {
1738792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1741792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM));
1743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1746bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen    public long getAlbumId() {
1747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return -1;
1750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1751bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen            return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID));
1752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1754792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public String getTrackName() {
1756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return null;
1759792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1760792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE));
1761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private boolean isPodcast() {
1765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return (mCursor.getInt(PODCASTCOLIDX) > 0);
1770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private long getBookmark() {
1774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        synchronized (this) {
1775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (mCursor == null) {
1776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return 0;
1777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mCursor.getLong(BOOKMARKCOLIDX);
1779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the duration of the file in milliseconds.
1784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Currently this method returns -1 for the duration of MIDI files.
1785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long duration() {
1787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1788792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.duration();
1789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Returns the current playback position in milliseconds
1795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1796792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long position() {
1797792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.position();
1799792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1800792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1801792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1802792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1803792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
1804792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Seeks to the position specified.
1805792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     *
1806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * @param pos The position to seek to, in milliseconds
1807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1808792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    public long seek(long pos) {
1809792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        if (mPlayer.isInitialized()) {
1810792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (pos < 0) pos = 0;
1811792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            if (pos > mPlayer.duration()) pos = mPlayer.duration();
1812792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mPlayer.seek(pos);
1813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1814792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        return -1;
1815792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
1816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1817792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    /**
18181cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     * Sets the audio session ID.
18191cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     *
18201cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     * @param sessionId: the audio session ID.
18211cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     */
18221cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    public void setAudioSessionId(int sessionId) {
18231cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        synchronized (this) {
18241cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent            mPlayer.setAudioSessionId(sessionId);
18251cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        }
18261cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    }
18271cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent
18281cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    /**
18291cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     * Returns the audio session ID.
18301cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent     */
18311cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    public int getAudioSessionId() {
18321cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        synchronized (this) {
18331cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent            return mPlayer.getAudioSessionId();
18341cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        }
18351cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    }
18361cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent
18371cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent    /**
1838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * Provides a unified interface for dealing with midi files and
1839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     * other media files.
1840792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project     */
1841792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    private class MultiPlayer {
1842308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        private CompatMediaPlayer mCurrentMediaPlayer = new CompatMediaPlayer();
1843308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        private CompatMediaPlayer mNextMediaPlayer;
1844792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private Handler mHandler;
1845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        private boolean mIsInitialized = false;
1846792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1847792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public MultiPlayer() {
1848e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mCurrentMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK);
1849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1850792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1851792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setDataSource(String path) {
185290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path);
185390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            if (mIsInitialized) {
185490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                setNextDataSource(null);
185590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            }
1856e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        }
1857e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen
185890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen        private boolean setDataSourceImpl(MediaPlayer player, String path) {
1859792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            try {
1860e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                player.reset();
1861e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                player.setOnPreparedListener(null);
1862792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                if (path.startsWith("content://")) {
1863e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    player.setDataSource(MediaPlaybackService.this, Uri.parse(path));
1864792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                } else {
1865e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    player.setDataSource(path);
1866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1867e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                player.setAudioStreamType(AudioManager.STREAM_MUSIC);
1868e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                player.prepare();
1869792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IOException ex) {
1870792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
187190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                return false;
1872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            } catch (IllegalArgumentException ex) {
1873792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                // TODO: notify the user why the file couldn't be opened
187490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                return false;
1875792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1876e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            player.setOnCompletionListener(listener);
1877e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            player.setOnErrorListener(errorListener);
1878f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen            Intent i = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
1879f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen            i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId());
1880f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen            i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
1881f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen            sendBroadcast(i);
188290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            return true;
1883792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1884e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen
1885e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        public void setNextDataSource(String path) {
1886e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mCurrentMediaPlayer.setNextMediaPlayer(null);
1887e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            if (mNextMediaPlayer != null) {
1888e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                mNextMediaPlayer.release();
1889e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                mNextMediaPlayer = null;
1890e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            }
1891e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            if (path == null) {
1892e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                return;
1893e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            }
1894308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            mNextMediaPlayer = new CompatMediaPlayer();
1895e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mNextMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK);
1896e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mNextMediaPlayer.setAudioSessionId(getAudioSessionId());
189790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            if (setDataSourceImpl(mNextMediaPlayer, path)) {
189890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer);
189990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            } else {
190090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                // failed to open next, we'll transition the old fashioned way,
190190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                // which will skip over the faulty file
190290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                mNextMediaPlayer.release();
190390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen                mNextMediaPlayer = null;
190490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen            }
1905e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        }
1906792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1907792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public boolean isInitialized() {
1908792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return mIsInitialized;
1909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1910792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1911792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void start() {
19123988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen            MusicUtils.debugLog(new Exception("MultiPlayer.start called"));
1913e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mCurrentMediaPlayer.start();
1914792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1915792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1916792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void stop() {
1917e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mCurrentMediaPlayer.reset();
1918792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mIsInitialized = false;
1919792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1920792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
19212b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        /**
19222b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen         * You CANNOT use this player anymore after calling release()
19232b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen         */
19242b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        public void release() {
19252b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            stop();
1926e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mCurrentMediaPlayer.release();
19272b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        }
19282b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
1929792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void pause() {
1930e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mCurrentMediaPlayer.pause();
1931792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1932792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setHandler(Handler handler) {
1934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            mHandler = handler;
1935792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1936792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnCompletionListener listener = new MediaPlayer.OnCompletionListener() {
1938792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public void onCompletion(MediaPlayer mp) {
1939e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                if (mp == mCurrentMediaPlayer && mNextMediaPlayer != null) {
1940e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    mCurrentMediaPlayer.release();
1941e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    mCurrentMediaPlayer = mNextMediaPlayer;
1942e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    mNextMediaPlayer = null;
1943e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    mHandler.sendEmptyMessage(TRACK_WENT_TO_NEXT);
1944e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                } else {
1945e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    // Acquire a temporary wakelock, since when we return from
1946e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    // this callback the MediaPlayer will release its wakelock
1947e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    // and allow the device to go to sleep.
1948e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    // This temporary wakelock is released when the RELEASE_WAKELOCK
1949e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    // message is processed, but just in case, put a timeout on it.
1950e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    mWakeLock.acquire(30000);
1951e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    mHandler.sendEmptyMessage(TRACK_ENDED);
1952e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    mHandler.sendEmptyMessage(RELEASE_WAKELOCK);
1953e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                }
1954792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            }
1955792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1956792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1957792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        MediaPlayer.OnErrorListener errorListener = new MediaPlayer.OnErrorListener() {
1958792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            public boolean onError(MediaPlayer mp, int what, int extra) {
1959792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                switch (what) {
1960792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
1961792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mIsInitialized = false;
1962e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    mCurrentMediaPlayer.release();
1963792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // Creating a new MediaPlayer and settings its wakemode does not
1964792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // require the media service, so it's OK to do this now, while the
1965792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    // service is still being restarted
1966308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                    mCurrentMediaPlayer = new CompatMediaPlayer();
1967e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen                    mCurrentMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK);
1968792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    mHandler.sendMessageDelayed(mHandler.obtainMessage(SERVER_DIED), 2000);
1969792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    return true;
1970792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                default:
1971e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen                    Log.d("MultiPlayer", "Error: " + what + "," + extra);
1972792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                    break;
1973792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                }
1974792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project                return false;
1975792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project           }
1976792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        };
1977792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1978792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long duration() {
1979e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            return mCurrentMediaPlayer.getDuration();
1980792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1981792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1982792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long position() {
1983e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            return mCurrentMediaPlayer.getCurrentPosition();
1984792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1985792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1986792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long seek(long whereto) {
1987e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mCurrentMediaPlayer.seekTo((int) whereto);
1988792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project            return whereto;
1989792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
1990792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
1991792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setVolume(float vol) {
1992e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mCurrentMediaPlayer.setVolume(vol, vol);
1993792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
19941cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent
19951cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        public void setAudioSessionId(int sessionId) {
1996e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            mCurrentMediaPlayer.setAudioSessionId(sessionId);
19971cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        }
19981cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent
19991cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        public int getAudioSessionId() {
2000e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen            return mCurrentMediaPlayer.getAudioSessionId();
20011cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        }
2002792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project    }
2003792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project
2004308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen    static class CompatMediaPlayer extends MediaPlayer implements OnCompletionListener {
2005308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen
2006308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        private boolean mCompatMode = true;
2007308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        private MediaPlayer mNextPlayer;
2008308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        private OnCompletionListener mCompletion;
2009308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen
2010308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        public CompatMediaPlayer() {
2011308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            try {
2012308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                MediaPlayer.class.getMethod("setNextMediaPlayer", MediaPlayer.class);
2013308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                mCompatMode = false;
2014308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            } catch (NoSuchMethodException e) {
2015308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                mCompatMode = true;
2016308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                super.setOnCompletionListener(this);
2017308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            }
2018308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        }
2019308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen
2020308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        public void setNextMediaPlayer(MediaPlayer next) {
2021308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            if (mCompatMode) {
2022308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                mNextPlayer = next;
2023308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            } else {
2024308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                super.setNextMediaPlayer(next);
2025308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            }
2026308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        }
2027308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen
2028308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        @Override
2029308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        public void setOnCompletionListener(OnCompletionListener listener) {
2030308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            if (mCompatMode) {
2031308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                mCompletion = listener;
2032308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            } else {
2033308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                super.setOnCompletionListener(listener);
2034308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            }
2035308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        }
2036308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen
2037308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        @Override
2038308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        public void onCompletion(MediaPlayer mp) {
2039308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            if (mNextPlayer != null) {
2040308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                // as it turns out, starting a new MediaPlayer on the completion
2041308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                // of a previous player ends up slightly overlapping the two
2042308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                // playbacks, so slightly delaying the start of the next player
2043308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                // gives a better user experience
2044308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                SystemClock.sleep(50);
2045308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen                mNextPlayer.start();
2046308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            }
2047308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen            mCompletion.onCompletion(this);
2048308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen        }
2049308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen    }
2050308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen
20512b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    /*
20522b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * By making this a static class with a WeakReference to the Service, we
20532b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * ensure that the Service can be GCd even when the system process still
20542b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     * has a remote reference to the stub.
20552b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen     */
20562b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    static class ServiceStub extends IMediaPlaybackService.Stub {
20572b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        WeakReference<MediaPlaybackService> mService;
20582b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
20592b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        ServiceStub(MediaPlaybackService service) {
20602b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService = new WeakReference<MediaPlaybackService>(service);
20612b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen        }
20622b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen
20638d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen        public void openFile(String path)
2064792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        {
20658d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen            mService.get().open(path);
2066792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2067bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public void open(long [] list, int position) {
20682b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().open(list, position);
2069792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2070792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getQueuePosition() {
20712b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getQueuePosition();
2072792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2073792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setQueuePosition(int index) {
20742b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setQueuePosition(index);
2075792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2076792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public boolean isPlaying() {
20772b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().isPlaying();
2078792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2079792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void stop() {
20802b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().stop();
2081792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2082792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void pause() {
20832b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().pause();
2084792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2085792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void play() {
20862b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().play();
2087792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2088792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void prev() {
20892b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().prev();
2090792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2091792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void next() {
2092bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen            mService.get().gotoNext(true);
2093792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2094792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getTrackName() {
20952b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getTrackName();
2096792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2097792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getAlbumName() {
20982b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAlbumName();
2099792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2100bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getAlbumId() {
21012b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAlbumId();
2102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getArtistName() {
21042b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getArtistName();
2105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2106bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getArtistId() {
21072b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getArtistId();
2108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2109bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public void enqueue(long [] list , int action) {
21102b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().enqueue(list, action);
2111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2112bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long [] getQueue() {
21132b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getQueue();
2114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void moveQueueItem(int from, int to) {
21162b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().moveQueueItem(from, to);
2117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public String getPath() {
21192b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getPath();
2120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2121bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public long getAudioId() {
21222b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getAudioId();
2123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long position() {
21252b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().position();
2126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long duration() {
21282b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().duration();
2129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public long seek(long pos) {
21312b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().seek(pos);
2132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setShuffleMode(int shufflemode) {
21342b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setShuffleMode(shufflemode);
2135792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getShuffleMode() {
21372b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getShuffleMode();
2138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int removeTracks(int first, int last) {
21402b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().removeTracks(first, last);
2141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2142bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen        public int removeTrack(long id) {
21432b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().removeTrack(id);
2144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public void setRepeatMode(int repeatmode) {
21462b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            mService.get().setRepeatMode(repeatmode);
2147792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2148792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getRepeatMode() {
21492b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getRepeatMode();
2150792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
2151792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        public int getMediaMountedCount() {
21522b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen            return mService.get().getMediaMountedCount();
2153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project        }
21541cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        public int getAudioSessionId() {
21551cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent            return mService.get().getAudioSessionId();
21561cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent        }
21572b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    }
21583988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
21593988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    @Override
21603988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
2161bf555cee7a01aed223b05144d1cec0cffdd9a6aeMarco Nelissen        writer.println("" + mPlayListLen + " items in queue, currently at index " + mPlayPos);
21623988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println("Currently loaded:");
21633988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getArtistName());
21643988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getAlbumName());
21653988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getTrackName());
21663988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println(getPath());
21673988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        writer.println("playing: " + mIsSupposedToBePlaying);
2168e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen        writer.println("actual: " + mPlayer.mCurrentMediaPlayer.isPlaying());
2169bf555cee7a01aed223b05144d1cec0cffdd9a6aeMarco Nelissen        writer.println("shuffle mode: " + mShuffleMode);
21703988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen        MusicUtils.debugDump(writer);
21713988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen    }
21723988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen
21732b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen    private final IBinder mBinder = new ServiceStub(this);
2174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project}
2175