move auto flattr and gpodnet play action inside FeedMedia

This commit is contained in:
Domingos Lopes 2016-05-04 08:20:01 -04:00
parent 12d62d5519
commit d18cf41f20
8 changed files with 118 additions and 115 deletions

View File

@ -1,5 +1,6 @@
package de.danoeh.antennapod.core.feed;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
@ -14,12 +15,16 @@ import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetEpisodeAction;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.ChapterUtils;
import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
import de.danoeh.antennapod.core.util.playback.Playable;
public class FeedMedia extends FeedFile implements Playable {
@ -48,6 +53,8 @@ public class FeedMedia extends FeedFile implements Playable {
private String mime_type;
@Nullable private volatile FeedItem item;
private Date playbackCompletionDate;
private int startPosition = -1;
private int playedDurationWhenStarted;
// if null: unknown, will be checked
private Boolean hasEmbeddedPicture;
@ -73,6 +80,7 @@ public class FeedMedia extends FeedFile implements Playable {
this.duration = duration;
this.position = position;
this.played_duration = played_duration;
this.playedDurationWhenStarted = played_duration;
this.size = size;
this.mime_type = mime_type;
this.playbackCompletionDate = playbackCompletionDate == null
@ -472,15 +480,59 @@ public class FeedMedia extends FeedFile implements Playable {
}
setPosition(newPosition);
setLastPlayedTime(timeStamp);
if(startPosition>=0 && position > startPosition) {
setDuration(playedDurationWhenStarted + position - startPosition);
}
DBWriter.setFeedMediaPlaybackInformation(this);
}
@Override
public void onPlaybackStart() {
startPosition = (position > 0) ? position : 0;
playedDurationWhenStarted = played_duration;
}
@Override
public void onPlaybackCompleted() {
@Override
public void onPlaybackPause(Context context) {
if (position > startPosition) {
played_duration = playedDurationWhenStarted + position - startPosition;
playedDurationWhenStarted = played_duration;
}
postPlaybackTasks(context, false);
startPosition = position;
}
@Override
public void onPlaybackCompleted(Context context) {
postPlaybackTasks(context, true);
startPosition = -1;
}
private void postPlaybackTasks(Context context, boolean completed) {
if (item != null) {
// gpodder play action
if (startPosition >= 0 && (completed || startPosition < position) &&
GpodnetPreferences.loggedIn()) {
GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, GpodnetEpisodeAction.Action.PLAY)
.currentDeviceId()
.currentTimestamp()
.started(startPosition / 1000)
.position((completed ? duration : position) / 1000)
.total(duration / 1000)
.build();
GpodnetPreferences.enqueueEpisodeAction(action);
}
// Auto flattr
float autoFlattrThreshold = UserPreferences.getAutoFlattrPlayedDurationThreshold();
if (FlattrUtils.hasToken() &&
UserPreferences.isAutoFlattr() &&
item.getPaymentLink() != null &&
item.getFlattrStatus().getUnflattred() &&
(completed && autoFlattrThreshold <= 1.0f ||
played_duration >= autoFlattrThreshold * duration)) {
DBTasks.flattrItemIfLoggedIn(context, item);
}
}
}
@Override

View File

@ -146,6 +146,8 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
if (!media.getIdentifier().equals(playable.getIdentifier())) {
final Playable oldMedia = media;
executor.submit(() -> callback.onPostPlayback(oldMedia, false, true));
} else {
media.onPlaybackPause(context);
}
setPlayerStatus(PlayerStatus.INDETERMINATE, null);
@ -253,6 +255,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
Log.d(TAG, "Pausing playback.");
mediaPlayer.pause();
setPlayerStatus(PlayerStatus.PAUSED, media);
media.onPlaybackPause(context.getApplicationContext());
if (abandonFocus) {
audioManager.abandonAudioFocus(audioFocusChangeListener);
@ -370,10 +373,8 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
if (playerStatus == PlayerStatus.PLAYING
|| playerStatus == PlayerStatus.PAUSED
|| playerStatus == PlayerStatus.PREPARED) {
if (!stream) {
statusBeforeSeeking = playerStatus;
setPlayerStatus(PlayerStatus.SEEKING, media);
}
statusBeforeSeeking = playerStatus;
setPlayerStatus(PlayerStatus.SEEKING, media);
if(seekLatch != null && seekLatch.getCount() > 0) {
try {
seekLatch.await(3, TimeUnit.SECONDS);
@ -382,6 +383,10 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
}
}
seekLatch = new CountDownLatch(1);
if (statusBeforeSeeking == PlayerStatus.PLAYING) {
media.setPosition(getPosition());
media.onPlaybackPause(context);
}
mediaPlayer.seekTo(t);
try {
seekLatch.await(3, TimeUnit.SECONDS);
@ -926,7 +931,14 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
seekLatch.countDown();
}
playerLock.lock();
media.setPosition(getPosition());
if (playerStatus == PlayerStatus.PLAYING) {
media.onPlaybackStart();
}
if (playerStatus == PlayerStatus.SEEKING) {
if (statusBeforeSeeking == PlayerStatus.PLAYING) {
media.onPlaybackStart();
}
setPlayerStatus(statusBeforeSeeking, media);
}
playerLock.unlock();

View File

@ -52,9 +52,6 @@ import de.danoeh.antennapod.core.feed.FeedItem;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetEpisodeAction;
import de.danoeh.antennapod.core.gpoddernet.model.GpodnetEpisodeAction.Action;
import de.danoeh.antennapod.core.preferences.GpodnetPreferences;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
@ -63,7 +60,6 @@ import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.IntList;
import de.danoeh.antennapod.core.util.QueueAccess;
import de.danoeh.antennapod.core.util.flattr.FlattrUtils;
import de.danoeh.antennapod.core.util.playback.ExternalMedia;
import de.danoeh.antennapod.core.util.playback.Playable;
@ -206,8 +202,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
*/
private MediaSessionCompat mediaSession;
private int startPosition;
private static volatile MediaType currentMediaType = MediaType.UNKNOWN;
private final IBinder mBinder = new LocalBinder();
@ -473,7 +467,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
UserPreferences.shouldHardwareButtonSkip()) {
// assume the skip command comes from a notification or the lockscreen
// a >| skip button should actually skip
mediaPlayer.endPlayback();
mediaPlayer.skip();
} else {
// assume skip command comes from a (bluetooth) media button
// user actually wants to fast-forward
@ -530,7 +524,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
private final PlaybackServiceTaskManager.PSTMCallback taskManagerCallback = new PlaybackServiceTaskManager.PSTMCallback() {
@Override
public void positionSaverTick() {
saveCurrentPosition(true, PlaybackServiceTaskManager.POSITION_SAVER_WAITING_INTERVAL);
saveCurrentPosition();
}
@Override
@ -583,7 +577,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
case PAUSED:
taskManager.cancelPositionSaver();
saveCurrentPosition(false, 0);
saveCurrentPosition();
taskManager.cancelWidgetUpdater();
if ((UserPreferences.isPersistNotify() || isCasting) &&
android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
@ -595,22 +589,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
stopForeground(true);
}
writePlayerStatusPlaybackPreferences();
final Playable playable = newInfo.playable;
// Gpodder: send play action
if(GpodnetPreferences.loggedIn() && playable instanceof FeedMedia) {
FeedMedia media = (FeedMedia) playable;
FeedItem item = media.getItem();
GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, Action.PLAY)
.currentDeviceId()
.currentTimestamp()
.started(startPosition / 1000)
.position(getCurrentPosition() / 1000)
.total(getDuration() / 1000)
.build();
GpodnetPreferences.enqueueEpisodeAction(action);
}
break;
case STOPPED:
@ -627,7 +605,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
writePlayerStatusPlaybackPreferences();
setupNotification(newInfo);
started = true;
startPosition = mediaPlayer.getPosition();
break;
case ERROR:
@ -790,21 +767,10 @@ public class PlaybackService extends MediaBrowserServiceCompat {
Log.d(TAG, "smart mark as played");
}
// auto-flattr if enabled
if (isAutoFlattrable(media) && UserPreferences.getAutoFlattrPlayedDurationThreshold() == 1.0f) {
DBTasks.flattrItemIfLoggedIn(PlaybackService.this, item);
}
// gpodder play action
if (GpodnetPreferences.loggedIn()) {
GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, Action.PLAY)
.currentDeviceId()
.currentTimestamp()
.started(startPosition / 1000)
.position(((ended || smartMarkAsPlayed) ? media.getDuration() : media.getPosition()) / 1000)
.total(media.getDuration() / 1000)
.build();
GpodnetPreferences.enqueueEpisodeAction(action);
if (ended || smartMarkAsPlayed) {
media.onPlaybackCompleted(getApplicationContext());
} else {
media.onPlaybackPause(getApplicationContext());
}
if (item != null) {
@ -1234,29 +1200,13 @@ public class PlaybackService extends MediaBrowserServiceCompat {
/**
* 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.
*/
private synchronized void saveCurrentPosition(boolean updatePlayedDuration, int deltaPlayedDuration) {
private synchronized void saveCurrentPosition() {
int position = getCurrentPosition();
int duration = getDuration();
float playbackSpeed = getCurrentPlaybackSpeed();
final Playable playable = mediaPlayer.getPlayable();
if (position != INVALID_TIME && duration != INVALID_TIME && playable != null) {
Log.d(TAG, "Saving current position to " + position);
if (updatePlayedDuration && playable instanceof FeedMedia) {
FeedMedia media = (FeedMedia) playable;
FeedItem item = media.getItem();
media.setPlayedDuration(media.getPlayedDuration() + ((int) (deltaPlayedDuration * playbackSpeed)));
// Auto flattr
if (isAutoFlattrable(media) &&
(media.getPlayedDuration() > UserPreferences.getAutoFlattrPlayedDurationThreshold() * duration)) {
Log.d(TAG, "saveCurrentPosition: performing auto flattr since played duration " + Integer.toString(media.getPlayedDuration())
+ " is " + UserPreferences.getAutoFlattrPlayedDurationThreshold() * 100 + "% of file duration " + Integer.toString(duration));
DBTasks.flattrItemIfLoggedIn(this, item);
}
}
playable.saveCurrentPosition(
PreferenceManager.getDefaultSharedPreferences(getApplicationContext()),
position,
@ -1424,7 +1374,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
public void onReceive(Context context, Intent intent) {
if (TextUtils.equals(intent.getAction(), ACTION_SKIP_CURRENT_EPISODE)) {
Log.d(TAG, "Received SKIP_CURRENT_EPISODE intent");
mediaPlayer.endPlayback();
mediaPlayer.skip();
}
}
};
@ -1517,26 +1467,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
public void seekTo(final int t) {
if(mediaPlayer.getPlayerStatus() == PlayerStatus.PLAYING
&& GpodnetPreferences.loggedIn()) {
final Playable playable = mediaPlayer.getPlayable();
if (playable instanceof FeedMedia) {
FeedMedia media = (FeedMedia) playable;
FeedItem item = media.getItem();
GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, Action.PLAY)
.currentDeviceId()
.currentTimestamp()
.started(startPosition / 1000)
.position(getCurrentPosition() / 1000)
.total(getDuration() / 1000)
.build();
GpodnetPreferences.enqueueEpisodeAction(action);
}
}
mediaPlayer.seekTo(t);
if(mediaPlayer.getPlayerStatus() == PlayerStatus.PLAYING ) {
startPosition = t;
}
}
@ -1545,10 +1476,10 @@ public class PlaybackService extends MediaBrowserServiceCompat {
}
/**
* @see LocalPSMP#seekToChapter(de.danoeh.antennapod.core.feed.Chapter)
* Seek to the start of the specified chapter.
*/
public void seekToChapter(Chapter c) {
mediaPlayer.seekToChapter(c);
seekTo((int) c.getStart());
}
/**
@ -1575,15 +1506,6 @@ public class PlaybackService extends MediaBrowserServiceCompat {
return mediaPlayer.getVideoSize();
}
private boolean isAutoFlattrable(FeedMedia media) {
if (media != null) {
FeedItem item = media.getItem();
return item != null && FlattrUtils.hasToken() && UserPreferences.isAutoFlattr() && item.getPaymentLink() != null && item.getFlattrStatus().getUnflattred();
} else {
return false;
}
}
private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() {
private static final String TAG = "MediaSessionCompat";
@ -1656,7 +1578,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
public void onSkipToNext() {
Log.d(TAG, "onSkipToNext()");
if(UserPreferences.shouldHardwareButtonSkip()) {
mediaPlayer.endPlayback();
mediaPlayer.skip();
} else {
seekDelta(UserPreferences.getFastFowardSecs() * 1000);
}
@ -1699,7 +1621,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
PlaybackServiceMediaPlayer getMediaPlayer();
void setIsCasting(boolean isCasting);
void sendNotificationBroadcast(int type, int code);
void saveCurrentPosition(boolean updatePlayedDuration, int deltaPlayedDuration);
void saveCurrentPosition();
void setupNotification(boolean connected, PlaybackServiceMediaPlayer.PSMPInfo info);
MediaSessionCompat getMediaSession();
Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter);
@ -1733,8 +1655,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
}
@Override
public void saveCurrentPosition(boolean updatePlayedDuration, int deltaPlayedDuration) {
PlaybackService.this.saveCurrentPosition(updatePlayedDuration, deltaPlayedDuration);
public void saveCurrentPosition() {
PlaybackService.this.saveCurrentPosition();
}
@Override

View File

@ -8,7 +8,6 @@ import android.util.Log;
import android.util.Pair;
import android.view.SurfaceHolder;
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.util.playback.Playable;
@ -126,13 +125,6 @@ public abstract class PlaybackServiceMediaPlayer {
*/
public abstract void seekDelta(int d);
/**
* Seek to the start of the specified chapter.
*/
public void seekToChapter(@NonNull Chapter c) {
seekTo((int) c.getStart());
}
/**
* Returns the duration of the current media object or INVALID_TIME if the duration could not be retrieved.
*/
@ -233,7 +225,7 @@ public abstract class PlaybackServiceMediaPlayer {
protected abstract void setPlayable(Playable playable);
public void endPlayback() {
public void skip() {
endPlayback(true);
}

View File

@ -1,5 +1,6 @@
package de.danoeh.antennapod.core.util.playback;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.MediaMetadataRetriever;
@ -205,7 +206,12 @@ public class ExternalMedia implements Playable {
}
@Override
public void onPlaybackCompleted() {
public void onPlaybackPause(Context context) {
}
@Override
public void onPlaybackCompleted(Context context) {
}

View File

@ -138,14 +138,27 @@ public interface Playable extends Parcelable,
void setLastPlayedTime(long lastPlayedTimestamp);
/**
* Is called by the PlaybackService when playback starts.
* This method should be called every time playback starts on this object.
* <p/>
* Position held by this Playable should be set accurately before a call to this method is made.
*/
void onPlaybackStart();
/**
* Is called by the PlaybackService when playback is completed.
* This method should be called every time playback pauses or stops on this object,
* including just before a seeking operation is performed, after which a call to
* {@link #onPlaybackStart()} should be made. If playback completes, calling this method is not
* necessary, as long as a call to {@link #onPlaybackCompleted(Context)} is made.
* <p/>
* Position held by this Playable should be set accurately before a call to this method is made.
*/
void onPlaybackCompleted();
void onPlaybackPause(Context context);
/**
* This method should be called when playback completes for this object.
* @param context
*/
void onPlaybackCompleted(Context context);
/**
* Returns an integer that must be unique among all Playable classes. The

View File

@ -1,5 +1,6 @@
package de.danoeh.antennapod.core.cast;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Parcel;
@ -255,7 +256,12 @@ public class RemoteMedia implements Playable {
}
@Override
public void onPlaybackCompleted() {
public void onPlaybackPause(Context context) {
// no-op
}
@Override
public void onPlaybackCompleted(Context context) {
// no-op
}

View File

@ -108,7 +108,7 @@ public class PlaybackServiceFlavorHelper {
// to the latest position.
PlaybackServiceMediaPlayer mediaPlayer = callback.getMediaPlayer();
if (mediaPlayer != null) {
callback.saveCurrentPosition(false, 0);
callback.saveCurrentPosition();
infoBeforeCastDisconnection = mediaPlayer.getPSMPInfo();
if (reason != BaseCastManager.DISCONNECT_REASON_EXPLICIT &&
infoBeforeCastDisconnection.playerStatus == PlayerStatus.PLAYING) {
@ -160,7 +160,7 @@ public class PlaybackServiceFlavorHelper {
// could be pause, but this way we make sure the new player will get the correct position,
// since pause runs asynchronously and we could be directing the new player to play even before
// the old player gives us back the position.
callback.saveCurrentPosition(false, 0);
callback.saveCurrentPosition();
}
}
if (info == null) {