Merge pull request #1260 from stevomit/rewind-after-pause
Rewind after pause feature
This commit is contained in:
commit
bcef62d11e
@ -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));
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
@ -144,6 +149,11 @@ public class ExternalMedia implements Playable {
|
||||
return position;
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
@ -187,6 +199,11 @@ public class ExternalMedia implements Playable {
|
||||
duration = newDuration;
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
@ -81,6 +81,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,13 +121,22 @@ 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.
|
||||
*/
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user