diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 40709265..e6281184 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -26,7 +26,7 @@ THE SOFTWARE.
android:versionName="0.9.13"
android:versionCode="0913"
android:installLocation="auto">
-
+
diff --git a/project.properties b/project.properties
index 88054ae6..03c5e078 100644
--- a/project.properties
+++ b/project.properties
@@ -10,7 +10,7 @@
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
-target=android-15
+target=android-16
## do not enable: breaks settings in SDK15
##proguard.config=proguard.config
diff --git a/src/ch/blinkenlights/android/vanilla/PlaybackService.java b/src/ch/blinkenlights/android/vanilla/PlaybackService.java
index 4162436e..9efe4b34 100644
--- a/src/ch/blinkenlights/android/vanilla/PlaybackService.java
+++ b/src/ch/blinkenlights/android/vanilla/PlaybackService.java
@@ -296,6 +296,7 @@ public final class PlaybackService extends Service
private Looper mLooper;
private Handler mHandler;
MediaPlayer mMediaPlayer;
+ MediaPlayer mPreparedMediaPlayer;
private boolean mMediaPlayerInitialized;
private PowerManager.WakeLock mWakeLock;
private NotificationManager mNotificationManager;
@@ -385,11 +386,8 @@ public final class PlaybackService extends Service
mTimeline.setCallback(this);
int state = loadState();
- mMediaPlayer = new MediaPlayer();
- mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- mMediaPlayer.setOnCompletionListener(this);
- mMediaPlayer.setOnErrorListener(this);
-
+ mMediaPlayer = getNewMediaPlayer();
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
try {
mEqualizer = new CompatEq(mMediaPlayer);
@@ -573,6 +571,58 @@ public final class PlaybackService extends Service
super.onDestroy();
}
+ /**
+ * Returns a new MediaPlayer object
+ */
+ public MediaPlayer getNewMediaPlayer() {
+ MediaPlayer mp = new MediaPlayer();
+ mp.setAudioStreamType(AudioManager.STREAM_MUSIC);
+ mp.setOnCompletionListener(this);
+ mp.setOnErrorListener(this);
+ return mp;
+ }
+
+ public void triggerGaplessUpdate() {
+ Log.d("VanillaMusic", "triggering gapless update");
+
+ if(mMediaPlayerInitialized != true)
+ return;
+
+ if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
+ return; /* setNextMediaPlayer is supported since JB */
+
+ if(mPreparedMediaPlayer != null) {
+ /* an old prepared player exists and is
+ * most likely invalid -> destroy it now
+ */
+ mMediaPlayer.setNextMediaPlayer(null);
+ mPreparedMediaPlayer.release();
+ mPreparedMediaPlayer = null;
+ Log.d("VanillaMusic", "old prepared player destroyed");
+ }
+
+ int fa = finishAction(mState);
+ Song nextSong = getSong(1);
+ if( nextSong != null
+ && fa != SongTimeline.FINISH_REPEAT_CURRENT
+ && fa != SongTimeline.FINISH_STOP_CURRENT
+ && !mTimeline.isEndOfQueue() ) {
+ try {
+ mPreparedMediaPlayer = getNewMediaPlayer();
+ mPreparedMediaPlayer.setDataSource(nextSong.path);
+ mPreparedMediaPlayer.prepare();
+ mMediaPlayer.setNextMediaPlayer(mPreparedMediaPlayer);
+ Log.d("VanillaMusic", "New media player prepared as "+mPreparedMediaPlayer+" with path "+nextSong.path);
+ } catch (IOException e) {
+ Log.e("VanillaMusic", "IOException", e);
+ }
+ }
+ else {
+ Log.d("VanillaMusic", "Must not create new media player object");
+ }
+
+ }
+
/**
* Return the SharedPreferences instance containing the PlaybackService
* settings, creating it if necessary.
@@ -796,6 +846,8 @@ public final class PlaybackService extends Service
mTimeline.setShuffleMode(shuffleMode(state));
if ((toggled & MASK_FINISH) != 0)
mTimeline.setFinishAction(finishAction(state));
+
+ triggerGaplessUpdate();
}
private void broadcastChange(int state, Song song, long uptime)
@@ -1054,8 +1106,18 @@ public final class PlaybackService extends Service
mMediaPlayer.reset();
mMediaPlayer.setDataSource(song.path);
mMediaPlayer.prepare();
+
+ if(mPreparedMediaPlayer != null &&
+ mPreparedMediaPlayer.isPlaying()) {
+ Log.v("VanillaMusic", "Replacing existing mediaplayer object with prepared version");
+ mMediaPlayer.release();
+ mMediaPlayer = mPreparedMediaPlayer;
+ mPreparedMediaPlayer = null;
+ }
+
mMediaPlayerInitialized = true;
-
+ triggerGaplessUpdate();
+
if (mPendingSeek != 0 && mPendingSeekSong == song.id) {
mMediaPlayer.seekTo(mPendingSeek);
mPendingSeek = 0;