From bdb93df55fc4f37181a21fc7cbe3fab2c51015ca Mon Sep 17 00:00:00 2001 From: Christopher Eby Date: Sun, 4 Apr 2010 14:40:21 -0500 Subject: [PATCH] Handle loss of media gracefully When the sd card is unmounted, the song will immediately stop and the no media message will appear. The message will now automatically go away when media is available --- src/org/kreed/vanilla/OneCellWidget.java | 2 +- src/org/kreed/vanilla/PlaybackService.java | 46 +++++++++++++++++++--- src/org/kreed/vanilla/Song.java | 4 +- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/org/kreed/vanilla/OneCellWidget.java b/src/org/kreed/vanilla/OneCellWidget.java index 2ae92db1..6a3e0914 100644 --- a/src/org/kreed/vanilla/OneCellWidget.java +++ b/src/org/kreed/vanilla/OneCellWidget.java @@ -35,7 +35,7 @@ public class OneCellWidget extends AppWidgetProvider { Song song = null; if (state.load(context)) { song = new Song(state.savedIds[state.savedIndex]); - if (!song.populate()) + if (!song.populate(false)) song = null; } diff --git a/src/org/kreed/vanilla/PlaybackService.java b/src/org/kreed/vanilla/PlaybackService.java index 3337b296..fa5f85fb 100644 --- a/src/org/kreed/vanilla/PlaybackService.java +++ b/src/org/kreed/vanilla/PlaybackService.java @@ -31,10 +31,12 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.Service; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; +import android.database.ContentObserver; import android.media.AudioManager; import android.media.MediaPlayer; import android.os.Build; @@ -44,6 +46,7 @@ import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.preference.PreferenceManager; +import android.provider.MediaStore; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; @@ -92,6 +95,7 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On private int mPendingGo = -1; private Song mLastSongBroadcast; private boolean mPlugged; + private ContentObserver mMediaObserver; private Method mIsWiredHeadsetOn; private Method mStartForeground; @@ -203,7 +207,7 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On PlaybackServiceState state = new PlaybackServiceState(); if (state.load(this)) { Song song = new Song(state.savedIds[state.savedIndex]); - if (song.populate()) { + if (song.populate(false)) { broadcastChange(mState, mState, song); mSongTimeline = new ArrayList(state.savedIds.length); @@ -329,6 +333,9 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On private boolean updateState(int state) { + if ((state & FLAG_NO_MEDIA) != 0) + state &= ~FLAG_PLAYING; + Song song = getSong(0); if (song == null && (state & FLAG_PLAYING) != 0) return false; @@ -342,6 +349,16 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On if (state != oldState || song != lastBroadcast) updateNotification(song); + if ((state & FLAG_NO_MEDIA) != 0 && (oldState & FLAG_NO_MEDIA) == 0) { + ContentResolver resolver = ContextApplication.getContext().getContentResolver(); + mMediaObserver = new MediaContentObserver(mHandler); + resolver.registerContentObserver(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, true, mMediaObserver); + } else if ((state & FLAG_NO_MEDIA) == 0 && (oldState & FLAG_NO_MEDIA) != 0) { + ContentResolver resolver = ContextApplication.getContext().getContentResolver(); + resolver.unregisterContentObserver(mMediaObserver); + mMediaObserver = null; + } + if ((state & FLAG_PLAYING) != 0 && (oldState & FLAG_PLAYING) == 0) { if (mNotificationMode != NEVER) startForegroundCompat(NOTIFICATION_ID, mNotification); @@ -417,6 +434,8 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On if (song == null) { setFlag(FLAG_NO_MEDIA); return; + } else { + unsetFlag(FLAG_NO_MEDIA); } synchronized (mSongTimeline) { @@ -453,7 +472,11 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On { Log.e("VanillaMusic", "MediaPlayer error: " + what + " " + extra); mMediaPlayer.reset(); - mHandler.sendEmptyMessage(TRACK_CHANGED); + Song song = getSong(+1); + if (song != null && !song.populate(true)) + setFlag(FLAG_NO_MEDIA); + else + mHandler.sendEmptyMessage(TRACK_CHANGED); return true; } @@ -481,9 +504,9 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On } } - if (!song.populate()) { + if (!song.populate(false)) { song.randomize(); - if (!song.populate()) + if (!song.populate(false)) return null; } @@ -500,7 +523,7 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On public void onReceive(Context content, Intent intent) { String action = intent.getAction(); - if (Intent.ACTION_HEADSET_PLUG.equals(action) && mHandler != null) { + if (Intent.ACTION_HEADSET_PLUG.equals(action)) { boolean oldPlugged = mPlugged; mPlugged = intent.getIntExtra("state", 0) != 0; if (mPlugged != oldPlugged && (mHeadsetPause && !mPlugged || mHeadsetOnly && !isSpeakerOn())) @@ -529,6 +552,19 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On } }; + private class MediaContentObserver extends ContentObserver { + public MediaContentObserver(Handler handler) + { + super(handler); + } + + @Override + public void onChange(boolean selfChange) + { + setCurrentSong(0); + } + } + public void onSharedPreferenceChanged(SharedPreferences settings, String key) { loadPreference(key); diff --git a/src/org/kreed/vanilla/Song.java b/src/org/kreed/vanilla/Song.java index 6bd9e1d4..51faf9a3 100644 --- a/src/org/kreed/vanilla/Song.java +++ b/src/org/kreed/vanilla/Song.java @@ -54,9 +54,9 @@ public class Song implements Parcelable { this.id = id; } - public boolean populate() + public boolean populate(boolean force) { - if (path != null) + if (path != null && !force) return true; if (id == -1) return false;