summaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
authorTom Hennen <TomHennen@users.noreply.github.com>2015-10-17 11:50:14 -0400
committerTom Hennen <TomHennen@users.noreply.github.com>2015-10-17 11:50:14 -0400
commitbcef62d11eb997005ae0ab7814b4f70acfd80162 (patch)
tree5357816cc3e78d808fe8b88228b6612261ea15e6 /core/src/main
parent0e2b056d4e069d1ec25bdc7c3f5758254efb2df6 (diff)
parent87d27a7c0b327b0827c09dfcb6a0b9162266003e (diff)
downloadAntennaPod-bcef62d11eb997005ae0ab7814b4f70acfd80162.zip
Merge pull request #1260 from stevomit/rewind-after-pause
Rewind after pause feature
Diffstat (limited to 'core/src/main')
-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
8 files changed, 164 insertions, 37 deletions
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;
}
}