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 } 206ea5075144c4f6da8dfd743ba1deb4ec7c59ef1c0kenthin if (mPlayPos >= 0 && mPlayPos < mPlayList.length) { 207ea5075144c4f6da8dfd743ba1deb4ec7c59ef1c0kenthin mCursor = getCursorForId(mPlayList[mPlayPos]); 208ea5075144c4f6da8dfd743ba1deb4ec7c59ef1c0kenthin } 209e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen notifyChange(META_CHANGED); 210e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen updateNotification(); 211e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen setNextTrack(); 212e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen break; 213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project case TRACK_ENDED: 214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mRepeatMode == REPEAT_CURRENT) { 215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project seek(0); 216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 218bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen gotoNext(false); 219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project break; 221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project case RELEASE_WAKELOCK: 222792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mWakeLock.release(); 223792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project break; 2247181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen 2257181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen case FOCUSCHANGE: 2267181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen // This code is here so we can better synchronize it with the code that 2277181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen // handles fade-in 2287181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen switch (msg.arg1) { 2297181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen case AudioManager.AUDIOFOCUS_LOSS: 2307181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS"); 2317181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen if(isPlaying()) { 2327181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mPausedByTransientLossOfFocus = false; 2337181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen } 2347181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen pause(); 2357181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen break; 2367181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 2377bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen mMediaplayerHandler.removeMessages(FADEUP); 2387bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen mMediaplayerHandler.sendEmptyMessage(FADEDOWN); 2397bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen break; 2407bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 2417181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS_TRANSIENT"); 2427181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen if(isPlaying()) { 2437181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mPausedByTransientLossOfFocus = true; 2447181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen } 2457181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen pause(); 2467181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen break; 2477181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen case AudioManager.AUDIOFOCUS_GAIN: 2487181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_GAIN"); 2497181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen if(!isPlaying() && mPausedByTransientLossOfFocus) { 2507181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mPausedByTransientLossOfFocus = false; 2517181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mCurrentVolume = 0f; 2527181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mPlayer.setVolume(mCurrentVolume); 2537181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen play(); // also queues a fade-in 2547181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen } else { 2557bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen mMediaplayerHandler.removeMessages(FADEDOWN); 2567181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mMediaplayerHandler.sendEmptyMessage(FADEUP); 2577181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen } 2587181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen break; 2597181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen default: 2607181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen Log.e(LOGTAG, "Unknown audio focus change code"); 2617181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen } 2627181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen break; 2637181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen 264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project default: 265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project break; 266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 268792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 269792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onReceive(Context context, Intent intent) { 273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String action = intent.getAction(); 274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String cmd = intent.getStringExtra("command"); 2753988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen MusicUtils.debugLog("mIntentReceiver.onReceive " + action + " / " + cmd); 276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) { 277bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen gotoNext(true); 278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) { 279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project prev(); 280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) { 281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (isPlaying()) { 282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project pause(); 283aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 287792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) { 288792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project pause(); 289aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 290fc1c0dc301b5cae2e8c5661e7a217dc57dacac1eMarco Nelissen } else if (CMDPLAY.equals(cmd)) { 291fc1c0dc301b5cae2e8c5661e7a217dc57dacac1eMarco Nelissen play(); 292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (CMDSTOP.equals(cmd)) { 293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project pause(); 294aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project seek(0); 296490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project } else if (MediaAppWidgetProvider.CMDAPPWIDGETUPDATE.equals(cmd)) { 297490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project // Someone asked us to refresh a set of specific widgets, probably 298792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // because they were just added. 299490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); 300490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project mAppWidgetProvider.performUpdate(MediaPlaybackService.this, appWidgetIds); 301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 305085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() { 306f4cfdfd4a99040be44a1ccd74edbde762edc845bJean-Michel Trivi public void onAudioFocusChange(int focusChange) { 3077181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mMediaplayerHandler.obtainMessage(FOCUSCHANGE, focusChange, 0).sendToTarget(); 308085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi } 309085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi }; 310085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi 311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public MediaPlaybackService() { 312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 314792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 315792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onCreate() { 316792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project super.onCreate(); 317085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi 318085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 3198717d3490e179e9591eac98a91a14995d98291adMarco Nelissen ComponentName rec = new ComponentName(getPackageName(), 3208717d3490e179e9591eac98a91a14995d98291adMarco Nelissen MediaButtonIntentReceiver.class.getName()); 3218717d3490e179e9591eac98a91a14995d98291adMarco Nelissen mAudioManager.registerMediaButtonEventReceiver(rec); 3228ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood 3238ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood Intent i = new Intent(Intent.ACTION_MEDIA_BUTTON); 3248ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood i.setComponent(rec); 3258ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood PendingIntent pi = PendingIntent.getBroadcast(this /*context*/, 3268ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood 0 /*requestCode, ignored*/, i /*intent*/, 0 /*flags*/); 3278ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood mRemoteControlClient = new RemoteControlClient(pi); 3288ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood mAudioManager.registerRemoteControlClient(mRemoteControlClient); 3298ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood 3308ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood int flags = RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS 3318ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood | RemoteControlClient.FLAG_KEY_MEDIA_NEXT 3328ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood | RemoteControlClient.FLAG_KEY_MEDIA_PLAY 3338ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE 3348ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE 3358ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood | RemoteControlClient.FLAG_KEY_MEDIA_STOP; 3368ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood mRemoteControlClient.setTransportControlFlags(flags); 337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 338792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPreferences = getSharedPreferences("Music", MODE_WORLD_READABLE | MODE_WORLD_WRITEABLE); 33987bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen mCardId = MusicUtils.getCardId(this); 340792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project registerExternalStorageListener(); 342792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 343792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Needs to be done in this thread, since otherwise ApplicationContext.getPowerManager() crashes. 344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayer = new MultiPlayer(); 345792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayer.setHandler(mMediaplayerHandler); 346792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 347792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project reloadQueue(); 3488717d3490e179e9591eac98a91a14995d98291adMarco Nelissen notifyChange(QUEUE_CHANGED); 3498717d3490e179e9591eac98a91a14995d98291adMarco Nelissen notifyChange(META_CHANGED); 3508717d3490e179e9591eac98a91a14995d98291adMarco Nelissen 351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project IntentFilter commandFilter = new IntentFilter(); 352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project commandFilter.addAction(SERVICECMD); 353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project commandFilter.addAction(TOGGLEPAUSE_ACTION); 354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project commandFilter.addAction(PAUSE_ACTION); 355792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project commandFilter.addAction(NEXT_ACTION); 356792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project commandFilter.addAction(PREVIOUS_ACTION); 357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project registerReceiver(mIntentReceiver, commandFilter); 358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); 360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName()); 361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mWakeLock.setReferenceCounted(false); 362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // If the service was idle, but got killed before it stopped itself, the 364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // system will relaunch it. Make sure it gets stopped again in that case. 365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Message msg = mDelayedStopHandler.obtainMessage(); 366792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY); 367792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 369792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 370792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onDestroy() { 371792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Check that we're not being destroyed while something is still playing. 372792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (isPlaying()) { 373e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen Log.e(LOGTAG, "Service being destroyed while still playing."); 374792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 3752b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen // release all MediaPlayer resources, including the native player and wakelocks 376f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION); 377f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId()); 378f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName()); 379f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen sendBroadcast(i); 3802b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mPlayer.release(); 3812b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mPlayer = null; 382085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi 383085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi mAudioManager.abandonAudioFocus(mAudioFocusListener); 3848ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood mAudioManager.unregisterRemoteControlClient(mRemoteControlClient); 385792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 3862b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen // make sure there aren't any other messages coming 3872b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mDelayedStopHandler.removeCallbacksAndMessages(null); 38849e36ea916aefba042c6e927c771b10708b6891eMarco Nelissen mMediaplayerHandler.removeCallbacksAndMessages(null); 3892b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen 390792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor != null) { 391792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor.close(); 392792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor = null; 393792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 394792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 395792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project unregisterReceiver(mIntentReceiver); 396792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mUnmountReceiver != null) { 397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project unregisterReceiver(mUnmountReceiver); 398792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mUnmountReceiver = null; 399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mWakeLock.release(); 401792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project super.onDestroy(); 402792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private final char hexdigits [] = new char [] { 405792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project '0', '1', '2', '3', 406792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project '4', '5', '6', '7', 407792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project '8', '9', 'a', 'b', 408792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 'c', 'd', 'e', 'f' 409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void saveQueue(boolean full) { 4128d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen if (!mQueueIsSaveable) { 413792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 4158d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen 416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Editor ed = mPreferences.edit(); 417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project //long start = System.currentTimeMillis(); 418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (full) { 419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project StringBuilder q = new StringBuilder(); 420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // The current playlist is saved as a list of "reverse hexadecimal" 422792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // numbers, which we can generate faster than normal decimal or 423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // hexadecimal numbers, which in turn allows us to save the playlist 424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // more often without worrying too much about performance. 425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // (saving the full state takes about 40 ms under no-load conditions 426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // on the phone) 427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int len = mPlayListLen; 428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < len; i++) { 429bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen long n = mPlayList[i]; 430133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen if (n < 0) { 431133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen continue; 432133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen } else if (n == 0) { 433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project q.append("0;"); 434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project while (n != 0) { 436bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen int digit = (int)(n & 0xf); 437133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen n >>>= 4; 438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project q.append(hexdigits[digit]); 439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project q.append(";"); 441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project //Log.i("@@@@ service", "created queue string in " + (System.currentTimeMillis() - start) + " ms"); 444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putString("queue", q.toString()); 445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putInt("cardid", mCardId); 44663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (mShuffleMode != SHUFFLE_NONE) { 44763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen // In shuffle mode we need to save the history too 44863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen len = mHistory.size(); 44963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen q.setLength(0); 45063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen for (int i = 0; i < len; i++) { 45163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen int n = mHistory.get(i); 45263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (n == 0) { 45363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen q.append("0;"); 45463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } else { 45563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen while (n != 0) { 45663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen int digit = (n & 0xf); 457133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen n >>>= 4; 45863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen q.append(hexdigits[digit]); 45963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 46063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen q.append(";"); 46163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 46263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 46363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen ed.putString("history", q.toString()); 46463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putInt("curpos", mPlayPos); 467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayer.isInitialized()) { 468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putLong("seekpos", mPlayer.position()); 469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putInt("repeatmode", mRepeatMode); 471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putInt("shufflemode", mShuffleMode); 47214c3caeb7bc2de0dd7abbb1e5f217dbb6367afbaBrad Fitzpatrick SharedPreferencesCompat.apply(ed); 47314c3caeb7bc2de0dd7abbb1e5f217dbb6367afbaBrad Fitzpatrick 474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project //Log.i("@@@@ service", "saved state in " + (System.currentTimeMillis() - start) + " ms"); 475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void reloadQueue() { 478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String q = null; 479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project boolean newstyle = false; 481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int id = mCardId; 482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPreferences.contains("cardid")) { 483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project newstyle = true; 484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project id = mPreferences.getInt("cardid", ~mCardId); 485792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 486792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (id == mCardId) { 487792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Only restore the saved playlist if the card is still 488792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // the same one as when the playlist was saved 489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project q = mPreferences.getString("queue", ""); 490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 4916c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen int qlen = q != null ? q.length() : 0; 4926c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen if (qlen > 1) { 493792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project //Log.i("@@@@ service", "loaded queue: " + q); 494bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen int plen = 0; 495bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen int n = 0; 496bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen int shift = 0; 497bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen for (int i = 0; i < qlen; i++) { 498bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen char c = q.charAt(i); 499bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen if (c == ';') { 500bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen ensurePlayListCapacity(plen + 1); 501bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen mPlayList[plen] = n; 502bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen plen++; 503bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen n = 0; 504bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen shift = 0; 505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 506bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen if (c >= '0' && c <= '9') { 507bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen n += ((c - '0') << shift); 508bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen } else if (c >= 'a' && c <= 'f') { 509bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen n += ((10 + c - 'a') << shift); 510bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen } else { 511bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen // bogus playlist data 512bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen plen = 0; 513bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen break; 514bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen } 515bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen shift += 4; 516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 518bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen mPlayListLen = plen; 519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int pos = mPreferences.getInt("curpos", 0); 521bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen if (pos < 0 || pos >= mPlayListLen) { 522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // The saved playlist is bogus, discard it 523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen = 0; 524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = pos; 527792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 528792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // When reloadQueue is called in response to a card-insertion, 529792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // we might not be able to query the media provider right away. 530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // To deal with this, try querying for the current file, and if 531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // that fails, wait a while and try again. If that too fails, 532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // assume there is a problem and don't restore the state. 53363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen Cursor crsr = MusicUtils.query(this, 534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project new String [] {"_id"}, "_id=" + mPlayList[mPlayPos] , null, null); 53663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (crsr == null || crsr.getCount() == 0) { 537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // wait a bit and try again 538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project SystemClock.sleep(3000); 53963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen crsr = getContentResolver().query( 540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursorCols, "_id=" + mPlayList[mPlayPos] , null, null); 542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 54363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (crsr != null) { 54463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen crsr.close(); 545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Make sure we don't auto-skip to the next song, since that 548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // also starts playback. What could happen in that case is: 549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // - music is paused 550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // - go to UMS and delete some files, including the currently playing one 551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // - come back from UMS 552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // (time passes) 553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // - music app is killed for some reason (out of memory) 554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // - music service is restarted, service restores state, doesn't find 555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // the "current" file, goes to the next and: playback starts on its 556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // own, potentially at some random inconvenient time. 557792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mOpenFailedCounter = 20; 558792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mQuietMode = true; 559e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 560792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mQuietMode = false; 561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (!mPlayer.isInitialized()) { 562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // couldn't restore the saved state 563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen = 0; 564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project long seekpos = mPreferences.getLong("seekpos", 0); 568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project seek(seekpos >= 0 && seekpos < duration() ? seekpos : 0); 569e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen Log.d(LOGTAG, "restored queue, currently at position " 570e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen + position() + "/" + duration() 571e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen + " (requested " + seekpos + ")"); 572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int repmode = mPreferences.getInt("repeatmode", REPEAT_NONE); 574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (repmode != REPEAT_ALL && repmode != REPEAT_CURRENT) { 575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project repmode = REPEAT_NONE; 576792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mRepeatMode = repmode; 578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int shufmode = mPreferences.getInt("shufflemode", SHUFFLE_NONE); 580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (shufmode != SHUFFLE_AUTO && shufmode != SHUFFLE_NORMAL) { 581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project shufmode = SHUFFLE_NONE; 582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 58363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (shufmode != SHUFFLE_NONE) { 58463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen // in shuffle mode we need to restore the history too 58563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen q = mPreferences.getString("history", ""); 58663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen qlen = q != null ? q.length() : 0; 58763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (qlen > 1) { 58863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen plen = 0; 58963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen n = 0; 59063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen shift = 0; 59163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen mHistory.clear(); 59263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen for (int i = 0; i < qlen; i++) { 59363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen char c = q.charAt(i); 59463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (c == ';') { 59563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (n >= mPlayListLen) { 59663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen // bogus history data 59763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen mHistory.clear(); 59863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen break; 59963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 60063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen mHistory.add(n); 60163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen n = 0; 60263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen shift = 0; 60363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } else { 60463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (c >= '0' && c <= '9') { 60563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen n += ((c - '0') << shift); 60663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } else if (c >= 'a' && c <= 'f') { 60763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen n += ((10 + c - 'a') << shift); 60863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } else { 60963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen // bogus history data 61063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen mHistory.clear(); 61163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen break; 61263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 61363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen shift += 4; 61463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 61563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 61663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 61763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (shufmode == SHUFFLE_AUTO) { 619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (! makeAutoShuffleList()) { 620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project shufmode = SHUFFLE_NONE; 621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mShuffleMode = shufmode; 624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public IBinder onBind(Intent intent) { 629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.removeCallbacksAndMessages(null); 630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mServiceInUse = true; 631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mBinder; 632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onRebind(Intent intent) { 636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.removeCallbacksAndMessages(null); 637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mServiceInUse = true; 638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 641c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen public int onStartCommand(Intent intent, int flags, int startId) { 642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mServiceStartId = startId; 643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.removeCallbacksAndMessages(null); 644c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen 645c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen if (intent != null) { 646c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen String action = intent.getAction(); 647c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen String cmd = intent.getStringExtra("command"); 6483988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen MusicUtils.debugLog("onStartCommand " + action + " / " + cmd); 649c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen 650c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) { 651bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen gotoNext(true); 652c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) { 653b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen if (position() < 2000) { 654b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen prev(); 655b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen } else { 656b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen seek(0); 657b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen play(); 658b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen } 659c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) { 660c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen if (isPlaying()) { 661c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen pause(); 662aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 663c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } else { 664c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen play(); 665c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } 666c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) { 667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project pause(); 668aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 66947dd847ba35375d95c15bc1ee141d638f03ec82eJaikumar Ganesh } else if (CMDPLAY.equals(cmd)) { 67047dd847ba35375d95c15bc1ee141d638f03ec82eJaikumar Ganesh play(); 671c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } else if (CMDSTOP.equals(cmd)) { 672c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen pause(); 673aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 674c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen seek(0); 675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // make sure the service will shut down on its own if it was 679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // just started but not bound to and nothing is playing 680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.removeCallbacksAndMessages(null); 681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Message msg = mDelayedStopHandler.obtainMessage(); 682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY); 683c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen return START_STICKY; 684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public boolean onUnbind(Intent intent) { 688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mServiceInUse = false; 689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Take a snapshot of the current playlist 691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(true); 692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 693aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi if (isPlaying() || mPausedByTransientLossOfFocus) { 694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // something is currently playing, or will be playing once 695aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi // an in-progress action requesting audio focus ends, so don't stop the service now. 696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return true; 697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // If there is a playlist but playback is paused, then wait a while 700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // before stopping the service, so that pause/resume isn't slow. 701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Also delay stopping the service if we're transitioning between tracks. 702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayListLen > 0 || mMediaplayerHandler.hasMessages(TRACK_ENDED)) { 703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Message msg = mDelayedStopHandler.obtainMessage(); 704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY); 705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return true; 706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // No active playlist, OK to stop the service right now 709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stopSelf(mServiceStartId); 710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return true; 711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private Handler mDelayedStopHandler = new Handler() { 714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void handleMessage(Message msg) { 716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Check again to make sure nothing is playing right now 717aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi if (isPlaying() || mPausedByTransientLossOfFocus || mServiceInUse 718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project || mMediaplayerHandler.hasMessages(TRACK_ENDED)) { 719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // save the queue again, because it might have changed 722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // since the user exited the music app (because of 723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // party-shuffle or because the play-position changed) 724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(true); 725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stopSelf(mServiceStartId); 726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 728f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen 729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Called when we receive a ACTION_MEDIA_EJECT notification. 731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * 732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param storagePath path to mount point for the removed media 733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void closeExternalStorageFiles(String storagePath) { 735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // stop playback and clean up if the SD card is going to be unmounted. 736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(true); 737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 738792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 741792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Registers an intent to listen for ACTION_MEDIA_EJECT notifications. 743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * The intent will call closeExternalStorageFiles() if the external media 744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * is going to be ejected, so applications can clean up any files they have open. 745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void registerExternalStorageListener() { 747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mUnmountReceiver == null) { 748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mUnmountReceiver = new BroadcastReceiver() { 749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onReceive(Context context, Intent intent) { 751792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String action = intent.getAction(); 752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (action.equals(Intent.ACTION_MEDIA_EJECT)) { 753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(true); 7548d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen mQueueIsSaveable = false; 755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project closeExternalStorageFiles(intent.getData().getPath()); 756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) { 757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mMediaMountedCount++; 75887bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen mCardId = MusicUtils.getCardId(MediaPlaybackService.this); 759792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project reloadQueue(); 7608d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen mQueueIsSaveable = true; 761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project IntentFilter iFilter = new IntentFilter(); 767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project iFilter.addAction(Intent.ACTION_MEDIA_EJECT); 768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); 769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project iFilter.addDataScheme("file"); 770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project registerReceiver(mUnmountReceiver, iFilter); 771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Notify the change-receivers that something has changed. 776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * The intent that is sent contains the following data 777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * for the currently playing track: 778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "id" - Integer: the database row ID 779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "artist" - String: the name of the artist 780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "album" - String: the name of the album 781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "track" - String: the name of the track 782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * The intent has an action that is one of 783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "com.android.music.metachanged" 784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "com.android.music.queuechanged", 785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "com.android.music.playbackcomplete" 786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "com.android.music.playstatechanged" 787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * respectively indicating that a new track has 788792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * started playing, that the playback queue has 789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * changed, that playback has stopped because 790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * the last file in the list has been played, 791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * or that the play-state changed (paused/resumed). 792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void notifyChange(String what) { 7948717d3490e179e9591eac98a91a14995d98291adMarco Nelissen 795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Intent i = new Intent(what); 796bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen i.putExtra("id", Long.valueOf(getAudioId())); 797792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project i.putExtra("artist", getArtistName()); 798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project i.putExtra("album",getAlbumName()); 799792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project i.putExtra("track", getTrackName()); 8006b507de7beda7f4a8b969b437dfbf81f5ecd5e5eMarco Nelissen i.putExtra("playing", isPlaying()); 8016b507de7beda7f4a8b969b437dfbf81f5ecd5e5eMarco Nelissen sendStickyBroadcast(i); 8028717d3490e179e9591eac98a91a14995d98291adMarco Nelissen 8038717d3490e179e9591eac98a91a14995d98291adMarco Nelissen if (what.equals(PLAYSTATE_CHANGED)) { 8048ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood mRemoteControlClient.setPlaybackState(isPlaying() ? 8058ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood RemoteControlClient.PLAYSTATE_PLAYING : RemoteControlClient.PLAYSTATE_PAUSED); 8068717d3490e179e9591eac98a91a14995d98291adMarco Nelissen } else if (what.equals(META_CHANGED)) { 8078ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood RemoteControlClient.MetadataEditor ed = mRemoteControlClient.editMetadata(true); 8088ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, getTrackName()); 8098ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, getAlbumName()); 8108ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, getArtistName()); 8118ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, duration()); 8128ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood Bitmap b = MusicUtils.getArtwork(this, getAudioId(), getAlbumId(), false); 8138ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood if (b != null) { 8148ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.putBitmap(MetadataEditor.BITMAP_KEY_ARTWORK, b); 8158ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood } 8168ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.apply(); 8178717d3490e179e9591eac98a91a14995d98291adMarco Nelissen } 8188717d3490e179e9591eac98a91a14995d98291adMarco Nelissen 819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (what.equals(QUEUE_CHANGED)) { 820792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(true); 821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(false); 823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 825490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project // Share this notification directly with our widgets 826490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project mAppWidgetProvider.notifyChange(this, what); 827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 829792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void ensurePlayListCapacity(int size) { 830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayList == null || size > mPlayList.length) { 831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // reallocate at 2x requested size so we don't 832792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // need to grow and copy the array for every 833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // insert 834bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen long [] newlist = new long[size * 2]; 835bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen int len = mPlayList != null ? mPlayList.length : mPlayListLen; 836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < len; i++) { 837792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project newlist[i] = mPlayList[i]; 838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList = newlist; 840792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 841792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // FIXME: shrink the array when the needed size is much smaller 842792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // than the allocated size 843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 844792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // insert the list of songs at the specified position in the playlist 846bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen private void addToPlayList(long [] list, int position) { 847792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int addlen = list.length; 848792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (position < 0) { // overwrite 849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen = 0; 850792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project position = 0; 851792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ensurePlayListCapacity(mPlayListLen + addlen); 853792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (position > mPlayListLen) { 854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project position = mPlayListLen; 855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 856792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // move part of list after insertion point 858792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int tailsize = mPlayListLen - position; 859792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = tailsize ; i > 0 ; i--) { 860792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList[position + i] = mPlayList[position + i - addlen]; 861792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 862792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 863792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // copy list into playlist 864792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < addlen; i++) { 865792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList[position + i] = list[i]; 866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 867792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen += addlen; 8683aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen if (mPlayListLen == 0) { 8693aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen mCursor.close(); 8703aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen mCursor = null; 8713aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen notifyChange(META_CHANGED); 8723aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen } 873792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 874792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 875792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 876792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Appends a list of tracks to the current playlist. 877792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * If nothing is playing currently, playback will be started at 878792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * the first track. 879792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * If the action is NOW, playback will switch to the first of 880792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * the new tracks immediately. 881792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param list The list of tracks to append. 882792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param action NOW, NEXT or LAST 883792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 884bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public void enqueue(long [] list, int action) { 885792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized(this) { 886792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (action == NEXT && mPlayPos + 1 < mPlayListLen) { 887792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project addToPlayList(list, mPlayPos + 1); 888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 889792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // action == LAST || action == NOW || mPlayPos + 1 == mPlayListLen 891792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project addToPlayList(list, Integer.MAX_VALUE); 892792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 893792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (action == NOW) { 894792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = mPlayListLen - list.length; 895e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 896792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 897792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 899792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 900792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 901792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos < 0) { 902792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = 0; 903e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 904792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 905792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 906792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 907792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 908792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 910792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 911792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Replaces the current playlist with a new list, 912792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * and prepares for starting playback at the specified 913792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * position in the list, or a random position if the 914792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * specified position is 0. 915792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param list The new list of tracks. 916792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 917bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public void open(long [] list, int position) { 918792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 919792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mShuffleMode == SHUFFLE_AUTO) { 920792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mShuffleMode = SHUFFLE_NORMAL; 921792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 922bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen long oldId = getAudioId(); 923792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int listlength = list.length; 924792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project boolean newlist = true; 925792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayListLen == listlength) { 926792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // possible fast path: list might be the same 927792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project newlist = false; 928792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < listlength; i++) { 929792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (list[i] != mPlayList[i]) { 930792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project newlist = true; 931792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project break; 932792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 935792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (newlist) { 936792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project addToPlayList(list, -1); 937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 938792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 939792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int oldpos = mPlayPos; 940792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (position >= 0) { 941792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = position; 942792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 943792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = mRand.nextInt(mPlayListLen); 944792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 945792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mHistory.clear(); 946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 947792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveBookmarkIfNeeded(); 948e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 949d8c696753687ddb0177f869fad5f709eadfe27afJeffrey Sharkey if (oldId != getAudioId()) { 950792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 951792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 952792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 953792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 954792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 955792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 956792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Moves the item at index1 to index2. 957792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param index1 958792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param index2 959792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 960792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void moveQueueItem(int index1, int index2) { 961792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 962792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (index1 >= mPlayListLen) { 963792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project index1 = mPlayListLen - 1; 964792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 965792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (index2 >= mPlayListLen) { 966792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project index2 = mPlayListLen - 1; 967792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 968792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (index1 < index2) { 969bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen long tmp = mPlayList[index1]; 970792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = index1; i < index2; i++) { 971792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList[i] = mPlayList[i+1]; 972792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 973792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList[index2] = tmp; 974792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos == index1) { 975792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = index2; 976792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (mPlayPos >= index1 && mPlayPos <= index2) { 977792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos--; 978792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 979792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (index2 < index1) { 980bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen long tmp = mPlayList[index1]; 981792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = index1; i > index2; i--) { 982792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList[i] = mPlayList[i-1]; 983792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 984792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList[index2] = tmp; 985792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos == index1) { 986792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = index2; 987792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (mPlayPos >= index2 && mPlayPos <= index1) { 988792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos++; 989792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 990792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 991792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 992792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 993792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 994792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 995792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 996792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Returns the current play list 997792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @return An array of integers containing the IDs of the tracks in the play list 998792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 999bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long [] getQueue() { 1000792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1001792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int len = mPlayListLen; 1002bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen long [] list = new long[len]; 1003792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < len; i++) { 1004792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project list[i] = mPlayList[i]; 1005792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1006792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return list; 1007792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1008792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1009792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1010e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen private Cursor getCursorForId(long lid) { 1011e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen String id = String.valueOf(lid); 1012e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1013e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen Cursor c = getContentResolver().query( 1014e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 1015e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCursorCols, "_id=" + id , null, null); 1016c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen if (c != null) { 1017c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen c.moveToFirst(); 1018c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen } 1019e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return c; 1020e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1021e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1022e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen private void openCurrentAndNext() { 1023792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1024792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor != null) { 1025792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor.close(); 1026792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor = null; 1027792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 10288d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen 1029792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayListLen == 0) { 1030792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 1031792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1032792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(false); 1033792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 103490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mCursor = getCursorForId(mPlayList[mPlayPos]); 1035c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen while(true) { 1036c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen if (mCursor != null && mCursor.getCount() != 0 && 1037c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen open(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + 1038c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen mCursor.getLong(IDCOLIDX))) { 1039c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen break; 1040c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen } 1041c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen // if we get here then opening the file failed. We can close the cursor now, because 1042c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen // we're either going to create a new one next, or stop trying 1043c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen if (mCursor != null) { 1044c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen mCursor.close(); 1045c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen mCursor = null; 10466fb8551aad7f7af3f099dfa286df587a31484000Marco Nelissen } 104790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (mOpenFailedCounter++ < 10 && mPlayListLen > 1) { 104890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen int pos = getNextPosition(false); 104990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (pos < 0) { 105090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen gotoIdleState(); 105190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (mIsSupposedToBePlaying) { 105290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mIsSupposedToBePlaying = false; 105390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen notifyChange(PLAYSTATE_CHANGED); 105490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 105590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return; 105690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 105790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mPlayPos = pos; 105890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen stop(false); 105990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mPlayPos = pos; 106090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mCursor = getCursorForId(mPlayList[mPlayPos]); 106190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } else { 106290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mOpenFailedCounter = 0; 106390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (!mQuietMode) { 106490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen Toast.makeText(this, R.string.playback_failed, Toast.LENGTH_SHORT).show(); 106590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 106690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen Log.d(LOGTAG, "Failed to open file for playback"); 1067c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen gotoIdleState(); 1068c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen if (mIsSupposedToBePlaying) { 1069c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen mIsSupposedToBePlaying = false; 1070c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen notifyChange(PLAYSTATE_CHANGED); 1071c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen } 107290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return; 1073e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1074792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 107590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen 107690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen // go to bookmark if needed 107790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (isPodcast()) { 107890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen long bookmark = getBookmark(); 107990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen // Start playing a little bit before the bookmark, 108090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen // so it's easier to get back in to the narrative. 108190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen seek(bookmark - 5000); 108290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 108390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen setNextTrack(); 1084792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1085792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1086792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1087e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen private void setNextTrack() { 1088e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextPlayPos = getNextPosition(false); 1089e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (mNextPlayPos >= 0) { 1090e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen long id = mPlayList[mNextPlayPos]; 1091e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mPlayer.setNextDataSource(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + id); 10920a7f03fa179055114f63bf4e5b1535aefc65066fJun Tian } else { 10930a7f03fa179055114f63bf4e5b1535aefc65066fJun Tian mPlayer.setNextDataSource(null); 1094e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1095e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1096e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1097792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1098792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Opens the specified file and readies it for playback. 1099792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * 1100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param path The full path of the file to be opened. 1101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 110290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen public boolean open(String path) { 1103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (path == null) { 110590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return false; 1106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // if mCursor is null, try to associate path with a database cursor 1109792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ContentResolver resolver = getContentResolver(); 1112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Uri uri; 1113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String where; 1114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String selectionArgs[]; 1115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (path.startsWith("content://media/")) { 1116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project uri = Uri.parse(path); 1117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project where = null; 1118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project selectionArgs = null; 1119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project uri = MediaStore.Audio.Media.getContentUriForPath(path); 1121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project where = MediaStore.Audio.Media.DATA + "=?"; 1122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project selectionArgs = new String[] { path }; 1123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1124792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project try { 1126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor = resolver.query(uri, mCursorCols, where, selectionArgs, null); 1127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor != null) { 1128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor.getCount() == 0) { 1129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor.close(); 1130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor = null; 1131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor.moveToNext(); 1133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ensurePlayListCapacity(1); 1134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen = 1; 1135bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen mPlayList[0] = mCursor.getLong(IDCOLIDX); 1136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = 0; 1137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } catch (UnsupportedOperationException ex) { 1140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1142792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mFileToPlay = path; 1143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayer.setDataSource(mFileToPlay); 114490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (mPlayer.isInitialized()) { 1145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mOpenFailedCounter = 0; 114690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return true; 1147792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 114890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen stop(true); 114990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return false; 1150792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1151792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1152792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1154792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Starts playback of a previously opened file. 1155792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1156792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void play() { 1157085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi mAudioManager.requestAudioFocus(mAudioFocusListener, AudioManager.STREAM_MUSIC, 1158085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi AudioManager.AUDIOFOCUS_GAIN); 11593d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi mAudioManager.registerMediaButtonEventReceiver(new ComponentName(this.getPackageName(), 11603d22fc22dd66be08df07c86edd533dfe3d06efc1Jean-Michel Trivi MediaButtonIntentReceiver.class.getName())); 1161085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi 1162792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayer.isInitialized()) { 1163272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle // if we are at the end of the song, go to the next song first 11642f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen long duration = mPlayer.duration(); 11652f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen if (mRepeatMode != REPEAT_CURRENT && duration > 2000 && 11662f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen mPlayer.position() >= duration - 2000) { 1167bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen gotoNext(true); 1168272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle } 1169272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle 1170792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayer.start(); 11717181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen // make sure we fade in, in case a previous fadein was stopped because 11727181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen // of another focus loss 11737bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen mMediaplayerHandler.removeMessages(FADEDOWN); 11747181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mMediaplayerHandler.sendEmptyMessage(FADEUP); 1175792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1176e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen updateNotification(); 1177c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen if (!mIsSupposedToBePlaying) { 1178347fe57e4c8a860dfbad6f0ec1991171bfa69d77Mike Cleron mIsSupposedToBePlaying = true; 1179792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(PLAYSTATE_CHANGED); 1180792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1181347fe57e4c8a860dfbad6f0ec1991171bfa69d77Mike Cleron 1182792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (mPlayListLen <= 0) { 1183792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // This is mostly so that if you press 'play' on a bluetooth headset 1184792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // without every having played anything before, it will still play 1185792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // something. 1186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project setShuffleMode(SHUFFLE_AUTO); 1187792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1189e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1190e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen private void updateNotification() { 1191e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen RemoteViews views = new RemoteViews(getPackageName(), R.layout.statusbar); 1192e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen views.setImageViewResource(R.id.icon, R.drawable.stat_notify_musicplayer); 1193e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (getAudioId() < 0) { 1194e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // streaming 1195e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen views.setTextViewText(R.id.trackname, getPath()); 1196e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen views.setTextViewText(R.id.artistalbum, null); 1197e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } else { 1198e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen String artist = getArtistName(); 1199e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen views.setTextViewText(R.id.trackname, getTrackName()); 1200e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (artist == null || artist.equals(MediaStore.UNKNOWN_STRING)) { 1201e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen artist = getString(R.string.unknown_artist_name); 1202e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1203e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen String album = getAlbumName(); 1204e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (album == null || album.equals(MediaStore.UNKNOWN_STRING)) { 1205e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen album = getString(R.string.unknown_album_name); 1206e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1207e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1208e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen views.setTextViewText(R.id.artistalbum, 1209e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen getString(R.string.notification_artist_album, artist, album) 1210e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen ); 1211e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1212e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen Notification status = new Notification(); 1213e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen status.contentView = views; 1214e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen status.flags |= Notification.FLAG_ONGOING_EVENT; 1215e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen status.icon = R.drawable.stat_notify_musicplayer; 1216e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen status.contentIntent = PendingIntent.getActivity(this, 0, 1217e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen new Intent("com.android.music.PLAYBACK_VIEWER") 1218e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0); 1219e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen startForeground(PLAYBACKSERVICE_STATUS, status); 1220e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1221e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1222792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void stop(boolean remove_status_icon) { 1223b1c285c7e2da5492b4224f3e66ea5696b6df5fa8Glenn Kasten if (mPlayer != null && mPlayer.isInitialized()) { 1224792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayer.stop(); 1225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1226792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mFileToPlay = null; 1227792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor != null) { 1228792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor.close(); 1229792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor = null; 1230792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1231792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (remove_status_icon) { 1232792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project gotoIdleState(); 1233d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn } else { 1234d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn stopForeground(false); 1235792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1236792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (remove_status_icon) { 1237c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen mIsSupposedToBePlaying = false; 1238792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1240792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1241792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1242792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Stops playback. 1243792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1244792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void stop() { 1245792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(true); 1246792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1247792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1248792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1249792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Pauses playback (call play() to resume) 1250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void pause() { 1252407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen synchronized(this) { 12537181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mMediaplayerHandler.removeMessages(FADEUP); 1254407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen if (isPlaying()) { 1255407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen mPlayer.pause(); 1256407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen gotoIdleState(); 1257407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen mIsSupposedToBePlaying = false; 1258407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen notifyChange(PLAYSTATE_CHANGED); 1259407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen saveBookmarkIfNeeded(); 1260407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen } 1261792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1264b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen /** Returns whether something is currently playing 1265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * 1266b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen * @return true if something is playing (or will be playing shortly, in case 1267b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen * we're currently transitioning between tracks), false if not. 1268792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1269792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public boolean isPlaying() { 1270c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen return mIsSupposedToBePlaying; 1271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /* 1274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Desired behavior for prev/next/shuffle: 1275792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project - NEXT will move to the next track in the list when not shuffling, and to 1277792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project a track randomly picked from the not-yet-played tracks when shuffling. 1278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project If all tracks have already been played, pick from the full set, but 1279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project avoid picking the previously played track if possible. 1280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project - when shuffling, PREV will go to the previously played track. Hitting PREV 1281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project again will go to the track played before that, etc. When the start of the 1282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project history has been reached, PREV is a no-op. 1283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project When not shuffling, PREV will go to the sequentially previous track (the 1284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project difference with the shuffle-case is mainly that when not shuffling, the 1285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project user can back up to tracks that are not in the history). 1286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1287792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Example: 1288792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project When playing an album with 10 tracks from the start, and enabling shuffle 1289792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project while playing track 5, the remaining tracks (6-10) will be shuffled, e.g. 1290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project the final play order might be 1-2-3-4-5-8-10-6-9-7. 1291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project When hitting 'prev' 8 times while playing track 7 in this example, the 1292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project user will go to tracks 9-6-10-8-5-4-3-2. If the user then hits 'next', 1293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project a random track will be picked again. If at any time user disables shuffling 1294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project the next/previous track will be picked in sequential order again. 1295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1297792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void prev() { 1298792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mShuffleMode == SHUFFLE_NORMAL) { 1300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // go to previously-played track and remove it from the history 1301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int histsize = mHistory.size(); 1302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (histsize == 0) { 1303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // prev is a no-op 1304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 1305792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1306792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Integer pos = mHistory.remove(histsize - 1); 1307792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = pos.intValue(); 1308792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1309792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos > 0) { 1310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos--; 1311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = mPlayListLen - 1; 1313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1314792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1315792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveBookmarkIfNeeded(); 1316792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(false); 1317e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 1318792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 1319792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 1320792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1321792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1322792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1323bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen /** 1324bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen * Get the next position to play. Note that this may actually modify mPlayPos 1325bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen * if playback is in SHUFFLE_AUTO mode and the shuffle list window needed to 1326bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen * be adjusted. Either way, the return value is the next value that should be 1327bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen * assigned to mPlayPos; 1328bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen */ 1329bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen private int getNextPosition(boolean force) { 1330e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (mRepeatMode == REPEAT_CURRENT) { 1331e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (mPlayPos < 0) return 0; 1332e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return mPlayPos; 1333e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } else if (mShuffleMode == SHUFFLE_NORMAL) { 1334bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // Pick random next track from the not-yet-played ones 1335bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // TODO: make it work right after adding/removing items in the queue. 1336663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen 1337bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // Store the current file in the history, but keep the history at a 1338bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // reasonable size 1339bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mPlayPos >= 0) { 1340bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen mHistory.add(mPlayPos); 1341bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1342bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mHistory.size() > MAX_HISTORY_SIZE) { 1343bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen mHistory.removeElementAt(0); 1344bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1345792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1346bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int numTracks = mPlayListLen; 1347bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int[] tracks = new int[numTracks]; 1348bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen for (int i=0;i < numTracks; i++) { 1349bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen tracks[i] = i; 1350bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 13513f502de8e8963224054a97730d132f82ac87d522Marco Nelissen 1352bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int numHistory = mHistory.size(); 1353bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int numUnplayed = numTracks; 1354bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen for (int i=0;i < numHistory; i++) { 1355bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int idx = mHistory.get(i).intValue(); 1356bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (idx < numTracks && tracks[idx] >= 0) { 1357bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen numUnplayed--; 1358bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen tracks[idx] = -1; 1359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1360bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1362bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // 'numUnplayed' now indicates how many tracks have not yet 1363bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // been played, and 'tracks' contains the indices of those 1364bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // tracks. 1365bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (numUnplayed <=0) { 1366bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // everything's already been played 1367bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mRepeatMode == REPEAT_ALL || force) { 1368bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen //pick from full set 1369bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen numUnplayed = numTracks; 1370bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen for (int i=0;i < numTracks; i++) { 1371bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen tracks[i] = i; 1372792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1373bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } else { 1374bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // all done 1375bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return -1; 1376792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1377bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1378bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int skip = mRand.nextInt(numUnplayed); 1379bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int cnt = -1; 1380bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen while (true) { 1381bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen while (tracks[++cnt] < 0) 1382bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen ; 1383bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen skip--; 1384bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (skip < 0) { 1385bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen break; 1386792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1387bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1388bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return cnt; 1389bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } else if (mShuffleMode == SHUFFLE_AUTO) { 1390bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen doAutoShuffleUpdate(); 1391bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return mPlayPos + 1; 1392bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } else { 1393bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mPlayPos >= mPlayListLen - 1) { 1394bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // we're at the end of the list 1395bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mRepeatMode == REPEAT_NONE && !force) { 1396bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // all done 1397bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return -1; 1398bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } else if (mRepeatMode == REPEAT_ALL || force) { 1399bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return 0; 1400792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1401bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return -1; 1402792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1403bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return mPlayPos + 1; 1404bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1405bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1406bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1407bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen 1408bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen public void gotoNext(boolean force) { 1409bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen synchronized (this) { 1410bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mPlayListLen <= 0) { 1411bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen Log.d(LOGTAG, "No play queue"); 1412bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return; 1413bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1414bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen 1415bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int pos = getNextPosition(force); 1416bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (pos < 0) { 1417bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen gotoIdleState(); 1418bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mIsSupposedToBePlaying) { 1419bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen mIsSupposedToBePlaying = false; 1420bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen notifyChange(PLAYSTATE_CHANGED); 1421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1422bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return; 1423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1424bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen mPlayPos = pos; 1425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveBookmarkIfNeeded(); 1426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(false); 1427e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mPlayPos = pos; 1428e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 1429792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 1430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 1431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void gotoIdleState() { 1435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.removeCallbacksAndMessages(null); 1436792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Message msg = mDelayedStopHandler.obtainMessage(); 1437792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY); 1438d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn stopForeground(true); 1439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void saveBookmarkIfNeeded() { 1442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project try { 1443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (isPodcast()) { 1444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project long pos = position(); 1445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project long bookmark = getBookmark(); 1446792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project long duration = duration(); 1447792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if ((pos < bookmark && (pos + 10000) > bookmark) || 1448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project (pos > bookmark && (pos - 10000) < bookmark)) { 1449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // The existing bookmark is close to the current 1450792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // position, so don't update it. 1451792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 1452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1453792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (pos < 15000 || (pos + 10000) > duration) { 1454792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // if we're near the start or end, clear the bookmark 1455792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project pos = 0; 1456792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1457792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1458792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // write 'pos' to the bookmark field 1459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ContentValues values = new ContentValues(); 1460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project values.put(MediaStore.Audio.Media.BOOKMARK, pos); 1461792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Uri uri = ContentUris.withAppendedId( 1462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursor.getLong(IDCOLIDX)); 1463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project getContentResolver().update(uri, values, null, null); 1464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } catch (SQLiteException ex) { 1466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Make sure there are at least 5 items after the currently playing item 1470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // and no more than 10 items before. 1471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void doAutoShuffleUpdate() { 1472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project boolean notify = false; 14733f502de8e8963224054a97730d132f82ac87d522Marco Nelissen 1474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // remove old entries 1475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos > 10) { 1476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project removeTracks(0, mPlayPos - 9); 1477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notify = true; 1478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // add new entries if needed 1480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int to_add = 7 - (mPlayListLen - (mPlayPos < 0 ? -1 : mPlayPos)); 1481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < to_add; i++) { 1482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // pick something at random from the list 14833f502de8e8963224054a97730d132f82ac87d522Marco Nelissen 14843f502de8e8963224054a97730d132f82ac87d522Marco Nelissen int lookback = mHistory.size(); 14853f502de8e8963224054a97730d132f82ac87d522Marco Nelissen int idx = -1; 14863f502de8e8963224054a97730d132f82ac87d522Marco Nelissen while(true) { 14873f502de8e8963224054a97730d132f82ac87d522Marco Nelissen idx = mRand.nextInt(mAutoShuffleList.length); 14883f502de8e8963224054a97730d132f82ac87d522Marco Nelissen if (!wasRecentlyUsed(idx, lookback)) { 14893f502de8e8963224054a97730d132f82ac87d522Marco Nelissen break; 14903f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 14913f502de8e8963224054a97730d132f82ac87d522Marco Nelissen lookback /= 2; 14923f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 14933f502de8e8963224054a97730d132f82ac87d522Marco Nelissen mHistory.add(idx); 14943f502de8e8963224054a97730d132f82ac87d522Marco Nelissen if (mHistory.size() > MAX_HISTORY_SIZE) { 14953f502de8e8963224054a97730d132f82ac87d522Marco Nelissen mHistory.remove(0); 14963f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 1497792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ensurePlayListCapacity(mPlayListLen + 1); 14983f502de8e8963224054a97730d132f82ac87d522Marco Nelissen mPlayList[mPlayListLen++] = mAutoShuffleList[idx]; 1499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notify = true; 1500792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1501792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (notify) { 1502792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 1503792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1504792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1505792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 15063f502de8e8963224054a97730d132f82ac87d522Marco Nelissen // check that the specified idx is not in the history (but only look at at 15073f502de8e8963224054a97730d132f82ac87d522Marco Nelissen // most lookbacksize entries in the history) 15083f502de8e8963224054a97730d132f82ac87d522Marco Nelissen private boolean wasRecentlyUsed(int idx, int lookbacksize) { 15093f502de8e8963224054a97730d132f82ac87d522Marco Nelissen 15103f502de8e8963224054a97730d132f82ac87d522Marco Nelissen // early exit to prevent infinite loops in case idx == mPlayPos 15113f502de8e8963224054a97730d132f82ac87d522Marco Nelissen if (lookbacksize == 0) { 15123f502de8e8963224054a97730d132f82ac87d522Marco Nelissen return false; 15133f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 15143f502de8e8963224054a97730d132f82ac87d522Marco Nelissen 15153f502de8e8963224054a97730d132f82ac87d522Marco Nelissen int histsize = mHistory.size(); 15163f502de8e8963224054a97730d132f82ac87d522Marco Nelissen if (histsize < lookbacksize) { 15173f502de8e8963224054a97730d132f82ac87d522Marco Nelissen Log.d(LOGTAG, "lookback too big"); 15183f502de8e8963224054a97730d132f82ac87d522Marco Nelissen lookbacksize = histsize; 15193f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 15203f502de8e8963224054a97730d132f82ac87d522Marco Nelissen int maxidx = histsize - 1; 15213f502de8e8963224054a97730d132f82ac87d522Marco Nelissen for (int i = 0; i < lookbacksize; i++) { 15223f502de8e8963224054a97730d132f82ac87d522Marco Nelissen long entry = mHistory.get(maxidx - i); 15233f502de8e8963224054a97730d132f82ac87d522Marco Nelissen if (entry == idx) { 15243f502de8e8963224054a97730d132f82ac87d522Marco Nelissen return true; 15253f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 15263f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 15273f502de8e8963224054a97730d132f82ac87d522Marco Nelissen return false; 15283f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 15293f502de8e8963224054a97730d132f82ac87d522Marco Nelissen 1530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // A simple variation of Random that makes sure that the 1531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // value it returns is not equal to the value it returned 1532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // previously, unless the interval is 1. 1533756c3f57f11a7bb3bf1cf1333ee8ffbc51039748Marco Nelissen private static class Shuffler { 1534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int mPrevious; 1535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private Random mRandom = new Random(); 1536792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int nextInt(int interval) { 1537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int ret; 1538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project do { 1539792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ret = mRandom.nextInt(interval); 1540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } while (ret == mPrevious && interval > 1); 1541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPrevious = ret; 1542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return ret; 1543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 1545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private boolean makeAutoShuffleList() { 1547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ContentResolver res = getContentResolver(); 1548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Cursor c = null; 1549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project try { 1550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project c = res.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 1551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project new String[] {MediaStore.Audio.Media._ID}, MediaStore.Audio.Media.IS_MUSIC + "=1", 1552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project null, null); 1553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (c == null || c.getCount() == 0) { 1554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return false; 1555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int len = c.getCount(); 1557bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen long [] list = new long[len]; 1558792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < len; i++) { 1559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project c.moveToNext(); 1560bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen list[i] = c.getLong(0); 1561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mAutoShuffleList = list; 1563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return true; 1564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } catch (RuntimeException ex) { 1565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } finally { 1566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (c != null) { 1567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project c.close(); 1568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return false; 1571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Removes the range of tracks specified from the play list. If a file within the range is 1575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * the file currently being played, playback will move to the next file after the 1576792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * range. 1577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param first The first file to be removed 1578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param last The last file to be removed 1579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @return the number of tracks deleted 1580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int removeTracks(int first, int last) { 1582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int numremoved = removeTracksInternal(first, last); 1583792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (numremoved > 0) { 1584792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 1585792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1586792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return numremoved; 1587792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1588792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1589792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int removeTracksInternal(int first, int last) { 1590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1591792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (last < first) return 0; 1592792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (first < 0) first = 0; 1593792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (last >= mPlayListLen) last = mPlayListLen - 1; 1594792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1595792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project boolean gotonext = false; 1596792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (first <= mPlayPos && mPlayPos <= last) { 1597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = first; 1598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project gotonext = true; 1599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (mPlayPos > last) { 1600792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos -= (last - first + 1); 1601792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1602792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int num = mPlayListLen - last - 1; 1603792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < num; i++) { 1604792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList[first + i] = mPlayList[last + 1 + i]; 1605792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1606792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen -= last - first + 1; 1607792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1608792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (gotonext) { 1609792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayListLen == 0) { 1610792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(true); 1611792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = -1; 16123aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen if (mCursor != null) { 16133aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen mCursor.close(); 16143aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen mCursor = null; 16153aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen } 1616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1617792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos >= mPlayListLen) { 1618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = 0; 1619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project boolean wasPlaying = isPlaying(); 1621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(false); 1622e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 1623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (wasPlaying) { 1624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 1625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 16273aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen notifyChange(META_CHANGED); 1628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return last - first + 1; 1630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Removes all instances of the track with the given id 1635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * from the playlist. 1636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param id The id to be removed 1637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @return how many instances of the track were removed 1638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1639bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public int removeTrack(long id) { 1640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int numremoved = 0; 1641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1642792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < mPlayListLen; i++) { 1643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayList[i] == id) { 1644792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project numremoved += removeTracksInternal(i, i); 1645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project i--; 1646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (numremoved > 0) { 1650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 1651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1652792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return numremoved; 1653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1654792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1655792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setShuffleMode(int shufflemode) { 1656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized(this) { 1657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mShuffleMode == shufflemode && mPlayListLen > 0) { 1658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 1659792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mShuffleMode = shufflemode; 1661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mShuffleMode == SHUFFLE_AUTO) { 1662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (makeAutoShuffleList()) { 1663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen = 0; 1664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project doAutoShuffleUpdate(); 1665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = 0; 1666e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 1667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 1668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 1669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 1670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // failed to build a list of files to shuffle 1672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mShuffleMode = SHUFFLE_NONE; 1673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(false); 1676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getShuffleMode() { 1679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mShuffleMode; 1680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setRepeatMode(int repeatmode) { 1683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized(this) { 1684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mRepeatMode = repeatmode; 1685e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen setNextTrack(); 1686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(false); 1687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getRepeatMode() { 1690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mRepeatMode; 1691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getMediaMountedCount() { 1694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mMediaMountedCount; 1695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Returns the path of the currently playing file, or null if 1699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * no file is currently playing. 1700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getPath() { 1702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mFileToPlay; 1703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Returns the rowid of the currently playing file, or -1 if 1707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * no file is currently playing. 1708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1709bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getAudioId() { 1710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos >= 0 && mPlayer.isInitialized()) { 1712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mPlayList[mPlayPos]; 1713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Returns the position in the queue 1720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @return the position in the queue 1721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getQueuePosition() { 1723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized(this) { 1724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mPlayPos; 1725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1728792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Starts playing the track at the given position in the queue. 1730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param pos The position in the queue of the track that will be played. 1731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setQueuePosition(int pos) { 1733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized(this) { 1734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(false); 1735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = pos; 1736e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 1737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 1738792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 1739ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen if (mShuffleMode == SHUFFLE_AUTO) { 1740ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen doAutoShuffleUpdate(); 1741ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen } 1742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getArtistName() { 1746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized(this) { 1747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return null; 1749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)); 1751792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1754bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getArtistId() { 1755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1759bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID)); 1760792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getAlbumName() { 1764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return null; 1767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM)); 1769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1772bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getAlbumId() { 1773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1777bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID)); 1778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getTrackName() { 1782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return null; 1785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1786792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)); 1787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1788792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private boolean isPodcast() { 1791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return false; 1794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1795792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return (mCursor.getInt(PODCASTCOLIDX) > 0); 1796792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1797792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1799792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private long getBookmark() { 1800792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1801792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1802792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return 0; 1803792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1804792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mCursor.getLong(BOOKMARKCOLIDX); 1805792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1808792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1809792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Returns the duration of the file in milliseconds. 1810792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Currently this method returns -1 for the duration of MIDI files. 1811792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1812792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long duration() { 1813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayer.isInitialized()) { 1814792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mPlayer.duration(); 1815792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1817792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1820792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Returns the current playback position in milliseconds 1821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long position() { 1823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayer.isInitialized()) { 1824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mPlayer.position(); 1825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1826792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1829792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Seeks to the position specified. 1831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * 1832792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param pos The position to seek to, in milliseconds 1833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long seek(long pos) { 1835792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayer.isInitialized()) { 1836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (pos < 0) pos = 0; 1837792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (pos > mPlayer.duration()) pos = mPlayer.duration(); 1838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mPlayer.seek(pos); 1839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1840792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1841792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1842792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 18441cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent * Sets the audio session ID. 18451cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent * 18461cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent * @param sessionId: the audio session ID. 18471cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent */ 18481cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent public void setAudioSessionId(int sessionId) { 18491cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent synchronized (this) { 18501cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent mPlayer.setAudioSessionId(sessionId); 18511cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 18521cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 18531cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent 18541cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent /** 18551cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent * Returns the audio session ID. 18561cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent */ 18571cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent public int getAudioSessionId() { 18581cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent synchronized (this) { 18591cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent return mPlayer.getAudioSessionId(); 18601cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 18611cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 18621cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent 18631cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent /** 1864792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Provides a unified interface for dealing with midi files and 1865792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * other media files. 1866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1867792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private class MultiPlayer { 1868308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen private CompatMediaPlayer mCurrentMediaPlayer = new CompatMediaPlayer(); 1869308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen private CompatMediaPlayer mNextMediaPlayer; 1870792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private Handler mHandler; 1871792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private boolean mIsInitialized = false; 1872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1873792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public MultiPlayer() { 1874e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK); 1875792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1876792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1877792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setDataSource(String path) { 187890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path); 187990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (mIsInitialized) { 188090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen setNextDataSource(null); 188190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 1882e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1883e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 188490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen private boolean setDataSourceImpl(MediaPlayer player, String path) { 1885792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project try { 1886e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.reset(); 1887e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setOnPreparedListener(null); 1888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (path.startsWith("content://")) { 1889e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setDataSource(MediaPlaybackService.this, Uri.parse(path)); 1890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1891e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setDataSource(path); 1892792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1893e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setAudioStreamType(AudioManager.STREAM_MUSIC); 1894e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.prepare(); 1895792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } catch (IOException ex) { 1896792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // TODO: notify the user why the file couldn't be opened 189790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return false; 1898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } catch (IllegalArgumentException ex) { 1899792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // TODO: notify the user why the file couldn't be opened 190090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return false; 1901792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1902e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setOnCompletionListener(listener); 1903e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setOnErrorListener(errorListener); 1904f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen Intent i = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION); 1905f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId()); 1906f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName()); 1907f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen sendBroadcast(i); 190890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return true; 1909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1910e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1911e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen public void setNextDataSource(String path) { 1912e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.setNextMediaPlayer(null); 1913e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (mNextMediaPlayer != null) { 1914e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextMediaPlayer.release(); 1915e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextMediaPlayer = null; 1916e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1917e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (path == null) { 1918e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return; 1919e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1920308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mNextMediaPlayer = new CompatMediaPlayer(); 1921e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK); 1922e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextMediaPlayer.setAudioSessionId(getAudioSessionId()); 192390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (setDataSourceImpl(mNextMediaPlayer, path)) { 192490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer); 192590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } else { 192690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen // failed to open next, we'll transition the old fashioned way, 192790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen // which will skip over the faulty file 192890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mNextMediaPlayer.release(); 192990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mNextMediaPlayer = null; 193090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 1931e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1932792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public boolean isInitialized() { 1934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mIsInitialized; 1935792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1936792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void start() { 19383988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen MusicUtils.debugLog(new Exception("MultiPlayer.start called")); 1939e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.start(); 1940792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1941792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1942792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void stop() { 1943e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.reset(); 1944792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mIsInitialized = false; 1945792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 19472b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen /** 19482b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen * You CANNOT use this player anymore after calling release() 19492b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen */ 19502b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen public void release() { 19512b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen stop(); 1952e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.release(); 19532b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen } 19542b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen 1955792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void pause() { 1956e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.pause(); 1957792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1958792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1959792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setHandler(Handler handler) { 1960792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mHandler = handler; 1961792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1962792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1963792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project MediaPlayer.OnCompletionListener listener = new MediaPlayer.OnCompletionListener() { 1964792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onCompletion(MediaPlayer mp) { 1965e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (mp == mCurrentMediaPlayer && mNextMediaPlayer != null) { 1966e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.release(); 1967e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer = mNextMediaPlayer; 1968e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextMediaPlayer = null; 1969e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mHandler.sendEmptyMessage(TRACK_WENT_TO_NEXT); 1970e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } else { 1971e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // Acquire a temporary wakelock, since when we return from 1972e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // this callback the MediaPlayer will release its wakelock 1973e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // and allow the device to go to sleep. 1974e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // This temporary wakelock is released when the RELEASE_WAKELOCK 1975e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // message is processed, but just in case, put a timeout on it. 1976e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mWakeLock.acquire(30000); 1977e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mHandler.sendEmptyMessage(TRACK_ENDED); 1978e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mHandler.sendEmptyMessage(RELEASE_WAKELOCK); 1979e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1980792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1981792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 1982792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1983792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project MediaPlayer.OnErrorListener errorListener = new MediaPlayer.OnErrorListener() { 1984792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public boolean onError(MediaPlayer mp, int what, int extra) { 1985792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project switch (what) { 1986792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project case MediaPlayer.MEDIA_ERROR_SERVER_DIED: 1987792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mIsInitialized = false; 1988e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.release(); 1989792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Creating a new MediaPlayer and settings its wakemode does not 1990792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // require the media service, so it's OK to do this now, while the 1991792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // service is still being restarted 1992308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mCurrentMediaPlayer = new CompatMediaPlayer(); 1993e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK); 1994792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mHandler.sendMessageDelayed(mHandler.obtainMessage(SERVER_DIED), 2000); 1995792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return true; 1996792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project default: 1997e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen Log.d("MultiPlayer", "Error: " + what + "," + extra); 1998792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project break; 1999792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2000792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return false; 2001792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2002792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 2003792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 2004792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long duration() { 2005e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return mCurrentMediaPlayer.getDuration(); 2006792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2007792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 2008792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long position() { 2009e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return mCurrentMediaPlayer.getCurrentPosition(); 2010792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2011792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 2012792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long seek(long whereto) { 2013e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.seekTo((int) whereto); 2014792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return whereto; 2015792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2016792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 2017792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setVolume(float vol) { 2018e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.setVolume(vol, vol); 2019792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 20201cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent 20211cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent public void setAudioSessionId(int sessionId) { 2022e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.setAudioSessionId(sessionId); 20231cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 20241cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent 20251cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent public int getAudioSessionId() { 2026e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return mCurrentMediaPlayer.getAudioSessionId(); 20271cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 2028792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2029792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 2030308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen static class CompatMediaPlayer extends MediaPlayer implements OnCompletionListener { 2031308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen 2032308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen private boolean mCompatMode = true; 2033308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen private MediaPlayer mNextPlayer; 2034308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen private OnCompletionListener mCompletion; 2035308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen 2036308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen public CompatMediaPlayer() { 2037308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen try { 2038308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen MediaPlayer.class.getMethod("setNextMediaPlayer", MediaPlayer.class); 2039308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mCompatMode = false; 2040308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } catch (NoSuchMethodException e) { 2041308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mCompatMode = true; 2042308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen super.setOnCompletionListener(this); 2043308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2044308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2045308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen 2046308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen public void setNextMediaPlayer(MediaPlayer next) { 2047308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen if (mCompatMode) { 2048308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mNextPlayer = next; 2049308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } else { 2050308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen super.setNextMediaPlayer(next); 2051308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2052308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2053308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen 2054308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen @Override 2055308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen public void setOnCompletionListener(OnCompletionListener listener) { 2056308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen if (mCompatMode) { 2057308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mCompletion = listener; 2058308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } else { 2059308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen super.setOnCompletionListener(listener); 2060308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2061308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2062308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen 2063308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen @Override 2064308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen public void onCompletion(MediaPlayer mp) { 2065308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen if (mNextPlayer != null) { 2066308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen // as it turns out, starting a new MediaPlayer on the completion 2067308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen // of a previous player ends up slightly overlapping the two 2068308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen // playbacks, so slightly delaying the start of the next player 2069308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen // gives a better user experience 2070308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen SystemClock.sleep(50); 2071308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mNextPlayer.start(); 2072308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2073308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mCompletion.onCompletion(this); 2074308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2075308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2076308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen 20772b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen /* 20782b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen * By making this a static class with a WeakReference to the Service, we 20792b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen * ensure that the Service can be GCd even when the system process still 20802b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen * has a remote reference to the stub. 20812b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen */ 20822b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen static class ServiceStub extends IMediaPlaybackService.Stub { 20832b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen WeakReference<MediaPlaybackService> mService; 20842b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen 20852b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen ServiceStub(MediaPlaybackService service) { 20862b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService = new WeakReference<MediaPlaybackService>(service); 20872b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen } 20882b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen 20898d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen public void openFile(String path) 2090792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project { 20918d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen mService.get().open(path); 2092792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2093bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public void open(long [] list, int position) { 20942b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().open(list, position); 2095792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2096792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getQueuePosition() { 20972b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getQueuePosition(); 2098792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2099792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setQueuePosition(int index) { 21002b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().setQueuePosition(index); 2101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public boolean isPlaying() { 21032b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().isPlaying(); 2104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void stop() { 21062b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().stop(); 2107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void pause() { 21092b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().pause(); 2110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void play() { 21122b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().play(); 2113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void prev() { 21152b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().prev(); 2116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void next() { 2118bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen mService.get().gotoNext(true); 2119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getTrackName() { 21212b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getTrackName(); 2122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getAlbumName() { 21242b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getAlbumName(); 2125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2126bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getAlbumId() { 21272b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getAlbumId(); 2128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getArtistName() { 21302b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getArtistName(); 2131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2132bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getArtistId() { 21332b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getArtistId(); 2134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2135bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public void enqueue(long [] list , int action) { 21362b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().enqueue(list, action); 2137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2138bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long [] getQueue() { 21392b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getQueue(); 2140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void moveQueueItem(int from, int to) { 21422b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().moveQueueItem(from, to); 2143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getPath() { 21452b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getPath(); 2146792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2147bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getAudioId() { 21482b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getAudioId(); 2149792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2150792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long position() { 21512b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().position(); 2152792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long duration() { 21542b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().duration(); 2155792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2156792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long seek(long pos) { 21572b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().seek(pos); 2158792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setShuffleMode(int shufflemode) { 21602b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().setShuffleMode(shufflemode); 2161792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2162792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getShuffleMode() { 21632b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getShuffleMode(); 2164792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2165792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int removeTracks(int first, int last) { 21662b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().removeTracks(first, last); 2167792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2168bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public int removeTrack(long id) { 21692b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().removeTrack(id); 2170792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2171792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setRepeatMode(int repeatmode) { 21722b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().setRepeatMode(repeatmode); 2173792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getRepeatMode() { 21752b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getRepeatMode(); 2176792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2177792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getMediaMountedCount() { 21782b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getMediaMountedCount(); 2179792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 21801cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent public int getAudioSessionId() { 21811cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent return mService.get().getAudioSessionId(); 21821cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 21832b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen } 21843988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen 21853988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen @Override 21863988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 2187bf555cee7a01aed223b05144d1cec0cffdd9a6aeMarco Nelissen writer.println("" + mPlayListLen + " items in queue, currently at index " + mPlayPos); 21883988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println("Currently loaded:"); 21893988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println(getArtistName()); 21903988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println(getAlbumName()); 21913988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println(getTrackName()); 21923988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println(getPath()); 21933988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println("playing: " + mIsSupposedToBePlaying); 2194e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen writer.println("actual: " + mPlayer.mCurrentMediaPlayer.isPlaying()); 2195bf555cee7a01aed223b05144d1cec0cffdd9a6aeMarco Nelissen writer.println("shuffle mode: " + mShuffleMode); 21963988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen MusicUtils.debugDump(writer); 21973988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen } 21983988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen 21992b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen private final IBinder mBinder = new ServiceStub(this); 2200792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project} 2201