diff options
author | ByteHamster <ByteHamster@users.noreply.github.com> | 2021-03-28 22:46:37 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-28 22:46:37 +0200 |
commit | 7465b747f3630a82ee6375c766dcba015aa78cfc (patch) | |
tree | 9744412b09ee9e12f3a3fb002cd343fdbf659376 /core/src | |
parent | dcbe5e6905e8fb2c37bb73f9c692d07ae21111a8 (diff) | |
parent | 998535515bae8ec5bcd2bd95bc0cf4f34416dff7 (diff) | |
download | AntennaPod-7465b747f3630a82ee6375c766dcba015aa78cfc.zip |
Merge pull request #5055 from ByteHamster/spotbugs
Add SpotBugs CI check
Diffstat (limited to 'core/src')
15 files changed, 32 insertions, 709 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java index c05e2e9f1..6ca84ff87 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java @@ -94,7 +94,7 @@ public class OpmlBackupAgent extends BackupAgentHelper { if (len != -1) { byte[] oldChecksum = new byte[len]; - inState.read(oldChecksum); + IOUtils.read(inState, oldChecksum, 0, len); Log.d(TAG, "Old checksum: " + new BigInteger(1, oldChecksum).toString(16)); if (Arrays.equals(oldChecksum, newChecksum)) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java index 08a531d17..1c13471a5 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/Chapter.java @@ -43,7 +43,7 @@ public abstract class Chapter extends FeedComponent { String imageUrl = cursor.getString(indexImage); int chapterType = cursor.getInt(indexChapterType); - Chapter chapter = null; + Chapter chapter; switch (chapterType) { case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER: chapter = new SimpleChapter(start, title, link, imageUrl); @@ -54,6 +54,8 @@ public abstract class Chapter extends FeedComponent { case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER: chapter = new VorbisCommentChapter(start, title, link, imageUrl); break; + default: + throw new IllegalArgumentException("Unknown chapter type"); } chapter.setId(id); return chapter; diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java index d6926385e..25857dad2 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java @@ -43,7 +43,7 @@ public class FeedItem extends FeedComponent implements Serializable { private Date pubDate; private FeedMedia media; - private Feed feed; + private transient Feed feed; private long feedId; private int state; @@ -65,7 +65,7 @@ public class FeedItem extends FeedComponent implements Serializable { * The list of chapters of this item. This might be null even if there are chapters of this item * in the database. The 'hasChapters' attribute should be used to check if this item has any chapters. * */ - private List<Chapter> chapters; + private transient List<Chapter> chapters; private String imageUrl; /* diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java index 519d625e2..d6d63fed0 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ChapterImageModelLoader.java @@ -1,7 +1,6 @@ package de.danoeh.antennapod.core.glide; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.bumptech.glide.Priority; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.Options; @@ -36,7 +35,6 @@ public final class ChapterImageModelLoader implements ModelLoader<EmbeddedChapte } } - @Nullable @Override public LoadData<ByteBuffer> buildLoadData(@NonNull EmbeddedChapterImage model, int width, @@ -65,9 +63,9 @@ public final class ChapterImageModelLoader implements ModelLoader<EmbeddedChapte if (image.getMedia().localFileAvailable()) { File localFile = new File(image.getMedia().getLocalMediaUrl()); stream = new BufferedInputStream(new FileInputStream(localFile)); - stream.skip(image.getPosition()); + IOUtils.skip(stream, image.getPosition()); byte[] imageContent = new byte[image.getLength()]; - stream.read(imageContent, 0, image.getLength()); + IOUtils.read(stream, imageContent, 0, image.getLength()); callback.onDataReady(ByteBuffer.wrap(imageContent)); } else { Request.Builder httpReq = new Request.Builder(); @@ -88,10 +86,13 @@ public final class ChapterImageModelLoader implements ModelLoader<EmbeddedChapte } } - @Override public void cleanup() { + @Override + public void cleanup() { // nothing to clean up } - @Override public void cancel() { + + @Override + public void cancel() { // cannot cancel } diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java index 1f8ae5ad9..4de6a7315 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java +++ b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java @@ -8,6 +8,7 @@ import android.util.Log; import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; +import java.nio.charset.Charset; import java.security.MessageDigest; public class FastBlurTransformation extends BitmapTransformation { @@ -43,7 +44,7 @@ public class FastBlurTransformation extends BitmapTransformation { @Override public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) { - messageDigest.update(TAG.getBytes()); + messageDigest.update(TAG.getBytes(Charset.defaultCharset())); } private static Bitmap fastBlur(Bitmap bitmap, int radius) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java index c4029d57f..4d1d44908 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java @@ -120,7 +120,7 @@ public class AntennapodHttpClient { SocketAddress address = InetSocketAddress.createUnresolved(config.host, port); Proxy proxy = new Proxy(config.type, address); builder.proxy(proxy); - if (!TextUtils.isEmpty(config.username)) { + if (!TextUtils.isEmpty(config.username) && config.password != null) { String credentials = Credentials.basic(config.username, config.password); builder.interceptors().add(chain -> { Request request = chain.request().newBuilder() diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java index 2d955859f..5050225f7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java @@ -188,8 +188,11 @@ public class HttpDownloader extends Downloader { out = new RandomAccessFile(destination, "rw"); out.seek(request.getSoFar()); } else { - destination.delete(); - destination.createNewFile(); + boolean success = destination.delete(); + success |= destination.createNewFile(); + if (!success) { + throw new IOException("Unable to recreate partially downloaded file"); + } out = new RandomAccessFile(destination, "rw"); } 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 1f047ceee..785784497 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 @@ -217,7 +217,7 @@ public abstract class PlaybackServiceMediaPlayer { * could result in nonsensical results (like a status of PLAYING, but a null playable) * @return the current player status */ - public PlayerStatus getPlayerStatus() { + public synchronized PlayerStatus getPlayerStatus() { return playerStatus; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DatabaseExporter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DatabaseExporter.java index 271babc6e..a0fac0c74 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DatabaseExporter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DatabaseExporter.java @@ -91,7 +91,10 @@ public class DatabaseExporter { db.close(); File currentDB = context.getDatabasePath(PodDBAdapter.DATABASE_NAME); - currentDB.delete(); + boolean success = currentDB.delete(); + if (!success) { + throw new IOException("Unable to delete old database"); + } FileUtils.moveFile(tempDB, currentDB); } catch (IOException | SQLiteException e) { Log.e(TAG, Log.getStackTraceString(e)); 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 98d5e6310..7ab776856 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 @@ -331,7 +331,7 @@ public class PodDBAdapter { PodDBAdapter.context = context.getApplicationContext(); } - public static PodDBAdapter getInstance() { + public static synchronized PodDBAdapter getInstance() { if (instance == null) { instance = new PodDBAdapter(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java index cecfc0d2c..cd0fc93ea 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/sync/gpoddernet/GpodnetService.java @@ -667,11 +667,11 @@ public class GpodnetService implements ISyncService { while ((count = in.read(buffer)) > 0) { outputStream.write(buffer, 0, count); } + return outputStream.toString("UTF-8"); } catch (IOException e) { e.printStackTrace(); throw new GpodnetServiceException(e); } - return outputStream.toString(); } private void checkStatusCode(@NonNull Response response) throws GpodnetServiceException { diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/HtmlToPlainText.java b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/HtmlToPlainText.java index baa467acf..37dee0486 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/HtmlToPlainText.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/HtmlToPlainText.java @@ -34,8 +34,7 @@ import java.util.regex.Pattern; public class HtmlToPlainText { /** - * Use this method to strip off HTML encoding from given text - * <p> + * Use this method to strip off HTML encoding from given text. * Replaces bullet points with *, ignores colors/bold/... * * @param str String with any encoding @@ -60,10 +59,8 @@ public class HtmlToPlainText { * @return <b>True</b> if text contains any HTML tags<br /><b>False</b> is no HTML tag is found */ private static boolean isHtml(String str) { - final String HTML_TAG_PATTERN = "<(\"[^\"]*\"|'[^']*'|[^'\">])*>"; - Pattern htmlValidator = TextUtils.isEmpty(HTML_TAG_PATTERN) ? null : Pattern.compile(HTML_TAG_PATTERN); - - return htmlValidator.matcher(str).find(); + final String htmlTagPattern = "<(\"[^\"]*\"|'[^']*'|[^'\">])*>"; + return Pattern.compile(htmlTagPattern).matcher(str).find(); } /** diff --git a/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java b/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java index 48c3bfbfc..dd07b9cd8 100644 --- a/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java +++ b/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java @@ -23,13 +23,11 @@ package de.danoeh.antennapod.core.cast; import android.content.Context; -import android.os.Build; import androidx.annotation.NonNull; import androidx.core.view.ActionProvider; import androidx.core.view.MenuItemCompat; import androidx.mediarouter.media.MediaRouter; import android.util.Log; -import android.view.KeyEvent; import android.view.MenuItem; import com.google.android.gms.cast.ApplicationMetadata; @@ -46,7 +44,6 @@ import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; import com.google.android.libraries.cast.companionlibrary.cast.BaseCastManager; import com.google.android.libraries.cast.companionlibrary.cast.CastConfiguration; -import com.google.android.libraries.cast.companionlibrary.cast.MediaQueue; 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.OnFailedListener; @@ -58,9 +55,7 @@ import java.io.IOException; import java.util.List; import java.util.Locale; import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.R; @@ -97,32 +92,14 @@ public class CastManager extends BaseCastManager implements OnFailedListener { public static final String CAST_APP_ID = CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID; - public static final double DEFAULT_VOLUME_STEP = 0.05; - public static final long DEFAULT_LIVE_STREAM_DURATION_MS = TimeUnit.HOURS.toMillis(2); - private double volumeStep = DEFAULT_VOLUME_STEP; - private MediaQueue mediaQueue; private MediaStatus mediaStatus; - private static CastManager INSTANCE; private RemoteMediaPlayer remoteMediaPlayer; private int state = MediaStatus.PLAYER_STATE_IDLE; - private int idleReason; private final Set<CastConsumer> castConsumers = new CopyOnWriteArraySet<>(); - private long liveStreamDuration = DEFAULT_LIVE_STREAM_DURATION_MS; - private MediaQueueItem preLoadingItem; public static final int QUEUE_OPERATION_LOAD = 1; - public static final int QUEUE_OPERATION_INSERT_ITEMS = 2; - public static final int QUEUE_OPERATION_UPDATE_ITEMS = 3; - public static final int QUEUE_OPERATION_JUMP = 4; - public static final int QUEUE_OPERATION_REMOVE_ITEM = 5; - public static final int QUEUE_OPERATION_REMOVE_ITEMS = 6; - public static final int QUEUE_OPERATION_REORDER = 7; - public static final int QUEUE_OPERATION_MOVE = 8; public static final int QUEUE_OPERATION_APPEND = 9; - public static final int QUEUE_OPERATION_NEXT = 10; - public static final int QUEUE_OPERATION_PREV = 11; - public static final int QUEUE_OPERATION_SET_REPEAT = 12; private CastManager(Context context, CastConfiguration castConfiguration) { super(context, castConfiguration); @@ -176,19 +153,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { return remoteMediaPlayer; } - /** - * Determines if the media that is loaded remotely is a live stream or not. - * - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public final boolean isRemoteStreamLive() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - MediaInfo info = getRemoteMediaInformation(); - return (info != null) && (info.getStreamType() == MediaInfo.STREAM_TYPE_LIVE); - } - /* * A simple check to make sure remoteMediaPlayer is not null */ @@ -199,25 +163,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { } /** - * Returns the url for the media that is currently playing on the remote device. If there is no - * connection, this will return <code>null</code>. - * - * @throws NoConnectionException If no connectivity to the device exists - * @throws TransientNetworkDisconnectionException If framework is still trying to recover from - * a possibly transient loss of network - */ - public String getRemoteMediaUrl() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - if (remoteMediaPlayer != null && remoteMediaPlayer.getMediaInfo() != null) { - MediaInfo info = remoteMediaPlayer.getMediaInfo(); - remoteMediaPlayer.getMediaStatus().getPlayerState(); - return info.getContentId(); - } - throw new NoConnectionException(); - } - - /** * Indicates if the remote media is currently playing (or buffering). * * @throws NoConnectionException @@ -256,20 +201,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { } /** - * Returns the {@link MediaInfo} for the current media - * - * @throws NoConnectionException If no connectivity to the device exists - * @throws TransientNetworkDisconnectionException If framework is still trying to recover from - * a possibly transient loss of network - */ - public MediaInfo getRemoteMediaInformation() throws TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - checkRemoteMediaPlayerAvailable(); - return remoteMediaPlayer.getMediaInfo(); - } - - /** * Gets the remote's system volume. It internally detects what type of volume is used. * * @throws NoConnectionException If no connectivity to the device exists @@ -327,30 +258,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { } /** - * Returns <code>true</code> if remote device is muted. - * - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public boolean isMute() throws TransientNetworkDisconnectionException, NoConnectionException { - return isStreamMute() || isDeviceMute(); - } - - /** - * Mutes or un-mutes the stream volume. - * - * @throws CastException - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void setStreamMute(boolean mute) throws CastException, TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - checkRemoteMediaPlayerAvailable(); - remoteMediaPlayer.setStreamMute(mApiClient, mute); - } - - /** * Returns the duration of the media that is loaded, in milliseconds. * * @throws NoConnectionException @@ -364,23 +271,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { } /** - * Returns the time left (in milliseconds) of the current media. If there is no - * {@code RemoteMediaPlayer}, it returns -1. - * - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public long getMediaTimeRemaining() - throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (remoteMediaPlayer == null) { - return -1; - } - return isRemoteStreamLive() ? liveStreamDuration : remoteMediaPlayer.getStreamDuration() - - remoteMediaPlayer.getApproximateStreamPosition(); - } - - /** * Returns the current (approximate) position of the current media, in milliseconds. * * @throws NoConnectionException @@ -671,435 +561,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { } /** - * Inserts a list of new media items into the queue. - * - * @param itemsToInsert List of items to insert into the queue, in the order that they should be - * played. The itemId field of the items should be unassigned or the - * request will fail with an INVALID_PARAMS error. Must not be {@code null} - * or empty. - * @param insertBeforeItemId ID of the item that will be located immediately after the inserted - * list. If the value is {@link MediaQueueItem#INVALID_ITEM_ID} or - * invalid, the inserted list will be appended to the end of the - * queue. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws IllegalArgumentException - */ - public void queueInsertItems(final MediaQueueItem[] itemsToInsert, final int insertBeforeItemId, - final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - Log.d(TAG, "queueInsertItems"); - checkConnectivity(); - if (itemsToInsert == null || itemsToInsert.length == 0) { - throw new IllegalArgumentException("items cannot be empty or null"); - } - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to insert into queue with no active media session"); - throw new NoConnectionException(); - } - remoteMediaPlayer - .queueInsertItems(mApiClient, itemsToInsert, insertBeforeItemId, customData) - .setResultCallback( - result -> { - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult( - QUEUE_OPERATION_INSERT_ITEMS, - result.getStatus().getStatusCode()); - } - }); - } - - /** - * Updates properties of a subset of the existing items in the media queue. - * - * @param itemsToUpdate List of queue items to be updated. The items will retain the existing - * order and will be fully replaced with the ones provided, including the - * media information. Any other items currently in the queue will remain - * unchanged. The tracks information can not change once the item is loaded - * (if the item is the currentItem). If any of the items does not exist it - * will be ignored. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueUpdateItems(final MediaQueueItem[] itemsToUpdate, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - checkConnectivity(); - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to update the queue with no active media session"); - throw new NoConnectionException(); - } - remoteMediaPlayer - .queueUpdateItems(mApiClient, itemsToUpdate, customData).setResultCallback( - result -> { - Log.d(TAG, "queueUpdateItems() " + result.getStatus() + result.getStatus() - .isSuccess()); - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_UPDATE_ITEMS, - result.getStatus().getStatusCode()); - } - }); - } - - /** - * Plays the item with {@code itemId} in the queue. - * <p> - * If {@code itemId} is not found in the queue, this method will report success without sending - * a request to the receiver. - * - * @param itemId The ID of the item to which to jump. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws IllegalArgumentException - */ - public void queueJumpToItem(int itemId, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException, - IllegalArgumentException { - checkConnectivity(); - if (itemId == MediaQueueItem.INVALID_ITEM_ID) { - throw new IllegalArgumentException("itemId is not valid"); - } - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to jump in a queue with no active media session"); - throw new NoConnectionException(); - } - remoteMediaPlayer - .queueJumpToItem(mApiClient, itemId, customData).setResultCallback( - result -> { - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_JUMP, - result.getStatus().getStatusCode()); - } - }); - } - - /** - * Removes a list of items from the queue. If the remaining queue is empty, the media session - * will be terminated. - * - * @param itemIdsToRemove The list of media item IDs to remove. Must not be {@code null} or - * empty. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws IllegalArgumentException - */ - public void queueRemoveItems(final int[] itemIdsToRemove, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException, - IllegalArgumentException { - Log.d(TAG, "queueRemoveItems"); - checkConnectivity(); - if (itemIdsToRemove == null || itemIdsToRemove.length == 0) { - throw new IllegalArgumentException("itemIds cannot be empty or null"); - } - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to remove items from queue with no active media session"); - throw new NoConnectionException(); - } - remoteMediaPlayer - .queueRemoveItems(mApiClient, itemIdsToRemove, customData).setResultCallback( - result -> { - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_REMOVE_ITEMS, - result.getStatus().getStatusCode()); - } - }); - } - - /** - * Removes the item with {@code itemId} from the queue. - * <p> - * If {@code itemId} is not found in the queue, this method will silently return without sending - * a request to the receiver. A {@code itemId} may not be in the queue because it wasn't - * originally in the queue, or it was removed by another sender. - * - * @param itemId The ID of the item to be removed. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws IllegalArgumentException - */ - public void queueRemoveItem(final int itemId, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException, - IllegalArgumentException { - Log.d(TAG, "queueRemoveItem"); - checkConnectivity(); - if (itemId == MediaQueueItem.INVALID_ITEM_ID) { - throw new IllegalArgumentException("itemId is invalid"); - } - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to remove an item from queue with no active media session"); - throw new NoConnectionException(); - } - remoteMediaPlayer - .queueRemoveItem(mApiClient, itemId, customData).setResultCallback( - result -> { - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_REMOVE_ITEM, - result.getStatus().getStatusCode()); - } - }); - } - - /** - * Reorder a list of media items in the queue. - * - * @param itemIdsToReorder The list of media item IDs to reorder, in the new order. Any other - * items currently in the queue will maintain their existing order. The - * list will be inserted just before the item specified by - * {@code insertBeforeItemId}, or at the end of the queue if - * {@code insertBeforeItemId} is {@link MediaQueueItem#INVALID_ITEM_ID}. - * <p> - * For example: - * <p> - * If insertBeforeItemId is not specified <br> - * Existing queue: "A","D","G","H","B","E" <br> - * itemIds: "D","H","B" <br> - * New Order: "A","G","E","D","H","B" <br> - * <p> - * If insertBeforeItemId is "A" <br> - * Existing queue: "A","D","G","H","B" <br> - * itemIds: "D","H","B" <br> - * New Order: "D","H","B","A","G","E" <br> - * <p> - * If insertBeforeItemId is "G" <br> - * Existing queue: "A","D","G","H","B" <br> - * itemIds: "D","H","B" <br> - * New Order: "A","D","H","B","G","E" <br> - * <p> - * If any of the items does not exist it will be ignored. - * Must not be {@code null} or empty. - * @param insertBeforeItemId ID of the item that will be located immediately after the reordered - * list. If set to {@link MediaQueueItem#INVALID_ITEM_ID}, the - * reordered list will be appended at the end of the queue. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueReorderItems(final int[] itemIdsToReorder, final int insertBeforeItemId, - final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException, - IllegalArgumentException { - Log.d(TAG, "queueReorderItems"); - checkConnectivity(); - if (itemIdsToReorder == null || itemIdsToReorder.length == 0) { - throw new IllegalArgumentException("itemIdsToReorder cannot be empty or null"); - } - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to reorder items in a queue with no active media session"); - throw new NoConnectionException(); - } - remoteMediaPlayer - .queueReorderItems(mApiClient, itemIdsToReorder, insertBeforeItemId, customData) - .setResultCallback( - result -> { - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_REORDER, - result.getStatus().getStatusCode()); - } - }); - } - - /** - * Moves the item with {@code itemId} to a new position in the queue. - * <p> - * If {@code itemId} is not found in the queue, either because it wasn't there originally or it - * was removed by another sender before calling this function, this function will silently - * return without sending a request to the receiver. - * - * @param itemId The ID of the item to be moved. - * @param newIndex The new index of the item. If the value is negative, an error will be - * returned. If the value is out of bounds, or becomes out of bounds because the - * queue was shortened by another sender while this request is in progress, the - * item will be moved to the end of the queue. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueMoveItemToNewIndex(int itemId, int newIndex, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - Log.d(TAG, "queueMoveItemToNewIndex"); - checkConnectivity(); - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to mote item to new index with no active media session"); - throw new NoConnectionException(); - } - remoteMediaPlayer - .queueMoveItemToNewIndex(mApiClient, itemId, newIndex, customData) - .setResultCallback( - result -> { - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_MOVE, - result.getStatus().getStatusCode()); - } - }); - } - - /** - * Appends a new media item to the end of the queue. - * - * @param item The item to append. Must not be {@code null}. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueAppendItem(MediaQueueItem item, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - Log.d(TAG, "queueAppendItem"); - checkConnectivity(); - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to append item with no active media session"); - throw new NoConnectionException(); - } - remoteMediaPlayer - .queueAppendItem(mApiClient, item, customData) - .setResultCallback( - result -> { - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_APPEND, - result.getStatus().getStatusCode()); - } - }); - } - - /** - * Jumps to the next item in the queue. - * - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueNext(final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - Log.d(TAG, "queueNext"); - checkConnectivity(); - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to update the queue with no active media session"); - throw new NoConnectionException(); - } - remoteMediaPlayer - .queueNext(mApiClient, customData).setResultCallback( - result -> { - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_NEXT, - result.getStatus().getStatusCode()); - } - }); - } - - /** - * Jumps to the previous item in the queue. - * - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queuePrev(final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - Log.d(TAG, "queuePrev"); - checkConnectivity(); - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to update the queue with no active media session"); - throw new NoConnectionException(); - } - remoteMediaPlayer - .queuePrev(mApiClient, customData).setResultCallback( - result -> { - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_PREV, - result.getStatus().getStatusCode()); - } - }); - } - - /** - * Inserts an item in the queue and starts the playback of that newly inserted item. It is - * assumed that we are inserting before the "current item" - * - * @param item The item to be inserted - * @param insertBeforeItemId ID of the item that will be located immediately after the inserted - * and is assumed to be the "current item" - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - * @throws IllegalArgumentException - */ - public void queueInsertBeforeCurrentAndPlay(MediaQueueItem item, int insertBeforeItemId, - final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - Log.d(TAG, "queueInsertBeforeCurrentAndPlay"); - checkConnectivity(); - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to insert into queue with no active media session"); - throw new NoConnectionException(); - } - if (item == null || insertBeforeItemId == MediaQueueItem.INVALID_ITEM_ID) { - throw new IllegalArgumentException( - "item cannot be empty or insertBeforeItemId cannot be invalid"); - } - remoteMediaPlayer.queueInsertItems(mApiClient, new MediaQueueItem[]{item}, - insertBeforeItemId, customData).setResultCallback( - result -> { - if (result.getStatus().isSuccess()) { - - try { - queuePrev(customData); - } catch (TransientNetworkDisconnectionException | - NoConnectionException e) { - Log.e(TAG, "queuePrev() Failed to skip to previous", e); - } - } - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_INSERT_ITEMS, - result.getStatus().getStatusCode()); - } - }); - } - - /** - * Sets the repeat mode of the queue. - * - * @param repeatMode The repeat playback mode for the queue. - * @param customData Custom application-specific data to pass along with the request. May be - * {@code null}. - * @throws TransientNetworkDisconnectionException - * @throws NoConnectionException - */ - public void queueSetRepeatMode(final int repeatMode, final JSONObject customData) - throws TransientNetworkDisconnectionException, NoConnectionException { - Log.d(TAG, "queueSetRepeatMode"); - checkConnectivity(); - if (remoteMediaPlayer == null) { - Log.e(TAG, "Trying to update the queue with no active media session"); - throw new NoConnectionException(); - } - remoteMediaPlayer - .queueSetRepeatMode(mApiClient, repeatMode, customData).setResultCallback( - result -> { - if (!result.getStatus().isSuccess()) { - Log.d(TAG, "Failed with status: " + result.getStatus()); - } - for (CastConsumer consumer : castConsumers) { - consumer.onMediaQueueOperationResult(QUEUE_OPERATION_SET_REPEAT, - result.getStatus().getStatusCode()); - } - }); - } - - /** * Plays the loaded media. * * @param position Where to start the playback. Units is milliseconds. @@ -1294,29 +755,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { }); } - /** - * Toggles the playback of the media. - * - * @throws CastException - * @throws NoConnectionException - * @throws TransientNetworkDisconnectionException - */ - public void togglePlayback() throws CastException, TransientNetworkDisconnectionException, - NoConnectionException { - checkConnectivity(); - boolean isPlaying = isRemoteMediaPlaying(); - if (isPlaying) { - pause(); - } else { - if (state == MediaStatus.PLAYER_STATE_IDLE - && idleReason == MediaStatus.IDLE_REASON_FINISHED) { - loadMedia(getRemoteMediaInformation(), true, 0); - } else { - play(); - } - } - } - private void attachMediaChannel() throws TransientNetworkDisconnectionException, NoConnectionException { Log.d(TAG, "attachMediaChannel()"); @@ -1400,22 +838,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { } /** - * Returns the playback status of the remote device. - * - * @return Returns one of the values - * <ul> - * <li> <code>MediaStatus.PLAYER_STATE_UNKNOWN</code></li> - * <li> <code>MediaStatus.PLAYER_STATE_IDLE</code></li> - * <li> <code>MediaStatus.PLAYER_STATE_PLAYING</code></li> - * <li> <code>MediaStatus.PLAYER_STATE_PAUSED</code></li> - * <li> <code>MediaStatus.PLAYER_STATE_BUFFERING</code></li> - * </ul> - */ - public int getPlaybackStatus() { - return state; - } - - /** * Returns the latest retrieved value for the {@link MediaStatus}. This value is updated * whenever the onStatusUpdated callback is called. */ @@ -1423,24 +845,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { return mediaStatus; } - /** - * Returns the Idle reason, defined in <code>MediaStatus.IDLE_*</code>. Note that the returned - * value is only meaningful if the status is truly <code>MediaStatus.PLAYER_STATE_IDLE - * </code> - * - * <p>Possible values are: - * <ul> - * <li>IDLE_REASON_NONE</li> - * <li>IDLE_REASON_FINISHED</li> - * <li>IDLE_REASON_CANCELED</li> - * <li>IDLE_REASON_INTERRUPTED</li> - * <li>IDLE_REASON_ERROR</li> - * </ul> - */ - public int getIdleReason() { - return idleReason; - } - /* * This is called by onStatusUpdated() of the RemoteMediaPlayer */ @@ -1465,7 +869,7 @@ public class CastManager extends BaseCastManager implements OnFailedListener { onQueueUpdated(null, null, MediaStatus.REPEAT_MODE_REPEAT_OFF, false); } state = mediaStatus.getPlayerState(); - idleReason = mediaStatus.getIdleReason(); + int idleReason = mediaStatus.getIdleReason(); if (state == MediaStatus.PLAYER_STATE_PLAYING) { Log.d(TAG, "onRemoteMediaPlayerStatusUpdated(): Player status = playing"); @@ -1503,17 +907,12 @@ public class CastManager extends BaseCastManager implements OnFailedListener { if (mediaStatus != null) { item = mediaStatus.getQueueItemById(mediaStatus.getPreloadedItemId()); } - preLoadingItem = item; Log.d(TAG, "onRemoteMediaPreloadStatusUpdated() " + item); for (CastConsumer consumer : castConsumers) { consumer.onRemoteMediaPreloadStatusUpdated(item); } } - public MediaQueueItem getPreLoadingItem() { - return preLoadingItem; - } - /* * This is called by onQueueStatusUpdated() of RemoteMediaPlayer */ @@ -1522,13 +921,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { Log.d(TAG, "onQueueUpdated() reached"); Log.d(TAG, String.format(Locale.US, "Queue Items size: %d, Item: %s, Repeat Mode: %d, Shuffle: %s", queueItems == null ? 0 : queueItems.size(), item, repeatMode, shuffle)); - if (queueItems != null) { - mediaQueue = new MediaQueue(new CopyOnWriteArrayList<>(queueItems), item, shuffle, - repeatMode); - } else { - mediaQueue = new MediaQueue(new CopyOnWriteArrayList<>(), null, false, - MediaStatus.REPEAT_MODE_REPEAT_OFF); - } for (CastConsumer consumer : castConsumers) { consumer.onMediaQueueUpdated(queueItems, item, repeatMode, shuffle); } @@ -1599,7 +991,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { super.onDisconnected(stopAppOnExit, clearPersistedConnectionData, setDefaultRoute); state = MediaStatus.PLAYER_STATE_IDLE; mediaStatus = null; - mediaQueue = null; } class CastListener extends Cast.Listener { @@ -1635,77 +1026,6 @@ public class CastManager extends BaseCastManager implements OnFailedListener { } /** - * Clients can call this method to delegate handling of the volume. Clients should override - * {@code dispatchEvent} and call this method: - * <pre> - public boolean dispatchKeyEvent(KeyEvent event) { - if (mCastManager.onDispatchVolumeKeyEvent(event, VOLUME_DELTA)) { - return true; - } - return super.dispatchKeyEvent(event); - } - * </pre> - * @param event The dispatched event. - * @param volumeDelta The amount by which volume should be increased or decreased in each step - * @return <code>true</code> if volume is handled by the library, <code>false</code> otherwise. - */ - public boolean onDispatchVolumeKeyEvent(KeyEvent event, double volumeDelta) { - if (isConnected()) { - boolean isKeyDown = event.getAction() == KeyEvent.ACTION_DOWN; - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_VOLUME_UP: - return changeVolume(volumeDelta, isKeyDown); - case KeyEvent.KEYCODE_VOLUME_DOWN: - return changeVolume(-volumeDelta, isKeyDown); - } - } - return false; - } - - private boolean changeVolume(double volumeIncrement, boolean isKeyDown) { - if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) - && getPlaybackStatus() == MediaStatus.PLAYER_STATE_PLAYING - && isFeatureEnabled(CastConfiguration.FEATURE_LOCKSCREEN)) { - return false; - } - - if (isKeyDown) { - try { - adjustDeviceVolume(volumeIncrement); - } catch (CastException | TransientNetworkDisconnectionException | - NoConnectionException e) { - Log.e(TAG, "Failed to change volume", e); - } - } - return true; - } - - /** - * Sets the volume step, i.e. the fraction by which volume will increase or decrease each time - * user presses the hard volume buttons on the device. - * - * @param volumeStep Should be a double between 0 and 1, inclusive. - */ - public CastManager setVolumeStep(double volumeStep) { - if ((volumeStep > 1) || (volumeStep < 0)) { - throw new IllegalArgumentException("Volume Step should be between 0 and 1, inclusive"); - } - this.volumeStep = volumeStep; - return this; - } - - /** - * Returns the volume step. The default value is {@code DEFAULT_VOLUME_STEP}. - */ - public double getVolumeStep() { - return volumeStep; - } - - public final MediaQueue getMediaQueue() { - return mediaQueue; - } - - /** * Checks whether the selected Cast Device has the specified audio or video capabilities. * * @param capability capability from: diff --git a/core/src/play/java/de/danoeh/antennapod/core/cast/CastUtils.java b/core/src/play/java/de/danoeh/antennapod/core/cast/CastUtils.java index 86c85de6b..248f6dc46 100644 --- a/core/src/play/java/de/danoeh/antennapod/core/cast/CastUtils.java +++ b/core/src/play/java/de/danoeh/antennapod/core/cast/CastUtils.java @@ -35,7 +35,6 @@ public class CastUtils { public static final String KEY_FEED_URL = "de.danoeh.antennapod.core.cast.FeedUrl"; public static final String KEY_FEED_WEBSITE = "de.danoeh.antennapod.core.cast.FeedWebsite"; public static final String KEY_EPISODE_NOTES = "de.danoeh.antennapod.core.cast.EpisodeNotes"; - public static final int EPISODE_NOTES_MAX_LENGTH = Integer.MAX_VALUE; /** * The field <code>AntennaPod.FormatVersion</code> specifies which version of MediaMetaData diff --git a/core/src/play/java/de/danoeh/antennapod/core/cast/MediaInfoCreator.java b/core/src/play/java/de/danoeh/antennapod/core/cast/MediaInfoCreator.java index 91de5418d..a9df49176 100644 --- a/core/src/play/java/de/danoeh/antennapod/core/cast/MediaInfoCreator.java +++ b/core/src/play/java/de/danoeh/antennapod/core/cast/MediaInfoCreator.java @@ -39,9 +39,6 @@ public class MediaInfoCreator { } String notes = media.getNotes(); if (notes != null) { - if (notes.length() > CastUtils.EPISODE_NOTES_MAX_LENGTH) { - notes = notes.substring(0, CastUtils.EPISODE_NOTES_MAX_LENGTH); - } metadata.putString(CastUtils.KEY_EPISODE_NOTES, notes); } // Default id value |