summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java49
-rw-r--r--app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java44
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java2
-rw-r--r--app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java51
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java31
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java11
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java13
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java47
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java29
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java61
17 files changed, 308 insertions, 51 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java b/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java
new file mode 100644
index 000000000..80dded59f
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/entities/ExternalMediaTest.java
@@ -0,0 +1,49 @@
+package de.test.antennapod.entities;
+
+import android.annotation.SuppressLint;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.test.InstrumentationTestCase;
+
+import de.danoeh.antennapod.core.feed.MediaType;
+import de.danoeh.antennapod.core.util.playback.ExternalMedia;
+
+/**
+ * Tests for {@link ExternalMedia} entity.
+ */
+public class ExternalMediaTest extends InstrumentationTestCase {
+
+ private static final int NOT_SET = -1;
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ clearSharedPrefs();
+ }
+
+ @SuppressLint("CommitPrefEdits")
+ private void clearSharedPrefs() {
+ SharedPreferences prefs = getDefaultSharedPrefs();
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.clear();
+ editor.commit();
+ }
+
+ private SharedPreferences getDefaultSharedPrefs() {
+ return PreferenceManager.getDefaultSharedPreferences(getInstrumentation().getTargetContext());
+ }
+
+ public void testSaveCurrentPositionUpdatesPreferences() {
+ final int POSITION = 50;
+ final int LAST_PLAYED_TIME = 1650;
+
+ assertEquals(NOT_SET, getDefaultSharedPrefs().getInt(ExternalMedia.PREF_POSITION, NOT_SET));
+ assertEquals(NOT_SET, getDefaultSharedPrefs().getLong(ExternalMedia.PREF_LAST_PLAYED_TIME, NOT_SET));
+
+ ExternalMedia media = new ExternalMedia("source", MediaType.AUDIO);
+ media.saveCurrentPosition(getDefaultSharedPrefs(), POSITION, LAST_PLAYED_TIME);
+
+ assertEquals(POSITION, getDefaultSharedPrefs().getInt(ExternalMedia.PREF_POSITION, NOT_SET));
+ assertEquals(LAST_PLAYED_TIME, getDefaultSharedPrefs().getLong(ExternalMedia.PREF_LAST_PLAYED_TIME, NOT_SET));
+ }
+}
diff --git a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
index 13a0e3f78..5836bb699 100644
--- a/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/handler/FeedHandlerTest.java
@@ -173,7 +173,7 @@ public class FeedHandlerTest extends InstrumentationTestCase {
feed.getItems().add(item);
if (withFeedMedia) {
item.setMedia(new FeedMedia(0, item, 4711, 0, 1024*1024, "audio/mp3", null, "http://example.com/media-" + i,
- false, null, 0));
+ false, null, 0, 0));
}
}
diff --git a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
index 96bcd6452..d7a170c17 100644
--- a/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/service/playback/PlaybackServiceMediaPlayerTest.java
@@ -121,7 +121,7 @@ public class PlaybackServiceMediaPlayerTest extends InstrumentationTestCase {
f.setItems(new ArrayList<>());
FeedItem i = new FeedItem(0, "t", "i", "l", new Date(), FeedItem.UNPLAYED, f);
f.getItems().add(i);
- FeedMedia media = new FeedMedia(0, i, 0, 0, 0, "audio/wav", fileUrl, downloadUrl, fileUrl != null, null, 0);
+ FeedMedia media = new FeedMedia(0, i, 0, 0, 0, "audio/wav", fileUrl, downloadUrl, fileUrl != null, null, 0, 0);
i.setMedia(media);
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
index 7b84c288a..afdaeead0 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBCleanupTests.java
@@ -117,7 +117,7 @@ public class DBCleanupTests extends InstrumentationTestCase {
File f = new File(destFolder, "file " + i);
assertTrue(f.createNewFile());
files.add(f);
- item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, playbackCompletionDate, 0));
+ item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true, playbackCompletionDate, 0, 0));
items.add(item);
}
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
index 38bc0c380..18a8d63d1 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBNullCleanupAlgorithmTest.java
@@ -93,7 +93,7 @@ public class DBNullCleanupAlgorithmTest extends InstrumentationTestCase {
assertTrue(f.createNewFile());
files.add(f);
item.setMedia(new FeedMedia(0, item, 1, 0, 1L, "m", f.getAbsolutePath(), "url", true,
- new Date(NUM_ITEMS - i), 0));
+ new Date(NUM_ITEMS - i), 0, 0));
items.add(item);
}
diff --git a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
index 585e27e0b..f5240b873 100644
--- a/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/storage/DBWriterTest.java
@@ -59,6 +59,37 @@ public class DBWriterTest extends InstrumentationTestCase {
adapter.close();
}
+ public void testSetFeedMediaPlaybackInformation() throws IOException, ExecutionException, InterruptedException {
+ final int POSITION = 50;
+ final long LAST_PLAYED_TIME = 1000;
+ final int PLAYED_DURATION = 60;
+ final int DURATION = 100;
+
+ Feed feed = new Feed("url", new Date(), "title");
+ List<FeedItem> items = new ArrayList<>();
+ feed.setItems(items);
+ FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.PLAYED, feed);
+ items.add(item);
+ FeedMedia media = new FeedMedia(0, item, DURATION, 1, 1, "mime_type", "dummy path", "download_url", true, null, 0, 0);
+ item.setMedia(media);
+
+ DBWriter.setFeedItem(item).get();
+
+ media.setPosition(POSITION);
+ media.setLastPlayedTime(LAST_PLAYED_TIME);
+ media.setPlayedDuration(PLAYED_DURATION);
+
+ DBWriter.setFeedMediaPlaybackInformation(item.getMedia()).get();
+
+ FeedItem itemFromDb = DBReader.getFeedItem(item.getId());
+ FeedMedia mediaFromDb = itemFromDb.getMedia();
+
+ assertEquals(POSITION, mediaFromDb.getPosition());
+ assertEquals(LAST_PLAYED_TIME, mediaFromDb.getLastPlayedTime());
+ assertEquals(PLAYED_DURATION, mediaFromDb.getPlayedDuration());
+ assertEquals(DURATION, mediaFromDb.getDuration());
+ }
+
public void testDeleteFeedMediaOfItemFileExists() throws IOException, ExecutionException, InterruptedException {
File dest = new File(getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER), "testFile");
@@ -69,7 +100,7 @@ public class DBWriterTest extends InstrumentationTestCase {
feed.setItems(items);
FeedItem item = new FeedItem(0, "Item", "Item", "url", new Date(), FeedItem.PLAYED, feed);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", dest.getAbsolutePath(), "download_url", true, null, 0);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", dest.getAbsolutePath(), "download_url", true, null, 0, 0);
item.setMedia(media);
items.add(item);
@@ -113,7 +144,7 @@ public class DBWriterTest extends InstrumentationTestCase {
assertTrue(enc.createNewFile());
itemFiles.add(enc);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0, 0);
item.setMedia(media);
item.setChapters(new ArrayList<Chapter>());
@@ -180,7 +211,7 @@ public class DBWriterTest extends InstrumentationTestCase {
assertTrue(enc.createNewFile());
itemFiles.add(enc);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", true, null, 0, 0);
item.setMedia(media);
}
@@ -386,7 +417,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File enc = new File(destFolder, "file " + i);
itemFiles.add(enc);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null, 0);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null, 0, 0);
item.setMedia(media);
}
@@ -458,7 +489,7 @@ public class DBWriterTest extends InstrumentationTestCase {
File enc = new File(destFolder, "file " + i);
itemFiles.add(enc);
- FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null, 0);
+ FeedMedia media = new FeedMedia(0, item, 1, 1, 1, "mime_type", enc.getAbsolutePath(), "download_url", false, null, 0, 0);
item.setMedia(media);
}
@@ -499,7 +530,7 @@ public class DBWriterTest extends InstrumentationTestCase {
Feed feed = new Feed("url", new Date(), "title");
feed.setItems(new ArrayList<FeedItem>());
FeedItem item = new FeedItem(0, "title", "id", "link", new Date(), FeedItem.PLAYED, feed);
- FeedMedia media = new FeedMedia(0, item, 10, 0, 1, "mime", null, "url", false, playbackCompletionDate, 0);
+ FeedMedia media = new FeedMedia(0, item, 10, 0, 1, "mime", null, "url", false, playbackCompletionDate, 0, 0);
feed.getItems().add(item);
item.setMedia(media);
PodDBAdapter adapter = PodDBAdapter.getInstance();
@@ -796,5 +827,4 @@ public class DBWriterTest extends InstrumentationTestCase {
assertTrue(item.isPlayed());
}
}
-
}
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
index 9670a596a..dc5294324 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/UITestUtils.java
@@ -156,7 +156,7 @@ public class UITestUtils {
items.add(item);
File mediaFile = newMediaFile("feed-" + i + "-episode-" + j + ".mp3");
- item.setMedia(new FeedMedia(j, item, 0, 0, mediaFile.length(), "audio/mp3", null, hostFile(mediaFile), false, null, 0));
+ item.setMedia(new FeedMedia(j, item, 0, 0, mediaFile.length(), "audio/mp3", null, hostFile(mediaFile), false, null, 0, 0));
}
feed.setItems(items);
diff --git a/app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java b/app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java
new file mode 100644
index 000000000..fcfb16eb4
--- /dev/null
+++ b/app/src/androidTest/java/de/test/antennapod/util/RewindAfterPauseUtilTest.java
@@ -0,0 +1,51 @@
+package de.test.antennapod.util;
+
+import junit.framework.*;
+
+import de.danoeh.antennapod.core.util.*;
+
+/**
+ * Tests for {@link RewindAfterPauseUtils}.
+ */
+public class RewindAfterPauseUtilTest extends TestCase {
+
+ public void testCalculatePositionWithRewindNoRewind() {
+ final int ORIGINAL_POSITION = 10000;
+ long lastPlayed = System.currentTimeMillis();
+ int position = RewindAfterPauseUtils.calculatePositionWithRewind(ORIGINAL_POSITION, lastPlayed);
+
+ assertEquals(ORIGINAL_POSITION, position);
+ }
+
+ public void testCalculatePositionWithRewindSmallRewind() {
+ final int ORIGINAL_POSITION = 10000;
+ long lastPlayed = System.currentTimeMillis() - RewindAfterPauseUtils.ELAPSED_TIME_FOR_SHORT_REWIND - 1000;
+ int position = RewindAfterPauseUtils.calculatePositionWithRewind(ORIGINAL_POSITION, lastPlayed);
+
+ assertEquals(ORIGINAL_POSITION - RewindAfterPauseUtils.SHORT_REWIND, position);
+ }
+
+ public void testCalculatePositionWithRewindMediumRewind() {
+ final int ORIGINAL_POSITION = 10000;
+ long lastPlayed = System.currentTimeMillis() - RewindAfterPauseUtils.ELAPSED_TIME_FOR_MEDIUM_REWIND - 1000;
+ int position = RewindAfterPauseUtils.calculatePositionWithRewind(ORIGINAL_POSITION, lastPlayed);
+
+ assertEquals(ORIGINAL_POSITION - RewindAfterPauseUtils.MEDIUM_REWIND, position);
+ }
+
+ public void testCalculatePositionWithRewindLongRewind() {
+ final int ORIGINAL_POSITION = 30000;
+ long lastPlayed = System.currentTimeMillis() - RewindAfterPauseUtils.ELAPSED_TIME_FOR_LONG_REWIND - 1000;
+ int position = RewindAfterPauseUtils.calculatePositionWithRewind(ORIGINAL_POSITION, lastPlayed);
+
+ assertEquals(ORIGINAL_POSITION - RewindAfterPauseUtils.LONG_REWIND, position);
+ }
+
+ public void testCalculatePositionWithRewindNegativeNumber() {
+ final int ORIGINAL_POSITION = 100;
+ long lastPlayed = System.currentTimeMillis() - RewindAfterPauseUtils.ELAPSED_TIME_FOR_LONG_REWIND - 1000;
+ int position = RewindAfterPauseUtils.calculatePositionWithRewind(ORIGINAL_POSITION, lastPlayed);
+
+ assertEquals(0, position);
+ }
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index feb0681f2..e15f4c85e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.danoeh.antennapod"
- android:versionCode="1040001"
- android:versionName="1.4.0.1">
+ android:versionCode="1040002"
+ android:versionName="1.4.0.2">
<!--
Version code schema:
"1.2.3-SNAPSHOT" -> 1020300
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
index 7397dd935..5a345b9d6 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java
@@ -40,6 +40,7 @@ public class FeedMedia extends FeedFile implements Playable {
private int duration;
private int position; // Current position in file
+ private long lastPlayedTime; // Last time this media was played (in ms)
private int played_duration; // How many ms of this file have been played (for autoflattring)
private long size; // File size in Byte
private String mime_type;
@@ -62,7 +63,8 @@ public class FeedMedia extends FeedFile implements Playable {
public FeedMedia(long id, FeedItem item, int duration, int position,
long size, String mime_type, String file_url, String download_url,
- boolean downloaded, Date playbackCompletionDate, int played_duration) {
+ boolean downloaded, Date playbackCompletionDate, int played_duration,
+ long lastPlayedTime) {
super(file_url, download_url, downloaded);
this.id = id;
this.item = item;
@@ -73,14 +75,15 @@ public class FeedMedia extends FeedFile implements Playable {
this.mime_type = mime_type;
this.playbackCompletionDate = playbackCompletionDate == null
? null : (Date) playbackCompletionDate.clone();
+ this.lastPlayedTime = lastPlayedTime;
}
public FeedMedia(long id, FeedItem item, int duration, int position,
long size, String mime_type, String file_url, String download_url,
boolean downloaded, Date playbackCompletionDate, int played_duration,
- Boolean hasEmbeddedPicture) {
+ Boolean hasEmbeddedPicture, long lastPlayedTime) {
this(id, item, duration, position, size, mime_type, file_url, download_url, downloaded,
- playbackCompletionDate, played_duration);
+ playbackCompletionDate, played_duration, lastPlayedTime);
this.hasEmbeddedPicture = hasEmbeddedPicture;
}
@@ -95,6 +98,7 @@ public class FeedMedia extends FeedFile implements Playable {
int indexDownloadUrl = cursor.getColumnIndex(PodDBAdapter.KEY_DOWNLOAD_URL);
int indexDownloaded = cursor.getColumnIndex(PodDBAdapter.KEY_DOWNLOADED);
int indexPlayedDuration = cursor.getColumnIndex(PodDBAdapter.KEY_PLAYED_DURATION);
+ int indexLastPlayedTime = cursor.getColumnIndex(PodDBAdapter.KEY_LAST_PLAYED_TIME);
long mediaId = cursor.getLong(indexId);
Date playbackCompletionDate = null;
@@ -128,7 +132,8 @@ public class FeedMedia extends FeedFile implements Playable {
cursor.getInt(indexDownloaded) > 0,
playbackCompletionDate,
cursor.getInt(indexPlayedDuration),
- hasEmbeddedPicture
+ hasEmbeddedPicture,
+ cursor.getLong(indexLastPlayedTime)
);
}
@@ -231,6 +236,11 @@ public class FeedMedia extends FeedFile implements Playable {
this.duration = duration;
}
+ @Override
+ public void setLastPlayedTime(long lastPlayedTime) {
+ this.lastPlayedTime = lastPlayedTime;
+ }
+
public int getPlayedDuration() {
return played_duration;
}
@@ -243,6 +253,11 @@ public class FeedMedia extends FeedFile implements Playable {
return position;
}
+ @Override
+ public long getLastPlayedTime() {
+ return lastPlayedTime;
+ }
+
public void setPosition(int position) {
this.position = position;
if(position > 0 && item.isNew()) {
@@ -336,6 +351,7 @@ public class FeedMedia extends FeedFile implements Playable {
dest.writeByte((byte) ((downloaded) ? 1 : 0));
dest.writeLong((playbackCompletionDate != null) ? playbackCompletionDate.getTime() : 0);
dest.writeInt(played_duration);
+ dest.writeLong(lastPlayedTime);
}
@Override
@@ -438,12 +454,13 @@ public class FeedMedia extends FeedFile implements Playable {
}
@Override
- public void saveCurrentPosition(SharedPreferences pref, int newPosition) {
- DBWriter.setFeedMediaPlaybackInformation(this);
+ public void saveCurrentPosition(SharedPreferences pref, int newPosition, long timeStamp) {
if(item.isNew()) {
DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId());
}
setPosition(newPosition);
+ setLastPlayedTime(timeStamp);
+ DBWriter.setFeedMediaPlaybackInformation(this);
}
@Override
@@ -488,7 +505,7 @@ public class FeedMedia extends FeedFile implements Playable {
final long id = in.readLong();
final long itemID = in.readLong();
FeedMedia result = new FeedMedia(id, null, in.readInt(), in.readInt(), in.readLong(), in.readString(), in.readString(),
- in.readString(), in.readByte() != 0, new Date(in.readLong()), in.readInt());
+ in.readString(), in.readByte() != 0, new Date(in.readLong()), in.readInt(), in.readLong());
result.itemID = itemID;
return result;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
index cdd63ef62..ab49bad08 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java
@@ -923,7 +923,7 @@ public class PlaybackService extends Service {
}
/**
- * Saves the current position of the media file to the DB
+ * Persists the current position and last played time of the media file.
*
* @param updatePlayedDuration true if played_duration should be updated. This applies only to FeedMedia objects
* @param deltaPlayedDuration value by which played_duration should be increased.
@@ -948,8 +948,9 @@ public class PlaybackService extends Service {
}
}
playable.saveCurrentPosition(PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext()),
- position
+ .getDefaultSharedPreferences(getApplicationContext()),
+ position,
+ System.currentTimeMillis()
);
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
index 9d6827ed9..41a9a08f8 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
@@ -39,6 +39,7 @@ import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBWriter;
+import de.danoeh.antennapod.core.util.RewindAfterPauseUtils;
import de.danoeh.antennapod.core.util.playback.AudioPlayer;
import de.danoeh.antennapod.core.util.playback.IPlayer;
import de.danoeh.antennapod.core.util.playback.Playable;
@@ -330,10 +331,14 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
if (focusGained == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
acquireWifiLockIfNecessary();
setSpeed(Float.parseFloat(UserPreferences.getPlaybackSpeed()));
- mediaPlayer.start();
- if (playerStatus == PlayerStatus.PREPARED && media.getPosition() > 0) {
- mediaPlayer.seekTo(media.getPosition());
+
+ if (media.getPosition() > 0) {
+ int newPosition = RewindAfterPauseUtils.calculatePositionWithRewind(
+ media.getPosition(),
+ media.getLastPlayedTime());
+ mediaPlayer.seekTo(newPosition);
}
+ mediaPlayer.start();
setPlayerStatus(PlayerStatus.PLAYING, media);
pausedBecauseOfTransientAudiofocusLoss = false;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
index bae31b52b..73584c40a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java
@@ -732,7 +732,7 @@ public class DBWriter {
}
/**
- * Saves the 'position' and 'duration' attributes of a FeedMedia object
+ * Saves the 'position', 'duration' and 'last played time' attributes of a FeedMedia object
*
* @param media The FeedMedia object.
*/
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
index d55d4c231..7d1afc039 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
@@ -103,7 +103,7 @@ public class PodDBAdapter {
public static final String KEY_HIDE = "hide";
public static final String KEY_LAST_UPDATE_FAILED = "last_update_failed";
public static final String KEY_HAS_EMBEDDED_PICTURE = "has_embedded_picture";
-
+ public static final String KEY_LAST_PLAYED_TIME = "last_played_time";
// Table names
public static final String TABLE_NAME_FEEDS = "Feeds";
@@ -160,7 +160,8 @@ public class PodDBAdapter {
+ KEY_PLAYBACK_COMPLETION_DATE + " INTEGER,"
+ KEY_FEEDITEM + " INTEGER,"
+ KEY_PLAYED_DURATION + " INTEGER,"
- + KEY_HAS_EMBEDDED_PICTURE + " INTEGER)";
+ + KEY_HAS_EMBEDDED_PICTURE + " INTEGER,"
+ + KEY_LAST_PLAYED_TIME + " INTEGER)";
public static final String CREATE_TABLE_DOWNLOAD_LOG = "CREATE TABLE "
+ TABLE_NAME_DOWNLOAD_LOG + " (" + TABLE_PRIMARY_KEY + KEY_FEEDFILE
@@ -444,6 +445,7 @@ public class PodDBAdapter {
values.put(KEY_DOWNLOADED, media.isDownloaded());
values.put(KEY_FILE_URL, media.getFile_url());
values.put(KEY_HAS_EMBEDDED_PICTURE, media.hasEmbeddedPicture());
+ values.put(KEY_LAST_PLAYED_TIME, media.getLastPlayedTime());
if (media.getPlaybackCompletionDate() != null) {
values.put(KEY_PLAYBACK_COMPLETION_DATE, media.getPlaybackCompletionDate().getTime());
@@ -468,6 +470,7 @@ public class PodDBAdapter {
values.put(KEY_POSITION, media.getPosition());
values.put(KEY_DURATION, media.getDuration());
values.put(KEY_PLAYED_DURATION, media.getPlayedDuration());
+ values.put(KEY_LAST_PLAYED_TIME, media.getLastPlayedTime());
db.update(TABLE_NAME_FEED_MEDIA, values, KEY_ID + "=?",
new String[]{String.valueOf(media.getId())});
} else {
@@ -1439,7 +1442,7 @@ public class PodDBAdapter {
*/
private static class PodDBHelper extends SQLiteOpenHelper {
- private final static int VERSION = 1040001;
+ private final static int VERSION = 1040002;
private Context context;
@@ -1673,6 +1676,10 @@ public class PodDBAdapter {
if(oldVersion < 1040001) {
db.execSQL(CREATE_TABLE_FAVORITES);
}
+ if (oldVersion < 1040002) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEED_MEDIA
+ + " ADD COLUMN " + PodDBAdapter.KEY_LAST_PLAYED_TIME + " INTEGER DEFAULT 0");
+ }
EventBus.getDefault().post(ProgressEvent.end());
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java
new file mode 100644
index 000000000..ee306a401
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java
@@ -0,0 +1,47 @@
+package de.danoeh.antennapod.core.util;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class calculates the proper rewind time after the pause and resume.
+ * <p>
+ * User might loose context if he/she pauses and resumes the media after longer time.
+ * Media file should be "rewinded" x seconds after user resumes the playback.
+ */
+public class RewindAfterPauseUtils {
+
+ public static final long ELAPSED_TIME_FOR_SHORT_REWIND = TimeUnit.MINUTES.toMillis(1);
+ public static final long ELAPSED_TIME_FOR_MEDIUM_REWIND = TimeUnit.HOURS.toMillis(1);
+ public static final long ELAPSED_TIME_FOR_LONG_REWIND = TimeUnit.DAYS.toMillis(1);
+
+ public static final long SHORT_REWIND = TimeUnit.SECONDS.toMillis(3);
+ public static final long MEDIUM_REWIND = TimeUnit.SECONDS.toMillis(10);
+ public static final long LONG_REWIND = TimeUnit.SECONDS.toMillis(20);
+
+ /**
+ * @param currentPosition current position in a media file in ms
+ * @param lastPlayedTime timestamp when was media paused
+ * @return new rewinded position for playback in milliseconds
+ */
+ public static int calculatePositionWithRewind(int currentPosition, long lastPlayedTime) {
+ if (currentPosition > 0 && lastPlayedTime > 0) {
+ long elapsedTime = System.currentTimeMillis() - lastPlayedTime;
+ long rewindTime = 0;
+
+ if (elapsedTime > ELAPSED_TIME_FOR_LONG_REWIND) {
+ rewindTime = LONG_REWIND;
+ } else if (elapsedTime > ELAPSED_TIME_FOR_MEDIUM_REWIND) {
+ rewindTime = MEDIUM_REWIND;
+ } else if (elapsedTime > ELAPSED_TIME_FOR_SHORT_REWIND) {
+ rewindTime = SHORT_REWIND;
+ }
+
+ int newPosition = currentPosition - (int) rewindTime;
+
+ return newPosition > 0 ? newPosition : 0;
+ }
+ else {
+ return currentPosition;
+ }
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java
index 49769f4f0..ec50dce7c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java
@@ -20,6 +20,7 @@ public class ExternalMedia implements Playable {
public static final String PREF_SOURCE_URL = "ExternalMedia.PrefSourceUrl";
public static final String PREF_POSITION = "ExternalMedia.PrefPosition";
public static final String PREF_MEDIA_TYPE = "ExternalMedia.PrefMediaType";
+ public static final String PREF_LAST_PLAYED_TIME = "ExternalMedia.PrefLastPlayedTime";
private String source;
@@ -29,6 +30,7 @@ public class ExternalMedia implements Playable {
private List<Chapter> chapters;
private int duration;
private int position;
+ private long lastPlayedTime;
public ExternalMedia(String source, MediaType mediaType) {
super();
@@ -36,9 +38,10 @@ public class ExternalMedia implements Playable {
this.mediaType = mediaType;
}
- public ExternalMedia(String source, MediaType mediaType, int position) {
+ public ExternalMedia(String source, MediaType mediaType, int position, long lastPlayedTime) {
this(source, mediaType);
this.position = position;
+ this.lastPlayedTime = lastPlayedTime;
}
@Override
@@ -51,6 +54,7 @@ public class ExternalMedia implements Playable {
dest.writeString(source);
dest.writeString(mediaType.toString());
dest.writeInt(position);
+ dest.writeLong(lastPlayedTime);
}
@Override
@@ -58,6 +62,7 @@ public class ExternalMedia implements Playable {
prefEditor.putString(PREF_SOURCE_URL, source);
prefEditor.putString(PREF_MEDIA_TYPE, mediaType.toString());
prefEditor.putInt(PREF_POSITION, position);
+ prefEditor.putLong(PREF_LAST_PLAYED_TIME, lastPlayedTime);
}
@Override
@@ -145,6 +150,11 @@ public class ExternalMedia implements Playable {
}
@Override
+ public long getLastPlayedTime() {
+ return lastPlayedTime;
+ }
+
+ @Override
public MediaType getMediaType() {
return mediaType;
}
@@ -170,10 +180,12 @@ public class ExternalMedia implements Playable {
}
@Override
- public void saveCurrentPosition(SharedPreferences pref, int newPosition) {
+ public void saveCurrentPosition(SharedPreferences pref, int newPosition, long timestamp) {
SharedPreferences.Editor editor = pref.edit();
editor.putInt(PREF_POSITION, newPosition);
+ editor.putLong(PREF_LAST_PLAYED_TIME, timestamp);
position = newPosition;
+ lastPlayedTime = timestamp;
editor.commit();
}
@@ -188,6 +200,11 @@ public class ExternalMedia implements Playable {
}
@Override
+ public void setLastPlayedTime(long lastPlayedTime) {
+ this.lastPlayedTime = lastPlayedTime;
+ }
+
+ @Override
public void onPlaybackStart() {
}
@@ -215,8 +232,12 @@ public class ExternalMedia implements Playable {
if (in.dataAvail() > 0) {
position = in.readInt();
}
- ExternalMedia extMedia = new ExternalMedia(source, type, position);
- return extMedia;
+ long lastPlayedTime = 0;
+ if (in.dataAvail() > 0) {
+ lastPlayedTime = in.readLong();
+ }
+
+ return new ExternalMedia(source, type, position, lastPlayedTime);
}
public ExternalMedia[] newArray(int size) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java
index 6e306d30a..86ec4fbd0 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java
@@ -82,6 +82,12 @@ public interface Playable extends Parcelable,
public int getPosition();
/**
+ * Returns last time (in ms) when this playable was played or 0
+ * if last played time is unknown.
+ */
+ public long getLastPlayedTime();
+
+ /**
* Returns the type of media. This method should return the correct value
* BEFORE loadMetadata() is called.
*/
@@ -115,14 +121,23 @@ public interface Playable extends Parcelable,
* Saves the current position of this object. Implementations can use the
* provided SharedPreference to save this information and retrieve it later
* via PlayableUtils.createInstanceFromPreferences.
+ *
+ * @param pref shared prefs that might be used to store this object
+ * @param newPosition new playback position in ms
+ * @param timestamp current time in ms
*/
- public void saveCurrentPosition(SharedPreferences pref, int newPosition);
+ public void saveCurrentPosition(SharedPreferences pref, int newPosition, long timestamp);
public void setPosition(int newPosition);
public void setDuration(int newDuration);
/**
+ * @param lastPlayedTimestamp timestamp in ms
+ */
+ public void setLastPlayedTime(long lastPlayedTimestamp);
+
+ /**
* Is called by the PlaybackService when playback starts.
*/
public void onPlaybackStart();
@@ -159,28 +174,42 @@ public interface Playable extends Parcelable,
*/
public static Playable createInstanceFromPreferences(Context context, int type,
SharedPreferences pref) {
+ Playable result = null;
// ADD new Playable types here:
switch (type) {
case FeedMedia.PLAYABLE_TYPE_FEEDMEDIA:
- long mediaId = pref.getLong(FeedMedia.PREF_MEDIA_ID, -1);
- if (mediaId != -1) {
- return DBReader.getFeedMedia(mediaId);
- }
+ result = createFeedMediaInstance(pref);
break;
case ExternalMedia.PLAYABLE_TYPE_EXTERNAL_MEDIA:
- String source = pref.getString(ExternalMedia.PREF_SOURCE_URL,
- null);
- String mediaType = pref.getString(
- ExternalMedia.PREF_MEDIA_TYPE, null);
- if (source != null && mediaType != null) {
- int position = pref.getInt(ExternalMedia.PREF_POSITION, 0);
- return new ExternalMedia(source,
- MediaType.valueOf(mediaType), position);
- }
+ result = createExternalMediaInstance(pref);
break;
}
- Log.e(TAG, "Could not restore Playable object from preferences");
- return null;
+ if (result == null) {
+ Log.e(TAG, "Could not restore Playable object from preferences");
+ }
+ return result;
+ }
+
+ private static Playable createFeedMediaInstance(SharedPreferences pref) {
+ Playable result = null;
+ long mediaId = pref.getLong(FeedMedia.PREF_MEDIA_ID, -1);
+ if (mediaId != -1) {
+ result = DBReader.getFeedMedia(mediaId);
+ }
+ return result;
+ }
+
+ private static Playable createExternalMediaInstance(SharedPreferences pref) {
+ Playable result = null;
+ String source = pref.getString(ExternalMedia.PREF_SOURCE_URL, null);
+ String mediaType = pref.getString(ExternalMedia.PREF_MEDIA_TYPE, null);
+ if (source != null && mediaType != null) {
+ int position = pref.getInt(ExternalMedia.PREF_POSITION, 0);
+ long lastPlayedTime = pref.getLong(ExternalMedia.PREF_LAST_PLAYED_TIME, 0);
+ result = new ExternalMedia(source, MediaType.valueOf(mediaType),
+ position, lastPlayedTime);
+ }
+ return result;
}
}