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