diff options
author | ByteHamster <info@bytehamster.com> | 2020-08-15 19:56:21 +0200 |
---|---|---|
committer | ByteHamster <info@bytehamster.com> | 2020-08-15 19:56:34 +0200 |
commit | b25e0933ab606ac45ef9c26a745f25845d3af3fc (patch) | |
tree | 0344f78cbc1bbf1148ea07c63bdd1212a412a2e7 /core/src/main/java/de/danoeh/antennapod | |
parent | 3c5e1138ca1c616dd7add9d567442cc0d9a510ac (diff) | |
parent | d8674e8050fd98961f7eaa9fa844eb03d8bbfb48 (diff) | |
download | AntennaPod-b25e0933ab606ac45ef9c26a745f25845d3af3fc.zip |
Merge branch 'develop' into add-local-feeds
Diffstat (limited to 'core/src/main/java/de/danoeh/antennapod')
50 files changed, 561 insertions, 388 deletions
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java index 24a71ec96..efd53ab9d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadEvent.java @@ -1,5 +1,7 @@ package de.danoeh.antennapod.core.event; +import androidx.annotation.NonNull; + import java.util.ArrayList; import java.util.List; @@ -19,6 +21,7 @@ public class DownloadEvent { return new DownloadEvent(update); } + @NonNull @Override public String toString() { return "DownloadEvent{" + diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadLogEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadLogEvent.java index 7428c5b00..5ab5decf9 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/event/DownloadLogEvent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloadLogEvent.java @@ -1,5 +1,7 @@ package de.danoeh.antennapod.core.event; +import androidx.annotation.NonNull; + public class DownloadLogEvent { private DownloadLogEvent() { @@ -9,6 +11,7 @@ public class DownloadLogEvent { return new DownloadLogEvent(); } + @NonNull @Override public String toString() { return "DownloadLogEvent"; diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java index f549940b7..10992408d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java +++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java @@ -46,6 +46,7 @@ public class DownloaderUpdate { this.mediaIds = mediaIds1.toArray(); } + @NonNull @Override public String toString() { return "DownloaderUpdate{" + diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java index 578007561..d3be8fac0 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/event/FavoritesEvent.java @@ -1,5 +1,7 @@ package de.danoeh.antennapod.core.event; +import androidx.annotation.NonNull; + import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -27,6 +29,7 @@ public class FavoritesEvent { return new FavoritesEvent(Action.REMOVED, item); } + @NonNull @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java index 4b14a72d2..02559b2f5 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java @@ -21,7 +21,7 @@ public class FeedItemEvent { private final Action action; @NonNull public final List<FeedItem> items; - private FeedItemEvent(Action action, List<FeedItem> items) { + private FeedItemEvent(@NonNull Action action, @NonNull List<FeedItem> items) { this.action = action; this.items = items; } @@ -42,6 +42,7 @@ public class FeedItemEvent { return updated(Arrays.asList(items)); } + @NonNull @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java b/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java new file mode 100644 index 000000000..60c38a391 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/export/favorites/FavoritesWriter.java @@ -0,0 +1,132 @@ +package de.danoeh.antennapod.core.export.favorites; + +import android.content.Context; +import android.util.Log; + +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import de.danoeh.antennapod.core.export.ExportWriter; +import de.danoeh.antennapod.core.feed.Feed; +import de.danoeh.antennapod.core.feed.FeedItem; +import de.danoeh.antennapod.core.storage.DBReader; + +/** Writes saved favorites to file. */ +public class FavoritesWriter implements ExportWriter { + private static final String TAG = "FavoritesWriter"; + + private static final int PAGE_LIMIT = 100; + + private static final String FAVORITE_TEMPLATE = "html-export-favorites-item-template.html"; + private static final String FEED_TEMPLATE = "html-export-feed-template.html"; + private static final String UTF_8 = "UTF-8"; + + @Override + public void writeDocument(List<Feed> feeds, Writer writer, Context context) + throws IllegalArgumentException, IllegalStateException, IOException { + Log.d(TAG, "Starting to write document"); + + InputStream templateStream = context.getAssets().open("html-export-template.html"); + String template = IOUtils.toString(templateStream, UTF_8); + template = template.replaceAll("\\{TITLE\\}", "Favorites"); + String[] templateParts = template.split("\\{FEEDS\\}"); + + InputStream favTemplateStream = context.getAssets().open(FAVORITE_TEMPLATE); + String favTemplate = IOUtils.toString(favTemplateStream, UTF_8); + + InputStream feedTemplateStream = context.getAssets().open(FEED_TEMPLATE); + String feedTemplate = IOUtils.toString(feedTemplateStream, UTF_8); + + Map<Long, List<FeedItem>> favoriteByFeed = getFeedMap(getFavorites()); + + writer.append(templateParts[0]); + + for (Long feedId : favoriteByFeed.keySet()) { + List<FeedItem> favorites = favoriteByFeed.get(feedId); + writer.append("<li><div>\n"); + writeFeed(writer, favorites.get(0).getFeed(), feedTemplate); + + writer.append("<ul>\n"); + for (FeedItem item : favorites) { + writeFavoriteItem(writer, item, favTemplate); + } + writer.append("</ul></div></li>\n"); + } + + writer.append(templateParts[1]); + + Log.d(TAG, "Finished writing document"); + } + + private List<FeedItem> getFavorites() { + int page = 0; + + List<FeedItem> favoritesList = new ArrayList<>(); + List<FeedItem> favoritesPage; + do { + favoritesPage = DBReader.getFavoriteItemsList(page * PAGE_LIMIT, PAGE_LIMIT); + favoritesList.addAll(favoritesPage); + ++page; + } while (!favoritesPage.isEmpty() && favoritesPage.size() == PAGE_LIMIT); + + // sort in descending order + Collections.sort(favoritesList, (lhs, rhs) -> rhs.getPubDate().compareTo(lhs.getPubDate())); + + return favoritesList; + } + + /** + * Group favorite episodes by feed, sorting them by publishing date in descending order. + * + * @param favoritesList {@code List} of all favorite episodes. + * @return A {@code Map} favorite episodes, keyed by feed ID. + */ + private Map<Long, List<FeedItem>> getFeedMap(List<FeedItem> favoritesList) { + Map<Long, List<FeedItem>> feedMap = new TreeMap<>(); + + for (FeedItem item : favoritesList) { + List<FeedItem> feedEpisodes = feedMap.get(item.getFeedId()); + + if (feedEpisodes == null) { + feedEpisodes = new ArrayList<>(); + feedMap.put(item.getFeedId(), feedEpisodes); + } + + feedEpisodes.add(item); + } + + return feedMap; + } + + private void writeFeed(Writer writer, Feed feed, String feedTemplate) throws IOException { + String feedInfo = feedTemplate + .replace("{FEED_IMG}", feed.getImageUrl()) + .replace("{FEED_TITLE}", feed.getTitle()) + .replace("{FEED_LINK}", feed.getLink()) + .replace("{FEED_WEBSITE}", feed.getDownload_url()); + + writer.append(feedInfo); + } + + private void writeFavoriteItem(Writer writer, FeedItem item, String favoriteTemplate) throws IOException { + String favItem = favoriteTemplate + .replace("{FAV_TITLE}", item.getTitle().trim()) + .replace("{FAV_WEBSITE}", item.getLink()) + .replace("{FAV_MEDIA}", item.getMedia().getDownload_url()); + + writer.append(favItem); + } + + @Override + public String fileExtension() { + return "html"; + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java b/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java index 93b66daed..3f34343ee 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/export/html/HtmlWriter.java @@ -25,6 +25,7 @@ public class HtmlWriter implements ExportWriter { InputStream templateStream = context.getAssets().open("html-export-template.html"); String template = IOUtils.toString(templateStream, "UTF-8"); + template = template.replaceAll("\\{TITLE\\}", "Subscriptions"); String[] templateParts = template.split("\\{FEEDS\\}"); writer.append(templateParts[0]); diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java index 2610d253f..3edecd35c 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedComponent.java @@ -50,7 +50,7 @@ public abstract class FeedComponent { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || !(o instanceof FeedComponent)) return false; + if (!(o instanceof FeedComponent)) return false; FeedComponent that = (FeedComponent) o; diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedEvent.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedEvent.java index 15cdf92dc..044554451 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedEvent.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedEvent.java @@ -1,5 +1,7 @@ package de.danoeh.antennapod.core.feed; +import androidx.annotation.NonNull; + import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -18,6 +20,7 @@ public class FeedEvent { this.feedId = feedId; } + @NonNull @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) 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 892592a4b..131cbe563 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 @@ -1,12 +1,15 @@ package de.danoeh.antennapod.core.feed; import android.database.Cursor; + +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.text.TextUtils; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; +import java.io.Serializable; import java.util.Date; import java.util.HashSet; import java.util.List; @@ -24,7 +27,7 @@ import de.danoeh.antennapod.core.util.ShownotesProvider; * * @author daniel */ -public class FeedItem extends FeedComponent implements ShownotesProvider, ImageResource { +public class FeedItem extends FeedComponent implements ShownotesProvider, ImageResource, Serializable { /** tag that indicates this item is in the queue */ public static final String TAG_QUEUE = "Queue"; @@ -481,6 +484,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, ImageR */ public void removeTag(String tag) { tags.remove(tag); } + @NonNull @Override public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java index 719383d23..d34e23506 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilter.java @@ -1,8 +1,10 @@ package de.danoeh.antennapod.core.feed; import android.text.TextUtils; +import android.util.Log; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import de.danoeh.antennapod.core.storage.DBReader; @@ -11,17 +13,21 @@ import de.danoeh.antennapod.core.util.LongList; import static de.danoeh.antennapod.core.feed.FeedItem.TAG_FAVORITE; public class FeedItemFilter { + private final String[] mProperties; private boolean showPlayed = false; private boolean showUnplayed = false; private boolean showPaused = false; + private boolean showNotPaused = false; private boolean showQueued = false; private boolean showNotQueued = false; private boolean showDownloaded = false; private boolean showNotDownloaded = false; private boolean showHasMedia = false; + private boolean showNoMedia = false; private boolean showIsFavorite = false; + private boolean showNotFavorite = false; public FeedItemFilter(String properties) { this(TextUtils.split(properties, ",")); @@ -29,15 +35,18 @@ public class FeedItemFilter { public FeedItemFilter(String[] properties) { this.mProperties = properties; - for(String property : properties) { + for (String property : properties) { // see R.arrays.feed_filter_values - switch(property) { + switch (property) { case "unplayed": showUnplayed = true; break; case "paused": showPaused = true; break; + case "not_paused": + showNotPaused = true; + break; case "played": showPlayed = true; break; @@ -56,9 +65,17 @@ public class FeedItemFilter { case "has_media": showHasMedia = true; break; + case "no_media": + showNoMedia = true; + break; case "is_favorite": showIsFavorite = true; break; + case "not_favorite": + showNotFavorite = true; + break; + default: + break; } } } @@ -77,12 +94,15 @@ public class FeedItemFilter { if (showQueued && showNotQueued) return result; if (showDownloaded && showNotDownloaded) return result; - final LongList queuedIds = DBReader.getQueueIDList(); - for(FeedItem item : items) { + final LongList queuedIds = DBReader.getQueueIDList(); + for (FeedItem item : items) { // If the item does not meet a requirement, skip it. + if (showPlayed && !item.isPlayed()) continue; if (showUnplayed && item.isPlayed()) continue; + if (showPaused && item.getState() != FeedItem.State.IN_PROGRESS) continue; + if (showNotPaused && item.getState() == FeedItem.State.IN_PROGRESS) continue; boolean queued = queuedIds.contains(item.getId()); if (showQueued && !queued) continue; @@ -93,8 +113,10 @@ public class FeedItemFilter { if (showNotDownloaded && downloaded) continue; if (showHasMedia && !item.hasMedia()) continue; + if (showNoMedia && item.hasMedia()) continue; if (showIsFavorite && !item.isTagged(TAG_FAVORITE)) continue; + if (showNotFavorite && item.isTagged(TAG_FAVORITE)) continue; // If the item reaches here, it meets all criteria result.add(item); diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilterGroup.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilterGroup.java new file mode 100644 index 000000000..fcbe2e4ab --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItemFilterGroup.java @@ -0,0 +1,36 @@ +package de.danoeh.antennapod.core.feed; + +import de.danoeh.antennapod.core.R; + +public enum FeedItemFilterGroup { + PLAYED(new ItemProperties(R.string.hide_played_episodes_label, "played"), + new ItemProperties(R.string.not_played, "unplayed")), + PAUSED(new ItemProperties(R.string.hide_paused_episodes_label, "paused"), + new ItemProperties(R.string.not_paused, "not_paused")), + FAVORITE(new ItemProperties(R.string.hide_is_favorite_label, "is_favorite"), + new ItemProperties(R.string.not_favorite, "not_favorite")), + MEDIA(new ItemProperties(R.string.has_media, "has_media"), + new ItemProperties(R.string.no_media, "no_media")), + QUEUED(new ItemProperties(R.string.queued_label, "queued"), + new ItemProperties(R.string.not_queued_label, "not_queued")), + DOWNLOADED(new ItemProperties(R.string.hide_downloaded_episodes_label, "downloaded"), + new ItemProperties(R.string.hide_not_downloaded_episodes_label, "not_downloaded")); + + public final ItemProperties[] values; + + FeedItemFilterGroup(ItemProperties... values) { + this.values = values; + } + + public static class ItemProperties { + + public final int displayName; + public final String filterId; + + public ItemProperties(int displayName, String filterId) { + this.displayName = displayName; + this.filterId = filterId; + } + + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java index 083e8c500..92e45376a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java @@ -482,7 +482,7 @@ public class FeedMedia extends FeedFile implements Playable { @Override public void onPlaybackStart() { - startPosition = (position > 0) ? position : 0; + startPosition = Math.max(position, 0); playedDurationWhenStarted = played_duration; } 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 36da11eca..35a9d987b 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 @@ -28,8 +28,9 @@ import org.apache.commons.io.IOUtils; public final class ChapterImageModelLoader implements ModelLoader<EmbeddedChapterImage, ByteBuffer> { public static class Factory implements ModelLoaderFactory<EmbeddedChapterImage, ByteBuffer> { + @NonNull @Override - public ModelLoader<EmbeddedChapterImage, ByteBuffer> build(MultiModelLoaderFactory unused) { + public ModelLoader<EmbeddedChapterImage, ByteBuffer> build(@NonNull MultiModelLoaderFactory unused) { return new ChapterImageModelLoader(); } @@ -41,12 +42,15 @@ public final class ChapterImageModelLoader implements ModelLoader<EmbeddedChapte @Nullable @Override - public LoadData<ByteBuffer> buildLoadData(EmbeddedChapterImage model, int width, int height, Options options) { + public LoadData<ByteBuffer> buildLoadData(@NonNull EmbeddedChapterImage model, + int width, + int height, + @NonNull Options options) { return new LoadData<>(new ObjectKey(model), new EmbeddedImageFetcher(model)); } @Override - public boolean handles(EmbeddedChapterImage model) { + public boolean handles(@NonNull EmbeddedChapterImage model) { return true; } 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 d0301db2f..1f8ae5ad9 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 @@ -21,7 +21,10 @@ public class FastBlurTransformation extends BitmapTransformation { } @Override - protected Bitmap transform(BitmapPool pool, Bitmap source, int outWidth, int outHeight) { + protected Bitmap transform(@NonNull BitmapPool pool, + @NonNull Bitmap source, + int outWidth, + int outHeight) { int targetWidth = outWidth / 3; int targetHeight = (int) (1.0 * outHeight * targetWidth / outWidth); Bitmap resized = ThumbnailUtils.extractThumbnail(source, targetWidth, targetHeight); diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java index 876251563..3488d125e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java +++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java @@ -19,10 +19,14 @@ import org.json.JSONException; import java.io.File; import java.io.IOException; import java.net.Proxy; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -64,6 +68,7 @@ public class UserPreferences { private static final String PREF_SHOW_AUTO_DOWNLOAD_REPORT = "prefShowAutoDownloadReport"; public static final String PREF_BACK_BUTTON_BEHAVIOR = "prefBackButtonBehavior"; private static final String PREF_BACK_BUTTON_GO_TO_PAGE = "prefBackButtonGoToPage"; + public static final String PREF_FILTER_FEED = "prefFeedFilter"; public static final String PREF_QUEUE_KEEP_SORTED = "prefQueueKeepSorted"; public static final String PREF_QUEUE_KEEP_SORTED_ORDER = "prefQueueKeepSortedOrder"; @@ -146,6 +151,8 @@ public class UserPreferences { public static final int FEED_COUNTER_SHOW_UNPLAYED = 2; public static final int FEED_COUNTER_SHOW_NONE = 3; public static final int FEED_COUNTER_SHOW_DOWNLOADED = 4; + public static final int FEED_FILTER_NONE = 0; + public static final int FEED_FILTER_COUNTER_ZERO = 1; private static Context context; private static SharedPreferences prefs; @@ -414,7 +421,7 @@ public class UserPreferences { return prefs.getBoolean(PREF_PLAYBACK_SKIP_SILENCE, false); } - public static float[] getPlaybackSpeedArray() { + public static List<Float> getPlaybackSpeedArray() { return readPlaybackSpeedArray(prefs.getString(PREF_PLAYBACK_SPEED_ARRAY, null)); } @@ -628,8 +635,7 @@ public class UserPreferences { } public static boolean isQueueLocked() { - return prefs.getBoolean(PREF_QUEUE_LOCKED, false) - || isQueueKeepSorted(); + return prefs.getBoolean(PREF_QUEUE_LOCKED, false); } public static void setFastForwardSecs(int secs) { @@ -662,10 +668,13 @@ public class UserPreferences { .apply(); } - public static void setPlaybackSpeedArray(String[] speeds) { + public static void setPlaybackSpeedArray(List<Float> speeds) { + DecimalFormatSymbols format = new DecimalFormatSymbols(Locale.US); + format.setDecimalSeparator('.'); + DecimalFormat speedFormat = new DecimalFormat("0.00", format); JSONArray jsonArray = new JSONArray(); - for (String speed : speeds) { - jsonArray.put(speed); + for (float speed : speeds) { + jsonArray.put(speedFormat.format(speed)); } prefs.edit() .putString(PREF_PLAYBACK_SPEED_ARRAY, jsonArray.toString()) @@ -775,13 +784,13 @@ public class UserPreferences { } } - private static float[] readPlaybackSpeedArray(String valueFromPrefs) { + private static List<Float> readPlaybackSpeedArray(String valueFromPrefs) { if (valueFromPrefs != null) { try { JSONArray jsonArray = new JSONArray(valueFromPrefs); - float[] selectedSpeeds = new float[jsonArray.length()]; + List<Float> selectedSpeeds = new ArrayList<>(); for (int i = 0; i < jsonArray.length(); i++) { - selectedSpeeds[i] = (float) jsonArray.getDouble(i); + selectedSpeeds.add((float) jsonArray.getDouble(i)); } return selectedSpeeds; } catch (JSONException e) { @@ -790,7 +799,7 @@ public class UserPreferences { } } // If this preference hasn't been set yet, return the default options - return new float[] { 0.75f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f }; + return Arrays.asList(0.75f, 1.0f, 1.25f, 1.5f, 1.75f, 2.0f); } public static String getMediaPlayer() { @@ -826,8 +835,8 @@ public class UserPreferences { public static VideoBackgroundBehavior getVideoBackgroundBehavior() { switch (prefs.getString(PREF_VIDEO_BEHAVIOR, "pip")) { case "stop": return VideoBackgroundBehavior.STOP; - case "pip": return VideoBackgroundBehavior.PICTURE_IN_PICTURE; case "continue": return VideoBackgroundBehavior.CONTINUE_PLAYING; + case "pip": //Deliberate fall-through default: return VideoBackgroundBehavior.PICTURE_IN_PICTURE; } } @@ -977,11 +986,11 @@ public class UserPreferences { public static BackButtonBehavior getBackButtonBehavior() { switch (prefs.getString(PREF_BACK_BUTTON_BEHAVIOR, "default")) { - case "default": return BackButtonBehavior.DEFAULT; case "drawer": return BackButtonBehavior.OPEN_DRAWER; case "doubletap": return BackButtonBehavior.DOUBLE_TAP; case "prompt": return BackButtonBehavior.SHOW_PROMPT; case "page": return BackButtonBehavior.GO_TO_PAGE; + case "default": // Deliberate fall-through default: return BackButtonBehavior.DEFAULT; } } @@ -1052,4 +1061,16 @@ public class UserPreferences { .putString(PREF_QUEUE_KEEP_SORTED_ORDER, sortOrder.name()) .apply(); } + + public static int getFeedFilter() { + String value = prefs.getString(PREF_FILTER_FEED, "" + FEED_FILTER_NONE); + return Integer.parseInt(value); + } + + public static void setFeedFilter(String value) { + prefs.edit() + .putString(PREF_FILTER_FEED, value) + .commit(); + } + } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java index 4562f1393..7585e9d33 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java @@ -103,12 +103,8 @@ public class PlayerWidgetJobService extends SafeJobIntentService { AppWidgetManager manager = AppWidgetManager.getInstance(this); int[] widgetIds = manager.getAppWidgetIds(playerWidget); RemoteViews views = new RemoteViews(getPackageName(), R.layout.player_widget); - PendingIntent startMediaplayer = PendingIntent.getActivity(this, 0, - PlaybackService.getPlayerActivityIntent(this), 0); - - final PendingIntent startAppPending = PendingIntent.getActivity(this, 0, - PlaybackService.getPlayerActivityIntent(this), - PendingIntent.FLAG_UPDATE_CURRENT); + final PendingIntent startMediaPlayer = PendingIntent.getActivity(this, R.id.pending_intent_player_activity, + PlaybackService.getPlayerActivityIntent(this), PendingIntent.FLAG_UPDATE_CURRENT); boolean nothingPlaying = false; Playable media; @@ -122,10 +118,10 @@ public class PlayerWidgetJobService extends SafeJobIntentService { } if (media != null) { - views.setOnClickPendingIntent(R.id.layout_left, startMediaplayer); + views.setOnClickPendingIntent(R.id.layout_left, startMediaPlayer); try { - Bitmap icon = null; + Bitmap icon; int iconSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size); icon = Glide.with(PlayerWidgetJobService.this) .asBitmap() @@ -170,8 +166,8 @@ public class PlayerWidgetJobService extends SafeJobIntentService { if (nothingPlaying) { // start the app if they click anything - views.setOnClickPendingIntent(R.id.layout_left, startAppPending); - views.setOnClickPendingIntent(R.id.butPlay, startAppPending); + views.setOnClickPendingIntent(R.id.layout_left, startMediaPlayer); + views.setOnClickPendingIntent(R.id.butPlay, startMediaPlayer); views.setViewVisibility(R.id.txtvProgress, View.GONE); views.setViewVisibility(R.id.txtvTitle, View.GONE); views.setViewVisibility(R.id.txtNoPlaying, View.VISIBLE); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/ProviderInstallerInterceptor.java b/core/src/main/java/de/danoeh/antennapod/core/service/ProviderInstallerInterceptor.java new file mode 100644 index 000000000..4fa1fc3d7 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/service/ProviderInstallerInterceptor.java @@ -0,0 +1,18 @@ +package de.danoeh.antennapod.core.service; + +import androidx.annotation.NonNull; +import okhttp3.Interceptor; +import okhttp3.Response; + +import java.io.IOException; + +public class ProviderInstallerInterceptor implements Interceptor { + public static Runnable installer = () -> { }; + + @Override + @NonNull + public Response intercept(Chain chain) throws IOException { + installer.run(); + return chain.proceed(chain.request()); + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/UserAgentInterceptor.java b/core/src/main/java/de/danoeh/antennapod/core/service/UserAgentInterceptor.java index 5fcf8317d..3676347f7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/UserAgentInterceptor.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/UserAgentInterceptor.java @@ -7,10 +7,6 @@ import okhttp3.Response; import java.io.IOException; public class UserAgentInterceptor implements Interceptor { - - public UserAgentInterceptor() { - } - @Override public Response intercept(Chain chain) throws IOException { return chain.proceed(chain.request().newBuilder() 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 e0c23bdac..9d0b3c5ad 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 @@ -32,6 +32,7 @@ import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.service.ProviderInstallerInterceptor; import de.danoeh.antennapod.core.service.UserAgentInterceptor; import de.danoeh.antennapod.core.storage.DBWriter; import okhttp3.Cache; @@ -116,6 +117,7 @@ public class AntennapodHttpClient { } return response; }); + builder.interceptors().add(new ProviderInstallerInterceptor()); builder.interceptors().add(new BasicAuthorizationInterceptor()); builder.networkInterceptors().add(new UserAgentInterceptor()); @@ -154,8 +156,8 @@ public class AntennapodHttpClient { // workaround for Android 4.x for certain web sites. // see: https://github.com/square/okhttp/issues/4053#issuecomment-402579554 - List<CipherSuite> cipherSuites = new ArrayList<>(); - cipherSuites.addAll(ConnectionSpec.MODERN_TLS.cipherSuites()); + List<CipherSuite> cipherSuites = new ArrayList<>( + ConnectionSpec.MODERN_TLS.cipherSuites()); cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA); cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java index 78c4d3f48..3f503c6b4 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java @@ -115,7 +115,7 @@ public class DownloadRequest implements Parcelable { @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || !(o instanceof DownloadRequest)) return false; + if (!(o instanceof DownloadRequest)) return false; DownloadRequest that = (DownloadRequest) o; diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java index 28523ef0a..e44aa716a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java @@ -17,6 +17,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.sync.SyncService; import org.apache.commons.io.FileUtils; import org.greenrobot.eventbus.EventBus; @@ -87,8 +88,6 @@ public class DownloadService extends Service { public static final String EXTRA_CLEANUP_MEDIA = "cleanupMedia"; - public static final int NOTIFICATION_ID = 2; - /** * Contains all completed downloads that have not been included in the report yet. */ @@ -165,7 +164,7 @@ public class DownloadService extends Service { if (intent != null && intent.getParcelableArrayListExtra(EXTRA_REQUESTS) != null) { Notification notification = notificationManager.updateNotifications( requester.getNumberOfDownloads(), downloads); - startForeground(NOTIFICATION_ID, notification); + startForeground(R.id.notification_downloading, notification); syncExecutor.execute(() -> onDownloadQueued(intent)); } else if (numberOfDownloads.get() == 0) { stopSelf(); @@ -191,7 +190,7 @@ public class DownloadService extends Service { Notification notification = notificationManager.updateNotifications( requester.getNumberOfDownloads(), downloads); - startForeground(NOTIFICATION_ID, notification); + startForeground(R.id.notification_downloading, notification); } @Override @@ -229,7 +228,7 @@ public class DownloadService extends Service { stopForeground(true); NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - nm.cancel(NOTIFICATION_ID); + nm.cancel(R.id.notification_downloading); // if this was the initial gpodder sync, i.e. we just synced the feeds successfully, // it is now time to sync the episode actions @@ -480,12 +479,9 @@ public class DownloadService extends Service { } handler.post(() -> { downloads.add(downloader); + downloadExecutor.submit(downloader); postDownloaders(); }); - // Needs to be done after postDownloaders() because otherwise, - // it might take long before the progress bar circle starts spinning - ClientConfig.installSslProvider(this); - handler.post(() -> downloadExecutor.submit(downloader)); } handler.post(this::queryDownloads); } @@ -566,7 +562,7 @@ public class DownloadService extends Service { setupNotificationUpdater(); Notification notification = notificationManager.updateNotifications( requester.getNumberOfDownloads(), downloads); - startForeground(NOTIFICATION_ID, notification); + startForeground(R.id.notification_downloading, notification); } } @@ -642,7 +638,7 @@ public class DownloadService extends Service { Notification n = notificationManager.updateNotifications(requester.getNumberOfDownloads(), downloads); if (n != null) { NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - nm.notify(NOTIFICATION_ID, n); + nm.notify(R.id.notification_downloading, n); } } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java index f487193f3..64666d25d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceNotification.java @@ -17,8 +17,6 @@ import java.util.List; public class DownloadServiceNotification { private static final String TAG = "DownloadSvcNotification"; - private static final int REPORT_ID = 3; - private static final int AUTO_REPORT_ID = 4; private final Context context; private NotificationCompat.Builder notificationCompatBuilder; @@ -147,14 +145,14 @@ public class DownloadServiceNotification { titleId = R.string.auto_download_report_title; iconId = R.drawable.ic_notification_auto_download_complete; intent = ClientConfig.downloadServiceCallbacks.getAutoDownloadReportNotificationContentIntent(context); - id = AUTO_REPORT_ID; + id = R.id.notification_auto_download_report; content = createAutoDownloadNotificationContent(reportQueue); } else { channelId = NotificationUtils.CHANNEL_ID_ERROR; titleId = R.string.download_report_title; iconId = R.drawable.ic_notification_sync_error; intent = ClientConfig.downloadServiceCallbacks.getReportNotificationContentIntent(context); - id = REPORT_ID; + id = R.id.notification_download_report; content = String.format(context.getString(R.string.download_report_content), successfulDownloads, failedDownloads); } 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 54b8d321a..61608992b 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 @@ -65,11 +65,12 @@ public class HttpDownloader extends Downloader { final URI uri = URIUtil.getURIFromRequestUrl(request.getSource()); Request.Builder httpReq = new Request.Builder().url(uri.toURL()); httpReq.tag(request); + httpReq.cacheControl(new CacheControl.Builder().noStore().build()); + if (request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) { // set header explicitly so that okhttp doesn't do transparent gzip Log.d(TAG, "addHeader(\"Accept-Encoding\", \"identity\")"); httpReq.addHeader("Accept-Encoding", "identity"); - httpReq.cacheControl(new CacheControl.Builder().noStore().build()); } if (!TextUtils.isEmpty(request.getLastModified())) { @@ -189,7 +190,7 @@ public class HttpDownloader extends Downloader { } byte[] buffer = new byte[BUFFER_SIZE]; - int count = 0; + int count; request.setStatusMsg(R.string.download_running); Log.d(TAG, "Getting size of download"); request.setSize(responseBody.contentLength() + request.getSoFar()); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java index 05e602db8..c50162788 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedParserTask.java @@ -49,10 +49,7 @@ public class FeedParserTask implements Callable<FeedHandlerResult> { try { result = feedHandler.parseFeed(feed); Log.d(TAG, feed.getTitle() + " parsed"); - if (!checkFeedData(feed)) { - throw new InvalidFeedException(); - } - + checkFeedData(feed); } catch (SAXException | IOException | ParserConfigurationException e) { successful = false; e.printStackTrace(); @@ -95,23 +92,17 @@ public class FeedParserTask implements Callable<FeedHandlerResult> { /** * Checks if the feed was parsed correctly. */ - private boolean checkFeedData(Feed feed) { + private void checkFeedData(Feed feed) throws InvalidFeedException { if (feed.getTitle() == null) { - Log.e(TAG, "Feed has no title."); - return false; - } - if (!hasValidFeedItems(feed)) { - Log.e(TAG, "Feed has invalid items"); - return false; + throw new InvalidFeedException("Feed has no title"); } - return true; + checkFeedItems(feed); } - private boolean hasValidFeedItems(Feed feed) { + private void checkFeedItems(Feed feed) throws InvalidFeedException { for (FeedItem item : feed.getItems()) { if (item.getTitle() == null) { - Log.e(TAG, "Item has no title"); - return false; + throw new InvalidFeedException("Item has no title: " + item); } if (item.getPubDate() == null) { Log.e(TAG, "Item has no pubDate. Using current time as pubDate"); @@ -121,7 +112,6 @@ public class FeedParserTask implements Callable<FeedHandlerResult> { item.setPubDate(new Date()); } } - return true; } public DownloadStatus getDownloadStatus() { diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index 33a2a72ff..111e2d37c 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -79,6 +79,7 @@ import de.danoeh.antennapod.core.util.playback.ExternalMedia; import de.danoeh.antennapod.core.util.playback.Playable; import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter; import io.reactivex.Observable; +import io.reactivex.Single; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import org.greenrobot.eventbus.EventBus; @@ -204,9 +205,6 @@ public class PlaybackService extends MediaBrowserServiceCompat { */ private static volatile boolean isCasting = false; - private static final int NOTIFICATION_ID = 1; - private static final int NOTIFICATION_ID_STREAMING = 2; - private PlaybackServiceMediaPlayer mediaPlayer; private PlaybackServiceTaskManager taskManager; private PlaybackServiceFlavorHelper flavorHelper; @@ -271,7 +269,6 @@ public class PlaybackService extends MediaBrowserServiceCompat { stateManager = new PlaybackServiceStateManager(this); notificationBuilder = new PlaybackServiceNotificationBuilder(this); - stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build()); registerReceiver(autoStateUpdated, new IntentFilter("com.google.android.gms.car.media.STATUS")); registerReceiver(headsetDisconnected, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); @@ -307,18 +304,16 @@ public class PlaybackService extends MediaBrowserServiceCompat { npe.printStackTrace(); } - List<MediaSessionCompat.QueueItem> queueItems = new ArrayList<>(); - try { + Single.<List<MediaSessionCompat.QueueItem>>create(emitter -> { + List<MediaSessionCompat.QueueItem> queueItems = new ArrayList<>(); for (FeedItem feedItem : taskManager.getQueue()) { if (feedItem.getMedia() != null) { MediaDescriptionCompat mediaDescription = feedItem.getMedia().getMediaItem().getDescription(); queueItems.add(new MediaSessionCompat.QueueItem(mediaDescription, feedItem.getId())); } } - mediaSession.setQueue(queueItems); - } catch (InterruptedException e) { - e.printStackTrace(); - } + emitter.onSuccess(queueItems); + }).subscribe(queueItems -> mediaSession.setQueue(queueItems), Throwable::printStackTrace); flavorHelper.initializeMediaPlayer(PlaybackService.this); mediaSession.setActive(true); @@ -334,7 +329,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { if (notificationBuilder.getPlayerStatus() == PlayerStatus.PLAYING) { notificationBuilder.setPlayerStatus(PlayerStatus.STOPPED); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); - notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); + notificationManager.notify(R.id.notification_playing, notificationBuilder.build()); } stateManager.stopForeground(!UserPreferences.isPersistNotify()); isRunning = false; @@ -424,7 +419,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { e.printStackTrace(); } } else if (parentId.startsWith("FeedId:")) { - Long feedId = Long.parseLong(parentId.split(":")[1]); + long feedId = Long.parseLong(parentId.split(":")[1]); List<FeedItem> feedItems = DBReader.getFeedItemList(DBReader.getFeed(feedId)); for (FeedItem feedItem : feedItems) { if (feedItem.getMedia() != null && feedItem.getMedia().getMediaItem() != null) { @@ -450,9 +445,9 @@ public class PlaybackService extends MediaBrowserServiceCompat { super.onStartCommand(intent, flags, startId); Log.d(TAG, "OnStartCommand called"); - stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build()); + stateManager.startForeground(R.id.notification_playing, notificationBuilder.build()); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); - notificationManager.cancel(NOTIFICATION_ID_STREAMING); + notificationManager.cancel(R.id.notification_streaming_confirmation); final int keycode = intent.getIntExtra(MediaButtonReceiver.EXTRA_KEYCODE, -1); final boolean castDisconnect = intent.getBooleanExtra(EXTRA_CAST_DISCONNECT, false); @@ -542,9 +537,11 @@ public class PlaybackService extends MediaBrowserServiceCompat { intentAllowThisTime.putExtra(EXTRA_ALLOW_STREAM_THIS_TIME, true); PendingIntent pendingIntentAllowThisTime; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - pendingIntentAllowThisTime = PendingIntent.getForegroundService(this, 0, intentAllowThisTime, PendingIntent.FLAG_UPDATE_CURRENT); + pendingIntentAllowThisTime = PendingIntent.getForegroundService(this, + R.id.pending_intent_allow_stream_this_time, intentAllowThisTime, PendingIntent.FLAG_UPDATE_CURRENT); } else { - pendingIntentAllowThisTime = PendingIntent.getService(this, 0, intentAllowThisTime, PendingIntent.FLAG_UPDATE_CURRENT); + pendingIntentAllowThisTime = PendingIntent.getService(this, + R.id.pending_intent_allow_stream_this_time, intentAllowThisTime, PendingIntent.FLAG_UPDATE_CURRENT); } Intent intentAlwaysAllow = new Intent(intentAllowThisTime); @@ -552,12 +549,15 @@ public class PlaybackService extends MediaBrowserServiceCompat { intentAlwaysAllow.putExtra(EXTRA_ALLOW_STREAM_ALWAYS, true); PendingIntent pendingIntentAlwaysAllow; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - pendingIntentAlwaysAllow = PendingIntent.getForegroundService(this, 0, intentAlwaysAllow, PendingIntent.FLAG_UPDATE_CURRENT); + pendingIntentAlwaysAllow = PendingIntent.getForegroundService(this, + R.id.pending_intent_allow_stream_always, intentAlwaysAllow, PendingIntent.FLAG_UPDATE_CURRENT); } else { - pendingIntentAlwaysAllow = PendingIntent.getService(this, 0, intentAlwaysAllow, PendingIntent.FLAG_UPDATE_CURRENT); + pendingIntentAlwaysAllow = PendingIntent.getService(this, + R.id.pending_intent_allow_stream_always, intentAlwaysAllow, PendingIntent.FLAG_UPDATE_CURRENT); } - NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationUtils.CHANNEL_ID_USER_ACTION) + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, + NotificationUtils.CHANNEL_ID_USER_ACTION) .setSmallIcon(R.drawable.ic_stream_white) .setContentTitle(getString(R.string.confirm_mobile_streaming_notification_title)) .setContentText(getString(R.string.confirm_mobile_streaming_notification_message)) @@ -573,7 +573,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { pendingIntentAlwaysAllow) .setAutoCancel(true); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); - notificationManager.notify(NOTIFICATION_ID_STREAMING, builder.build()); + notificationManager.notify(R.id.notification_streaming_confirmation, builder.build()); } /** @@ -711,9 +711,12 @@ public class PlaybackService extends MediaBrowserServiceCompat { } @Override - public void onSleepTimerAlmostExpired() { - float leftVolume = 0.1f * UserPreferences.getLeftVolume(); - float rightVolume = 0.1f * UserPreferences.getRightVolume(); + public void onSleepTimerAlmostExpired(long timeLeft) { + final float[] multiplicators = {0.1f, 0.2f, 0.3f, 0.3f, 0.3f, 0.4f, 0.4f, 0.4f, 0.6f, 0.8f}; + float multiplicator = multiplicators[Math.max(0, (int) timeLeft / 1000)]; + Log.d(TAG, "onSleepTimerAlmostExpired: " + multiplicator); + float leftVolume = multiplicator * UserPreferences.getLeftVolume(); + float rightVolume = multiplicator * UserPreferences.getRightVolume(); mediaPlayer.setVolume(leftVolume, rightVolume); } @@ -1140,13 +1143,11 @@ public class PlaybackService extends MediaBrowserServiceCompat { case INITIALIZING: state = PlaybackStateCompat.STATE_CONNECTING; break; - case INITIALIZED: - case INDETERMINATE: - state = PlaybackStateCompat.STATE_NONE; - break; case ERROR: state = PlaybackStateCompat.STATE_ERROR; break; + case INITIALIZED: // Deliberate fall-through + case INDETERMINATE: default: state = PlaybackStateCompat.STATE_NONE; break; @@ -1158,7 +1159,8 @@ public class PlaybackService extends MediaBrowserServiceCompat { long capabilities = PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_REWIND | PlaybackStateCompat.ACTION_FAST_FORWARD - | PlaybackStateCompat.ACTION_SKIP_TO_NEXT; + | PlaybackStateCompat.ACTION_SKIP_TO_NEXT + | PlaybackStateCompat.ACTION_SEEK_TO; if (useSkipToPreviousForRewindInLockscreen()) { // Workaround to fool Android so that Lockscreen will expose a skip-to-previous button, @@ -1238,9 +1240,8 @@ public class PlaybackService extends MediaBrowserServiceCompat { } } if (!Thread.currentThread().isInterrupted() && stateManager.hasReceivedValidStartCommand()) { - mediaSession.setSessionActivity(PendingIntent.getActivity(this, 0, - PlaybackService.getPlayerActivityIntent(this), - PendingIntent.FLAG_UPDATE_CURRENT)); + mediaSession.setSessionActivity(PendingIntent.getActivity(this, R.id.pending_intent_player_activity, + PlaybackService.getPlayerActivityIntent(this), PendingIntent.FLAG_UPDATE_CURRENT)); try { mediaSession.setMetadata(builder.build()); } catch (OutOfMemoryError e) { @@ -1289,7 +1290,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { notificationBuilder.updatePosition(getCurrentPosition(), getCurrentPlaybackSpeed()); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); - notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); + notificationManager.notify(R.id.notification_playing, notificationBuilder.build()); startForegroundIfPlaying(playerStatus); if (!notificationBuilder.isIconCached()) { @@ -1297,7 +1298,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { Log.d(TAG, "Loading notification icon"); notificationBuilder.loadIcon(); if (!Thread.currentThread().isInterrupted()) { - notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); + notificationManager.notify(R.id.notification_playing, notificationBuilder.build()); } }); notificationSetupThread.start(); @@ -1309,12 +1310,12 @@ public class PlaybackService extends MediaBrowserServiceCompat { if (stateManager.hasReceivedValidStartCommand()) { if (isCasting || status == PlayerStatus.PLAYING || status == PlayerStatus.PREPARING || status == PlayerStatus.SEEKING) { - stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build()); + stateManager.startForeground(R.id.notification_playing, notificationBuilder.build()); Log.d(TAG, "foreground"); } else { stateManager.stopForeground(false); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); - notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); + notificationManager.notify(R.id.notification_playing, notificationBuilder.build()); } } } @@ -1717,7 +1718,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { notificationBuilder.updatePosition(getCurrentPosition(), getCurrentPlaybackSpeed()); NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build()); + notificationManager.notify(R.id.notification_playing, notificationBuilder.build()); } skipEndingIfNecessary(); }); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java index 174b43846..3239f3378 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java @@ -131,7 +131,7 @@ public class PlaybackServiceNotificationBuilder { } } else { notification.setContentTitle(context.getString(R.string.app_name)); - notification.setContentText("Service is running"); + notification.setContentText("Loading. If this does not go away, play any episode and contact us."); } notification.setContentIntent(getPlayerActivityPendingIntent()); @@ -146,8 +146,8 @@ public class PlaybackServiceNotificationBuilder { } private PendingIntent getPlayerActivityPendingIntent() { - return PendingIntent.getActivity(context, 0, PlaybackService.getPlayerActivityIntent(context), - PendingIntent.FLAG_UPDATE_CURRENT); + return PendingIntent.getActivity(context, R.id.pending_intent_player_activity, + PlaybackService.getPlayerActivityIntent(context), PendingIntent.FLAG_UPDATE_CURRENT); } private void addActions(NotificationCompat.Builder notification, MediaSessionCompat.Token mediaSessionToken, @@ -183,15 +183,14 @@ public class PlaybackServiceNotificationBuilder { notification.addAction(R.drawable.ic_notification_pause, //pause action context.getString(R.string.pause_label), pauseButtonPendingIntent); - compactActionList.add(numActions++); } else { PendingIntent playButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_PLAY, numActions); notification.addAction(R.drawable.ic_notification_play, //play action context.getString(R.string.play_label), playButtonPendingIntent); - compactActionList.add(numActions++); } + compactActionList.add(numActions++); // ff follows play, then we have skip (if it's present) PendingIntent ffButtonPendingIntent = getPendingIntentForMediaAction( diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java index e71c1dfa7..55212cd46 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java @@ -316,7 +316,8 @@ public class PlaybackServiceTaskManager { }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(() -> callback.onChapterLoaded(media)); + .subscribe(() -> callback.onChapterLoaded(media), + throwable -> Log.d(TAG, "Error loading chapters: " + Log.getStackTraceString(throwable))); } } @@ -359,7 +360,8 @@ public class PlaybackServiceTaskManager { class SleepTimer implements Runnable { private static final String TAG = "SleepTimer"; private static final long UPDATE_INTERVAL = 1000L; - private static final long NOTIFICATION_THRESHOLD = 10000; + public static final long NOTIFICATION_THRESHOLD = 10000; + private boolean hasVibrated = false; private final long waitingTime; private long timeLeft; private ShakeListener shakeListener; @@ -389,7 +391,6 @@ public class PlaybackServiceTaskManager { @Override public void run() { Log.d(TAG, "Starting"); - boolean notifiedAlmostExpired = false; long lastTick = System.currentTimeMillis(); while (timeLeft > 0) { try { @@ -404,19 +405,19 @@ public class PlaybackServiceTaskManager { timeLeft -= now - lastTick; lastTick = now; - if (timeLeft < NOTIFICATION_THRESHOLD && !notifiedAlmostExpired) { + if (timeLeft < NOTIFICATION_THRESHOLD) { Log.d(TAG, "Sleep timer is about to expire"); - if (SleepTimerPreferences.vibrate()) { + if (SleepTimerPreferences.vibrate() && !hasVibrated) { Vibrator v = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); if (v != null) { v.vibrate(500); + hasVibrated = true; } } if (shakeListener == null && SleepTimerPreferences.shakeToReset()) { shakeListener = new ShakeListener(context, this); } - postCallback(callback::onSleepTimerAlmostExpired); - notifiedAlmostExpired = true; + postCallback(() -> callback.onSleepTimerAlmostExpired(timeLeft)); } if (timeLeft <= 0) { Log.d(TAG, "Sleep timer expired"); @@ -424,6 +425,7 @@ public class PlaybackServiceTaskManager { shakeListener.pause(); shakeListener = null; } + hasVibrated = false; if (!Thread.currentThread().isInterrupted()) { postCallback(callback::onSleepTimerExpired); } else { @@ -460,7 +462,7 @@ public class PlaybackServiceTaskManager { public interface PSTMCallback { void positionSaverTick(); - void onSleepTimerAlmostExpired(); + void onSleepTimerAlmostExpired(long timeLeft); void onSleepTimerExpired(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java index b0b6e164d..b967577af 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java @@ -58,7 +58,6 @@ class ShakeListener implements SensorEventListener @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { - return; } }
\ No newline at end of file diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index c30f46315..0de67b306 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -72,19 +72,13 @@ public final class DBReader { @NonNull private static List<Feed> getFeedList(PodDBAdapter adapter) { - Cursor cursor = null; - try { - cursor = adapter.getAllFeedsCursor(); + try (Cursor cursor = adapter.getAllFeedsCursor()) { List<Feed> feeds = new ArrayList<>(cursor.getCount()); while (cursor.moveToNext()) { Feed feed = extractFeedFromCursorRow(cursor); feeds.add(feed); } return feeds; - } finally { - if (cursor != null) { - cursor.close(); - } } } @@ -96,18 +90,13 @@ public final class DBReader { public static List<String> getFeedListDownloadUrls() { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = null; - try { - cursor = adapter.getFeedCursorDownloadUrls(); + try (Cursor cursor = adapter.getFeedCursorDownloadUrls()) { List<String> result = new ArrayList<>(cursor.getCount()); while (cursor.moveToNext()) { result.add(cursor.getString(1)); } return result; } finally { - if (cursor != null) { - cursor.close(); - } adapter.close(); } } @@ -172,9 +161,7 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = null; - try { - cursor = adapter.getAllItemsOfFeedCursor(feed); + try (Cursor cursor = adapter.getAllItemsOfFeedCursor(feed)) { List<FeedItem> items = extractItemlistFromCursor(adapter, cursor); Collections.sort(items, new FeedItemPubdateComparator()); for (FeedItem item : items) { @@ -182,9 +169,6 @@ public final class DBReader { } return items; } finally { - if (cursor != null) { - cursor.close(); - } adapter.close(); } } @@ -226,16 +210,10 @@ public final class DBReader { @NonNull static List<FeedItem> getQueue(PodDBAdapter adapter) { Log.d(TAG, "getQueue()"); - Cursor cursor = null; - try { - cursor = adapter.getQueueCursor(); + try (Cursor cursor = adapter.getQueueCursor()) { List<FeedItem> items = extractItemlistFromCursor(adapter, cursor); loadAdditionalFeedItemListData(items); return items; - } finally { - if (cursor != null) { - cursor.close(); - } } } @@ -257,18 +235,12 @@ public final class DBReader { } private static LongList getQueueIDList(PodDBAdapter adapter) { - Cursor cursor = null; - try { - cursor = adapter.getQueueIDCursor(); + try (Cursor cursor = adapter.getQueueIDCursor()) { LongList queueIds = new LongList(cursor.getCount()); while (cursor.moveToNext()) { queueIds.add(cursor.getLong(0)); } return queueIds; - } finally { - if (cursor != null) { - cursor.close(); - } } } @@ -302,17 +274,12 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = null; - try { - cursor = adapter.getDownloadedItemsCursor(); + try (Cursor cursor = adapter.getDownloadedItemsCursor()) { List<FeedItem> items = extractItemlistFromCursor(adapter, cursor); loadAdditionalFeedItemListData(items); Collections.sort(items, new FeedItemPubdateComparator()); return items; } finally { - if (cursor != null) { - cursor.close(); - } adapter.close(); } } @@ -328,16 +295,11 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = null; - try { - cursor = adapter.getPlayedItemsCursor(); + try (Cursor cursor = adapter.getPlayedItemsCursor()) { List<FeedItem> items = extractItemlistFromCursor(adapter, cursor); loadAdditionalFeedItemListData(items); return items; } finally { - if (cursor != null) { - cursor.close(); - } adapter.close(); } } @@ -355,16 +317,11 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = null; - try { - cursor = adapter.getNewItemsCursor(offset, limit); + try (Cursor cursor = adapter.getNewItemsCursor(offset, limit)) { List<FeedItem> items = extractItemlistFromCursor(adapter, cursor); loadAdditionalFeedItemListData(items); return items; } finally { - if (cursor != null) { - cursor.close(); - } adapter.close(); } } @@ -381,16 +338,11 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = null; - try { - cursor = adapter.getFavoritesCursor(offset, limit); + try (Cursor cursor = adapter.getFavoritesCursor(offset, limit)) { List<FeedItem> items = extractItemlistFromCursor(adapter, cursor); loadAdditionalFeedItemListData(items); return items; } finally { - if (cursor != null) { - cursor.close(); - } adapter.close(); } } @@ -400,18 +352,13 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = null; - try { - cursor = adapter.getFavoritesCursor(0, Integer.MAX_VALUE); + try (Cursor cursor = adapter.getFavoritesCursor(0, Integer.MAX_VALUE)) { LongList favoriteIDs = new LongList(cursor.getCount()); while (cursor.moveToNext()) { favoriteIDs.add(cursor.getLong(0)); } return favoriteIDs; } finally { - if (cursor != null) { - cursor.close(); - } adapter.close(); } } @@ -428,16 +375,11 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = null; - try { - cursor = adapter.getRecentlyPublishedItemsCursor(offset, limit); + try (Cursor cursor = adapter.getRecentlyPublishedItemsCursor(offset, limit)) { List<FeedItem> items = extractItemlistFromCursor(adapter, cursor); loadAdditionalFeedItemListData(items); return items; } finally { - if (cursor != null) { - cursor.close(); - } adapter.close(); } } @@ -492,9 +434,7 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = null; - try { - cursor = adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE); + try (Cursor cursor = adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE)) { List<DownloadStatus> downloadLog = new ArrayList<>(cursor.getCount()); while (cursor.moveToNext()) { downloadLog.add(DownloadStatus.fromCursor(cursor)); @@ -502,9 +442,6 @@ public final class DBReader { Collections.sort(downloadLog, new DownloadStatusComparator()); return downloadLog; } finally { - if (cursor != null) { - cursor.close(); - } adapter.close(); } } @@ -521,9 +458,7 @@ public final class DBReader { PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = null; - try { - cursor = adapter.getDownloadLog(Feed.FEEDFILETYPE_FEED, feedId); + try (Cursor cursor = adapter.getDownloadLog(Feed.FEEDFILETYPE_FEED, feedId)) { List<DownloadStatus> downloadLog = new ArrayList<>(cursor.getCount()); while (cursor.moveToNext()) { downloadLog.add(DownloadStatus.fromCursor(cursor)); @@ -531,9 +466,6 @@ public final class DBReader { Collections.sort(downloadLog, new DownloadStatusComparator()); return downloadLog; } finally { - if (cursor != null) { - cursor.close(); - } adapter.close(); } } @@ -560,9 +492,7 @@ public final class DBReader { @Nullable static Feed getFeed(final long feedId, PodDBAdapter adapter) { Feed feed = null; - Cursor cursor = null; - try { - cursor = adapter.getFeedCursor(feedId); + try (Cursor cursor = adapter.getFeedCursor(feedId)) { if (cursor.moveToNext()) { feed = extractFeedFromCursorRow(cursor); feed.setItems(getFeedItemList(feed)); @@ -570,10 +500,6 @@ public final class DBReader { Log.e(TAG, "getFeed could not find feed with id " + feedId); } return feed; - } finally { - if (cursor != null) { - cursor.close(); - } } } @@ -582,9 +508,7 @@ public final class DBReader { Log.d(TAG, "Loading feeditem with id " + itemId); FeedItem item = null; - Cursor cursor = null; - try { - cursor = adapter.getFeedItemCursor(Long.toString(itemId)); + try (Cursor cursor = adapter.getFeedItemCursor(Long.toString(itemId))) { if (cursor.moveToNext()) { List<FeedItem> list = extractItemlistFromCursor(adapter, cursor); if (!list.isEmpty()) { @@ -593,10 +517,6 @@ public final class DBReader { } } return item; - } finally { - if (cursor != null) { - cursor.close(); - } } } @@ -631,9 +551,7 @@ public final class DBReader { @Nullable private static FeedItem getFeedItemByUrl(final String podcastUrl, final String episodeUrl, PodDBAdapter adapter) { Log.d(TAG, "Loading feeditem with podcast url " + podcastUrl + " and episode url " + episodeUrl); - Cursor cursor = null; - try { - cursor = adapter.getFeedItemCursor(podcastUrl, episodeUrl); + try (Cursor cursor = adapter.getFeedItemCursor(podcastUrl, episodeUrl)) { if (!cursor.moveToNext()) { return null; } @@ -642,10 +560,6 @@ public final class DBReader { return list.get(0); } return null; - } finally { - if (cursor != null) { - cursor.close(); - } } } @@ -668,10 +582,8 @@ public final class DBReader { } private static String getImageAuthentication(final String imageUrl, PodDBAdapter adapter) { - String credentials = null; - Cursor cursor = null; - try { - cursor = adapter.getImageAuthenticationCursor(imageUrl); + String credentials; + try (Cursor cursor = adapter.getImageAuthenticationCursor(imageUrl)) { if (cursor.moveToFirst()) { String username = cursor.getString(0); String password = cursor.getString(1); @@ -683,10 +595,6 @@ public final class DBReader { } else { credentials = ""; } - } finally { - if (cursor != null) { - cursor.close(); - } } return credentials; } @@ -720,9 +628,7 @@ public final class DBReader { Log.d(TAG, "loadDescriptionOfFeedItem() called with: " + "item = [" + item + "]"); PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); - Cursor cursor = null; - try { - cursor = adapter.getDescriptionOfItem(item); + try (Cursor cursor = adapter.getDescriptionOfItem(item)) { if (cursor.moveToFirst()) { int indexDescription = cursor.getColumnIndex(PodDBAdapter.KEY_DESCRIPTION); String description = cursor.getString(indexDescription); @@ -732,9 +638,6 @@ public final class DBReader { item.setContentEncoded(contentEncoded); } } finally { - if (cursor != null) { - cursor.close(); - } adapter.close(); } } @@ -898,6 +801,16 @@ public final class DBReader { } final LongIntMap feedCounters = adapter.getFeedCounters(feedIds); + int feedFilter = UserPreferences.getFeedFilter(); + if (feedFilter == UserPreferences.FEED_FILTER_COUNTER_ZERO) { + for (int i = feeds.size() - 1; i >= 0; i--) { + if (feedCounters.get(feeds.get(i).getId()) <= 0) { + feedCounters.delete(feeds.get(i).getId()); + feeds.remove(i); + } + } + } + Comparator<Feed> comparator; int feedOrder = UserPreferences.getFeedOrder(); if (feedOrder == UserPreferences.FEED_ORDER_COUNTER) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java index 6f9e6b056..e3121caa2 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java @@ -274,7 +274,7 @@ public class DownloadRequester implements DownloadStateProvider { } File dest; - if (feedmedia.getFile_url() != null) { + if (feedmedia.getFile_url() != null && new File(feedmedia.getFile_url()).exists()) { dest = new File(feedmedia.getFile_url()); } else { dest = new File(getMediafilePath(feedmedia), getMediafilename(feedmedia)); @@ -340,7 +340,7 @@ public class DownloadRequester implements DownloadStateProvider { /** * Checks if feedfile is in the downloads list */ - public synchronized boolean isDownloadingFile(FeedFile item) { + public synchronized boolean isDownloadingFile(@NonNull FeedFile item) { return item.getDownload_url() != null && downloads.containsKey(item.getDownload_url()); } 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 a2247a3db..142763d75 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 @@ -1236,7 +1236,7 @@ public class PodDBAdapter { public Cursor searchItems(long feedID, String searchQuery) { String preparedQuery = prepareSearchQuery(searchQuery); - String queryFeedId = ""; + String queryFeedId; if (feedID != 0) { // search items in specific feed queryFeedId = KEY_FEED + " = " + feedID; diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java index 6985e4421..4c89ebc19 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java @@ -488,8 +488,8 @@ public class SyncService extends Worker { Intent intent = getApplicationContext().getPackageManager().getLaunchIntentForPackage( getApplicationContext().getPackageName()); - PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, - PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), + R.id.pending_intent_sync_error, intent, PendingIntent.FLAG_UPDATE_CURRENT); Notification notification = new NotificationCompat.Builder(getApplicationContext(), NotificationUtils.CHANNEL_ID_ERROR) .setContentTitle(getApplicationContext().getString(R.string.gpodnetsync_error_title)) 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 eae7a08af..62c8ce5f3 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 @@ -21,7 +21,6 @@ import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.ResponseBody; -import org.apache.commons.io.Charsets; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -34,6 +33,7 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; @@ -505,7 +505,7 @@ public class GpodnetService implements ISyncService { RequestBody requestBody = RequestBody.create(TEXT, ""); Request request = new Request.Builder().url(url).post(requestBody).build(); try { - String credential = Credentials.basic(username, password, Charsets.UTF_8); + String credential = Credentials.basic(username, password, Charset.forName("UTF-8")); Request authRequest = request.newBuilder().header("Authorization", credential).build(); Response response = httpClient.newCall(authRequest).execute(); checkStatusCode(response); @@ -519,8 +519,8 @@ public class GpodnetService implements ISyncService { private String executeRequest(@NonNull Request.Builder requestB) throws GpodnetServiceException { Request request = requestB.build(); - String responseString = null; - Response response = null; + String responseString; + Response response; ResponseBody body = null; try { diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java b/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java index 6154ccc84..798be8d96 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java +++ b/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeAction.java @@ -3,6 +3,7 @@ package de.danoeh.antennapod.core.sync.model; import android.text.TextUtils; import android.util.Log; +import androidx.annotation.NonNull; import androidx.core.util.ObjectsCompat; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.util.DateUtils; @@ -179,6 +180,7 @@ public class EpisodeAction { return obj; } + @NonNull @Override public String toString() { return "EpisodeAction{" diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java b/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java index 77942ffa0..90af585af 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java +++ b/core/src/main/java/de/danoeh/antennapod/core/sync/model/EpisodeActionChanges.java @@ -23,6 +23,7 @@ public class EpisodeActionChanges { return this.timestamp; } + @NonNull @Override public String toString() { return "EpisodeActionGetResponse{" diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java index c9f9f19c8..11588967a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/UnsupportedFeedtypeException.java @@ -36,6 +36,9 @@ public class UnsupportedFeedtypeException extends Exception { if (message != null) { return message; } else if (type == TypeGetter.Type.INVALID) { + if ("html".equals(rootElement)) { + return "The server returned a website, not a podcast feed"; + } return "Invalid type"; } else { return "Type " + type + " not supported"; diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java index 638383223..30b01f0bc 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSMedia.java @@ -14,114 +14,118 @@ import de.danoeh.antennapod.core.syndication.util.SyndTypeUtils; /** Processes tags from the http://search.yahoo.com/mrss/ namespace. */ public class NSMedia extends Namespace { - private static final String TAG = "NSMedia"; - - public static final String NSTAG = "media"; - public static final String NSURI = "http://search.yahoo.com/mrss/"; - - private static final String CONTENT = "content"; - private static final String DOWNLOAD_URL = "url"; - private static final String SIZE = "fileSize"; - private static final String MIME_TYPE = "type"; - private static final String DURATION = "duration"; - private static final String DEFAULT = "isDefault"; - private static final String MEDIUM = "medium"; - - private static final String MEDIUM_IMAGE = "image"; - private static final String MEDIUM_AUDIO = "audio"; - private static final String MEDIUM_VIDEO = "video"; - - private static final String IMAGE = "thumbnail"; - private static final String IMAGE_URL = "url"; - - private static final String DESCRIPTION = "description"; - private static final String DESCRIPTION_TYPE = "type"; - - @Override - public SyndElement handleElementStart(String localName, HandlerState state, - Attributes attributes) { - if (CONTENT.equals(localName)) { - String url = attributes.getValue(DOWNLOAD_URL); - String type = attributes.getValue(MIME_TYPE); - String defaultStr = attributes.getValue(DEFAULT); - String medium = attributes.getValue(MEDIUM); - boolean validTypeMedia = false; - boolean validTypeImage = false; - - boolean isDefault = "true".equals(defaultStr); - - if (MEDIUM_AUDIO.equals(medium) || MEDIUM_VIDEO.equals(medium)) { - validTypeMedia = true; - } else if (MEDIUM_IMAGE.equals(medium)) { - validTypeImage = true; - } else { - if (type == null) { - type = SyndTypeUtils.getMimeTypeFromUrl(url); - } - - if (SyndTypeUtils.enclosureTypeValid(type)) { - validTypeMedia = true; - } else if (SyndTypeUtils.imageTypeValid(type)) { - validTypeImage = true; - } - } - - if (state.getCurrentItem() != null && - (state.getCurrentItem().getMedia() == null || isDefault) && - url != null && validTypeMedia) { - long size = 0; - String sizeStr = attributes.getValue(SIZE); - try { - size = Long.parseLong(sizeStr); - } catch (NumberFormatException e) { - Log.e(TAG, "Size \"" + sizeStr + "\" could not be parsed."); - } - - int durationMs = 0; - String durationStr = attributes.getValue(DURATION); - if (!TextUtils.isEmpty(durationStr)) { - try { - long duration = Long.parseLong(durationStr); - durationMs = (int) TimeUnit.MILLISECONDS.convert(duration, TimeUnit.SECONDS); - } catch (NumberFormatException e) { - Log.e(TAG, "Duration \"" + durationStr + "\" could not be parsed"); - } - } - FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, type); - if (durationMs > 0) { - media.setDuration(durationMs); - } - state.getCurrentItem().setMedia(media); - } else if (state.getCurrentItem() != null && url != null && validTypeImage) { - state.getCurrentItem().setImageUrl(url); - } - } else if (IMAGE.equals(localName)) { - String url = attributes.getValue(IMAGE_URL); - if (url != null) { - if (state.getCurrentItem() != null) { - state.getCurrentItem().setImageUrl(url); - } else { - if (state.getFeed().getImageUrl() == null) { - state.getFeed().setImageUrl(url); - } - } - } - } else if (DESCRIPTION.equals(localName)) { - String type = attributes.getValue(DESCRIPTION_TYPE); - return new AtomText(localName, this, type); - } - return new SyndElement(localName, this); - } - - @Override - public void handleElementEnd(String localName, HandlerState state) { - if (DESCRIPTION.equals(localName)) { - String content = state.getContentBuf().toString(); - if (state.getCurrentItem() != null && content != null && - state.getCurrentItem().getDescription() == null) { - state.getCurrentItem().setDescription(content); - } - } - } + private static final String TAG = "NSMedia"; + + public static final String NSTAG = "media"; + public static final String NSURI = "http://search.yahoo.com/mrss/"; + + private static final String CONTENT = "content"; + private static final String DOWNLOAD_URL = "url"; + private static final String SIZE = "fileSize"; + private static final String MIME_TYPE = "type"; + private static final String DURATION = "duration"; + private static final String DEFAULT = "isDefault"; + private static final String MEDIUM = "medium"; + + private static final String MEDIUM_IMAGE = "image"; + private static final String MEDIUM_AUDIO = "audio"; + private static final String MEDIUM_VIDEO = "video"; + + private static final String IMAGE = "thumbnail"; + private static final String IMAGE_URL = "url"; + + private static final String DESCRIPTION = "description"; + private static final String DESCRIPTION_TYPE = "type"; + + @Override + public SyndElement handleElementStart(String localName, HandlerState state, + Attributes attributes) { + if (CONTENT.equals(localName)) { + String url = attributes.getValue(DOWNLOAD_URL); + String type = attributes.getValue(MIME_TYPE); + String defaultStr = attributes.getValue(DEFAULT); + String medium = attributes.getValue(MEDIUM); + boolean validTypeMedia = false; + boolean validTypeImage = false; + + boolean isDefault = "true".equals(defaultStr); + + if (MEDIUM_AUDIO.equals(medium)) { + validTypeMedia = true; + type = "audio/*"; + } else if (MEDIUM_VIDEO.equals(medium)) { + validTypeMedia = true; + type = "video/*"; + } else if (MEDIUM_IMAGE.equals(medium)) { + validTypeImage = true; + type = "image/*"; + } else { + if (type == null) { + type = SyndTypeUtils.getMimeTypeFromUrl(url); + } + + if (SyndTypeUtils.enclosureTypeValid(type)) { + validTypeMedia = true; + } else if (SyndTypeUtils.imageTypeValid(type)) { + validTypeImage = true; + } + } + + if (state.getCurrentItem() != null && (state.getCurrentItem().getMedia() == null || isDefault) + && url != null && validTypeMedia) { + long size = 0; + String sizeStr = attributes.getValue(SIZE); + try { + size = Long.parseLong(sizeStr); + } catch (NumberFormatException e) { + Log.e(TAG, "Size \"" + sizeStr + "\" could not be parsed."); + } + + int durationMs = 0; + String durationStr = attributes.getValue(DURATION); + if (!TextUtils.isEmpty(durationStr)) { + try { + long duration = Long.parseLong(durationStr); + durationMs = (int) TimeUnit.MILLISECONDS.convert(duration, TimeUnit.SECONDS); + } catch (NumberFormatException e) { + Log.e(TAG, "Duration \"" + durationStr + "\" could not be parsed"); + } + } + FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, type); + if (durationMs > 0) { + media.setDuration(durationMs); + } + state.getCurrentItem().setMedia(media); + } else if (state.getCurrentItem() != null && url != null && validTypeImage) { + state.getCurrentItem().setImageUrl(url); + } + } else if (IMAGE.equals(localName)) { + String url = attributes.getValue(IMAGE_URL); + if (url != null) { + if (state.getCurrentItem() != null) { + state.getCurrentItem().setImageUrl(url); + } else { + if (state.getFeed().getImageUrl() == null) { + state.getFeed().setImageUrl(url); + } + } + } + } else if (DESCRIPTION.equals(localName)) { + String type = attributes.getValue(DESCRIPTION_TYPE); + return new AtomText(localName, this, type); + } + return new SyndElement(localName, this); + } + + @Override + public void handleElementEnd(String localName, HandlerState state) { + if (DESCRIPTION.equals(localName)) { + String content = state.getContentBuf().toString(); + if (state.getCurrentItem() != null && content != null + && state.getCurrentItem().getDescription() == null) { + state.getCurrentItem().setDescription(content); + } + } + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java index e85d5fae1..0c0561279 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/AtomText.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.core.syndication.namespace.atom; -import android.os.Build; -import android.text.Html; +import androidx.core.text.HtmlCompat; + import de.danoeh.antennapod.core.syndication.namespace.Namespace; import de.danoeh.antennapod.core.syndication.namespace.SyndElement; @@ -24,11 +24,7 @@ public class AtomText extends SyndElement { if (type == null) { return content; } else if (type.equals(TYPE_HTML)) { - if (Build.VERSION.SDK_INT >= 24) { - return Html.fromHtml(content, Html.FROM_HTML_MODE_LEGACY).toString(); - } else { - return Html.fromHtml(content).toString(); - } + return HtmlCompat.fromHtml(content, HtmlCompat.FROM_HTML_MODE_LEGACY).toString(); } else if (type.equals(TYPE_XHTML)) { return content; } else { // Handle as text by default diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java index 7aa5a90e7..7e4350fd4 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/atom/NSAtom.java @@ -3,6 +3,7 @@ package de.danoeh.antennapod.core.syndication.namespace.atom; import android.text.TextUtils; import android.util.Log; +import de.danoeh.antennapod.core.syndication.util.SyndStringUtils; import org.xml.sax.Attributes; import de.danoeh.antennapod.core.feed.FeedItem; @@ -163,12 +164,13 @@ public class NSAtom extends Namespace { if (state.getTagstack().size() >= 2) { AtomText textElement = null; - String content; + String contentRaw; if (state.getContentBuf() != null) { - content = state.getContentBuf().toString(); + contentRaw = state.getContentBuf().toString(); } else { - content = ""; + contentRaw = ""; } + String content = SyndStringUtils.trimAllWhitespace(contentRaw); SyndElement topElement = state.getTagstack().peek(); String top = topElement.getName(); SyndElement secondElement = state.getSecondTag(); @@ -181,9 +183,9 @@ public class NSAtom extends Namespace { if (ID.equals(top)) { if (FEED.equals(second) && state.getFeed() != null) { - state.getFeed().setFeedIdentifier(content); + state.getFeed().setFeedIdentifier(contentRaw); } else if (ENTRY.equals(second) && state.getCurrentItem() != null) { - state.getCurrentItem().setItemIdentifier(content); + state.getCurrentItem().setItemIdentifier(contentRaw); } } else if (TITLE.equals(top) && textElement != null) { if (FEED.equals(second) && state.getFeed() != null) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java index 4fd54156b..859666464 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java @@ -6,6 +6,8 @@ import android.net.Uri; import androidx.annotation.NonNull; import android.util.Log; +import java.net.URLConnection; +import de.danoeh.antennapod.core.ClientConfig; import org.apache.commons.io.IOUtils; import java.io.BufferedInputStream; @@ -85,7 +87,9 @@ public class ChapterUtils { in = new CountingInputStream(context.getContentResolver().openInputStream(uri)); } else { URL url = new URL(p.getStreamUrl()); - in = new CountingInputStream(url.openStream()); + URLConnection urlConnection = url.openConnection(); + urlConnection.setRequestProperty("User-Agent", ClientConfig.USER_AGENT); + in = new CountingInputStream(urlConnection.getInputStream()); } List<Chapter> chapters = readChaptersFrom(in); if (!chapters.isEmpty()) { @@ -159,7 +163,9 @@ public class ChapterUtils { input = context.getContentResolver().openInputStream(uri); } else { URL url = new URL(media.getStreamUrl()); - input = url.openStream(); + URLConnection urlConnection = url.openConnection(); + urlConnection.setRequestProperty("User-Agent", ClientConfig.USER_AGENT); + input = urlConnection.getInputStream(); } if (input != null) { readOggChaptersFromInputStream(media, input); diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java b/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java index 220a783f3..2a387b7b0 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/FileNameGenerator.java @@ -4,6 +4,7 @@ import android.text.TextUtils; import androidx.annotation.VisibleForTesting; import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; @@ -29,6 +30,7 @@ public class FileNameGenerator { * characters of the given string. */ public static String generateFileName(String string) { + string = StringUtils.stripAccents(string); StringBuilder buf = new StringBuilder(); for (int i = 0; i < string.length(); i++) { char c = string.charAt(i); diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java b/core/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java index ebde1e412..a45136432 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/InvalidFeedException.java @@ -6,6 +6,7 @@ package de.danoeh.antennapod.core.util; public class InvalidFeedException extends Exception { private static final long serialVersionUID = 1L; - public InvalidFeedException() { + public InvalidFeedException(String message) { + super(message); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java index 366f86707..813c6d0f7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/RewindAfterPauseUtils.java @@ -39,7 +39,7 @@ public class RewindAfterPauseUtils { int newPosition = currentPosition - (int) rewindTime; - return newPosition > 0 ? newPosition : 0; + return Math.max(newPosition, 0); } else { return currentPosition; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java index e1dffef97..ac7f4848c 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java @@ -41,7 +41,7 @@ public final class URLChecker { String lowerCaseUrl = url.toLowerCase(); // protocol names are case insensitive if (lowerCaseUrl.startsWith("feed://")) { if (BuildConfig.DEBUG) Log.d(TAG, "Replacing feed:// with http://"); - return url.replaceFirst("feed://", "http://"); + return prepareURL(url.substring("feed://".length())); } else if (lowerCaseUrl.startsWith("pcast://")) { if (BuildConfig.DEBUG) Log.d(TAG, "Removing pcast://"); return prepareURL(url.substring("pcast://".length())); @@ -50,7 +50,7 @@ public final class URLChecker { return prepareURL(url.substring("pcast:".length())); } else if (lowerCaseUrl.startsWith("itpc")) { if (BuildConfig.DEBUG) Log.d(TAG, "Replacing itpc:// with http://"); - return url.replaceFirst("itpc://", "http://"); + return prepareURL(url.substring("itpc://".length())); } else if (lowerCaseUrl.startsWith(AP_SUBSCRIBE)) { if (BuildConfig.DEBUG) Log.d(TAG, "Removing antennapod-subscribe://"); return prepareURL(url.substring(AP_SUBSCRIBE.length())); diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java b/core/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java index 8bd23c2ed..920a1ef8a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/comparator/ChapterStartTimeComparator.java @@ -8,13 +8,7 @@ public class ChapterStartTimeComparator implements Comparator<Chapter> { @Override public int compare(Chapter lhs, Chapter rhs) { - if (lhs.getStart() == rhs.getStart()) { - return 0; - } else if (lhs.getStart() < rhs.getStart()) { - return -1; - } else { - return 1; - } + return Long.compare(lhs.getStart(), rhs.getStart()); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java index 991089910..a8ca43ccb 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java @@ -118,9 +118,8 @@ public class AutoUpdateManager { */ public static void runImmediate(@NonNull Context context) { Log.d(TAG, "Run auto update immediately in background."); - new Thread(() -> { - DBTasks.refreshAllFeeds(context.getApplicationContext(), true); - }, "ManualRefreshAllFeeds").start(); + new Thread(() -> DBTasks.refreshAllFeeds( + context.getApplicationContext(), true), "ManualRefreshAllFeeds").start(); } public static void disableAutoUpdate(Context context) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java index 4b3ffa389..aec53da4c 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/AudioPlayer.java @@ -6,6 +6,7 @@ import android.preference.PreferenceManager; import android.util.Log; import android.view.SurfaceHolder; +import de.danoeh.antennapod.core.ClientConfig; import org.antennapod.audio.MediaPlayer; import de.danoeh.antennapod.core.preferences.UserPreferences; @@ -17,7 +18,7 @@ public class AudioPlayer extends MediaPlayer implements IPlayer { private static final String TAG = "AudioPlayer"; public AudioPlayer(Context context) { - super(context); + super(context, true, ClientConfig.USER_AGENT); PreferenceManager.getDefaultSharedPreferences(context) .registerOnSharedPreferenceChangeListener((sharedPreferences, key) -> { if (key.equals(UserPreferences.PREF_MEDIA_PLAYER)) { diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java index 0b849aa1f..d47d26af9 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java @@ -508,6 +508,13 @@ public class PlaybackController { playbackService.setStartWhenPrepared(true); playbackService.prepare(); break; + default: + new PlaybackServiceStarter(activity, media) + .startWhenPrepared(true) + .streamIfLastWasStream() + .start(); + Log.w(TAG, "Play/Pause button was pressed and PlaybackService state was unknown"); + break; } } @@ -592,6 +599,13 @@ public class PlaybackController { } public void setPlaybackSpeed(float speed) { + PlaybackPreferences.setCurrentlyPlayingTemporaryPlaybackSpeed(speed); + if (getMedia() != null && getMedia().getMediaType() == MediaType.VIDEO) { + UserPreferences.setVideoPlaybackSpeed(speed); + } else { + UserPreferences.setPlaybackSpeed(speed); + } + if (playbackService != null) { playbackService.setSpeed(speed); } else { diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java index cdf171299..9277af6e6 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/vorbiscommentreader/OggInputStream.java @@ -39,7 +39,7 @@ class OggInputStream extends InputStream { private void readOggPage() throws IOException { // find OggS int[] buffer = new int[4]; - int c = 0; + int c; boolean isInOggS = false; while ((c = input.read()) != -1) { switch (c) { |