diff --git a/core/src/free/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/core/src/free/java/de/danoeh/antennapod/core/feed/FeedMedia.java deleted file mode 100644 index cde66835a..000000000 --- a/core/src/free/java/de/danoeh/antennapod/core/feed/FeedMedia.java +++ /dev/null @@ -1,567 +0,0 @@ -package de.danoeh.antennapod.core.feed; - -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.database.Cursor; -import android.media.MediaMetadataRetriever; -import android.os.Parcel; -import android.os.Parcelable; -import android.support.annotation.Nullable; - -import java.util.Date; -import java.util.List; -import java.util.concurrent.Callable; - -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.DBWriter; -import de.danoeh.antennapod.core.storage.PodDBAdapter; -import de.danoeh.antennapod.core.util.ChapterUtils; -import de.danoeh.antennapod.core.util.playback.Playable; - -public class FeedMedia extends FeedFile implements Playable { - private static final String TAG = "FeedMedia"; - - public static final int FEEDFILETYPE_FEEDMEDIA = 2; - public static final int PLAYABLE_TYPE_FEEDMEDIA = 1; - - public static final String PREF_MEDIA_ID = "FeedMedia.PrefMediaId"; - public static final String PREF_FEED_ID = "FeedMedia.PrefFeedId"; - - /** - * Indicates we've checked on the size of the item via the network - * and got an invalid response. Using Integer.MIN_VALUE because - * 1) we'll still check on it in case it gets downloaded (it's <= 0) - * 2) By default all FeedMedia have a size of 0 if we don't know it, - * so this won't conflict with existing practice. - */ - private static final int CHECKED_ON_SIZE_BUT_UNKNOWN = Integer.MIN_VALUE; - - 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; - @Nullable private volatile FeedItem item; - private Date playbackCompletionDate; - - // if null: unknown, will be checked - private Boolean hasEmbeddedPicture; - - /* Used for loading item when restoring from parcel. */ - private long itemID; - - public FeedMedia(FeedItem i, String download_url, long size, - String mime_type) { - super(null, download_url, false); - this.item = i; - this.size = size; - this.mime_type = mime_type; - } - - 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, - long lastPlayedTime) { - super(file_url, download_url, downloaded); - this.id = id; - this.item = item; - this.duration = duration; - this.position = position; - this.played_duration = played_duration; - this.size = size; - 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, long lastPlayedTime) { - this(id, item, duration, position, size, mime_type, file_url, download_url, downloaded, - playbackCompletionDate, played_duration, lastPlayedTime); - this.hasEmbeddedPicture = hasEmbeddedPicture; - } - - public static FeedMedia fromCursor(Cursor cursor) { - int indexId = cursor.getColumnIndex(PodDBAdapter.KEY_ID); - int indexPlaybackCompletionDate = cursor.getColumnIndex(PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE); - int indexDuration = cursor.getColumnIndex(PodDBAdapter.KEY_DURATION); - int indexPosition = cursor.getColumnIndex(PodDBAdapter.KEY_POSITION); - int indexSize = cursor.getColumnIndex(PodDBAdapter.KEY_SIZE); - int indexMimeType = cursor.getColumnIndex(PodDBAdapter.KEY_MIME_TYPE); - int indexFileUrl = cursor.getColumnIndex(PodDBAdapter.KEY_FILE_URL); - 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; - long playbackCompletionTime = cursor.getLong(indexPlaybackCompletionDate); - if (playbackCompletionTime > 0) { - playbackCompletionDate = new Date(playbackCompletionTime); - } - - Boolean hasEmbeddedPicture; - switch(cursor.getInt(cursor.getColumnIndex(PodDBAdapter.KEY_HAS_EMBEDDED_PICTURE))) { - case 1: - hasEmbeddedPicture = Boolean.TRUE; - break; - case 0: - hasEmbeddedPicture = Boolean.FALSE; - break; - default: - hasEmbeddedPicture = null; - break; - } - - return new FeedMedia( - mediaId, - null, - cursor.getInt(indexDuration), - cursor.getInt(indexPosition), - cursor.getLong(indexSize), - cursor.getString(indexMimeType), - cursor.getString(indexFileUrl), - cursor.getString(indexDownloadUrl), - cursor.getInt(indexDownloaded) > 0, - playbackCompletionDate, - cursor.getInt(indexPlayedDuration), - hasEmbeddedPicture, - cursor.getLong(indexLastPlayedTime) - ); - } - - - @Override - public String getHumanReadableIdentifier() { - if (item != null && item.getTitle() != null) { - return item.getTitle(); - } else { - return download_url; - } - } - - /** - * Uses mimetype to determine the type of media. - */ - public MediaType getMediaType() { - return MediaType.fromMimeType(mime_type); - } - - public void updateFromOther(FeedMedia other) { - super.updateFromOther(other); - if (other.size > 0) { - size = other.size; - } - if (other.mime_type != null) { - mime_type = other.mime_type; - } - } - - public boolean compareWithOther(FeedMedia other) { - if (super.compareWithOther(other)) { - return true; - } - if (other.mime_type != null) { - if (mime_type == null || !mime_type.equals(other.mime_type)) { - return true; - } - } - if (other.size > 0 && other.size != size) { - return true; - } - return false; - } - - /** - * Reads playback preferences to determine whether this FeedMedia object is - * currently being played. - */ - public boolean isPlaying() { - return PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA - && PlaybackPreferences.getCurrentlyPlayingFeedMediaId() == id; - } - - /** - * Reads playback preferences to determine whether this FeedMedia object is - * currently being played and the current player status is playing. - */ - public boolean isCurrentlyPlaying() { - return isPlaying() && - ((PlaybackPreferences.getCurrentPlayerStatus() == PlaybackPreferences.PLAYER_STATUS_PLAYING)); - } - - /** - * Reads playback preferences to determine whether this FeedMedia object is - * currently being played and the current player status is paused. - */ - public boolean isCurrentlyPaused() { - return isPlaying() && - ((PlaybackPreferences.getCurrentPlayerStatus() == PlaybackPreferences.PLAYER_STATUS_PAUSED)); - } - - - public boolean hasAlmostEnded() { - int smartMarkAsPlayedSecs = UserPreferences.getSmartMarkAsPlayedSecs(); - return this.position >= this.duration - smartMarkAsPlayedSecs * 1000; - } - - @Override - public int getTypeAsInt() { - return FEEDFILETYPE_FEEDMEDIA; - } - - public int getDuration() { - return duration; - } - - public void setDuration(int duration) { - this.duration = duration; - } - - @Override - public void setLastPlayedTime(long lastPlayedTime) { - this.lastPlayedTime = lastPlayedTime; - } - - public int getPlayedDuration() { - return played_duration; - } - - public void setPlayedDuration(int played_duration) { - this.played_duration = played_duration; - } - - public int getPosition() { - return position; - } - - @Override - public long getLastPlayedTime() { - return lastPlayedTime; - } - - public void setPosition(int position) { - this.position = position; - if(position > 0 && item != null && item.isNew()) { - this.item.setPlayed(false); - } - } - - public long getSize() { - return size; - } - - public void setSize(long size) { - this.size = size; - } - - /** - * Indicates we asked the service what the size was, but didn't - * get a valid answer and we shoudln't check using the network again. - */ - public void setCheckedOnSizeButUnknown() { - this.size = CHECKED_ON_SIZE_BUT_UNKNOWN; - } - - public boolean checkedOnSizeButUnknown() { - return (CHECKED_ON_SIZE_BUT_UNKNOWN == this.size); - } - - public String getMime_type() { - return mime_type; - } - - public void setMime_type(String mime_type) { - this.mime_type = mime_type; - } - - @Nullable - public FeedItem getItem() { - return item; - } - - /** - * Sets the item object of this FeedMedia. If the given - * FeedItem object is not null, it's 'media'-attribute value - * will also be set to this media object. - */ - public void setItem(FeedItem item) { - this.item = item; - if (item != null && item.getMedia() != this) { - item.setMedia(this); - } - } - - public Date getPlaybackCompletionDate() { - return playbackCompletionDate == null - ? null : (Date) playbackCompletionDate.clone(); - } - - public void setPlaybackCompletionDate(Date playbackCompletionDate) { - this.playbackCompletionDate = playbackCompletionDate == null - ? null : (Date) playbackCompletionDate.clone(); - } - - public boolean isInProgress() { - return (this.position > 0); - } - - @Override - public int describeContents() { - return 0; - } - - public boolean hasEmbeddedPicture() { - if(hasEmbeddedPicture == null) { - checkEmbeddedPicture(); - } - return hasEmbeddedPicture; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(id); - dest.writeLong(item != null ? item.getId() : 0L); - - dest.writeInt(duration); - dest.writeInt(position); - dest.writeLong(size); - dest.writeString(mime_type); - dest.writeString(file_url); - dest.writeString(download_url); - dest.writeByte((byte) ((downloaded) ? 1 : 0)); - dest.writeLong((playbackCompletionDate != null) ? playbackCompletionDate.getTime() : 0); - dest.writeInt(played_duration); - dest.writeLong(lastPlayedTime); - } - - @Override - public void writeToPreferences(Editor prefEditor) { - if(item != null && item.getFeed() != null) { - prefEditor.putLong(PREF_FEED_ID, item.getFeed().getId()); - } else { - prefEditor.putLong(PREF_FEED_ID, 0L); - } - prefEditor.putLong(PREF_MEDIA_ID, id); - } - - @Override - public void loadMetadata() throws PlayableException { - if (item == null && itemID != 0) { - item = DBReader.getFeedItem(itemID); - } - } - - @Override - public void loadChapterMarks() { - if (item == null && itemID != 0) { - item = DBReader.getFeedItem(itemID); - } - // check if chapters are stored in db and not loaded yet. - if (item != null && item.hasChapters() && item.getChapters() == null) { - DBReader.loadChaptersOfFeedItem(item); - } else if (item != null && item.getChapters() == null) { - if(localFileAvailable()) { - ChapterUtils.loadChaptersFromFileUrl(this); - } else { - ChapterUtils.loadChaptersFromStreamUrl(this); - } - if (getChapters() != null && item != null) { - DBWriter.setFeedItem(item); - } - } - } - - @Override - public String getEpisodeTitle() { - if (item == null) { - return null; - } - if (item.getTitle() != null) { - return item.getTitle(); - } else { - return item.getIdentifyingValue(); - } - } - - @Override - public List getChapters() { - if (item == null) { - return null; - } - return item.getChapters(); - } - - @Override - public String getWebsiteLink() { - if (item == null) { - return null; - } - return item.getLink(); - } - - @Override - public String getFeedTitle() { - if (item == null || item.getFeed() == null) { - return null; - } - return item.getFeed().getTitle(); - } - - @Override - public Object getIdentifier() { - return id; - } - - @Override - public String getLocalMediaUrl() { - return file_url; - } - - @Override - public String getStreamUrl() { - return download_url; - } - - @Override - public String getPaymentLink() { - if (item == null) { - return null; - } - return item.getPaymentLink(); - } - - @Override - public boolean localFileAvailable() { - return isDownloaded() && file_url != null; - } - - @Override - public boolean streamAvailable() { - return download_url != null; - } - - @Override - public void saveCurrentPosition(SharedPreferences pref, int newPosition, long timeStamp) { - if(item != null && item.isNew()) { - DBWriter.markItemPlayed(FeedItem.UNPLAYED, item.getId()); - } - setPosition(newPosition); - setLastPlayedTime(timeStamp); - DBWriter.setFeedMediaPlaybackInformation(this); - } - - @Override - public void onPlaybackStart() { - } - @Override - public void onPlaybackCompleted() { - - } - - @Override - public int getPlayableType() { - return PLAYABLE_TYPE_FEEDMEDIA; - } - - @Override - public void setChapters(List chapters) { - if(item != null) { - item.setChapters(chapters); - } - } - - @Override - public Callable loadShownotes() { - return () -> { - if (item == null) { - item = DBReader.getFeedItem( - itemID); - } - if (item.getContentEncoded() == null || item.getDescription() == null) { - DBReader.loadExtraInformationOfFeedItem( - item); - - } - return (item.getContentEncoded() != null) ? item.getContentEncoded() : item.getDescription(); - }; - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public FeedMedia createFromParcel(Parcel in) { - 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.readLong()); - result.itemID = itemID; - return result; - } - - public FeedMedia[] newArray(int size) { - return new FeedMedia[size]; - } - }; - - @Override - public String getImageLocation() { - if (hasEmbeddedPicture()) { - return getLocalMediaUrl(); - } else if(item != null) { - return item.getImageLocation(); - } else { - return null; - } - } - - public void setHasEmbeddedPicture(Boolean hasEmbeddedPicture) { - this.hasEmbeddedPicture = hasEmbeddedPicture; - } - - @Override - public void setDownloaded(boolean downloaded) { - super.setDownloaded(downloaded); - if(item != null && downloaded) { - item.setPlayed(false); - } - } - - @Override - public void setFile_url(String file_url) { - super.setFile_url(file_url); - } - - public void checkEmbeddedPicture() { - if (!localFileAvailable()) { - hasEmbeddedPicture = Boolean.FALSE; - return; - } - MediaMetadataRetriever mmr = new MediaMetadataRetriever(); - try { - mmr.setDataSource(getLocalMediaUrl()); - byte[] image = mmr.getEmbeddedPicture(); - if(image != null) { - hasEmbeddedPicture = Boolean.TRUE; - } else { - hasEmbeddedPicture = Boolean.FALSE; - } - } catch (Exception e) { - e.printStackTrace(); - hasEmbeddedPicture = Boolean.FALSE; - } - } - -// @Override -// public boolean equals(Object o) { -// if (o instanceof RemoteMedia) { -// return o.equals(this); -// } -// return super.equals(o); -// } -} diff --git a/core/src/free/java/de/danoeh/antennapod/core/feed/FeedMediaHelper.java b/core/src/free/java/de/danoeh/antennapod/core/feed/FeedMediaHelper.java new file mode 100644 index 000000000..c289d4587 --- /dev/null +++ b/core/src/free/java/de/danoeh/antennapod/core/feed/FeedMediaHelper.java @@ -0,0 +1,10 @@ +package de.danoeh.antennapod.core.feed; + +/** + * Implements methods for FeedMedia that are flavor dependent. + */ +public class FeedMediaHelper { + static boolean instanceOfRemoteMedia(Object o) { + return false; + } +} diff --git a/core/src/free/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java b/core/src/free/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java deleted file mode 100644 index abf787ce8..000000000 --- a/core/src/free/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java +++ /dev/null @@ -1,592 +0,0 @@ -//package de.danoeh.antennapod.core.service.playback; -// -//import android.content.Context; -//import android.media.MediaPlayer; -//import android.support.annotation.NonNull; -//import android.util.Log; -//import android.util.Pair; -//import android.view.SurfaceHolder; -// -//import com.google.android.gms.cast.Cast; -//import com.google.android.gms.cast.CastStatusCodes; -//import com.google.android.gms.cast.MediaInfo; -//import com.google.android.gms.cast.MediaStatus; -//import com.google.android.libraries.cast.companionlibrary.cast.exceptions.CastException; -//import com.google.android.libraries.cast.companionlibrary.cast.exceptions.NoConnectionException; -//import com.google.android.libraries.cast.companionlibrary.cast.exceptions.TransientNetworkDisconnectionException; -// -//import java.util.concurrent.atomic.AtomicBoolean; -// -//import de.danoeh.antennapod.core.R; -//import de.danoeh.antennapod.core.cast.CastConsumer; -//import de.danoeh.antennapod.core.cast.CastManager; -//import de.danoeh.antennapod.core.cast.CastUtils; -//import de.danoeh.antennapod.core.cast.DefaultCastConsumer; -//import de.danoeh.antennapod.core.cast.RemoteMedia; -//import de.danoeh.antennapod.core.feed.FeedMedia; -//import de.danoeh.antennapod.core.feed.MediaType; -//import de.danoeh.antennapod.core.util.RewindAfterPauseUtils; -//import de.danoeh.antennapod.core.util.playback.Playable; -// -///** -// * Implementation of PlaybackServiceMediaPlayer suitable for remote playback on Cast Devices. -// */ -//public class RemotePSMP extends PlaybackServiceMediaPlayer { -// -// public static final String TAG = "RemotePSMP"; -// -// public static final int CAST_ERROR = 3001; -// -// public static final int CAST_ERROR_PRIORITY_HIGH = 3005; -// -// private final CastManager castMgr; -// -// private volatile Playable media; -// private volatile MediaInfo remoteMedia; -// private volatile MediaType mediaType; -// -// private final AtomicBoolean isBuffering; -// -// private final AtomicBoolean startWhenPrepared; -// -// public RemotePSMP(@NonNull Context context, @NonNull PSMPCallback callback) { -// super(context, callback); -// -// castMgr = CastManager.getInstance(); -// media = null; -// mediaType = null; -// startWhenPrepared = new AtomicBoolean(false); -// isBuffering = new AtomicBoolean(false); -// -// try { -// if (castMgr.isConnected() && castMgr.isRemoteMediaLoaded()) { -// // updates the state, but does not start playing new media if it was going to -// onRemoteMediaPlayerStatusUpdated( -// ((p, playNextEpisode, wasSkipped, switchingPlayers) -> -// this.callback.endPlayback(p, false, wasSkipped, switchingPlayers))); -// } -// } catch (TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Unable to do initial check for loaded media", e); -// } -// -// castMgr.addCastConsumer(castConsumer); -// //TODO -// } -// -// private CastConsumer castConsumer = new DefaultCastConsumer() { -// @Override -// public void onRemoteMediaPlayerMetadataUpdated() { -// RemotePSMP.this.onRemoteMediaPlayerStatusUpdated(callback::endPlayback); -// } -// -// @Override -// public void onRemoteMediaPlayerStatusUpdated() { -// RemotePSMP.this.onRemoteMediaPlayerStatusUpdated(callback::endPlayback); -// } -// -// @Override -// public void onMediaLoadResult(int statusCode) { -// if (playerStatus == PlayerStatus.PREPARING) { -// if (statusCode == CastStatusCodes.SUCCESS) { -// setPlayerStatus(PlayerStatus.PREPARED, media); -// if (media.getDuration() == 0) { -// Log.d(TAG, "Setting duration of media"); -// try { -// media.setDuration((int) castMgr.getMediaDuration()); -// } catch (TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Unable to get remote media's duration"); -// } -// } -// } else if (statusCode != CastStatusCodes.REPLACED){ -// Log.d(TAG, "Remote media failed to load"); -// setPlayerStatus(PlayerStatus.INITIALIZED, media); -// } -// } else { -// Log.d(TAG, "onMediaLoadResult called, but Player Status wasn't in preparing state, so we ignore the result"); -// } -// } -// -// @Override -// public void onApplicationStatusChanged(String appStatus) { -// if (playerStatus != PlayerStatus.PLAYING) { -// Log.d(TAG, "onApplicationStatusChanged, but no media was playing"); -// return; -// } -// boolean playbackEnded = false; -// try { -// int standbyState = castMgr.getApplicationStandbyState(); -// Log.d(TAG, "standbyState: " + standbyState); -// playbackEnded = standbyState == Cast.STANDBY_STATE_YES; -// } catch (IllegalStateException e) { -// Log.d(TAG, "unable to get standbyState on onApplicationStatusChanged()"); -// } -// if (playbackEnded) { -// setPlayerStatus(PlayerStatus.INDETERMINATE, media); -// callback.endPlayback(media, true, false, false); -// } -// } -// -// @Override -// public void onFailed(int resourceId, int statusCode) { -// callback.onMediaPlayerInfo(CAST_ERROR, resourceId); -// } -// }; -// -// private void setBuffering(boolean buffering) { -// if (buffering && isBuffering.compareAndSet(false, true)) { -// callback.onMediaPlayerInfo(MediaPlayer.MEDIA_INFO_BUFFERING_START, 0); -// } else if (!buffering && isBuffering.compareAndSet(true, false)) { -// callback.onMediaPlayerInfo(MediaPlayer.MEDIA_INFO_BUFFERING_END, 0); -// } -// } -// -// private Playable localVersion(MediaInfo info){ -// if (info == null) { -// return null; -// } -// if (CastUtils.matches(info, media)) { -// return media; -// } -// return CastUtils.getPlayable(info, true); -// } -// -// private MediaInfo remoteVersion(Playable playable) { -// if (playable == null) { -// return null; -// } -// if (CastUtils.matches(remoteMedia, playable)) { -// return remoteMedia; -// } -// if (playable instanceof FeedMedia) { -// return CastUtils.convertFromFeedMedia((FeedMedia) playable); -// } -// if (playable instanceof RemoteMedia) { -// return ((RemoteMedia) playable).extractMediaInfo(); -// } -// return null; -// } -// -// private void onRemoteMediaPlayerStatusUpdated(@NonNull EndPlaybackCall endPlaybackCall) { -// MediaStatus status = castMgr.getMediaStatus(); -// if (status == null) { -// Log.d(TAG, "Received null MediaStatus"); -// //setBuffering(false); -// //setPlayerStatus(PlayerStatus.INDETERMINATE, null); -// return; -// } else { -// Log.d(TAG, "Received remote status/media update. New state=" + status.getPlayerState()); -// } -// Playable currentMedia = localVersion(status.getMediaInfo()); -// boolean updateUI = currentMedia != media; -// if (currentMedia != null) { -// long position = status.getStreamPosition(); -// if (position > 0 && currentMedia.getPosition() == 0) { -// currentMedia.setPosition((int) position); -// } -// } -// int state = status.getPlayerState(); -// setBuffering(state == MediaStatus.PLAYER_STATE_BUFFERING); -// switch (state) { -// case MediaStatus.PLAYER_STATE_PLAYING: -// setPlayerStatus(PlayerStatus.PLAYING, currentMedia); -// break; -// case MediaStatus.PLAYER_STATE_PAUSED: -// setPlayerStatus(PlayerStatus.PAUSED, currentMedia); -// break; -// case MediaStatus.PLAYER_STATE_BUFFERING: -// setPlayerStatus(playerStatus, currentMedia); -// break; -// case MediaStatus.PLAYER_STATE_IDLE: -// int reason = status.getIdleReason(); -// switch (reason) { -// case MediaStatus.IDLE_REASON_CANCELED: -// // check if we're already loading something else -// if (!updateUI || media == null) { -// setPlayerStatus(PlayerStatus.STOPPED, currentMedia); -// } else { -// updateUI = false; -// } -// break; -// case MediaStatus.IDLE_REASON_INTERRUPTED: -// // check if we're already loading something else -// if (!updateUI || media == null) { -// setPlayerStatus(PlayerStatus.PREPARING, currentMedia); -// } else { -// updateUI = false; -// } -// break; -// case MediaStatus.IDLE_REASON_NONE: -// setPlayerStatus(PlayerStatus.INITIALIZED, currentMedia); -// break; -// case MediaStatus.IDLE_REASON_FINISHED: -// boolean playing = playerStatus == PlayerStatus.PLAYING; -// setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); -// endPlaybackCall.endPlayback(currentMedia,playing, false, false); -// // endPlayback already updates the UI, so no need to trigger it ourselves -// updateUI = false; -// break; -// case MediaStatus.IDLE_REASON_ERROR: -// Log.w(TAG, "Got an error status from the Chromecast. Skipping, if possible, to the next episode..."); -// setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); -// callback.onMediaPlayerInfo(CAST_ERROR_PRIORITY_HIGH, -// R.string.cast_failed_media_error_skipping); -// endPlaybackCall.endPlayback(currentMedia, startWhenPrepared.get(), true, false); -// // endPlayback already updates the UI, so no need to trigger it ourselves -// updateUI = false; -// } -// break; -// case MediaStatus.PLAYER_STATE_UNKNOWN: -// //is this right? -// setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); -// break; -// default: -// Log.e(TAG, "Remote media state undetermined!"); -// setPlayerStatus(PlayerStatus.INDETERMINATE, currentMedia); -// } -// if (updateUI) { -// callback.onMediaChanged(true); -// } -// } -// -// @Override -// public void playMediaObject(@NonNull final Playable playable, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) { -// Log.d(TAG, "playMediaObject() called"); -// playMediaObject(playable, false, stream, startWhenPrepared, prepareImmediately); -// } -// -// /** -// * Internal implementation of playMediaObject. This method has an additional parameter that allows the caller to force a media player reset even if -// * the given playable parameter is the same object as the currently playing media. -// * -// * @see #playMediaObject(de.danoeh.antennapod.core.util.playback.Playable, boolean, boolean, boolean) -// */ -// private void playMediaObject(@NonNull final Playable playable, final boolean forceReset, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) { -// if (!CastUtils.isCastable(playable)) { -// Log.d(TAG, "media provided is not compatible with cast device"); -// callback.onMediaPlayerInfo(CAST_ERROR_PRIORITY_HIGH, R.string.cast_not_castable); -// try { -// playable.loadMetadata(); -// } catch (Playable.PlayableException e) { -// Log.e(TAG, "Unable to load metadata of playable", e); -// } -// callback.endPlayback(playable, startWhenPrepared, true, false); -// return; -// } -// -// if (media != null) { -// if (!forceReset && media.getIdentifier().equals(playable.getIdentifier()) -// && playerStatus == PlayerStatus.PLAYING) { -// // episode is already playing -> ignore method call -// Log.d(TAG, "Method call to playMediaObject was ignored: media file already playing."); -// return; -// } else { -// // set temporarily to pause in order to update list with current position -// try { -// if (castMgr.isRemoteMediaPlaying()) { -// setPlayerStatus(PlayerStatus.PAUSED, media); -// } -// } catch (TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Unable to determine whether media was playing, falling back to stored player status", e); -// // this might end up just being pointless if we need to query the remote device for the position -// if (playerStatus == PlayerStatus.PLAYING) { -// setPlayerStatus(PlayerStatus.PAUSED, media); -// } -// } -// smartMarkAsPlayed(media); -// -// -// setPlayerStatus(PlayerStatus.INDETERMINATE, null); -// } -// } -// -// this.media = playable; -// remoteMedia = remoteVersion(playable); -// //this.stream = stream; -// this.mediaType = media.getMediaType(); -// this.startWhenPrepared.set(startWhenPrepared); -// setPlayerStatus(PlayerStatus.INITIALIZING, media); -// try { -// media.loadMetadata(); -// callback.onMediaChanged(true); -// setPlayerStatus(PlayerStatus.INITIALIZED, media); -// if (prepareImmediately) { -// prepare(); -// } -// } catch (Playable.PlayableException e) { -// Log.e(TAG, "Error while loading media metadata", e); -// setPlayerStatus(PlayerStatus.STOPPED, null); -// } -// } -// -// @Override -// public void resume() { -// try { -// // TODO see comment on prepare() -// // setVolume(UserPreferences.getLeftVolume(), UserPreferences.getRightVolume()); -// if (playerStatus == PlayerStatus.PREPARED && media.getPosition() > 0) { -// int newPosition = RewindAfterPauseUtils.calculatePositionWithRewind( -// media.getPosition(), -// media.getLastPlayedTime()); -// castMgr.play(newPosition); -// } -// castMgr.play(); -// } catch (CastException | TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Unable to resume remote playback", e); -// } -// } -// -// @Override -// public void pause(boolean abandonFocus, boolean reinit) { -// try { -// if (castMgr.isRemoteMediaPlaying()) { -// castMgr.pause(); -// } -// } catch (CastException | TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Unable to pause", e); -// } -// } -// -// @Override -// public void prepare() { -// if (playerStatus == PlayerStatus.INITIALIZED) { -// Log.d(TAG, "Preparing media player"); -// setPlayerStatus(PlayerStatus.PREPARING, media); -// try { -// int position = media.getPosition(); -// if (position > 0) { -// position = RewindAfterPauseUtils.calculatePositionWithRewind( -// position, -// media.getLastPlayedTime()); -// } -// // TODO We're not supporting user set stream volume yet, as we need to make a UI -// // that doesn't allow changing playback speed or have different values for left/right -// //setVolume(UserPreferences.getLeftVolume(), UserPreferences.getRightVolume()); -// castMgr.loadMedia(remoteMedia, startWhenPrepared.get(), position); -// } catch (TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Error loading media", e); -// setPlayerStatus(PlayerStatus.INITIALIZED, media); -// } -// } -// } -// -// @Override -// public void reinit() { -// Log.d(TAG, "reinit() called"); -// if (media != null) { -// playMediaObject(media, true, false, startWhenPrepared.get(), false); -// } else { -// Log.d(TAG, "Call to reinit was ignored: media was null"); -// } -// } -// -// @Override -// public void seekTo(int t) { -// //TODO check other seek implementations and see if there's no issue with sending too many seek commands to the remote media player -// try { -// if (castMgr.isRemoteMediaLoaded()) { -// setPlayerStatus(PlayerStatus.SEEKING, media); -// castMgr.seek(t); -// } else if (media != null && playerStatus == PlayerStatus.INITIALIZED){ -// media.setPosition(t); -// startWhenPrepared.set(false); -// prepare(); -// } -// } catch (TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Unable to seek", e); -// } -// } -// -// @Override -// public void seekDelta(int d) { -// int position = getPosition(); -// if (position != INVALID_TIME) { -// seekTo(position + d); -// } else { -// Log.e(TAG, "getPosition() returned INVALID_TIME in seekDelta"); -// } -// } -// -// @Override -// public int getDuration() { -// int retVal = INVALID_TIME; -// boolean prepared; -// try { -// prepared = castMgr.isRemoteMediaLoaded(); -// } catch (TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Unable to check if remote media is loaded", e); -// prepared = playerStatus.isAtLeast(PlayerStatus.PREPARED); -// } -// if (prepared) { -// try { -// retVal = (int) castMgr.getMediaDuration(); -// } catch (TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Unable to determine remote media's duration", e); -// } -// } -// if(retVal == INVALID_TIME && media != null && media.getDuration() > 0) { -// retVal = media.getDuration(); -// } -// Log.d(TAG, "getDuration() -> " + retVal); -// return retVal; -// } -// -// @Override -// public int getPosition() { -// int retVal = INVALID_TIME; -// boolean prepared; -// try { -// prepared = castMgr.isRemoteMediaLoaded(); -// } catch (TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Unable to check if remote media is loaded", e); -// prepared = playerStatus.isAtLeast(PlayerStatus.PREPARED); -// } -// if (prepared) { -// try { -// retVal = (int) castMgr.getCurrentMediaPosition(); -// } catch (TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Unable to determine remote media's position", e); -// } -// } -// if(retVal <= 0 && media != null && media.getPosition() >= 0) { -// retVal = media.getPosition(); -// } -// Log.d(TAG, "getPosition() -> " + retVal); -// return retVal; -// } -// -// @Override -// public boolean isStartWhenPrepared() { -// return startWhenPrepared.get(); -// } -// -// @Override -// public void setStartWhenPrepared(boolean startWhenPrepared) { -// this.startWhenPrepared.set(startWhenPrepared); -// } -// -// //TODO I believe some parts of the code make the same decision skipping this check, so that -// //should be changed as well -// @Override -// public boolean canSetSpeed() { -// return false; -// } -// -// @Override -// public void setSpeed(float speed) { -// throw new UnsupportedOperationException("Setting playback speed unsupported for Remote Playback"); -// } -// -// @Override -// public float getPlaybackSpeed() { -// return 1; -// } -// -// @Override -// public void setVolume(float volumeLeft, float volumeRight) { -// Log.d(TAG, "Setting the Stream volume on Remote Media Player"); -// double volume = (volumeLeft+volumeRight)/2; -// if (volume > 1.0) { -// volume = 1.0; -// } -// if (volume < 0.0) { -// volume = 0.0; -// } -// try { -// castMgr.setStreamVolume(volume); -// } catch (TransientNetworkDisconnectionException | NoConnectionException | CastException e) { -// Log.e(TAG, "Unable to set the volume", e); -// } -// } -// -// @Override -// public boolean canDownmix() { -// return false; -// } -// -// @Override -// public void setDownmix(boolean enable) { -// throw new UnsupportedOperationException("Setting downmix unsupported in Remote Media Player"); -// } -// -// @Override -// public MediaType getCurrentMediaType() { -// return mediaType; -// } -// -// @Override -// public boolean isStreaming() { -// return true; -// } -// -// @Override -// public void shutdown() { -// castMgr.removeCastConsumer(castConsumer); -// } -// -// @Override -// public void shutdownQuietly() { -// shutdown(); -// } -// -// @Override -// public void setVideoSurface(SurfaceHolder surface) { -// throw new UnsupportedOperationException("Setting Video Surface unsupported in Remote Media Player"); -// } -// -// @Override -// public void resetVideoSurface() { -// Log.e(TAG, "Resetting Video Surface unsupported in Remote Media Player"); -// } -// -// @Override -// public Pair getVideoSize() { -// return null; -// } -// -// @Override -// public Playable getPlayable() { -// return media; -// } -// -// @Override -// protected void setPlayable(Playable playable) { -// if (playable != media) { -// media = playable; -// remoteMedia = remoteVersion(playable); -// } -// } -// -// @Override -// public void endPlayback(boolean wasSkipped, boolean switchingPlayers) { -// Log.d(TAG, "endPlayback() called"); -// boolean isPlaying = playerStatus == PlayerStatus.PLAYING; -// try { -// isPlaying = castMgr.isRemoteMediaPlaying(); -// } catch (TransientNetworkDisconnectionException | NoConnectionException e) { -// Log.e(TAG, "Could not determine if media is playing", e); -// } -// // TODO make sure we stop playback whenever there's no next episode. -// if (playerStatus != PlayerStatus.INDETERMINATE) { -// setPlayerStatus(PlayerStatus.INDETERMINATE, media); -// } -// callback.endPlayback(media, isPlaying, wasSkipped, switchingPlayers); -// } -// -// @Override -// public void stop() { -// if (playerStatus == PlayerStatus.INDETERMINATE) { -// setPlayerStatus(PlayerStatus.STOPPED, null); -// } else { -// Log.d(TAG, "Ignored call to stop: Current player state is: " + playerStatus); -// } -// } -// -// @Override -// protected boolean shouldLockWifi() { -// return false; -// } -// -// private interface EndPlaybackCall { -// boolean endPlayback(Playable media, boolean playNextEpisode, boolean wasSkipped, boolean switchingPlayers); -// } -//} diff --git a/core/src/play/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java similarity index 99% rename from core/src/play/java/de/danoeh/antennapod/core/feed/FeedMedia.java rename to core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java index 068669af9..3aea015c0 100644 --- a/core/src/play/java/de/danoeh/antennapod/core/feed/FeedMedia.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java @@ -12,7 +12,6 @@ import java.util.Date; import java.util.List; import java.util.concurrent.Callable; -import de.danoeh.antennapod.core.cast.RemoteMedia; import de.danoeh.antennapod.core.preferences.PlaybackPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.storage.DBReader; @@ -560,7 +559,7 @@ public class FeedMedia extends FeedFile implements Playable { @Override public boolean equals(Object o) { - if (o instanceof RemoteMedia) { + if (FeedMediaHelper.instanceOfRemoteMedia(o)) { return o.equals(this); } return super.equals(o); diff --git a/core/src/play/java/de/danoeh/antennapod/core/feed/FeedMediaHelper.java b/core/src/play/java/de/danoeh/antennapod/core/feed/FeedMediaHelper.java new file mode 100644 index 000000000..8fa281427 --- /dev/null +++ b/core/src/play/java/de/danoeh/antennapod/core/feed/FeedMediaHelper.java @@ -0,0 +1,12 @@ +package de.danoeh.antennapod.core.feed; + +import de.danoeh.antennapod.core.cast.RemoteMedia; + +/** + * Implements methods for FeedMedia that are flavor dependent. + */ +public class FeedMediaHelper { + static boolean instanceOfRemoteMedia(Object o) { + return o instanceof RemoteMedia; + } +}