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; 76b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 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; 80b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 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 98b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He public static final String TOGGLEPAUSE_ACTION = 99b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He "com.android.music.musicservicecommand.togglepause"; 100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public static final String PAUSE_ACTION = "com.android.music.musicservicecommand.pause"; 101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public static final String PREVIOUS_ACTION = "com.android.music.musicservicecommand.previous"; 102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public static final String NEXT_ACTION = "com.android.music.musicservicecommand.next"; 103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private static final int TRACK_ENDED = 1; 105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private static final int RELEASE_WAKELOCK = 2; 106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private static final int SERVER_DIED = 3; 1077181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen private static final int FOCUSCHANGE = 4; 1082da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen private static final int FADEDOWN = 5; 1092da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen private static final int FADEUP = 6; 110e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen private static final int TRACK_WENT_TO_NEXT = 7; 1113ec2ad9c8758d300864be808e491ae933dc9cd6bMarco Nelissen private static final int MAX_HISTORY_SIZE = 100; 112b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private MultiPlayer mPlayer; 114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private String mFileToPlay; 115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int mShuffleMode = SHUFFLE_NONE; 116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int mRepeatMode = REPEAT_NONE; 117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int mMediaMountedCount = 0; 118b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He private long[] mAutoShuffleList = null; 119b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He private long[] mPlayList = null; 120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int mPlayListLen = 0; 121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private Vector<Integer> mHistory = new Vector<Integer>(MAX_HISTORY_SIZE); 122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private Cursor mCursor; 123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int mPlayPos = -1; 124e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen private int mNextPlayPos = -1; 125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private static final String LOGTAG = "MediaPlaybackService"; 126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private final Shuffler mRand = new Shuffler(); 127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int mOpenFailedCounter = 0; 128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String[] mCursorCols = new String[] { 129b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He "audio._id AS _id", // index must match IDCOLIDX below 130b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM, 131b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA, 132b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.ALBUM_ID, 133792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project MediaStore.Audio.Media.ARTIST_ID, 134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project MediaStore.Audio.Media.IS_PODCAST, // index must match PODCASTCOLIDX below 135b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He MediaStore.Audio.Media.BOOKMARK // index must match BOOKMARKCOLIDX below 136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private final static int IDCOLIDX = 0; 138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private final static int PODCASTCOLIDX = 8; 139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private final static int BOOKMARKCOLIDX = 9; 140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private BroadcastReceiver mUnmountReceiver = null; 141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private WakeLock mWakeLock; 142792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int mServiceStartId = -1; 143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private boolean mServiceInUse = false; 144c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen private boolean mIsSupposedToBePlaying = false; 145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private boolean mQuietMode = false; 146085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi private AudioManager mAudioManager; 1478d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen private boolean mQueueIsSaveable = true; 148085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi // used to track what type of audio focus loss caused the playback to pause 149085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi private boolean mPausedByTransientLossOfFocus = false; 150085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi 151792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private SharedPreferences mPreferences; 152792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // We use this to distinguish between different cards when saving/restoring playlists. 153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // This will have to change if we want to support multiple simultaneous cards. 154792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int mCardId; 155b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 156490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project private MediaAppWidgetProvider mAppWidgetProvider = MediaAppWidgetProvider.getInstance(); 157b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 158792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // interval after which we stop the service when idle 159aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi private static final int IDLE_DELAY = 60000; 1608717d3490e179e9591eac98a91a14995d98291adMarco Nelissen 1618717d3490e179e9591eac98a91a14995d98291adMarco Nelissen private RemoteControlClient mRemoteControlClient; 1628717d3490e179e9591eac98a91a14995d98291adMarco Nelissen 163792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private Handler mMediaplayerHandler = new Handler() { 164792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project float mCurrentVolume = 1.0f; 165792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 166792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void handleMessage(Message msg) { 1673988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen MusicUtils.debugLog("mMediaplayerHandler.handleMessage " + msg.what); 168792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project switch (msg.what) { 1692da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen case FADEDOWN: 1702da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen mCurrentVolume -= .05f; 1712da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen if (mCurrentVolume > .2f) { 1722da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen mMediaplayerHandler.sendEmptyMessageDelayed(FADEDOWN, 10); 173792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1742da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen mCurrentVolume = .2f; 1752da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen } 1762da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen mPlayer.setVolume(mCurrentVolume); 1772da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen break; 1782da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen case FADEUP: 1792da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen mCurrentVolume += .01f; 1802da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen if (mCurrentVolume < 1.0f) { 1812da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen mMediaplayerHandler.sendEmptyMessageDelayed(FADEUP, 10); 1822da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen } else { 1832da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen mCurrentVolume = 1.0f; 184792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1852da473d14a11b552621b2f3cd5bdf1758b117ed5Marco Nelissen mPlayer.setVolume(mCurrentVolume); 186792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project break; 187792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project case SERVER_DIED: 188c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen if (mIsSupposedToBePlaying) { 189bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen gotoNext(true); 190792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 191792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // the server died when we were idle, so just 192792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // reopen the same song (it will start again 193792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // from the beginning though when the user 194792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // restarts) 195e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 196792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 197792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project break; 198e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen case TRACK_WENT_TO_NEXT: 199e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mPlayPos = mNextPlayPos; 200e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (mCursor != null) { 201e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCursor.close(); 202e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCursor = null; 203e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 204ea5075144c4f6da8dfd743ba1deb4ec7c59ef1c0kenthin if (mPlayPos >= 0 && mPlayPos < mPlayList.length) { 205ea5075144c4f6da8dfd743ba1deb4ec7c59ef1c0kenthin mCursor = getCursorForId(mPlayList[mPlayPos]); 206ea5075144c4f6da8dfd743ba1deb4ec7c59ef1c0kenthin } 207e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen notifyChange(META_CHANGED); 208e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen updateNotification(); 209e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen setNextTrack(); 210e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen break; 211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project case TRACK_ENDED: 212792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mRepeatMode == REPEAT_CURRENT) { 213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project seek(0); 214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 216bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen gotoNext(false); 217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project break; 219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project case RELEASE_WAKELOCK: 220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mWakeLock.release(); 221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project break; 2227181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen 2237181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen case FOCUSCHANGE: 2247181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen // This code is here so we can better synchronize it with the code that 2257181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen // handles fade-in 2267181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen switch (msg.arg1) { 2277181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen case AudioManager.AUDIOFOCUS_LOSS: 2287181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS"); 229b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He if (isPlaying()) { 2307181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mPausedByTransientLossOfFocus = false; 2317181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen } 2327181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen pause(); 2337181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen break; 2347181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 2357bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen mMediaplayerHandler.removeMessages(FADEUP); 2367bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen mMediaplayerHandler.sendEmptyMessage(FADEDOWN); 2377bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen break; 2387bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 2397181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_LOSS_TRANSIENT"); 240b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He if (isPlaying()) { 2417181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mPausedByTransientLossOfFocus = true; 2427181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen } 2437181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen pause(); 2447181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen break; 2457181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen case AudioManager.AUDIOFOCUS_GAIN: 2467181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen Log.v(LOGTAG, "AudioFocus: received AUDIOFOCUS_GAIN"); 247b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He if (!isPlaying() && mPausedByTransientLossOfFocus) { 2487181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mPausedByTransientLossOfFocus = false; 2497181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mCurrentVolume = 0f; 2507181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mPlayer.setVolume(mCurrentVolume); 2517181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen play(); // also queues a fade-in 2527181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen } else { 2537bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen mMediaplayerHandler.removeMessages(FADEDOWN); 2547181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mMediaplayerHandler.sendEmptyMessage(FADEUP); 2557181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen } 2567181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen break; 2577181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen default: 2587181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen Log.e(LOGTAG, "Unknown audio focus change code"); 2597181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen } 2607181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen break; 2617181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen 262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project default: 263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project break; 264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 268792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 269792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onReceive(Context context, Intent intent) { 271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String action = intent.getAction(); 272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String cmd = intent.getStringExtra("command"); 2733988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen MusicUtils.debugLog("mIntentReceiver.onReceive " + action + " / " + cmd); 274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) { 275bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen gotoNext(true); 276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) { 277792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project prev(); 278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) { 279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (isPlaying()) { 280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project pause(); 281aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) { 286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project pause(); 287aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 288fc1c0dc301b5cae2e8c5661e7a217dc57dacac1eMarco Nelissen } else if (CMDPLAY.equals(cmd)) { 289fc1c0dc301b5cae2e8c5661e7a217dc57dacac1eMarco Nelissen play(); 290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (CMDSTOP.equals(cmd)) { 291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project pause(); 292aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project seek(0); 294490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project } else if (MediaAppWidgetProvider.CMDAPPWIDGETUPDATE.equals(cmd)) { 295490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project // Someone asked us to refresh a set of specific widgets, probably 296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // because they were just added. 297490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); 298490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project mAppWidgetProvider.performUpdate(MediaPlaybackService.this, appWidgetIds); 299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 303085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() { 304f4cfdfd4a99040be44a1ccd74edbde762edc845bJean-Michel Trivi public void onAudioFocusChange(int focusChange) { 3057181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mMediaplayerHandler.obtainMessage(FOCUSCHANGE, focusChange, 0).sendToTarget(); 306085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi } 307085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi }; 308085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi 309b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He public MediaPlaybackService() {} 310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 312792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onCreate() { 313792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project super.onCreate(); 314085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi 315085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 316b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He ComponentName rec = 317b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He new ComponentName(getPackageName(), MediaButtonIntentReceiver.class.getName()); 3188717d3490e179e9591eac98a91a14995d98291adMarco Nelissen mAudioManager.registerMediaButtonEventReceiver(rec); 3198ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood 3208ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood Intent i = new Intent(Intent.ACTION_MEDIA_BUTTON); 3218ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood i.setComponent(rec); 322b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He PendingIntent pi = PendingIntent.getBroadcast( 323b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He this /*context*/, 0 /*requestCode, ignored*/, i /*intent*/, 0 /*flags*/); 3248ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood mRemoteControlClient = new RemoteControlClient(pi); 3258ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood mAudioManager.registerRemoteControlClient(mRemoteControlClient); 3268ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood 3278ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood int flags = RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS 328b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He | RemoteControlClient.FLAG_KEY_MEDIA_NEXT | RemoteControlClient.FLAG_KEY_MEDIA_PLAY 3298ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE 3308ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE 3318ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood | RemoteControlClient.FLAG_KEY_MEDIA_STOP; 3328ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood mRemoteControlClient.setTransportControlFlags(flags); 333b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 3346036ce6127022880a3d9c99bd15db4c968f3e6a3Dmitry Shmidt mPreferences = getSharedPreferences("Music", MODE_PRIVATE); 33587bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen mCardId = MusicUtils.getCardId(this); 336b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 337792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project registerExternalStorageListener(); 338792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 339b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // Needs to be done in this thread, since otherwise ApplicationContext.getPowerManager() 340b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // crashes. 341792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayer = new MultiPlayer(); 342792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayer.setHandler(mMediaplayerHandler); 343792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 344792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project reloadQueue(); 3458717d3490e179e9591eac98a91a14995d98291adMarco Nelissen notifyChange(QUEUE_CHANGED); 3468717d3490e179e9591eac98a91a14995d98291adMarco Nelissen notifyChange(META_CHANGED); 3478717d3490e179e9591eac98a91a14995d98291adMarco Nelissen 348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project IntentFilter commandFilter = new IntentFilter(); 349792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project commandFilter.addAction(SERVICECMD); 350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project commandFilter.addAction(TOGGLEPAUSE_ACTION); 351792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project commandFilter.addAction(PAUSE_ACTION); 352792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project commandFilter.addAction(NEXT_ACTION); 353792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project commandFilter.addAction(PREVIOUS_ACTION); 354792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project registerReceiver(mIntentReceiver, commandFilter); 355b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 356b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 357792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName()); 358792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mWakeLock.setReferenceCounted(false); 359792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 360792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // If the service was idle, but got killed before it stopped itself, the 361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // system will relaunch it. Make sure it gets stopped again in that case. 362792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Message msg = mDelayedStopHandler.obtainMessage(); 363792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY); 364792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 366792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 367792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onDestroy() { 368792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Check that we're not being destroyed while something is still playing. 369792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (isPlaying()) { 370e99341f9674462607f3fd5e8dbd100b34b973e1bMarco Nelissen Log.e(LOGTAG, "Service being destroyed while still playing."); 371792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 3722b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen // release all MediaPlayer resources, including the native player and wakelocks 373f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION); 374f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId()); 375f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName()); 376f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen sendBroadcast(i); 3772b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mPlayer.release(); 3782b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mPlayer = null; 379085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi 380085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi mAudioManager.abandonAudioFocus(mAudioFocusListener); 3818ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood mAudioManager.unregisterRemoteControlClient(mRemoteControlClient); 382b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 3832b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen // make sure there aren't any other messages coming 3842b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mDelayedStopHandler.removeCallbacksAndMessages(null); 38549e36ea916aefba042c6e927c771b10708b6891eMarco Nelissen mMediaplayerHandler.removeCallbacksAndMessages(null); 3862b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen 387792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor != null) { 388792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor.close(); 389792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor = null; 390792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 391792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 392792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project unregisterReceiver(mIntentReceiver); 393792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mUnmountReceiver != null) { 394792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project unregisterReceiver(mUnmountReceiver); 395792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mUnmountReceiver = null; 396792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 397792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mWakeLock.release(); 398792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project super.onDestroy(); 399792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 400b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 401b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He private final char hexdigits[] = new char[] { 402b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 403792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 404792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void saveQueue(boolean full) { 4058d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen if (!mQueueIsSaveable) { 406792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 407792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 4088d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen 409792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Editor ed = mPreferences.edit(); 410b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // long start = System.currentTimeMillis(); 411792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (full) { 412792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project StringBuilder q = new StringBuilder(); 413b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // The current playlist is saved as a list of "reverse hexadecimal" 415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // numbers, which we can generate faster than normal decimal or 416792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // hexadecimal numbers, which in turn allows us to save the playlist 417792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // more often without worrying too much about performance. 418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // (saving the full state takes about 40 ms under no-load conditions 419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // on the phone) 420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int len = mPlayListLen; 421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < len; i++) { 422bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen long n = mPlayList[i]; 423133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen if (n < 0) { 424133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen continue; 425133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen } else if (n == 0) { 426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project q.append("0;"); 427792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project while (n != 0) { 429b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He int digit = (int) (n & 0xf); 430133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen n >>>= 4; 431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project q.append(hexdigits[digit]); 432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project q.append(";"); 434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 436b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // Log.i("@@@@ service", "created queue string in " + (System.currentTimeMillis() - 437b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // start) + " ms"); 438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putString("queue", q.toString()); 439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putInt("cardid", mCardId); 44063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (mShuffleMode != SHUFFLE_NONE) { 44163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen // In shuffle mode we need to save the history too 44263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen len = mHistory.size(); 44363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen q.setLength(0); 44463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen for (int i = 0; i < len; i++) { 44563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen int n = mHistory.get(i); 44663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (n == 0) { 44763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen q.append("0;"); 44863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } else { 44963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen while (n != 0) { 45063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen int digit = (n & 0xf); 451133550210e448fe52698f6cd0e80e07b8cc480bdMarco Nelissen n >>>= 4; 45263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen q.append(hexdigits[digit]); 45363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 45463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen q.append(";"); 45563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 45663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 45763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen ed.putString("history", q.toString()); 45863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putInt("curpos", mPlayPos); 461792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayer.isInitialized()) { 462792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putLong("seekpos", mPlayer.position()); 463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putInt("repeatmode", mRepeatMode); 465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ed.putInt("shufflemode", mShuffleMode); 46614c3caeb7bc2de0dd7abbb1e5f217dbb6367afbaBrad Fitzpatrick SharedPreferencesCompat.apply(ed); 46714c3caeb7bc2de0dd7abbb1e5f217dbb6367afbaBrad Fitzpatrick 468b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // Log.i("@@@@ service", "saved state in " + (System.currentTimeMillis() - start) + " ms"); 469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void reloadQueue() { 472792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String q = null; 473b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 474792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project boolean newstyle = false; 475792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int id = mCardId; 476792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPreferences.contains("cardid")) { 477792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project newstyle = true; 478792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project id = mPreferences.getInt("cardid", ~mCardId); 479792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 480792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (id == mCardId) { 481792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Only restore the saved playlist if the card is still 482792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // the same one as when the playlist was saved 483792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project q = mPreferences.getString("queue", ""); 484792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 4856c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen int qlen = q != null ? q.length() : 0; 4866c615a208d88fe49c7da43c59720f9db6ca1e964Marco Nelissen if (qlen > 1) { 487b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // Log.i("@@@@ service", "loaded queue: " + q); 488bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen int plen = 0; 489bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen int n = 0; 490bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen int shift = 0; 491bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen for (int i = 0; i < qlen; i++) { 492bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen char c = q.charAt(i); 493bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen if (c == ';') { 494bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen ensurePlayListCapacity(plen + 1); 495bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen mPlayList[plen] = n; 496bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen plen++; 497bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen n = 0; 498bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen shift = 0; 499792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 500bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen if (c >= '0' && c <= '9') { 501bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen n += ((c - '0') << shift); 502bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen } else if (c >= 'a' && c <= 'f') { 503bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen n += ((10 + c - 'a') << shift); 504bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen } else { 505bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen // bogus playlist data 506bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen plen = 0; 507bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen break; 508bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen } 509bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen shift += 4; 510792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 511792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 512bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen mPlayListLen = plen; 513792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 514792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int pos = mPreferences.getInt("curpos", 0); 515bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen if (pos < 0 || pos >= mPlayListLen) { 516792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // The saved playlist is bogus, discard it 517792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen = 0; 518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = pos; 521b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // When reloadQueue is called in response to a card-insertion, 523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // we might not be able to query the media provider right away. 524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // To deal with this, try querying for the current file, and if 525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // that fails, wait a while and try again. If that too fails, 526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // assume there is a problem and don't restore the state. 527b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He Cursor crsr = MusicUtils.query(this, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 528b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He new String[] {"_id"}, "_id=" + mPlayList[mPlayPos], null, null); 52963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (crsr == null || crsr.getCount() == 0) { 530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // wait a bit and try again 531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project SystemClock.sleep(3000); 532b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He crsr = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 533b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mCursorCols, "_id=" + mPlayList[mPlayPos], null, null); 534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 53563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (crsr != null) { 53663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen crsr.close(); 537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 539792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Make sure we don't auto-skip to the next song, since that 540792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // also starts playback. What could happen in that case is: 541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // - music is paused 542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // - go to UMS and delete some files, including the currently playing one 543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // - come back from UMS 544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // (time passes) 545792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // - music app is killed for some reason (out of memory) 546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // - music service is restarted, service restores state, doesn't find 547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // the "current" file, goes to the next and: playback starts on its 548792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // own, potentially at some random inconvenient time. 549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mOpenFailedCounter = 20; 550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mQuietMode = true; 551e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mQuietMode = false; 553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (!mPlayer.isInitialized()) { 554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // couldn't restore the saved state 555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen = 0; 556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 557792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 558b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project long seekpos = mPreferences.getLong("seekpos", 0); 560792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project seek(seekpos >= 0 && seekpos < duration() ? seekpos : 0); 561b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He Log.d(LOGTAG, "restored queue, currently at position " + position() + "/" + duration() 562b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He + " (requested " + seekpos + ")"); 563b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 564792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int repmode = mPreferences.getInt("repeatmode", REPEAT_NONE); 565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (repmode != REPEAT_ALL && repmode != REPEAT_CURRENT) { 566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project repmode = REPEAT_NONE; 567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mRepeatMode = repmode; 569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int shufmode = mPreferences.getInt("shufflemode", SHUFFLE_NONE); 571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (shufmode != SHUFFLE_AUTO && shufmode != SHUFFLE_NORMAL) { 572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project shufmode = SHUFFLE_NONE; 573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 57463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (shufmode != SHUFFLE_NONE) { 57563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen // in shuffle mode we need to restore the history too 57663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen q = mPreferences.getString("history", ""); 57763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen qlen = q != null ? q.length() : 0; 57863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (qlen > 1) { 57963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen plen = 0; 58063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen n = 0; 58163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen shift = 0; 58263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen mHistory.clear(); 58363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen for (int i = 0; i < qlen; i++) { 58463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen char c = q.charAt(i); 58563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (c == ';') { 58663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (n >= mPlayListLen) { 58763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen // bogus history data 58863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen mHistory.clear(); 58963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen break; 59063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 59163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen mHistory.add(n); 59263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen n = 0; 59363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen shift = 0; 59463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } else { 59563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen if (c >= '0' && c <= '9') { 59663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen n += ((c - '0') << shift); 59763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } else if (c >= 'a' && c <= 'f') { 59863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen n += ((10 + c - 'a') << shift); 59963dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } else { 60063dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen // bogus history data 60163dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen mHistory.clear(); 60263dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen break; 60363dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 60463dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen shift += 4; 60563dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 60663dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 60763dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 60863dbbbb163b537f8447f5abdb44fe2966a525464Marco Nelissen } 609792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (shufmode == SHUFFLE_AUTO) { 610b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He if (!makeAutoShuffleList()) { 611792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project shufmode = SHUFFLE_NONE; 612792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 613792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mShuffleMode = shufmode; 615792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 617b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public IBinder onBind(Intent intent) { 620792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.removeCallbacksAndMessages(null); 621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mServiceInUse = true; 622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mBinder; 623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onRebind(Intent intent) { 627792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.removeCallbacksAndMessages(null); 628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mServiceInUse = true; 629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 632c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen public int onStartCommand(Intent intent, int flags, int startId) { 633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mServiceStartId = startId; 634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.removeCallbacksAndMessages(null); 635c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen 636c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen if (intent != null) { 637c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen String action = intent.getAction(); 638c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen String cmd = intent.getStringExtra("command"); 6393988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen MusicUtils.debugLog("onStartCommand " + action + " / " + cmd); 640c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen 641c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen if (CMDNEXT.equals(cmd) || NEXT_ACTION.equals(action)) { 642bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen gotoNext(true); 643c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } else if (CMDPREVIOUS.equals(cmd) || PREVIOUS_ACTION.equals(action)) { 644b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen if (position() < 2000) { 645b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen prev(); 646b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen } else { 647b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen seek(0); 648b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen play(); 649b63b5d1b6cae1cc9e28ba63b316fc15da5e16939Marco Nelissen } 650c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } else if (CMDTOGGLEPAUSE.equals(cmd) || TOGGLEPAUSE_ACTION.equals(action)) { 651c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen if (isPlaying()) { 652c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen pause(); 653aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 654c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } else { 655c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen play(); 656c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } 657c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } else if (CMDPAUSE.equals(cmd) || PAUSE_ACTION.equals(action)) { 658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project pause(); 659aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 66047dd847ba35375d95c15bc1ee141d638f03ec82eJaikumar Ganesh } else if (CMDPLAY.equals(cmd)) { 66147dd847ba35375d95c15bc1ee141d638f03ec82eJaikumar Ganesh play(); 662c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen } else if (CMDSTOP.equals(cmd)) { 663c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen pause(); 664aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi mPausedByTransientLossOfFocus = false; 665c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen seek(0); 666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 668b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 669792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // make sure the service will shut down on its own if it was 670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // just started but not bound to and nothing is playing 671792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.removeCallbacksAndMessages(null); 672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Message msg = mDelayedStopHandler.obtainMessage(); 673792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY); 674c1017e5fe69da3a4ffd2bf7d0890a1a216265a61Marco Nelissen return START_STICKY; 675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 676b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public boolean onUnbind(Intent intent) { 679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mServiceInUse = false; 680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Take a snapshot of the current playlist 682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(true); 683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 684aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi if (isPlaying() || mPausedByTransientLossOfFocus) { 685b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // something is currently playing, or will be playing once 686aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi // an in-progress action requesting audio focus ends, so don't stop the service now. 687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return true; 688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 689b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // If there is a playlist but playback is paused, then wait a while 691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // before stopping the service, so that pause/resume isn't slow. 692792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Also delay stopping the service if we're transitioning between tracks. 693b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He if (mPlayListLen > 0 || mMediaplayerHandler.hasMessages(TRACK_ENDED)) { 694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Message msg = mDelayedStopHandler.obtainMessage(); 695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY); 696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return true; 697792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 698b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // No active playlist, OK to stop the service right now 700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stopSelf(mServiceStartId); 701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return true; 702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 703b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private Handler mDelayedStopHandler = new Handler() { 705792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void handleMessage(Message msg) { 707792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Check again to make sure nothing is playing right now 708aa331877dd1a0777042481e5c925cd951682588fJean-Michel Trivi if (isPlaying() || mPausedByTransientLossOfFocus || mServiceInUse 709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project || mMediaplayerHandler.hasMessages(TRACK_ENDED)) { 710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 711792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // save the queue again, because it might have changed 713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // since the user exited the music app (because of 714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // party-shuffle or because the play-position changed) 715792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(true); 716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stopSelf(mServiceStartId); 717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 719f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen 720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 721792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Called when we receive a ACTION_MEDIA_EJECT notification. 722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * 723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param storagePath path to mount point for the removed media 724792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void closeExternalStorageFiles(String storagePath) { 726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // stop playback and clean up if the SD card is going to be unmounted. 727792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(true); 728792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 729792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Registers an intent to listen for ACTION_MEDIA_EJECT notifications. 734792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * The intent will call closeExternalStorageFiles() if the external media 735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * is going to be ejected, so applications can clean up any files they have open. 736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void registerExternalStorageListener() { 738792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mUnmountReceiver == null) { 739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mUnmountReceiver = new BroadcastReceiver() { 740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project @Override 741792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onReceive(Context context, Intent intent) { 742792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String action = intent.getAction(); 743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (action.equals(Intent.ACTION_MEDIA_EJECT)) { 744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(true); 7458d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen mQueueIsSaveable = false; 746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project closeExternalStorageFiles(intent.getData().getPath()); 747792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) { 748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mMediaMountedCount++; 74987bbf3c40cd044c3daa9fad28fb94e8570fcae05Marco Nelissen mCardId = MusicUtils.getCardId(MediaPlaybackService.this); 750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project reloadQueue(); 7518d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen mQueueIsSaveable = true; 752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 754792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project IntentFilter iFilter = new IntentFilter(); 758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project iFilter.addAction(Intent.ACTION_MEDIA_EJECT); 759792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); 760792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project iFilter.addDataScheme("file"); 761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project registerReceiver(mUnmountReceiver, iFilter); 762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 765792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Notify the change-receivers that something has changed. 767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * The intent that is sent contains the following data 768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * for the currently playing track: 769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "id" - Integer: the database row ID 770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "artist" - String: the name of the artist 771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "album" - String: the name of the album 772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "track" - String: the name of the track 773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * The intent has an action that is one of 774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "com.android.music.metachanged" 775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "com.android.music.queuechanged", 776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "com.android.music.playbackcomplete" 777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * "com.android.music.playstatechanged" 778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * respectively indicating that a new track has 779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * started playing, that the playback queue has 780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * changed, that playback has stopped because 781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * the last file in the list has been played, 782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * or that the play-state changed (paused/resumed). 783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void notifyChange(String what) { 785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Intent i = new Intent(what); 786bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen i.putExtra("id", Long.valueOf(getAudioId())); 787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project i.putExtra("artist", getArtistName()); 788b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He i.putExtra("album", getAlbumName()); 789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project i.putExtra("track", getTrackName()); 7906b507de7beda7f4a8b969b437dfbf81f5ecd5e5eMarco Nelissen i.putExtra("playing", isPlaying()); 7916b507de7beda7f4a8b969b437dfbf81f5ecd5e5eMarco Nelissen sendStickyBroadcast(i); 7928717d3490e179e9591eac98a91a14995d98291adMarco Nelissen 7938717d3490e179e9591eac98a91a14995d98291adMarco Nelissen if (what.equals(PLAYSTATE_CHANGED)) { 794b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mRemoteControlClient.setPlaybackState(isPlaying() 795b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He ? RemoteControlClient.PLAYSTATE_PLAYING 796b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He : RemoteControlClient.PLAYSTATE_PAUSED); 7978717d3490e179e9591eac98a91a14995d98291adMarco Nelissen } else if (what.equals(META_CHANGED)) { 7988ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood RemoteControlClient.MetadataEditor ed = mRemoteControlClient.editMetadata(true); 7998ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, getTrackName()); 8008ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, getAlbumName()); 8018ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, getArtistName()); 8028ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, duration()); 8038ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood Bitmap b = MusicUtils.getArtwork(this, getAudioId(), getAlbumId(), false); 8048ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood if (b != null) { 8058ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.putBitmap(MetadataEditor.BITMAP_KEY_ARTWORK, b); 8068ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood } 8078ef367969a0fd1f678b1f119b67d0ee409ea0389Mike Lockwood ed.apply(); 8088717d3490e179e9591eac98a91a14995d98291adMarco Nelissen } 8098717d3490e179e9591eac98a91a14995d98291adMarco Nelissen 810792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (what.equals(QUEUE_CHANGED)) { 811792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(true); 812792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(false); 814792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 815b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 816490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project // Share this notification directly with our widgets 817490384bf1b81cc703fd42de8674e593b216e3435The Android Open Source Project mAppWidgetProvider.notifyChange(this, what); 818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 820792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void ensurePlayListCapacity(int size) { 821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayList == null || size > mPlayList.length) { 822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // reallocate at 2x requested size so we don't 823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // need to grow and copy the array for every 824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // insert 825b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He long[] newlist = new long[size * 2]; 826bf0ea148eefcffd43e6f5023a6f8365d74fb829fMarco Nelissen int len = mPlayList != null ? mPlayList.length : mPlayListLen; 827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < len; i++) { 828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project newlist[i] = mPlayList[i]; 829792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList = newlist; 831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 832792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // FIXME: shrink the array when the needed size is much smaller 833792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // than the allocated size 834792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 835b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 836792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // insert the list of songs at the specified position in the playlist 837b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He private void addToPlayList(long[] list, int position) { 838792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int addlen = list.length; 839792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (position < 0) { // overwrite 840792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen = 0; 841792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project position = 0; 842792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 843792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ensurePlayListCapacity(mPlayListLen + addlen); 844792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (position > mPlayListLen) { 845792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project position = mPlayListLen; 846792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 847b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 848792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // move part of list after insertion point 849792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int tailsize = mPlayListLen - position; 850b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He for (int i = tailsize; i > 0; i--) { 851b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mPlayList[position + i] = mPlayList[position + i - addlen]; 852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 853b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // copy list into playlist 855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < addlen; i++) { 856792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList[position + i] = list[i]; 857792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 858792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen += addlen; 8593aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen if (mPlayListLen == 0) { 8603aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen mCursor.close(); 8613aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen mCursor = null; 8623aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen notifyChange(META_CHANGED); 8633aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen } 864792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 865b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 867792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Appends a list of tracks to the current playlist. 868792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * If nothing is playing currently, playback will be started at 869792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * the first track. 870792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * If the action is NOW, playback will switch to the first of 871792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * the new tracks immediately. 872792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param list The list of tracks to append. 873792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param action NOW, NEXT or LAST 874792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 875b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He public void enqueue(long[] list, int action) { 876b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He synchronized (this) { 877792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (action == NEXT && mPlayPos + 1 < mPlayListLen) { 878792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project addToPlayList(list, mPlayPos + 1); 879792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 880792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 881792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // action == LAST || action == NOW || mPlayPos + 1 == mPlayListLen 882792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project addToPlayList(list, Integer.MAX_VALUE); 883792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 884792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (action == NOW) { 885792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = mPlayListLen - list.length; 886e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 887792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 889792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 891792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 892792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos < 0) { 893792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = 0; 894e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 895792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 896792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 897792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 899792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 900792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 901792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 902792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Replaces the current playlist with a new list, 903792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * and prepares for starting playback at the specified 904792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * position in the list, or a random position if the 905792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * specified position is 0. 906792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param list The new list of tracks. 907792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 908b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He public void open(long[] list, int position) { 909792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 910792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mShuffleMode == SHUFFLE_AUTO) { 911792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mShuffleMode = SHUFFLE_NORMAL; 912792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 913bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen long oldId = getAudioId(); 914792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int listlength = list.length; 915792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project boolean newlist = true; 916792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayListLen == listlength) { 917792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // possible fast path: list might be the same 918792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project newlist = false; 919792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < listlength; i++) { 920792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (list[i] != mPlayList[i]) { 921792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project newlist = true; 922792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project break; 923792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 924792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 925792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 926792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (newlist) { 927792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project addToPlayList(list, -1); 928792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 929792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 930792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int oldpos = mPlayPos; 931792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (position >= 0) { 932792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = position; 933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = mRand.nextInt(mPlayListLen); 935792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 936792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mHistory.clear(); 937792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 938792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveBookmarkIfNeeded(); 939e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 940d8c696753687ddb0177f869fad5f709eadfe27afJeffrey Sharkey if (oldId != getAudioId()) { 941792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 942792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 943792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 944792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 945b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 947792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Moves the item at index1 to index2. 948792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param index1 949792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param index2 950792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 951792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void moveQueueItem(int index1, int index2) { 952792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 953792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (index1 >= mPlayListLen) { 954792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project index1 = mPlayListLen - 1; 955792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 956792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (index2 >= mPlayListLen) { 957792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project index2 = mPlayListLen - 1; 958792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 959792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (index1 < index2) { 960bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen long tmp = mPlayList[index1]; 961792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = index1; i < index2; i++) { 962b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mPlayList[i] = mPlayList[i + 1]; 963792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 964792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList[index2] = tmp; 965792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos == index1) { 966792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = index2; 967792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (mPlayPos >= index1 && mPlayPos <= index2) { 968b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mPlayPos--; 969792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 970792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (index2 < index1) { 971bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen long tmp = mPlayList[index1]; 972792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = index1; i > index2; i--) { 973b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mPlayList[i] = mPlayList[i - 1]; 974792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 975792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList[index2] = tmp; 976792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos == index1) { 977792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = index2; 978792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (mPlayPos >= index2 && mPlayPos <= index1) { 979b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mPlayPos++; 980792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 981792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 982792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 983792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 984792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 985792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 986792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 987792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Returns the current play list 988792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @return An array of integers containing the IDs of the tracks in the play list 989792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 990b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He public long[] getQueue() { 991792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 992792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int len = mPlayListLen; 993b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He long[] list = new long[len]; 994792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < len; i++) { 995792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project list[i] = mPlayList[i]; 996792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 997792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return list; 998792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 999792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1000792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1001e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen private Cursor getCursorForId(long lid) { 1002e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen String id = String.valueOf(lid); 1003e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1004e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen Cursor c = getContentResolver().query( 1005b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursorCols, "_id=" + id, null, null); 1006c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen if (c != null) { 1007c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen c.moveToFirst(); 1008c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen } 1009e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return c; 1010e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1011e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1012e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen private void openCurrentAndNext() { 1013792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1014792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor != null) { 1015792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor.close(); 1016792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor = null; 1017792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 10188d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen 1019792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayListLen == 0) { 1020792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 1021792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1022792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(false); 1023792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 102490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mCursor = getCursorForId(mPlayList[mPlayPos]); 1025b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He while (true) { 1026b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He if (mCursor != null && mCursor.getCount() != 0 1027b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He && open(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" 1028b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He + mCursor.getLong(IDCOLIDX))) { 1029c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen break; 1030c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen } 1031c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen // if we get here then opening the file failed. We can close the cursor now, because 1032c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen // we're either going to create a new one next, or stop trying 1033c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen if (mCursor != null) { 1034c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen mCursor.close(); 1035c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen mCursor = null; 10366fb8551aad7f7af3f099dfa286df587a31484000Marco Nelissen } 1037b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He if (mOpenFailedCounter++ < 10 && mPlayListLen > 1) { 103890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen int pos = getNextPosition(false); 103990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (pos < 0) { 104090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen gotoIdleState(); 104190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (mIsSupposedToBePlaying) { 104290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mIsSupposedToBePlaying = false; 104390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen notifyChange(PLAYSTATE_CHANGED); 104490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 104590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return; 104690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 104790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mPlayPos = pos; 104890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen stop(false); 104990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mPlayPos = pos; 105090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mCursor = getCursorForId(mPlayList[mPlayPos]); 105190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } else { 105290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mOpenFailedCounter = 0; 105390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (!mQuietMode) { 105490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen Toast.makeText(this, R.string.playback_failed, Toast.LENGTH_SHORT).show(); 105590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 105690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen Log.d(LOGTAG, "Failed to open file for playback"); 1057c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen gotoIdleState(); 1058c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen if (mIsSupposedToBePlaying) { 1059c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen mIsSupposedToBePlaying = false; 1060c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen notifyChange(PLAYSTATE_CHANGED); 1061c37b200d0198deaf488d0bfe1b114d1fd9037382Marco Nelissen } 106290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return; 1063e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1064792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 106590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen 106690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen // go to bookmark if needed 106790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (isPodcast()) { 106890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen long bookmark = getBookmark(); 106990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen // Start playing a little bit before the bookmark, 107090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen // so it's easier to get back in to the narrative. 107190d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen seek(bookmark - 5000); 107290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 107390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen setNextTrack(); 1074792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1075792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1076792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1077e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen private void setNextTrack() { 1078e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextPlayPos = getNextPosition(false); 1079e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (mNextPlayPos >= 0) { 1080e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen long id = mPlayList[mNextPlayPos]; 1081e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mPlayer.setNextDataSource(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + id); 10820a7f03fa179055114f63bf4e5b1535aefc65066fJun Tian } else { 10830a7f03fa179055114f63bf4e5b1535aefc65066fJun Tian mPlayer.setNextDataSource(null); 1084e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1085e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1086e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1087792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1088792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Opens the specified file and readies it for playback. 1089792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * 1090792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param path The full path of the file to be opened. 1091792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 109290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen public boolean open(String path) { 1093792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1094792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (path == null) { 109590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return false; 1096792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1097b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1098792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // if mCursor is null, try to associate path with a database cursor 1099792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1100792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ContentResolver resolver = getContentResolver(); 1101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Uri uri; 1102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String where; 1103792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project String selectionArgs[]; 1104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (path.startsWith("content://media/")) { 1105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project uri = Uri.parse(path); 1106792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project where = null; 1107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project selectionArgs = null; 1108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1109b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He uri = MediaStore.Audio.Media.getContentUriForPath(path); 1110b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He where = MediaStore.Audio.Media.DATA + "=?"; 1111b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He selectionArgs = new String[] {path}; 1112792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1113b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1114792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project try { 1115792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor = resolver.query(uri, mCursorCols, where, selectionArgs, null); 1116b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He if (mCursor != null) { 1117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor.getCount() == 0) { 1118792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor.close(); 1119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor = null; 1120792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1121792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor.moveToNext(); 1122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ensurePlayListCapacity(1); 1123792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen = 1; 1124bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen mPlayList[0] = mCursor.getLong(IDCOLIDX); 1125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = 0; 1126792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1127792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } catch (UnsupportedOperationException ex) { 1129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1130792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mFileToPlay = path; 1132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayer.setDataSource(mFileToPlay); 113390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (mPlayer.isInitialized()) { 1134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mOpenFailedCounter = 0; 113590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return true; 1136792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 113790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen stop(true); 113890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return false; 1139792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1142792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Starts playback of a previously opened file. 1144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1145792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void play() { 1146b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mAudioManager.requestAudioFocus( 1147b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mAudioFocusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); 1148b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mAudioManager.registerMediaButtonEventReceiver(new ComponentName( 1149b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He this.getPackageName(), MediaButtonIntentReceiver.class.getName())); 1150085cbfd3da2c00f5eddf74f344802d16df151988Jean-Michel Trivi 1151792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayer.isInitialized()) { 1152272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle // if we are at the end of the song, go to the next song first 11532f9a1ce2f3b0ae72d698c240ce8448bc7cfe3a77Marco Nelissen long duration = mPlayer.duration(); 1154b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He if (mRepeatMode != REPEAT_CURRENT && duration > 2000 1155b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He && mPlayer.position() >= duration - 2000) { 1156bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen gotoNext(true); 1157272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle } 1158272eb78d8836f969f7480454167bdffc6a6f6dd7Thomas Tuttle 1159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayer.start(); 11607181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen // make sure we fade in, in case a previous fadein was stopped because 11617181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen // of another focus loss 11627bae28fb4233e3d028b0436fb28f783dea14927eMarco Nelissen mMediaplayerHandler.removeMessages(FADEDOWN); 11637181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mMediaplayerHandler.sendEmptyMessage(FADEUP); 1164792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1165e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen updateNotification(); 1166c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen if (!mIsSupposedToBePlaying) { 1167347fe57e4c8a860dfbad6f0ec1991171bfa69d77Mike Cleron mIsSupposedToBePlaying = true; 1168792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(PLAYSTATE_CHANGED); 1169792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1170347fe57e4c8a860dfbad6f0ec1991171bfa69d77Mike Cleron 1171792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (mPlayListLen <= 0) { 1172792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // This is mostly so that if you press 'play' on a bluetooth headset 1173792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // without every having played anything before, it will still play 1174792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // something. 1175792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project setShuffleMode(SHUFFLE_AUTO); 1176792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1177792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1178e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1179e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen private void updateNotification() { 1180e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen RemoteViews views = new RemoteViews(getPackageName(), R.layout.statusbar); 1181e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen views.setImageViewResource(R.id.icon, R.drawable.stat_notify_musicplayer); 1182e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (getAudioId() < 0) { 1183e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // streaming 1184e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen views.setTextViewText(R.id.trackname, getPath()); 1185e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen views.setTextViewText(R.id.artistalbum, null); 1186e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } else { 1187e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen String artist = getArtistName(); 1188e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen views.setTextViewText(R.id.trackname, getTrackName()); 1189e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (artist == null || artist.equals(MediaStore.UNKNOWN_STRING)) { 1190e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen artist = getString(R.string.unknown_artist_name); 1191e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1192e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen String album = getAlbumName(); 1193e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (album == null || album.equals(MediaStore.UNKNOWN_STRING)) { 1194e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen album = getString(R.string.unknown_album_name); 1195e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1196e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1197b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He views.setTextViewText( 1198b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He R.id.artistalbum, getString(R.string.notification_artist_album, artist, album)); 1199e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1200e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen Notification status = new Notification(); 1201e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen status.contentView = views; 1202e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen status.flags |= Notification.FLAG_ONGOING_EVENT; 1203e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen status.icon = R.drawable.stat_notify_musicplayer; 1204b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He status.contentIntent = 1205b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He PendingIntent.getActivity(this, 0, new Intent("com.android.music.PLAYBACK_VIEWER") 1206b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 1207b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 0); 1208e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen startForeground(PLAYBACKSERVICE_STATUS, status); 1209e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1210e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1211792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void stop(boolean remove_status_icon) { 1212b1c285c7e2da5492b4224f3e66ea5696b6df5fa8Glenn Kasten if (mPlayer != null && mPlayer.isInitialized()) { 1213792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayer.stop(); 1214792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1215792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mFileToPlay = null; 1216792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor != null) { 1217792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor.close(); 1218792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mCursor = null; 1219792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1220792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (remove_status_icon) { 1221792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project gotoIdleState(); 1222d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn } else { 1223d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn stopForeground(false); 1224792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1225792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (remove_status_icon) { 1226c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen mIsSupposedToBePlaying = false; 1227792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1228792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1229792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1230792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1231792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Stops playback. 1232792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1233792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void stop() { 1234792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(true); 1235792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1236792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1237792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1238792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Pauses playback (call play() to resume) 1239792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1240792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void pause() { 1241b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He synchronized (this) { 12427181da85214e1527bba9e7983a3a27ed98bba91bMarco Nelissen mMediaplayerHandler.removeMessages(FADEUP); 1243407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen if (isPlaying()) { 1244407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen mPlayer.pause(); 1245407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen gotoIdleState(); 1246407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen mIsSupposedToBePlaying = false; 1247407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen notifyChange(PLAYSTATE_CHANGED); 1248407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen saveBookmarkIfNeeded(); 1249407cf91b661ceeb3ced16dc20af8243b9a0eb632Marco Nelissen } 1250792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1251792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1252792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1253b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen /** Returns whether something is currently playing 1254792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * 1255b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen * @return true if something is playing (or will be playing shortly, in case 1256b6e7bf7ddcc861e81219f9869b5dddc101341458Marco Nelissen * we're currently transitioning between tracks), false if not. 1257792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1258792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public boolean isPlaying() { 1259c1333370c94dd708f2d1555d8aee6ddf2bc88a37Marco Nelissen return mIsSupposedToBePlaying; 1260792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1261792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1262792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /* 1263792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Desired behavior for prev/next/shuffle: 1264792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1265792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project - NEXT will move to the next track in the list when not shuffling, and to 1266792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project a track randomly picked from the not-yet-played tracks when shuffling. 1267792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project If all tracks have already been played, pick from the full set, but 1268792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project avoid picking the previously played track if possible. 1269792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project - when shuffling, PREV will go to the previously played track. Hitting PREV 1270792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project again will go to the track played before that, etc. When the start of the 1271792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project history has been reached, PREV is a no-op. 1272792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project When not shuffling, PREV will go to the sequentially previous track (the 1273792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project difference with the shuffle-case is mainly that when not shuffling, the 1274792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project user can back up to tracks that are not in the history). 1275792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1276792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Example: 1277792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project When playing an album with 10 tracks from the start, and enabling shuffle 1278792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project while playing track 5, the remaining tracks (6-10) will be shuffled, e.g. 1279792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project the final play order might be 1-2-3-4-5-8-10-6-9-7. 1280792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project When hitting 'prev' 8 times while playing track 7 in this example, the 1281792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project user will go to tracks 9-6-10-8-5-4-3-2. If the user then hits 'next', 1282792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project a random track will be picked again. If at any time user disables shuffling 1283792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project the next/previous track will be picked in sequential order again. 1284792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1285792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1286792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void prev() { 1287792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1288792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mShuffleMode == SHUFFLE_NORMAL) { 1289792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // go to previously-played track and remove it from the history 1290792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int histsize = mHistory.size(); 1291792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (histsize == 0) { 1292792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // prev is a no-op 1293792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 1294792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1295792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Integer pos = mHistory.remove(histsize - 1); 1296792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = pos.intValue(); 1297792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1298792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos > 0) { 1299792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos--; 1300792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1301792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = mPlayListLen - 1; 1302792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1303792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1304792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveBookmarkIfNeeded(); 1305792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(false); 1306e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 1307792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 1308792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 1309792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1310792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1311792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1312bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen /** 1313bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen * Get the next position to play. Note that this may actually modify mPlayPos 1314bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen * if playback is in SHUFFLE_AUTO mode and the shuffle list window needed to 1315bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen * be adjusted. Either way, the return value is the next value that should be 1316bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen * assigned to mPlayPos; 1317bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen */ 1318bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen private int getNextPosition(boolean force) { 1319e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (mRepeatMode == REPEAT_CURRENT) { 1320e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (mPlayPos < 0) return 0; 1321e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return mPlayPos; 1322e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } else if (mShuffleMode == SHUFFLE_NORMAL) { 1323bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // Pick random next track from the not-yet-played ones 1324bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // TODO: make it work right after adding/removing items in the queue. 1325663fea34b586fbdf46acebdb86e163aca0e50323Marco Nelissen 1326bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // Store the current file in the history, but keep the history at a 1327bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // reasonable size 1328bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mPlayPos >= 0) { 1329bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen mHistory.add(mPlayPos); 1330bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1331bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mHistory.size() > MAX_HISTORY_SIZE) { 1332bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen mHistory.removeElementAt(0); 1333bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1334792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1335bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int numTracks = mPlayListLen; 1336bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int[] tracks = new int[numTracks]; 1337b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He for (int i = 0; i < numTracks; i++) { 1338bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen tracks[i] = i; 1339bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 13403f502de8e8963224054a97730d132f82ac87d522Marco Nelissen 1341bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int numHistory = mHistory.size(); 1342bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int numUnplayed = numTracks; 1343b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He for (int i = 0; i < numHistory; i++) { 1344bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int idx = mHistory.get(i).intValue(); 1345bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (idx < numTracks && tracks[idx] >= 0) { 1346bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen numUnplayed--; 1347bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen tracks[idx] = -1; 1348792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1349bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1350792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1351bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // 'numUnplayed' now indicates how many tracks have not yet 1352bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // been played, and 'tracks' contains the indices of those 1353bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // tracks. 1354b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He if (numUnplayed <= 0) { 1355bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // everything's already been played 1356bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mRepeatMode == REPEAT_ALL || force) { 1357b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // pick from full set 1358bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen numUnplayed = numTracks; 1359b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He for (int i = 0; i < numTracks; i++) { 1360bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen tracks[i] = i; 1361792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1362bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } else { 1363bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // all done 1364bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return -1; 1365792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1366bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1367bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int skip = mRand.nextInt(numUnplayed); 1368bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int cnt = -1; 1369bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen while (true) { 1370bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen while (tracks[++cnt] < 0) 1371bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen ; 1372bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen skip--; 1373bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (skip < 0) { 1374bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen break; 1375792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1376bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1377bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return cnt; 1378bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } else if (mShuffleMode == SHUFFLE_AUTO) { 1379bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen doAutoShuffleUpdate(); 1380bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return mPlayPos + 1; 1381bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } else { 1382bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mPlayPos >= mPlayListLen - 1) { 1383bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // we're at the end of the list 1384bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mRepeatMode == REPEAT_NONE && !force) { 1385bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen // all done 1386bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return -1; 1387bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } else if (mRepeatMode == REPEAT_ALL || force) { 1388bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return 0; 1389792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1390bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return -1; 1391792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1392bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return mPlayPos + 1; 1393bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1394bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1395bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1396bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen 1397bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen public void gotoNext(boolean force) { 1398bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen synchronized (this) { 1399bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mPlayListLen <= 0) { 1400bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen Log.d(LOGTAG, "No play queue"); 1401bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return; 1402bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen } 1403bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen 1404bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen int pos = getNextPosition(force); 1405bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (pos < 0) { 1406bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen gotoIdleState(); 1407bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen if (mIsSupposedToBePlaying) { 1408bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen mIsSupposedToBePlaying = false; 1409bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen notifyChange(PLAYSTATE_CHANGED); 1410792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1411bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen return; 1412792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1413bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen mPlayPos = pos; 1414792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveBookmarkIfNeeded(); 1415792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(false); 1416e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mPlayPos = pos; 1417e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 1418792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 1419792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 1420792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1421792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1422b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1423792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void gotoIdleState() { 1424792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.removeCallbacksAndMessages(null); 1425792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Message msg = mDelayedStopHandler.obtainMessage(); 1426792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mDelayedStopHandler.sendMessageDelayed(msg, IDLE_DELAY); 1427d5fc5b6cc39bc2c2693428fe957bb4ae7f90c0f7Dianne Hackborn stopForeground(true); 1428792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1429b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1430792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void saveBookmarkIfNeeded() { 1431792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project try { 1432792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (isPodcast()) { 1433792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project long pos = position(); 1434792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project long bookmark = getBookmark(); 1435792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project long duration = duration(); 1436b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He if ((pos < bookmark && (pos + 10000) > bookmark) 1437b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He || (pos > bookmark && (pos - 10000) < bookmark)) { 1438792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // The existing bookmark is close to the current 1439792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // position, so don't update it. 1440792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 1441792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1442792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (pos < 15000 || (pos + 10000) > duration) { 1443792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // if we're near the start or end, clear the bookmark 1444792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project pos = 0; 1445792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1446b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1447792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // write 'pos' to the bookmark field 1448792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ContentValues values = new ContentValues(); 1449792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project values.put(MediaStore.Audio.Media.BOOKMARK, pos); 1450792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Uri uri = ContentUris.withAppendedId( 1451792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, mCursor.getLong(IDCOLIDX)); 1452792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project getContentResolver().update(uri, values, null, null); 1453792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1454792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } catch (SQLiteException ex) { 1455792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1456792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1457792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1458792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // Make sure there are at least 5 items after the currently playing item 1459792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // and no more than 10 items before. 1460792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private void doAutoShuffleUpdate() { 1461792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project boolean notify = false; 14623f502de8e8963224054a97730d132f82ac87d522Marco Nelissen 1463792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // remove old entries 1464792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos > 10) { 1465792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project removeTracks(0, mPlayPos - 9); 1466792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notify = true; 1467792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1468792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // add new entries if needed 1469792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int to_add = 7 - (mPlayListLen - (mPlayPos < 0 ? -1 : mPlayPos)); 1470792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < to_add; i++) { 1471792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // pick something at random from the list 14723f502de8e8963224054a97730d132f82ac87d522Marco Nelissen 14733f502de8e8963224054a97730d132f82ac87d522Marco Nelissen int lookback = mHistory.size(); 14743f502de8e8963224054a97730d132f82ac87d522Marco Nelissen int idx = -1; 1475b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He while (true) { 14763f502de8e8963224054a97730d132f82ac87d522Marco Nelissen idx = mRand.nextInt(mAutoShuffleList.length); 14773f502de8e8963224054a97730d132f82ac87d522Marco Nelissen if (!wasRecentlyUsed(idx, lookback)) { 14783f502de8e8963224054a97730d132f82ac87d522Marco Nelissen break; 14793f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 14803f502de8e8963224054a97730d132f82ac87d522Marco Nelissen lookback /= 2; 14813f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 14823f502de8e8963224054a97730d132f82ac87d522Marco Nelissen mHistory.add(idx); 14833f502de8e8963224054a97730d132f82ac87d522Marco Nelissen if (mHistory.size() > MAX_HISTORY_SIZE) { 14843f502de8e8963224054a97730d132f82ac87d522Marco Nelissen mHistory.remove(0); 14853f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 1486792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ensurePlayListCapacity(mPlayListLen + 1); 14873f502de8e8963224054a97730d132f82ac87d522Marco Nelissen mPlayList[mPlayListLen++] = mAutoShuffleList[idx]; 1488792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notify = true; 1489792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1490792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (notify) { 1491792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 1492792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1493792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1494792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 14953f502de8e8963224054a97730d132f82ac87d522Marco Nelissen // check that the specified idx is not in the history (but only look at at 14963f502de8e8963224054a97730d132f82ac87d522Marco Nelissen // most lookbacksize entries in the history) 14973f502de8e8963224054a97730d132f82ac87d522Marco Nelissen private boolean wasRecentlyUsed(int idx, int lookbacksize) { 14983f502de8e8963224054a97730d132f82ac87d522Marco Nelissen // early exit to prevent infinite loops in case idx == mPlayPos 14993f502de8e8963224054a97730d132f82ac87d522Marco Nelissen if (lookbacksize == 0) { 15003f502de8e8963224054a97730d132f82ac87d522Marco Nelissen return false; 15013f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 15023f502de8e8963224054a97730d132f82ac87d522Marco Nelissen 15033f502de8e8963224054a97730d132f82ac87d522Marco Nelissen int histsize = mHistory.size(); 15043f502de8e8963224054a97730d132f82ac87d522Marco Nelissen if (histsize < lookbacksize) { 15053f502de8e8963224054a97730d132f82ac87d522Marco Nelissen Log.d(LOGTAG, "lookback too big"); 15063f502de8e8963224054a97730d132f82ac87d522Marco Nelissen lookbacksize = histsize; 15073f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 15083f502de8e8963224054a97730d132f82ac87d522Marco Nelissen int maxidx = histsize - 1; 15093f502de8e8963224054a97730d132f82ac87d522Marco Nelissen for (int i = 0; i < lookbacksize; i++) { 15103f502de8e8963224054a97730d132f82ac87d522Marco Nelissen long entry = mHistory.get(maxidx - i); 15113f502de8e8963224054a97730d132f82ac87d522Marco Nelissen if (entry == idx) { 15123f502de8e8963224054a97730d132f82ac87d522Marco Nelissen return true; 15133f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 15143f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 15153f502de8e8963224054a97730d132f82ac87d522Marco Nelissen return false; 15163f502de8e8963224054a97730d132f82ac87d522Marco Nelissen } 15173f502de8e8963224054a97730d132f82ac87d522Marco Nelissen 1518792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // A simple variation of Random that makes sure that the 1519792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // value it returns is not equal to the value it returned 1520792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // previously, unless the interval is 1. 1521756c3f57f11a7bb3bf1cf1333ee8ffbc51039748Marco Nelissen private static class Shuffler { 1522792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int mPrevious; 1523792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private Random mRandom = new Random(); 1524792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int nextInt(int interval) { 1525792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int ret; 1526792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project do { 1527792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ret = mRandom.nextInt(interval); 1528792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } while (ret == mPrevious && interval > 1); 1529792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPrevious = ret; 1530792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return ret; 1531792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1532792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 1533792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1534792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private boolean makeAutoShuffleList() { 1535792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project ContentResolver res = getContentResolver(); 1536792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project Cursor c = null; 1537792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project try { 1538792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project c = res.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, 1539b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He new String[] {MediaStore.Audio.Media._ID}, 1540b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He MediaStore.Audio.Media.IS_MUSIC + "=1", null, null); 1541792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (c == null || c.getCount() == 0) { 1542792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return false; 1543792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1544792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int len = c.getCount(); 1545b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He long[] list = new long[len]; 1546792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < len; i++) { 1547792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project c.moveToNext(); 1548bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen list[i] = c.getLong(0); 1549792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1550792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mAutoShuffleList = list; 1551792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return true; 1552792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } catch (RuntimeException ex) { 1553792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } finally { 1554792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (c != null) { 1555792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project c.close(); 1556792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1557792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1558792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return false; 1559792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1560b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1561792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1562792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Removes the range of tracks specified from the play list. If a file within the range is 1563792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * the file currently being played, playback will move to the next file after the 1564b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He * range. 1565792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param first The first file to be removed 1566792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param last The last file to be removed 1567792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @return the number of tracks deleted 1568792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1569792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int removeTracks(int first, int last) { 1570792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int numremoved = removeTracksInternal(first, last); 1571792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (numremoved > 0) { 1572792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 1573792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1574792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return numremoved; 1575792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1576b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1577792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private int removeTracksInternal(int first, int last) { 1578792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1579792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (last < first) return 0; 1580792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (first < 0) first = 0; 1581792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (last >= mPlayListLen) last = mPlayListLen - 1; 1582792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1583792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project boolean gotonext = false; 1584792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (first <= mPlayPos && mPlayPos <= last) { 1585792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = first; 1586792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project gotonext = true; 1587792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else if (mPlayPos > last) { 1588792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos -= (last - first + 1); 1589792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1590792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int num = mPlayListLen - last - 1; 1591792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < num; i++) { 1592792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayList[first + i] = mPlayList[last + 1 + i]; 1593792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1594792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen -= last - first + 1; 1595b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1596792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (gotonext) { 1597792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayListLen == 0) { 1598792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(true); 1599792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = -1; 16003aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen if (mCursor != null) { 16013aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen mCursor.close(); 16023aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen mCursor = null; 16033aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen } 1604792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1605792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos >= mPlayListLen) { 1606792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = 0; 1607792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1608792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project boolean wasPlaying = isPlaying(); 1609792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(false); 1610e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 1611792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (wasPlaying) { 1612792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 1613792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1614792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 16153aa9ad029bc85da2e07bba019cec928ad5d74043Marco Nelissen notifyChange(META_CHANGED); 1616792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1617792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return last - first + 1; 1618792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1619792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1620b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1621792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1622792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Removes all instances of the track with the given id 1623792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * from the playlist. 1624792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param id The id to be removed 1625792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @return how many instances of the track were removed 1626792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1627bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public int removeTrack(long id) { 1628792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project int numremoved = 0; 1629792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1630792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project for (int i = 0; i < mPlayListLen; i++) { 1631792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayList[i] == id) { 1632792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project numremoved += removeTracksInternal(i, i); 1633792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project i--; 1634792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1635792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1636792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1637792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (numremoved > 0) { 1638792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(QUEUE_CHANGED); 1639792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1640792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return numremoved; 1641792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1642b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1643792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setShuffleMode(int shufflemode) { 1644b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He synchronized (this) { 1645792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mShuffleMode == shufflemode && mPlayListLen > 0) { 1646792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 1647792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1648792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mShuffleMode = shufflemode; 1649792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mShuffleMode == SHUFFLE_AUTO) { 1650792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (makeAutoShuffleList()) { 1651792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayListLen = 0; 1652792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project doAutoShuffleUpdate(); 1653792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = 0; 1654e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 1655792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 1656792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 1657792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return; 1658792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1659792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // failed to build a list of files to shuffle 1660792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mShuffleMode = SHUFFLE_NONE; 1661792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1662792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1663792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(false); 1664792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1665792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1666792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getShuffleMode() { 1667792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mShuffleMode; 1668792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1669b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1670792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setRepeatMode(int repeatmode) { 1671b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He synchronized (this) { 1672792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mRepeatMode = repeatmode; 1673e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen setNextTrack(); 1674792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project saveQueue(false); 1675792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1676792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1677792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getRepeatMode() { 1678792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mRepeatMode; 1679792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1680792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1681792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getMediaMountedCount() { 1682792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mMediaMountedCount; 1683792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1684792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1685792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1686792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Returns the path of the currently playing file, or null if 1687792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * no file is currently playing. 1688792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1689792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getPath() { 1690792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mFileToPlay; 1691792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1692b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1693792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1694792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Returns the rowid of the currently playing file, or -1 if 1695792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * no file is currently playing. 1696792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1697bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getAudioId() { 1698792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1699792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayPos >= 0 && mPlayer.isInitialized()) { 1700792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mPlayList[mPlayPos]; 1701792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1702792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1703792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1704792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1705b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1706792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1707b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He * Returns the position in the queue 1708792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @return the position in the queue 1709792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1710792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getQueuePosition() { 1711b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He synchronized (this) { 1712792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mPlayPos; 1713792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1714792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1715b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1716792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1717792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Starts playing the track at the given position in the queue. 1718792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param pos The position in the queue of the track that will be played. 1719792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1720792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setQueuePosition(int pos) { 1721b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He synchronized (this) { 1722792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project stop(false); 1723792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mPlayPos = pos; 1724e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen openCurrentAndNext(); 1725792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project play(); 1726792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project notifyChange(META_CHANGED); 1727ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen if (mShuffleMode == SHUFFLE_AUTO) { 1728ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen doAutoShuffleUpdate(); 1729ec0c57a414c3563ebbf5767d92787a6a3f4a8820Marco Nelissen } 1730792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1731792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1732792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1733792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getArtistName() { 1734b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He synchronized (this) { 1735792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1736792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return null; 1737792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1738792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST)); 1739792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1740792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1741b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1742bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getArtistId() { 1743792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1744792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1745792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1746792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1747bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST_ID)); 1748792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1749792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1750792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1751792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getAlbumName() { 1752792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1753792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1754792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return null; 1755792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1756792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM)); 1757792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1758792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1759792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1760bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getAlbumId() { 1761792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1762792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1763792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1764792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1765bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen return mCursor.getLong(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ALBUM_ID)); 1766792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1767792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1768792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1769792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getTrackName() { 1770792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1771792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1772792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return null; 1773792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1774792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mCursor.getString(mCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.TITLE)); 1775792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1776792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1777792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1778792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private boolean isPodcast() { 1779792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1780792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1781792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return false; 1782792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1783792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return (mCursor.getInt(PODCASTCOLIDX) > 0); 1784792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1785792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1786b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1787792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private long getBookmark() { 1788792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project synchronized (this) { 1789792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mCursor == null) { 1790792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return 0; 1791792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1792792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mCursor.getLong(BOOKMARKCOLIDX); 1793792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1794792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1795b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1796792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1797792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Returns the duration of the file in milliseconds. 1798792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Currently this method returns -1 for the duration of MIDI files. 1799792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1800792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long duration() { 1801792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayer.isInitialized()) { 1802792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mPlayer.duration(); 1803792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1804792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1805792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1806792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1807792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1808792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Returns the current playback position in milliseconds 1809792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1810792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long position() { 1811792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayer.isInitialized()) { 1812792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mPlayer.position(); 1813792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1814792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1815792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1816792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1817792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 1818792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Seeks to the position specified. 1819792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * 1820792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * @param pos The position to seek to, in milliseconds 1821792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1822792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long seek(long pos) { 1823792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (mPlayer.isInitialized()) { 1824792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (pos < 0) pos = 0; 1825792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (pos > mPlayer.duration()) pos = mPlayer.duration(); 1826792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mPlayer.seek(pos); 1827792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1828792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return -1; 1829792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1830792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1831792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project /** 18321cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent * Sets the audio session ID. 18331cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent * 18341cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent * @param sessionId: the audio session ID. 18351cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent */ 18361cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent public void setAudioSessionId(int sessionId) { 18371cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent synchronized (this) { 18381cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent mPlayer.setAudioSessionId(sessionId); 18391cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 18401cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 18411cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent 18421cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent /** 18431cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent * Returns the audio session ID. 18441cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent */ 18451cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent public int getAudioSessionId() { 18461cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent synchronized (this) { 18471cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent return mPlayer.getAudioSessionId(); 18481cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 18491cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 18501cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent 18511cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent /** 1852792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * Provides a unified interface for dealing with midi files and 1853792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project * other media files. 1854792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project */ 1855792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private class MultiPlayer { 1856308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen private CompatMediaPlayer mCurrentMediaPlayer = new CompatMediaPlayer(); 1857308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen private CompatMediaPlayer mNextMediaPlayer; 1858792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private Handler mHandler; 1859792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project private boolean mIsInitialized = false; 1860792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1861792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public MultiPlayer() { 1862b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mCurrentMediaPlayer.setWakeMode( 1863b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK); 1864792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1865792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1866792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setDataSource(String path) { 186790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path); 186890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (mIsInitialized) { 186990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen setNextDataSource(null); 187090d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 1871e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1872e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 187390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen private boolean setDataSourceImpl(MediaPlayer player, String path) { 1874792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project try { 1875e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.reset(); 1876e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setOnPreparedListener(null); 1877792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project if (path.startsWith("content://")) { 1878e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setDataSource(MediaPlaybackService.this, Uri.parse(path)); 1879792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } else { 1880e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setDataSource(path); 1881792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1882e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setAudioStreamType(AudioManager.STREAM_MUSIC); 1883e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.prepare(); 1884792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } catch (IOException ex) { 1885792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // TODO: notify the user why the file couldn't be opened 188690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return false; 1887792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } catch (IllegalArgumentException ex) { 1888792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project // TODO: notify the user why the file couldn't be opened 188990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return false; 1890792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1891e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setOnCompletionListener(listener); 1892e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen player.setOnErrorListener(errorListener); 1893f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen Intent i = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION); 1894f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId()); 1895f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName()); 1896f2ef3b5153fd2f447939f267d8887ff3bba0d13fMarco Nelissen sendBroadcast(i); 189790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen return true; 1898792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1899e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen 1900e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen public void setNextDataSource(String path) { 1901e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.setNextMediaPlayer(null); 1902e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (mNextMediaPlayer != null) { 1903e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextMediaPlayer.release(); 1904e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextMediaPlayer = null; 1905e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1906e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (path == null) { 1907e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return; 1908e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1909308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mNextMediaPlayer = new CompatMediaPlayer(); 1910e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextMediaPlayer.setWakeMode(MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK); 1911e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextMediaPlayer.setAudioSessionId(getAudioSessionId()); 191290d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen if (setDataSourceImpl(mNextMediaPlayer, path)) { 191390d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer); 191490d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } else { 191590d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen // failed to open next, we'll transition the old fashioned way, 191690d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen // which will skip over the faulty file 191790d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mNextMediaPlayer.release(); 191890d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen mNextMediaPlayer = null; 191990d1f62b8edbc03a0d0b2b42217e9004e7d658d8Marco Nelissen } 1920e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1921b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1922792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public boolean isInitialized() { 1923792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return mIsInitialized; 1924792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1925792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1926792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void start() { 19273988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen MusicUtils.debugLog(new Exception("MultiPlayer.start called")); 1928e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.start(); 1929792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1930792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1931792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void stop() { 1932e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.reset(); 1933792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mIsInitialized = false; 1934792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1935792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 19362b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen /** 19372b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen * You CANNOT use this player anymore after calling release() 19382b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen */ 19392b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen public void release() { 19402b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen stop(); 1941e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.release(); 19422b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen } 1943b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1944792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void pause() { 1945e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.pause(); 1946792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1947b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 1948792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setHandler(Handler handler) { 1949792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project mHandler = handler; 1950792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1951792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1952792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project MediaPlayer.OnCompletionListener listener = new MediaPlayer.OnCompletionListener() { 1953792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void onCompletion(MediaPlayer mp) { 1954e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen if (mp == mCurrentMediaPlayer && mNextMediaPlayer != null) { 1955e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.release(); 1956e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer = mNextMediaPlayer; 1957e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mNextMediaPlayer = null; 1958e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mHandler.sendEmptyMessage(TRACK_WENT_TO_NEXT); 1959e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } else { 1960e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // Acquire a temporary wakelock, since when we return from 1961e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // this callback the MediaPlayer will release its wakelock 1962e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // and allow the device to go to sleep. 1963e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // This temporary wakelock is released when the RELEASE_WAKELOCK 1964e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen // message is processed, but just in case, put a timeout on it. 1965e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mWakeLock.acquire(30000); 1966e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mHandler.sendEmptyMessage(TRACK_ENDED); 1967e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mHandler.sendEmptyMessage(RELEASE_WAKELOCK); 1968e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen } 1969792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1970792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 1971792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1972792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project MediaPlayer.OnErrorListener errorListener = new MediaPlayer.OnErrorListener() { 1973792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public boolean onError(MediaPlayer mp, int what, int extra) { 1974792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project switch (what) { 1975b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He case MediaPlayer.MEDIA_ERROR_SERVER_DIED: 1976b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mIsInitialized = false; 1977b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mCurrentMediaPlayer.release(); 1978b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // Creating a new MediaPlayer and settings its wakemode does not 1979b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // require the media service, so it's OK to do this now, while the 1980b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He // service is still being restarted 1981b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mCurrentMediaPlayer = new CompatMediaPlayer(); 1982b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mCurrentMediaPlayer.setWakeMode( 1983b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He MediaPlaybackService.this, PowerManager.PARTIAL_WAKE_LOCK); 1984b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He mHandler.sendMessageDelayed(mHandler.obtainMessage(SERVER_DIED), 2000); 1985b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He return true; 1986b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He default: 1987b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He Log.d("MultiPlayer", "Error: " + what + "," + extra); 1988b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He break; 1989792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1990792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return false; 1991b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He } 1992792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project }; 1993792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1994792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long duration() { 1995e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return mCurrentMediaPlayer.getDuration(); 1996792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 1997792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 1998792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long position() { 1999e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return mCurrentMediaPlayer.getCurrentPosition(); 2000792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2001792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 2002792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long seek(long whereto) { 2003e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.seekTo((int) whereto); 2004792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project return whereto; 2005792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2006792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 2007792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setVolume(float vol) { 2008e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.setVolume(vol, vol); 2009792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 20101cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent 20111cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent public void setAudioSessionId(int sessionId) { 2012e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen mCurrentMediaPlayer.setAudioSessionId(sessionId); 20131cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 20141cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent 20151cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent public int getAudioSessionId() { 2016e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen return mCurrentMediaPlayer.getAudioSessionId(); 20171cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 2018792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2019792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project 2020308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen static class CompatMediaPlayer extends MediaPlayer implements OnCompletionListener { 2021308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen private boolean mCompatMode = true; 2022308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen private MediaPlayer mNextPlayer; 2023308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen private OnCompletionListener mCompletion; 2024308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen 2025308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen public CompatMediaPlayer() { 2026308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen try { 2027308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen MediaPlayer.class.getMethod("setNextMediaPlayer", MediaPlayer.class); 2028308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mCompatMode = false; 2029308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } catch (NoSuchMethodException e) { 2030308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mCompatMode = true; 2031308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen super.setOnCompletionListener(this); 2032308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2033308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2034308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen 2035308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen public void setNextMediaPlayer(MediaPlayer next) { 2036308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen if (mCompatMode) { 2037308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mNextPlayer = next; 2038308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } else { 2039308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen super.setNextMediaPlayer(next); 2040308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2041308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2042308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen 2043308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen @Override 2044308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen public void setOnCompletionListener(OnCompletionListener listener) { 2045308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen if (mCompatMode) { 2046308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mCompletion = listener; 2047308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } else { 2048308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen super.setOnCompletionListener(listener); 2049308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2050308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2051308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen 2052308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen @Override 2053308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen public void onCompletion(MediaPlayer mp) { 2054308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen if (mNextPlayer != null) { 2055308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen // as it turns out, starting a new MediaPlayer on the completion 2056308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen // of a previous player ends up slightly overlapping the two 2057308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen // playbacks, so slightly delaying the start of the next player 2058308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen // gives a better user experience 2059308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen SystemClock.sleep(50); 2060308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mNextPlayer.start(); 2061308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2062308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen mCompletion.onCompletion(this); 2063308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2064308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen } 2065308670290db0a553de41a21f1c07ca7d53b3fbf6Marco Nelissen 20662b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen /* 20672b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen * By making this a static class with a WeakReference to the Service, we 20682b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen * ensure that the Service can be GCd even when the system process still 20692b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen * has a remote reference to the stub. 20702b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen */ 20712b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen static class ServiceStub extends IMediaPlaybackService.Stub { 20722b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen WeakReference<MediaPlaybackService> mService; 2073b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He 20742b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen ServiceStub(MediaPlaybackService service) { 20752b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService = new WeakReference<MediaPlaybackService>(service); 20762b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen } 20772b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen 2078b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He public void openFile(String path) { 20798d08ec235831d71fdd7f7b6f7757c2bc19528faeMarco Nelissen mService.get().open(path); 2080792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2081b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He public void open(long[] list, int position) { 20822b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().open(list, position); 2083792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2084792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getQueuePosition() { 20852b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getQueuePosition(); 2086792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2087792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setQueuePosition(int index) { 20882b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().setQueuePosition(index); 2089792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2090792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public boolean isPlaying() { 20912b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().isPlaying(); 2092792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2093792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void stop() { 20942b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().stop(); 2095792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2096792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void pause() { 20972b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().pause(); 2098792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2099792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void play() { 21002b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().play(); 2101792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2102792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void prev() { 21032b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().prev(); 2104792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2105792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void next() { 2106bd0d2f10e06ec6fb83e21cb4966032916f68acc3Marco Nelissen mService.get().gotoNext(true); 2107792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2108792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getTrackName() { 21092b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getTrackName(); 2110792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2111792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getAlbumName() { 21122b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getAlbumName(); 2113792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2114bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getAlbumId() { 21152b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getAlbumId(); 2116792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2117792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getArtistName() { 21182b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getArtistName(); 2119792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2120bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getArtistId() { 21212b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getArtistId(); 2122792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2123b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He public void enqueue(long[] list, int action) { 21242b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().enqueue(list, action); 2125792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2126b0fba8b212a649f41c7cad4c9e7c33e94ca29bb0Jack He public long[] getQueue() { 21272b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getQueue(); 2128792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2129792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void moveQueueItem(int from, int to) { 21302b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().moveQueueItem(from, to); 2131792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2132792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public String getPath() { 21332b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getPath(); 2134792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2135bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public long getAudioId() { 21362b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getAudioId(); 2137792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2138792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long position() { 21392b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().position(); 2140792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2141792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long duration() { 21422b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().duration(); 2143792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2144792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public long seek(long pos) { 21452b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().seek(pos); 2146792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2147792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setShuffleMode(int shufflemode) { 21482b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().setShuffleMode(shufflemode); 2149792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2150792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getShuffleMode() { 21512b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getShuffleMode(); 2152792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2153792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int removeTracks(int first, int last) { 21542b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().removeTracks(first, last); 2155792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2156bd447b61c42589133257fb7992ccbed18a507a46Marco Nelissen public int removeTrack(long id) { 21572b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().removeTrack(id); 2158792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2159792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public void setRepeatMode(int repeatmode) { 21602b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen mService.get().setRepeatMode(repeatmode); 2161792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2162792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getRepeatMode() { 21632b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getRepeatMode(); 2164792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 2165792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project public int getMediaMountedCount() { 21662b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen return mService.get().getMediaMountedCount(); 2167792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project } 21681cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent public int getAudioSessionId() { 21691cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent return mService.get().getAudioSessionId(); 21701cc72a178de85e9aa254906dadb54a51423731f3Eric Laurent } 21712b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen } 21723988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen 21733988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen @Override 21743988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 2175bf555cee7a01aed223b05144d1cec0cffdd9a6aeMarco Nelissen writer.println("" + mPlayListLen + " items in queue, currently at index " + mPlayPos); 21763988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println("Currently loaded:"); 21773988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println(getArtistName()); 21783988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println(getAlbumName()); 21793988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println(getTrackName()); 21803988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println(getPath()); 21813988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen writer.println("playing: " + mIsSupposedToBePlaying); 2182e41bd18d3351b494306b7d7f2e1f562fa3fa8f8cMarco Nelissen writer.println("actual: " + mPlayer.mCurrentMediaPlayer.isPlaying()); 2183bf555cee7a01aed223b05144d1cec0cffdd9a6aeMarco Nelissen writer.println("shuffle mode: " + mShuffleMode); 21843988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen MusicUtils.debugDump(writer); 21853988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen } 21863988890280c37b2b4aa1cb29ce16da8aa38ffa83Marco Nelissen 21872b0b91376a7101fafdf8b007ae660d8b2a039530Marco Nelissen private final IBinder mBinder = new ServiceStub(this); 2188792a2206a4f05f6bd13fce902d3663892d2947afThe Android Open Source Project} 2189