From d652bd21842e851802b7a842856726048d7f2498 Mon Sep 17 00:00:00 2001 From: Spencer Visick Date: Thu, 19 Apr 2018 21:39:21 -0700 Subject: Fix Bluetooth Forward Skip Button for Android 8 It appears that Oreo has changed the behavior for Bluetooth KeyEvents. Starting with Android 8.0, KeyEvent.getSource() returns 0 (unknown source). This change explicitly sets when a key press is sent from a notification, or lockscreen event. Otherwise we use the customer-defined skip behavior. --- .../antennapod/core/service/playback/PlaybackService.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 ab25f0a5f..dd7e84857 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 @@ -447,8 +447,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { if (keycode != -1) { Log.d(TAG, "Received media button event"); - handleKeycode(keycode, intent.getIntExtra(MediaButtonReceiver.EXTRA_SOURCE, - InputDeviceCompat.SOURCE_CLASS_NONE)); + handleKeycode(keycode, true); } else if (!flavorHelper.castDisconnect(castDisconnect) && playable != null) { started = true; boolean stream = intent.getBooleanExtra(EXTRA_SHOULD_STREAM, @@ -472,7 +471,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { * Handles media button events * return: keycode was handled */ - private boolean handleKeycode(int keycode, int source) { + private boolean handleKeycode(int keycode, boolean notificationButton) { Log.d(TAG, "Handling keycode: " + keycode); final PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo(); final PlayerStatus status = info.playerStatus; @@ -505,7 +504,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { return true; case KeyEvent.KEYCODE_MEDIA_NEXT: - if (source == InputDevice.SOURCE_CLASS_NONE || + if (notificationButton || UserPreferences.shouldHardwareButtonSkip()) { // assume the skip command comes from a notification or the lockscreen // a >| skip button should actually skip @@ -1756,11 +1755,11 @@ public class PlaybackService extends MediaBrowserServiceCompat { public boolean onMediaButtonEvent(final Intent mediaButton) { Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")"); if (mediaButton != null) { - KeyEvent keyEvent = (KeyEvent) mediaButton.getExtras().get(Intent.EXTRA_KEY_EVENT); + KeyEvent keyEvent = (KeyEvent) mediaButton.getParcelableExtra(Intent.EXTRA_KEY_EVENT); if (keyEvent != null && keyEvent.getAction() == KeyEvent.ACTION_DOWN && keyEvent.getRepeatCount() == 0) { - return handleKeycode(keyEvent.getKeyCode(), keyEvent.getSource()); + return handleKeycode(keyEvent.getKeyCode(), false); } } return false; -- cgit v1.2.3 From 91120d98a461d4050da30f3d039eb9b7db01c23a Mon Sep 17 00:00:00 2001 From: mr-intj Date: Fri, 27 Apr 2018 17:30:40 -0700 Subject: Added "Random" and "Smart Shuffle" items at the bottom of the Queue|Sort menu. Added "Permutor" interface to allow specification of reordering logic to be specified in QueueSorter (vs. DBWriter), similar to the existing sort logic. Added "Random" and "Smart Shuffle" strings to core/src/main/res/values (did not add translations for non-English languages) Closes #2366, Closes #2602 --- .../danoeh/antennapod/core/storage/DBWriter.java | 27 ++++++ .../de/danoeh/antennapod/core/util/Permutor.java | 17 ++++ .../danoeh/antennapod/core/util/QueueSorter.java | 106 ++++++++++++++++++++- 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/Permutor.java (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java index 75510d2f6..49de7ffe7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java @@ -43,6 +43,7 @@ import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.service.download.DownloadStatus; import de.danoeh.antennapod.core.service.playback.PlaybackService; import de.danoeh.antennapod.core.util.LongList; +import de.danoeh.antennapod.core.util.Permutor; import de.danoeh.antennapod.core.util.flattr.FlattrStatus; import de.danoeh.antennapod.core.util.flattr.FlattrThing; import de.danoeh.antennapod.core.util.flattr.SimpleFlattrThing; @@ -991,6 +992,32 @@ public class DBWriter { }); } + /** + * Similar to sortQueue, but allows more complex reordering by providing whole-queue context. + * @param permutor Encapsulates whole-Queue reordering logic. + * @param broadcastUpdate true if this operation should trigger a + * QueueUpdateBroadcast. This option should be set to false + * if the caller wants to avoid unexpected updates of the GUI. + */ + public static Future reorderQueue(final Permutor permutor, final boolean broadcastUpdate) { + return dbExec.submit(() -> { + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); + final List queue = DBReader.getQueue(adapter); + + if (queue != null) { + permutor.reorder(queue); + adapter.setQueue(queue); + if (broadcastUpdate) { + EventBus.getDefault().post(QueueEvent.sorted(queue)); + } + } else { + Log.e(TAG, "reorderQueue: Could not load queue"); + } + adapter.close(); + }); + } + /** * Sets the 'auto_download'-attribute of specific FeedItem. * diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/Permutor.java b/core/src/main/java/de/danoeh/antennapod/core/util/Permutor.java new file mode 100644 index 000000000..7d6e20ab1 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/util/Permutor.java @@ -0,0 +1,17 @@ +package de.danoeh.antennapod.core.util; + +import java.util.List; + +/** + * Interface for passing around list permutor method. This is used for cases where a simple comparator + * won't work (e.g. Random, Smart Shuffle, etc). + * + * @param the type of elements in the list + */ +public interface Permutor { + /** + * Reorders the specified list. + * @param queue A (modifiable) list of elements to be reordered + */ + void reorder(List queue); +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java index c3b4c0e15..40b5bc24d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java @@ -2,7 +2,12 @@ package de.danoeh.antennapod.core.util; import android.content.Context; +import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import de.danoeh.antennapod.core.feed.FeedItem; import de.danoeh.antennapod.core.feed.FeedMedia; @@ -20,11 +25,15 @@ public class QueueSorter { DURATION_ASC, DURATION_DESC, FEED_TITLE_ASC, - FEED_TITLE_DESC + FEED_TITLE_DESC, + RANDOM, + SMART_SHUFFLE_ASC, + SMART_SHUFFLE_DESC } public static void sort(final Context context, final Rule rule, final boolean broadcastUpdate) { Comparator comparator = null; + Permutor permutor = null; switch (rule) { case EPISODE_TITLE_ASC: @@ -68,11 +77,106 @@ public class QueueSorter { case FEED_TITLE_DESC: comparator = (f1, f2) -> f2.getFeed().getTitle().compareTo(f1.getFeed().getTitle()); break; + case RANDOM: + permutor = Collections::shuffle; + break; + case SMART_SHUFFLE_ASC: + permutor = (queue) -> SmartShuffle(queue, true); + break; + case SMART_SHUFFLE_DESC: + permutor = (queue) -> SmartShuffle(queue, false); + break; default: } if (comparator != null) { DBWriter.sortQueue(comparator, broadcastUpdate); + } else if (permutor != null) { + DBWriter.reorderQueue(permutor, broadcastUpdate); + } + } + + /** + * Implements a reordering by pubdate that avoids consecutive episodes from the same feed in + * the queue. + * + * A listener might want to hear episodes from any given feed in pubdate order, but would + * prefer a more balanced ordering that avoids having to listen to clusters of consecutive + * episodes from the same feed. This is what "Smart Shuffle" tries to accomplish. + * + * The Smart Shuffle algorithm involves choosing episodes (in round-robin fashion) from a + * collection of individual, pubdate-sorted lists that each contain only items from a specific + * feed. + * + * Of course, clusters of consecutive episodes at the end of the queue may be + * unavoidable. This seems unlikely to be an issue for most users who presumably maintain + * large queues with new episodes continuously being added. + * + * For example, given a queue containing three episodes each from three different feeds + * (A, B, and C), a simple pubdate sort might result in a queue that looks like the following: + * + * B1, B2, B3, A1, A2, C1, C2, C3, A3 + * + * (note that feed B episodes were all published before the first feed A episode, so a simple + * pubdate sort will often result in significant clustering of episodes from a single feed) + * + * Using Smart Shuffle, the resulting queue would look like the following: + * + * A1, B1, C1, A2, B2, C2, A3, B3, C3 + * + * (note that episodes above aren't strictly ordered in terms of pubdate, but episodes + * of each feed do appear in pubdate order) + * + * @param queue A (modifiable) list of FeedItem elements to be reordered. + * @param ascending {@code true} to use ascending pubdate in the reordering; + * {@code false} for descending. + */ + private static void SmartShuffle(List queue, boolean ascending) { + + // Divide FeedItems into lists by feed + + Map> map = new HashMap<>(); + + while (!queue.isEmpty()) { + FeedItem item = queue.remove(0); + Long id = item.getFeedId(); + if (!map.containsKey(id)) + map.put(id, new ArrayList<>()); + map.get(id).add(item); + } + + // Sort each individual list by PubDate (ascending/descending) + + Comparator itemComparator = ascending + ? (f1, f2) -> f1.getPubDate().compareTo(f2.getPubDate()) + : (f1, f2) -> f2.getPubDate().compareTo(f1.getPubDate()); + + for (Long id : map.keySet()) + Collections.sort(map.get(id), itemComparator); + + // Create a list of the individual FeedItems lists, and sort it by feed title (ascending). + // Doing this ensures that the feed order we use is predictable/deterministic. + + List> feeds = new ArrayList<>(map.values()); + Collections.sort(feeds, + // (we use a desc sort here, since we're iterating back-to-front below) + (f1, f2) -> f2.get(0).getFeed().getTitle().compareTo(f1.get(0).getFeed().getTitle())); + + // Cycle through the (sorted) feed lists in a round-robin fashion, removing the first item + // and adding it back into to the original queue + + while (!feeds.isEmpty()) { + // Iterate across the (sorted) list of feeds, removing the first item in each, and + // appending it to the queue. Note that we're iterating back-to-front here, since we + // will be deleting feed lists as they become empty. + for (int i = feeds.size() - 1; i >= 0; --i) { + List items = feeds.get(i); + queue.add(items.remove(0)); + // Removed the last item in this particular feed? Then remove this feed from the + // list of feeds. + if (items.isEmpty()) + feeds.remove(i); + } } } } -- cgit v1.2.3 From 7be44370f6828c540ee3bcc7789b181aafadbbf4 Mon Sep 17 00:00:00 2001 From: mr-intj Date: Mon, 30 Apr 2018 14:44:13 -0700 Subject: * Using Camel Case for methods * Use braces on single-line blocks --- .../java/de/danoeh/antennapod/core/util/QueueSorter.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java index 40b5bc24d..5c827dfe9 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/QueueSorter.java @@ -81,10 +81,10 @@ public class QueueSorter { permutor = Collections::shuffle; break; case SMART_SHUFFLE_ASC: - permutor = (queue) -> SmartShuffle(queue, true); + permutor = (queue) -> smartShuffle(queue, true); break; case SMART_SHUFFLE_DESC: - permutor = (queue) -> SmartShuffle(queue, false); + permutor = (queue) -> smartShuffle(queue, false); break; default: } @@ -131,7 +131,7 @@ public class QueueSorter { * @param ascending {@code true} to use ascending pubdate in the reordering; * {@code false} for descending. */ - private static void SmartShuffle(List queue, boolean ascending) { + private static void smartShuffle(List queue, boolean ascending) { // Divide FeedItems into lists by feed @@ -140,8 +140,9 @@ public class QueueSorter { while (!queue.isEmpty()) { FeedItem item = queue.remove(0); Long id = item.getFeedId(); - if (!map.containsKey(id)) + if (!map.containsKey(id)) { map.put(id, new ArrayList<>()); + } map.get(id).add(item); } @@ -151,8 +152,9 @@ public class QueueSorter { ? (f1, f2) -> f1.getPubDate().compareTo(f2.getPubDate()) : (f1, f2) -> f2.getPubDate().compareTo(f1.getPubDate()); - for (Long id : map.keySet()) + for (Long id : map.keySet()) { Collections.sort(map.get(id), itemComparator); + } // Create a list of the individual FeedItems lists, and sort it by feed title (ascending). // Doing this ensures that the feed order we use is predictable/deterministic. @@ -174,8 +176,9 @@ public class QueueSorter { queue.add(items.remove(0)); // Removed the last item in this particular feed? Then remove this feed from the // list of feeds. - if (items.isEmpty()) + if (items.isEmpty()) { feeds.remove(i); + } } } } -- cgit v1.2.3 From 4bba6b30a1b5e82b93edc27742ec35362b08d1c7 Mon Sep 17 00:00:00 2001 From: orionlee Date: Mon, 30 Apr 2018 14:59:45 -0700 Subject: Issue #2579: Provide share Link in episode playback screen even when the episode has no link - Use podcast link as the fallback. Also bug fix share link with position: to include epsiode and podcast title. --- .../de/danoeh/antennapod/core/util/ShareUtils.java | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java index 898f7bedb..149cdcbc6 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java @@ -50,11 +50,30 @@ public class ShareUtils { return item.getFeed().getTitle() + ": " + item.getTitle(); } + /** + * Get the link for the feed item for the purpose of Share. It fallbacks to + * use the feed's link if the named feed item has no link. + */ + private static String getItemShareLink(FeedItem item) { + String link = item.getLink(); + if (link == null) { + Feed feed = item.getFeed(); + if (feed != null) { + link = feed.getLink(); + } + } + return link; + } + + public static boolean hasLinkToShare(FeedItem item) { + return ( item != null && getItemShareLink(item) != null ); + } + public static void shareFeedItemLink(Context context, FeedItem item, boolean withPosition) { - String text = getItemShareText(item) + " " + item.getLink(); + String text = getItemShareText(item) + " " + getItemShareLink(item); if(withPosition) { int pos = item.getMedia().getPosition(); - text = item.getLink() + " [" + Converter.getDurationStringLong(pos) + "]"; + text += " [" + Converter.getDurationStringLong(pos) + "]"; } shareLink(context, text); } -- cgit v1.2.3 From 345fcc17d0416f8db61a2506aa88c25b53718ebb Mon Sep 17 00:00:00 2001 From: orionlee Date: Mon, 30 Apr 2018 15:44:19 -0700 Subject: FeedItem Visit Website tweak: use feed website as a fallback, analogous to how share FeedItem link work. Applicable to both feed playback screen and feed information screen. --- .../de/danoeh/antennapod/core/util/FeedItemUtil.java | 15 +++++++++++++++ .../de/danoeh/antennapod/core/util/ShareUtils.java | 19 ++----------------- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java index 892e5ff38..129c1923e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java @@ -2,6 +2,7 @@ package de.danoeh.antennapod.core.util; import java.util.List; +import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; public class FeedItemUtil { @@ -75,4 +76,18 @@ public class FeedItemUtil { return false; } + /** + * Get the link for the feed item for the purpose of Share. It fallbacks to + * use the feed's link if the named feed item has no link. + */ + public static String getLinkWithFallback(FeedItem item) { + String link = item.getLink(); + if (link == null) { + Feed feed = item.getFeed(); + if (feed != null) { + link = feed.getLink(); + } + } + return link; + } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java index 149cdcbc6..0fbca2437 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java @@ -50,27 +50,12 @@ public class ShareUtils { return item.getFeed().getTitle() + ": " + item.getTitle(); } - /** - * Get the link for the feed item for the purpose of Share. It fallbacks to - * use the feed's link if the named feed item has no link. - */ - private static String getItemShareLink(FeedItem item) { - String link = item.getLink(); - if (link == null) { - Feed feed = item.getFeed(); - if (feed != null) { - link = feed.getLink(); - } - } - return link; - } - public static boolean hasLinkToShare(FeedItem item) { - return ( item != null && getItemShareLink(item) != null ); + return ( item != null && FeedItemUtil.getLinkWithFallback(item) != null ); } public static void shareFeedItemLink(Context context, FeedItem item, boolean withPosition) { - String text = getItemShareText(item) + " " + getItemShareLink(item); + String text = getItemShareText(item) + " " + FeedItemUtil.getLinkWithFallback(item); if(withPosition) { int pos = item.getMedia().getPosition(); text += " [" + Converter.getDurationStringLong(pos) + "]"; -- cgit v1.2.3 From ab0f4131850695537c22258633aecb4aca0aece5 Mon Sep 17 00:00:00 2001 From: orionlee Date: Mon, 30 Apr 2018 15:49:18 -0700 Subject: Make FeedItemUtil.getLinkWithFallback(item) tolerates null item. --- .../java/de/danoeh/antennapod/core/util/FeedItemUtil.java | 15 +++++++++------ .../java/de/danoeh/antennapod/core/util/ShareUtils.java | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java index 129c1923e..516c57d55 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java @@ -81,13 +81,16 @@ public class FeedItemUtil { * use the feed's link if the named feed item has no link. */ public static String getLinkWithFallback(FeedItem item) { - String link = item.getLink(); - if (link == null) { - Feed feed = item.getFeed(); - if (feed != null) { - link = feed.getLink(); + String link = null; + if (item != null) { + link = item.getLink(); + if (link == null) { + Feed feed = item.getFeed(); + if (feed != null) { + link = feed.getLink(); + } } - } + } // else null item, can only return null return link; } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java index 0fbca2437..5ae00460e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java @@ -51,7 +51,7 @@ public class ShareUtils { } public static boolean hasLinkToShare(FeedItem item) { - return ( item != null && FeedItemUtil.getLinkWithFallback(item) != null ); + return FeedItemUtil.getLinkWithFallback(item) != null; } public static void shareFeedItemLink(Context context, FeedItem item, boolean withPosition) { -- cgit v1.2.3 From 4c7531d277bf4b2a733031b9b1d3a7e9c1ad0241 Mon Sep 17 00:00:00 2001 From: orionlee Date: Wed, 2 May 2018 13:53:56 -0700 Subject: Flatten nested ifs, per @ByteHamster feedback --- .../de/danoeh/antennapod/core/util/FeedItemUtil.java | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java index 516c57d55..76a6549ae 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/FeedItemUtil.java @@ -2,7 +2,6 @@ package de.danoeh.antennapod.core.util; import java.util.List; -import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; public class FeedItemUtil { @@ -81,16 +80,13 @@ public class FeedItemUtil { * use the feed's link if the named feed item has no link. */ public static String getLinkWithFallback(FeedItem item) { - String link = null; - if (item != null) { - link = item.getLink(); - if (link == null) { - Feed feed = item.getFeed(); - if (feed != null) { - link = feed.getLink(); - } - } - } // else null item, can only return null - return link; + if (item == null) { + return null; + } else if (item.getLink() != null) { + return item.getLink(); + } else if (item.getFeed() != null) { + return item.getFeed().getLink(); + } + return null; } } -- cgit v1.2.3 From 1d0459b126d7d219a0d10ec4d8c8b2fbd48fd8fa Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Tue, 9 Jan 2018 19:08:23 +0100 Subject: Updated build tools --- .../de/danoeh/antennapod/core/service/playback/PlaybackService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 67a2cdad2..3479c3368 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 @@ -31,7 +31,7 @@ import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; import android.support.v4.view.InputDeviceCompat; -import android.support.v7.app.NotificationCompat; +import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -1293,7 +1293,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { PendingIntent stopButtonPendingIntent = getPendingIntentForMediaAction( KeyEvent.KEYCODE_MEDIA_STOP, numActions); - notificationBuilder.setStyle(new android.support.v7.app.NotificationCompat.MediaStyle() + notificationBuilder.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle() .setMediaSession(mediaSession.getSessionToken()) .setShowActionsInCompactView(compactActionList.toArray()) .setShowCancelButton(true) -- cgit v1.2.3 From 7ad176ce299bb2abfa3698ce64ffc69b16cfdc8b Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Wed, 10 Jan 2018 21:50:29 +0100 Subject: Added notification categories Android treats IMPORTANCE_DEFAULT as IMPORTANCE_HIGH https://issuetracker.google.com/issues/65108694 --- .../core/asynctask/FlattrClickWorker.java | 5 +- .../core/service/GpodnetSyncService.java | 3 +- .../core/service/download/DownloadService.java | 7 +-- .../core/service/playback/PlaybackService.java | 5 +- .../antennapod/core/util/NotificationUtils.java | 62 ++++++++++++++++++++++ 5 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/NotificationUtils.java (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java index 5bd65f4e9..627e601bd 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java @@ -10,6 +10,7 @@ import android.support.v4.app.NotificationCompat; import android.util.Log; import android.widget.Toast; +import de.danoeh.antennapod.core.util.NotificationUtils; import org.shredzone.flattr4j.exception.FlattrException; import java.util.LinkedList; @@ -175,7 +176,7 @@ public class FlattrClickWorker extends AsyncTask Date: Sun, 22 Apr 2018 22:21:46 +0200 Subject: Start PlaybackService lazily to allow using ForegroundService --- .../danoeh/antennapod/core/event/ServiceEvent.java | 13 +++ .../core/receiver/MediaButtonReceiver.java | 3 +- .../core/service/GpodnetSyncService.java | 21 ++++- .../core/service/download/DownloadService.java | 3 +- .../core/service/playback/PlaybackService.java | 73 ++++++++++++----- .../de/danoeh/antennapod/core/storage/DBTasks.java | 12 +-- .../antennapod/core/storage/DownloadRequester.java | 3 +- .../antennapod/core/util/NotificationUtils.java | 10 +++ .../core/util/playback/PlaybackController.java | 92 +++++++++++++++------- 9 files changed, 167 insertions(+), 63 deletions(-) create mode 100644 core/src/main/java/de/danoeh/antennapod/core/event/ServiceEvent.java (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/ServiceEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/ServiceEvent.java new file mode 100644 index 000000000..b3241a8b6 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/event/ServiceEvent.java @@ -0,0 +1,13 @@ +package de.danoeh.antennapod.core.event; + +public class ServiceEvent { + public enum Action { + SERVICE_STARTED + } + + public final Action action; + + public ServiceEvent(Action action) { + this.action = action; + } +} diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java index 9b4b91151..b191dbf8b 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java +++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java @@ -3,6 +3,7 @@ package de.danoeh.antennapod.core.receiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.support.v4.content.ContextCompat; import android.util.Log; import android.view.KeyEvent; @@ -29,7 +30,7 @@ public class MediaButtonReceiver extends BroadcastReceiver { Intent serviceIntent = new Intent(context, PlaybackService.class); serviceIntent.putExtra(EXTRA_KEYCODE, event.getKeyCode()); serviceIntent.putExtra(EXTRA_SOURCE, event.getSource()); - context.startService(serviceIntent); + ContextCompat.startForegroundService(context, serviceIntent); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java index d022dbf02..48398e0c5 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java @@ -8,6 +8,7 @@ import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.support.v4.app.NotificationCompat; +import android.support.v4.content.ContextCompat; import android.support.v4.util.ArrayMap; import android.util.Log; import android.util.Pair; @@ -58,6 +59,18 @@ public class GpodnetSyncService extends Service { private boolean syncSubscriptions = false; private boolean syncActions = false; + private static final int NOTIFICATION_ID = 2; + + @Override + public void onCreate() { + super.onCreate(); + startForeground(NOTIFICATION_ID, + new NotificationCompat.Builder(this, NotificationUtils.CHANNEL_ID_GPODNET) + .setSmallIcon(R.drawable.stat_notify_sync) + .setContentTitle(getString(R.string.gpodnet_main_label)) + .setContentText(getString(R.string.synchronizing)) + .build()); + } @Override public int onStartCommand(Intent intent, int flags, int startId) { @@ -110,6 +123,7 @@ public class GpodnetSyncService extends Service { private synchronized void sync() { if (!GpodnetPreferences.loggedIn() || !NetworkUtils.networkAvailable()) { + stopForeground(true); stopSelf(); return; } @@ -126,6 +140,7 @@ public class GpodnetSyncService extends Service { } syncActions = false; } + stopForeground(true); stopSelf(); } @@ -394,7 +409,7 @@ public class GpodnetSyncService extends Service { if (GpodnetPreferences.loggedIn()) { Intent intent = new Intent(context, GpodnetSyncService.class); intent.putExtra(ARG_ACTION, ACTION_SYNC); - context.startService(intent); + ContextCompat.startForegroundService(context, intent); } } @@ -402,7 +417,7 @@ public class GpodnetSyncService extends Service { if (GpodnetPreferences.loggedIn()) { Intent intent = new Intent(context, GpodnetSyncService.class); intent.putExtra(ARG_ACTION, ACTION_SYNC_SUBSCRIPTIONS); - context.startService(intent); + ContextCompat.startForegroundService(context, intent); } } @@ -410,7 +425,7 @@ public class GpodnetSyncService extends Service { if (GpodnetPreferences.loggedIn()) { Intent intent = new Intent(context, GpodnetSyncService.class); intent.putExtra(ARG_ACTION, ACTION_SYNC_ACTIONS); - context.startService(intent); + ContextCompat.startForegroundService(context, intent); } } } 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 24be93415..34cabf564 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 @@ -296,6 +296,7 @@ public class DownloadService extends Service { setupNotificationBuilders(); requester = DownloadRequester.getInstance(); + startForeground(NOTIFICATION_ID, updateNotifications()); } @Override @@ -353,7 +354,7 @@ public class DownloadService extends Service { /** * Updates the contents of the service's notifications. Should be called - * before setupNotificationBuilders. + * after setupNotificationBuilders. */ private Notification updateNotifications() { if (notificationCompatBuilder == null) { 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 03beec06a..0ec135923 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 @@ -24,6 +24,7 @@ import android.os.Vibrator; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.StringRes; +import android.support.v4.content.ContextCompat; import android.support.v4.media.MediaBrowserCompat; import android.support.v4.media.MediaBrowserServiceCompat; import android.support.v4.media.MediaDescriptionCompat; @@ -49,6 +50,7 @@ import java.util.List; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.R; import de.danoeh.antennapod.core.event.MessageEvent; +import de.danoeh.antennapod.core.event.ServiceEvent; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.Feed; import de.danoeh.antennapod.core.feed.FeedItem; @@ -314,6 +316,34 @@ public class PlaybackService extends MediaBrowserServiceCompat { flavorHelper.initializeMediaPlayer(PlaybackService.this); mediaSession.setActive(true); + + NotificationCompat.Builder notificationBuilder = createBasicNotification(); + startForeground(NOTIFICATION_ID, notificationBuilder.build()); + EventBus.getDefault().post(new ServiceEvent(ServiceEvent.Action.SERVICE_STARTED)); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + long currentlyPlayingMedia = PlaybackPreferences.getCurrentlyPlayingMedia(); + Playable lastPlayable = Playable.PlayableUtils.createInstanceFromPreferences( + getApplicationContext(), (int) currentlyPlayingMedia, prefs); + setupNotification(lastPlayable); + } + + private NotificationCompat.Builder createBasicNotification() { + final int smallIcon = ClientConfig.playbackServiceCallbacks.getNotificationIconResource(getApplicationContext()); + + final PendingIntent pIntent = PendingIntent.getActivity(this, 0, + PlaybackService.getPlayerActivityIntent(this), + PendingIntent.FLAG_UPDATE_CURRENT); + + return new NotificationCompat.Builder( + this, NotificationUtils.CHANNEL_ID_PLAYING) + .setContentTitle(getString(R.string.app_name)) + .setContentText("Service is running") // Just in case the notification is not updated (should not occur) + .setOngoing(false) + .setContentIntent(pIntent) + .setWhen(0) // we don't need the time + .setSmallIcon(smallIcon) + .setPriority(NotificationCompat.PRIORITY_MIN); } @Override @@ -568,8 +598,10 @@ public class PlaybackService extends MediaBrowserServiceCompat { } public void notifyVideoSurfaceAbandoned() { - stopForeground(!UserPreferences.isPersistNotify()); + mediaPlayer.pause(true, false); mediaPlayer.resetVideoSurface(); + setupNotification(getPlayable()); + stopForeground(!UserPreferences.isPersistNotify()); } private final PlaybackServiceTaskManager.PSTMCallback taskManagerCallback = new PlaybackServiceTaskManager.PSTMCallback() { @@ -763,6 +795,15 @@ public class PlaybackService extends MediaBrowserServiceCompat { } }; + public static void startService(final Context context, final Playable media, boolean startWhenPrepared, boolean shouldStream) { + Intent launchIntent = new Intent(context, PlaybackService.class); + launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); + launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, startWhenPrepared); + launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, shouldStream); + launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, true); + ContextCompat.startForegroundService(context, launchIntent); + } + private Playable getNextInQueue(final Playable currentMedia) { if (!(currentMedia instanceof FeedMedia)) { Log.d(TAG, "getNextInQueue(), but playable not an instance of FeedMedia, so not proceeding"); @@ -1172,10 +1213,10 @@ public class PlaybackService extends MediaBrowserServiceCompat { * Prepares notification and starts the service in the foreground. */ private void setupNotification(final PlaybackServiceMediaPlayer.PSMPInfo info) { - final PendingIntent pIntent = PendingIntent.getActivity(this, 0, - PlaybackService.getPlayerActivityIntent(this), - PendingIntent.FLAG_UPDATE_CURRENT); + setupNotification(info.playable); + } + private synchronized void setupNotification(final Playable playable) { if (notificationSetupThread != null) { notificationSetupThread.interrupt(); } @@ -1185,12 +1226,12 @@ public class PlaybackService extends MediaBrowserServiceCompat { @Override public void run() { Log.d(TAG, "Starting background work"); - if (info.playable != null) { + if (playable != null) { int iconSize = getResources().getDimensionPixelSize( android.R.dimen.notification_large_icon_width); try { icon = Glide.with(PlaybackService.this) - .load(info.playable.getImageLocation()) + .load(playable.getImageLocation()) .asBitmap() .diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY) .centerCrop() @@ -1209,24 +1250,18 @@ public class PlaybackService extends MediaBrowserServiceCompat { return; } PlayerStatus playerStatus = mediaPlayer.getPlayerStatus(); - final int smallIcon = ClientConfig.playbackServiceCallbacks.getNotificationIconResource(getApplicationContext()); - if (!Thread.currentThread().isInterrupted() && started && info.playable != null) { - String contentText = info.playable.getEpisodeTitle(); - String contentTitle = info.playable.getFeedTitle(); + if (!Thread.currentThread().isInterrupted() && started && playable != null) { + String contentText = playable.getEpisodeTitle(); + String contentTitle = playable.getFeedTitle(); Notification notification; // Builder is v7, even if some not overwritten methods return its parent's v4 interface - NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder( - PlaybackService.this, NotificationUtils.CHANNEL_ID_PLAYING) - .setContentTitle(contentTitle) + NotificationCompat.Builder notificationBuilder = createBasicNotification(); + notificationBuilder.setContentTitle(contentTitle) .setContentText(contentText) - .setOngoing(false) - .setContentIntent(pIntent) - .setLargeIcon(icon) - .setSmallIcon(smallIcon) - .setWhen(0) // we don't need the time - .setPriority(UserPreferences.getNotifyPriority()); // set notification priority + .setPriority(UserPreferences.getNotifyPriority()) + .setLargeIcon(icon); // set notification priority IntList compactActionList = new IntList(); int numActions = 0; // we start and 0 and then increment by 1 for each call to addAction diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java index 573954412..74f69406f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; +import android.support.v4.content.ContextCompat; import android.util.Log; import java.util.ArrayList; @@ -123,16 +124,7 @@ public final class DBTasks { media); } } - // Start playback Service - Intent launchIntent = new Intent(context, PlaybackService.class); - launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); - launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, - startWhenPrepared); - launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, - shouldStream); - launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, - true); - context.startService(launchIntent); + PlaybackService.startService(context, media, startWhenPrepared, shouldStream); if (showPlayer) { // Launch media player context.startActivity(PlaybackService.getPlayerActivityIntent( 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 a8fd79fda..df618e252 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 @@ -4,6 +4,7 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; import android.text.TextUtils; import android.util.Log; import android.webkit.URLUtil; @@ -81,7 +82,7 @@ public class DownloadRequester { Intent launchIntent = new Intent(context, DownloadService.class); launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request); - context.startService(launchIntent); + ContextCompat.startForegroundService(context, launchIntent); return true; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/NotificationUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/NotificationUtils.java index f3824294f..e81b03d77 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/NotificationUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/NotificationUtils.java @@ -13,6 +13,7 @@ public class NotificationUtils { public static final String CHANNEL_ID_DOWNLOADING = "downloading"; public static final String CHANNEL_ID_PLAYING = "playing"; public static final String CHANNEL_ID_ERROR = "error"; + public static final String CHANNEL_ID_GPODNET = "gpodnet"; public static void createChannels(Context context) { if (android.os.Build.VERSION.SDK_INT < 26) { @@ -25,6 +26,7 @@ public class NotificationUtils { mNotificationManager.createNotificationChannel(createChannelDownloading(context)); mNotificationManager.createNotificationChannel(createChannelPlaying(context)); mNotificationManager.createNotificationChannel(createChannelError(context)); + mNotificationManager.createNotificationChannel(createChannelGpodnet(context)); } } @@ -59,4 +61,12 @@ public class NotificationUtils { mChannel.setDescription(c.getString(R.string.notification_channel_error_description)); return mChannel; } + + @RequiresApi(api = Build.VERSION_CODES.O) + private static NotificationChannel createChannelGpodnet(Context c) { + NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_GPODNET, + c.getString(R.string.notification_channel_gpodnet), NotificationManager.IMPORTANCE_MIN); + mChannel.setDescription(c.getString(R.string.notification_channel_gpodnet_description)); + return mChannel; + } } 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 a160b4f0a..79772f015 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 @@ -14,6 +14,7 @@ import android.os.Build; import android.os.IBinder; import android.preference.PreferenceManager; import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -59,7 +60,7 @@ public abstract class PlaybackController { private PlaybackService playbackService; private Playable media; - private PlayerStatus status; + private PlayerStatus status = PlayerStatus.STOPPED; private final ScheduledThreadPoolExecutor schedExecutor; private static final int SCHED_EX_POOLSIZE = 1; @@ -69,6 +70,7 @@ public abstract class PlaybackController { private boolean mediaInfoLoaded = false; private boolean released = false; + private boolean initialized = false; private Subscription serviceBinder; @@ -92,10 +94,14 @@ public abstract class PlaybackController { } /** - * Creates a new connection to the playbackService. Should be called in the - * activity's onResume() method. + * Creates a new connection to the playbackService. */ - public void init() { + public synchronized void init() { + if (initialized) { + return; + } + initialized = true; + activity.registerReceiver(statusUpdate, new IntentFilter( PlaybackService.ACTION_PLAYER_STATUS_CHANGED)); @@ -167,7 +173,7 @@ public abstract class PlaybackController { */ private void bindToService() { Log.d(TAG, "Trying to connect to service"); - if(serviceBinder != null) { + if (serviceBinder != null) { serviceBinder.unsubscribe(); } serviceBinder = Observable.fromCallable(this::getPlayLastPlayedMediaIntent) @@ -178,7 +184,7 @@ public abstract class PlaybackController { if (!PlaybackService.started) { if (intent != null) { Log.d(TAG, "Calling start service"); - activity.startService(intent); + ContextCompat.startForegroundService(activity, intent); bound = activity.bindService(intent, mConnection, 0); } else { status = PlayerStatus.STOPPED; @@ -194,32 +200,37 @@ public abstract class PlaybackController { }, error -> Log.e(TAG, Log.getStackTraceString(error))); } + private Playable getMediaFromPreferences() { + long currentlyPlayingMedia = PlaybackPreferences.getCurrentlyPlayingMedia(); + if (currentlyPlayingMedia != PlaybackPreferences.NO_MEDIA_PLAYING) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( + activity.getApplicationContext()); + return PlayableUtils.createInstanceFromPreferences(activity, + (int) currentlyPlayingMedia, prefs); + } + return null; + } + /** * Returns an intent that starts the PlaybackService and plays the last * played media or null if no last played media could be found. */ private Intent getPlayLastPlayedMediaIntent() { Log.d(TAG, "Trying to restore last played media"); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( - activity.getApplicationContext()); - long currentlyPlayingMedia = PlaybackPreferences.getCurrentlyPlayingMedia(); - if (currentlyPlayingMedia != PlaybackPreferences.NO_MEDIA_PLAYING) { - Playable media = PlayableUtils.createInstanceFromPreferences(activity, - (int) currentlyPlayingMedia, prefs); - if (media != null) { - Intent serviceIntent = new Intent(activity, PlaybackService.class); - serviceIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); - serviceIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, false); - serviceIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, true); - boolean fileExists = media.localFileAvailable(); - boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream(); - if (!fileExists && !lastIsStream && media instanceof FeedMedia) { - DBTasks.notifyMissingFeedMediaFile(activity, (FeedMedia) media); - } - serviceIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, - lastIsStream || !fileExists); - return serviceIntent; + Playable media = getMediaFromPreferences(); + if (media != null) { + Intent serviceIntent = new Intent(activity, PlaybackService.class); + serviceIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); + serviceIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, false); + serviceIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, true); + boolean fileExists = media.localFileAvailable(); + boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream(); + if (!fileExists && !lastIsStream && media instanceof FeedMedia) { + DBTasks.notifyMissingFeedMediaFile(activity, (FeedMedia) media); } + serviceIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, + lastIsStream || !fileExists); + return serviceIntent; } Log.d(TAG, "No last played media found"); return null; @@ -511,7 +522,7 @@ public abstract class PlaybackController { "PlaybackService has no media object. Trying to restore last played media."); Intent serviceIntent = getPlayLastPlayedMediaIntent(); if (serviceIntent != null) { - activity.startService(serviceIntent); + ContextCompat.startForegroundService(activity, serviceIntent); } } */ @@ -576,6 +587,7 @@ public abstract class PlaybackController { public void playPause() { if (playbackService == null) { + PlaybackService.startService(activity, media, true, false); Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!"); return; } @@ -609,6 +621,8 @@ public abstract class PlaybackController { public int getPosition() { if (playbackService != null) { return playbackService.getCurrentPosition(); + } else if (media != null) { + return media.getPosition(); } else { return PlaybackService.INVALID_TIME; } @@ -617,12 +631,17 @@ public abstract class PlaybackController { public int getDuration() { if (playbackService != null) { return playbackService.getDuration(); + } else if (media != null) { + return media.getDuration(); } else { return PlaybackService.INVALID_TIME; } } public Playable getMedia() { + if (media == null) { + media = getMediaFromPreferences(); + } return media; } @@ -714,8 +733,13 @@ public abstract class PlaybackController { } public boolean isPlayingVideoLocally() { - return playbackService != null && PlaybackService.getCurrentMediaType() == MediaType.VIDEO - && !PlaybackService.isCasting(); + if (PlaybackService.isCasting()) { + return false; + } else if (playbackService != null) { + return PlaybackService.getCurrentMediaType() == MediaType.VIDEO; + } else { + return getMedia() != null && getMedia().getMediaType() == MediaType.VIDEO; + } } public Pair getVideoSize() { @@ -755,6 +779,18 @@ public abstract class PlaybackController { } } + public void resumeServiceNotRunning() { + if (getMedia().getMediaType() == MediaType.AUDIO) { + TypedArray res = activity.obtainStyledAttributes(new int[]{ + de.danoeh.antennapod.core.R.attr.av_play_big}); + getPlayButton().setImageResource( + res.getResourceId(0, de.danoeh.antennapod.core.R.drawable.ic_play_arrow_grey600_36dp)); + res.recycle(); + } else { + getPlayButton().setImageResource(R.drawable.ic_av_play_circle_outline_80dp); + } + } + /** * Refreshes the current position of the media file that is playing. */ -- cgit v1.2.3 From 2190101cf949d58057e0f0e2ca24dbe81d201426 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Thu, 3 May 2018 18:47:57 +0200 Subject: Added JobScheduler for feed updates --- .../core/preferences/UserPreferences.java | 70 ++++++++++++++++++---- .../core/service/FeedUpdateJobService.java | 30 ++++++++++ 2 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java (limited to 'core/src/main/java/de/danoeh/antennapod') 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 a93012d59..17362c721 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 @@ -2,17 +2,23 @@ package de.danoeh.antennapod.core.preferences; import android.app.AlarmManager; import android.app.PendingIntent; +import android.app.job.JobInfo; +import android.app.job.JobScheduler; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.os.Build; import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.annotation.IntRange; import android.support.annotation.NonNull; +import android.support.annotation.RequiresApi; import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import android.util.Log; +import de.danoeh.antennapod.core.service.FeedUpdateJobService; import org.json.JSONArray; import org.json.JSONException; @@ -103,6 +109,10 @@ public class UserPreferences { private static final String PREF_DATA_FOLDER = "prefDataFolder"; public static final String PREF_IMAGE_CACHE_SIZE = "prefImageCacheSize"; + // JobScheduler + private static final int JOB_ID_FEED_UPDATE = 42; + private static final float JOB_SCHEDULER_TIME_VARIATION = 1.5f; + // Mediaplayer private static final String PREF_PLAYBACK_SPEED = "prefPlaybackSpeed"; private static final String PREF_FAST_FORWARD_SECS = "prefFastForwardSecs"; @@ -797,18 +807,31 @@ public class UserPreferences { */ private static void restartUpdateIntervalAlarm(long triggerAtMillis, long intervalMillis) { Log.d(TAG, "Restarting update alarm."); + + if (intervalMillis <= 0) { + Log.d(TAG, "Automatic update was deactivated"); + return; + } + + if (Build.VERSION.SDK_INT >= 23) { + JobInfo.Builder builder = getFeedUpdateJobBuilder(); + builder.setOverrideDeadline((long) (triggerAtMillis * JOB_SCHEDULER_TIME_VARIATION)); + JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); + if (jobScheduler != null) { + jobScheduler.schedule(builder.build()); + Log.d(TAG, "JobScheduler was set for " + triggerAtMillis); + } + return; + } + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, FeedUpdateReceiver.class); PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, intent, 0); alarmManager.cancel(updateIntent); - if (intervalMillis > 0) { - alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + triggerAtMillis, - updateIntent); - Log.d(TAG, "Changed alarm to new interval " + TimeUnit.MILLISECONDS.toHours(intervalMillis) + " h"); - } else { - Log.d(TAG, "Automatic update was deactivated"); - } + alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + triggerAtMillis, + updateIntent); + Log.d(TAG, "Changed alarm to new interval " + TimeUnit.MILLISECONDS.toHours(intervalMillis) + " h"); } /** @@ -816,10 +839,6 @@ public class UserPreferences { */ private static void restartUpdateTimeOfDayAlarm(int hoursOfDay, int minute) { Log.d(TAG, "Restarting update alarm."); - AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, - new Intent(context, FeedUpdateReceiver.class), 0); - alarmManager.cancel(updateIntent); Calendar now = Calendar.getInstance(); Calendar alarm = (Calendar)now.clone(); @@ -828,6 +847,24 @@ public class UserPreferences { if (alarm.before(now) || alarm.equals(now)) { alarm.add(Calendar.DATE, 1); } + + if (Build.VERSION.SDK_INT >= 23) { + JobInfo.Builder builder = getFeedUpdateJobBuilder(); + long triggerAtMillis = alarm.getTimeInMillis() - now.getTimeInMillis(); + builder.setOverrideDeadline((long) (triggerAtMillis * JOB_SCHEDULER_TIME_VARIATION)); + JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); + if (jobScheduler != null) { + jobScheduler.schedule(builder.build()); + Log.d(TAG, "JobScheduler was set for " + triggerAtMillis); + } + return; + } + + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, + new Intent(context, FeedUpdateReceiver.class), 0); + alarmManager.cancel(updateIntent); + Log.d(TAG, "Alarm set for: " + alarm.toString() + " : " + alarm.getTimeInMillis()); alarmManager.set(AlarmManager.RTC_WAKEUP, alarm.getTimeInMillis(), @@ -835,6 +872,15 @@ public class UserPreferences { Log.d(TAG, "Changed alarm to new time of day " + hoursOfDay + ":" + minute); } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private static JobInfo.Builder getFeedUpdateJobBuilder() { + ComponentName serviceComponent = new ComponentName(context, FeedUpdateJobService.class); + JobInfo.Builder builder = new JobInfo.Builder(JOB_ID_FEED_UPDATE, serviceComponent); + builder.setMinimumLatency(15 * 60 * 1000); + builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); + return builder; + } + /** * Reads episode cache size as it is saved in the episode_cache_size_values array. */ diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java new file mode 100644 index 000000000..d9a7e31cc --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java @@ -0,0 +1,30 @@ +package de.danoeh.antennapod.core.service; + +import android.app.job.JobParameters; +import android.app.job.JobService; +import android.os.Build; +import android.support.annotation.RequiresApi; +import android.util.Log; +import de.danoeh.antennapod.core.ClientConfig; +import de.danoeh.antennapod.core.preferences.UserPreferences; +import de.danoeh.antennapod.core.storage.DBTasks; + +@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) +public class FeedUpdateJobService extends JobService { + private static final String TAG = "FeedUpdateJobService"; + + @Override + public boolean onStartJob(JobParameters params) { + Log.d(TAG, "Job started"); + ClientConfig.initialize(getApplicationContext()); + DBTasks.refreshAllFeeds(getApplicationContext(), null); + UserPreferences.restartUpdateAlarm(false); + return true; + } + + @Override + public boolean onStopJob(JobParameters params) { + return true; + } + +} -- cgit v1.2.3 From ffdfefc35d194aee0890e1640ad394f743bf030f Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Thu, 3 May 2018 19:36:40 +0200 Subject: Fixed fresh install crash --- .../de/danoeh/antennapod/core/util/playback/PlaybackController.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 79772f015..36253d075 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 @@ -780,6 +780,9 @@ public abstract class PlaybackController { } public void resumeServiceNotRunning() { + if (getMedia() == null) { + return; + } if (getMedia().getMediaType() == MediaType.AUDIO) { TypedArray res = activity.obtainStyledAttributes(new int[]{ de.danoeh.antennapod.core.R.attr.av_play_big}); -- cgit v1.2.3 From 9f0d187efdba753e110dbc32ed9ba58c2fe4ce66 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 4 May 2018 13:57:52 +0200 Subject: Fix empty contentEncoded This code duplication was forgotten in #2607 --- .../main/java/de/danoeh/antennapod/core/feed/FeedMedia.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 2d551e1b2..a22422596 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 @@ -554,15 +554,9 @@ public class FeedMedia extends FeedFile implements Playable { public Callable loadShownotes() { return () -> { if (item == null) { - item = DBReader.getFeedItem( - itemID); + item = DBReader.getFeedItem(itemID); } - if (item.getContentEncoded() == null || item.getDescription() == null) { - DBReader.loadExtraInformationOfFeedItem( - item); - - } - return (item.getContentEncoded() != null) ? item.getContentEncoded() : item.getDescription(); + return item.loadShownotes().call(); }; } -- cgit v1.2.3 From f66e19845c123160ba6174c2dec337070a6d9b22 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 4 May 2018 14:36:32 +0200 Subject: Review changes --- .../core/preferences/UserPreferences.java | 23 +++++++++++++--------- .../core/service/playback/PlaybackService.java | 6 ++++++ .../core/util/playback/PlaybackController.java | 12 +++++++++-- 3 files changed, 30 insertions(+), 11 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 17362c721..d2ef5d2a6 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 @@ -111,7 +111,6 @@ public class UserPreferences { // JobScheduler private static final int JOB_ID_FEED_UPDATE = 42; - private static final float JOB_SCHEDULER_TIME_VARIATION = 1.5f; // Mediaplayer private static final String PREF_PLAYBACK_SPEED = "prefPlaybackSpeed"; @@ -813,13 +812,19 @@ public class UserPreferences { return; } - if (Build.VERSION.SDK_INT >= 23) { - JobInfo.Builder builder = getFeedUpdateJobBuilder(); - builder.setOverrideDeadline((long) (triggerAtMillis * JOB_SCHEDULER_TIME_VARIATION)); + if (Build.VERSION.SDK_INT >= 24) { JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); if (jobScheduler != null) { - jobScheduler.schedule(builder.build()); - Log.d(TAG, "JobScheduler was set for " + triggerAtMillis); + JobInfo oldJob = jobScheduler.getPendingJob(JOB_ID_FEED_UPDATE); + if (oldJob == null || oldJob.getIntervalMillis() != intervalMillis) { + JobInfo.Builder builder = getFeedUpdateJobBuilder(); + builder.setPeriodic(intervalMillis); + jobScheduler.cancel(JOB_ID_FEED_UPDATE); + jobScheduler.schedule(builder.build()); + Log.d(TAG, "JobScheduler was set at interval " + intervalMillis); + } else { + Log.d(TAG, "JobScheduler was already set at interval " + intervalMillis + ", ignoring."); + } } return; } @@ -848,12 +853,13 @@ public class UserPreferences { alarm.add(Calendar.DATE, 1); } - if (Build.VERSION.SDK_INT >= 23) { + if (Build.VERSION.SDK_INT >= 24) { JobInfo.Builder builder = getFeedUpdateJobBuilder(); long triggerAtMillis = alarm.getTimeInMillis() - now.getTimeInMillis(); - builder.setOverrideDeadline((long) (triggerAtMillis * JOB_SCHEDULER_TIME_VARIATION)); + builder.setMinimumLatency(triggerAtMillis); JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); if (jobScheduler != null) { + jobScheduler.cancel(JOB_ID_FEED_UPDATE); jobScheduler.schedule(builder.build()); Log.d(TAG, "JobScheduler was set for " + triggerAtMillis); } @@ -876,7 +882,6 @@ public class UserPreferences { private static JobInfo.Builder getFeedUpdateJobBuilder() { ComponentName serviceComponent = new ComponentName(context, FeedUpdateJobService.class); JobInfo.Builder builder = new JobInfo.Builder(JOB_ID_FEED_UPDATE, serviceComponent); - builder.setMinimumLatency(15 * 60 * 1000); builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); return builder; } 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 0ec135923..5801ee3d5 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 @@ -795,6 +795,12 @@ public class PlaybackService extends MediaBrowserServiceCompat { } }; + public static void startIfNotRunning(final Context context, final Playable media, boolean startWhenPrepared, boolean shouldStream) { + if (!isRunning) { + startService(context, media, startWhenPrepared, shouldStream); + } + } + public static void startService(final Context context, final Playable media, boolean startWhenPrepared, boolean shouldStream) { Intent launchIntent = new Intent(context, PlaybackService.class); launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); 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 36253d075..0b874be1f 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 @@ -96,7 +96,15 @@ public abstract class PlaybackController { /** * Creates a new connection to the playbackService. */ - public synchronized void init() { + public void init() { + if (PlaybackService.isRunning) { + initServiceRunning(); + } else { + initServiceNotRunning(); + } + } + + private synchronized void initServiceRunning() { if (initialized) { return; } @@ -779,7 +787,7 @@ public abstract class PlaybackController { } } - public void resumeServiceNotRunning() { + private void initServiceNotRunning() { if (getMedia() == null) { return; } -- cgit v1.2.3 From a97b524a05ad40335822b9cb492692b2386d89de Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 4 May 2018 22:23:15 +0200 Subject: Review changes #2 --- .../core/preferences/UserPreferences.java | 17 ++++++++++++----- .../core/receiver/FeedUpdateReceiver.java | 9 ++------- .../core/service/FeedUpdateJobService.java | 4 ++-- .../de/danoeh/antennapod/core/storage/DBTasks.java | 1 + .../antennapod/core/util/FeedUpdateUtils.java | 21 +++++++++++++++++++++ 5 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java (limited to 'core/src/main/java/de/danoeh/antennapod') 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 d2ef5d2a6..6012e5b49 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 @@ -807,11 +807,6 @@ public class UserPreferences { private static void restartUpdateIntervalAlarm(long triggerAtMillis, long intervalMillis) { Log.d(TAG, "Restarting update alarm."); - if (intervalMillis <= 0) { - Log.d(TAG, "Automatic update was deactivated"); - return; - } - if (Build.VERSION.SDK_INT >= 24) { JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); if (jobScheduler != null) { @@ -820,6 +815,12 @@ public class UserPreferences { JobInfo.Builder builder = getFeedUpdateJobBuilder(); builder.setPeriodic(intervalMillis); jobScheduler.cancel(JOB_ID_FEED_UPDATE); + + if (intervalMillis <= 0) { + Log.d(TAG, "Automatic update was deactivated"); + return; + } + jobScheduler.schedule(builder.build()); Log.d(TAG, "JobScheduler was set at interval " + intervalMillis); } else { @@ -833,6 +834,12 @@ public class UserPreferences { Intent intent = new Intent(context, FeedUpdateReceiver.class); PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, intent, 0); alarmManager.cancel(updateIntent); + + if (intervalMillis <= 0) { + Log.d(TAG, "Automatic update was deactivated"); + return; + } + alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + triggerAtMillis, updateIntent); diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java index 9bbeb7c88..f1a316954 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java +++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java @@ -7,8 +7,7 @@ import android.util.Log; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.storage.DBTasks; -import de.danoeh.antennapod.core.util.NetworkUtils; +import de.danoeh.antennapod.core.util.FeedUpdateUtils; /** * Refreshes all feeds when it receives an intent @@ -21,11 +20,7 @@ public class FeedUpdateReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Log.d(TAG, "Received intent"); ClientConfig.initialize(context); - if (NetworkUtils.networkAvailable() && NetworkUtils.isDownloadAllowed()) { - DBTasks.refreshAllFeeds(context, null); - } else { - Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed"); - } + FeedUpdateUtils.startAutoUpdate(context); UserPreferences.restartUpdateAlarm(false); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java index d9a7e31cc..2d418218d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java @@ -7,7 +7,7 @@ import android.support.annotation.RequiresApi; import android.util.Log; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.preferences.UserPreferences; -import de.danoeh.antennapod.core.storage.DBTasks; +import de.danoeh.antennapod.core.util.FeedUpdateUtils; @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public class FeedUpdateJobService extends JobService { @@ -17,7 +17,7 @@ public class FeedUpdateJobService extends JobService { public boolean onStartJob(JobParameters params) { Log.d(TAG, "Job started"); ClientConfig.initialize(getApplicationContext()); - DBTasks.refreshAllFeeds(getApplicationContext(), null); + FeedUpdateUtils.startAutoUpdate(getApplicationContext()); UserPreferences.restartUpdateAlarm(false); return true; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java index 74f69406f..b6a203cb8 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java @@ -124,6 +124,7 @@ public final class DBTasks { media); } } + // Needs to be called even if the service is already running to deliver the new media intent PlaybackService.startService(context, media, startWhenPrepared, shouldStream); if (showPlayer) { // Launch media player diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java new file mode 100644 index 000000000..4d2dde88c --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java @@ -0,0 +1,21 @@ +package de.danoeh.antennapod.core.util; + +import android.content.Context; +import android.util.Log; +import de.danoeh.antennapod.core.storage.DBTasks; + +public class FeedUpdateUtils { + private static final String TAG = "FeedUpdateUtils"; + + private FeedUpdateUtils() { + + } + + public static void startAutoUpdate(Context context) { + if (NetworkUtils.networkAvailable() && NetworkUtils.isDownloadAllowed()) { + DBTasks.refreshAllFeeds(context, null); + } else { + Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed"); + } + } +} -- cgit v1.2.3 From eeb032e9382535e544eb16ea74ae9733302483df Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 4 May 2018 22:41:53 +0200 Subject: Notify system when job is done --- .../core/receiver/FeedUpdateReceiver.java | 2 +- .../core/service/FeedUpdateJobService.java | 9 +++- .../de/danoeh/antennapod/core/storage/DBTasks.java | 56 ++++++++++++---------- .../antennapod/core/util/FeedUpdateUtils.java | 8 +++- 4 files changed, 45 insertions(+), 30 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java index f1a316954..67f6d9348 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java +++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java @@ -20,7 +20,7 @@ public class FeedUpdateReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Log.d(TAG, "Received intent"); ClientConfig.initialize(context); - FeedUpdateUtils.startAutoUpdate(context); + FeedUpdateUtils.startAutoUpdate(context, false); UserPreferences.restartUpdateAlarm(false); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java index 2d418218d..3fc3551ee 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java @@ -17,8 +17,13 @@ public class FeedUpdateJobService extends JobService { public boolean onStartJob(JobParameters params) { Log.d(TAG, "Job started"); ClientConfig.initialize(getApplicationContext()); - FeedUpdateUtils.startAutoUpdate(getApplicationContext()); - UserPreferences.restartUpdateAlarm(false); + + new Thread(() -> { + FeedUpdateUtils.startAutoUpdate(getApplicationContext(), true); + UserPreferences.restartUpdateAlarm(false); + jobFinished(params, false); // needsReschedule = false + }).start(); + return true; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java index b6a203cb8..b1937985f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java @@ -151,36 +151,42 @@ public final class DBTasks { * @param context Might be used for accessing the database * @param feeds List of Feeds that should be refreshed. */ - public static void refreshAllFeeds(final Context context, - final List feeds) { + public static void refreshAllFeeds(final Context context, final List feeds) { + new Thread(() -> refreshAllFeedsSynchronously(context, feeds)).start(); + } + + /** + * Refreshes a given list of Feeds in the current Thread. This method might ignore subsequent calls if it is still + * enqueuing Feeds for download from a previous call. MUST NOT be executed from main thread. + * + * @param context Might be used for accessing the database + * @param feeds List of Feeds that should be refreshed. + */ + public static void refreshAllFeedsSynchronously(final Context context, final List feeds) { if (isRefreshing.compareAndSet(false, true)) { - new Thread() { - public void run() { - if (feeds != null) { - refreshFeeds(context, feeds); - } else { - refreshFeeds(context, DBReader.getFeedList()); - } - isRefreshing.set(false); + if (feeds != null) { + refreshFeeds(context, feeds); + } else { + refreshFeeds(context, DBReader.getFeedList()); + } + isRefreshing.set(false); - SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE); - prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply(); + SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE); + prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply(); - if (FlattrUtils.hasToken()) { - Log.d(TAG, "Flattring all pending things."); - new FlattrClickWorker(context).executeAsync(); // flattr pending things + if (FlattrUtils.hasToken()) { + Log.d(TAG, "Flattring all pending things."); + new FlattrClickWorker(context).executeAsync(); // flattr pending things - Log.d(TAG, "Fetching flattr status."); - new FlattrStatusFetcher(context).start(); + Log.d(TAG, "Fetching flattr status."); + new FlattrStatusFetcher(context).start(); - } - if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { - GpodnetSyncService.sendSyncIntent(context); - } - Log.d(TAG, "refreshAllFeeds autodownload"); - autodownloadUndownloadedItems(context); - } - }.start(); + } + if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { + GpodnetSyncService.sendSyncIntent(context); + } + Log.d(TAG, "refreshAllFeeds autodownload"); + autodownloadUndownloadedItems(context); } else { Log.d(TAG, "Ignoring request to refresh all feeds: Refresh lock is locked"); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java index 4d2dde88c..a57ab2ce6 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java @@ -11,9 +11,13 @@ public class FeedUpdateUtils { } - public static void startAutoUpdate(Context context) { + public static void startAutoUpdate(Context context, boolean synchronously) { if (NetworkUtils.networkAvailable() && NetworkUtils.isDownloadAllowed()) { - DBTasks.refreshAllFeeds(context, null); + if (synchronously) { + DBTasks.refreshAllFeedsSynchronously(context, null); + } else { + DBTasks.refreshAllFeeds(context, null); + } } else { Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed"); } -- cgit v1.2.3 From ca3d6b9a3deed4479160edbe823644513b7550a5 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Fri, 4 May 2018 22:47:53 +0200 Subject: Persist job through reboot --- .../main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java | 1 + 1 file changed, 1 insertion(+) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 6012e5b49..07a62b743 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 @@ -890,6 +890,7 @@ public class UserPreferences { ComponentName serviceComponent = new ComponentName(context, FeedUpdateJobService.class); JobInfo.Builder builder = new JobInfo.Builder(JOB_ID_FEED_UPDATE, serviceComponent); builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); + builder.setPersisted(true); return builder; } -- cgit v1.2.3 From 0b54d97a0a9a2caeb51c85a68749df9afe0dbdb3 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 5 May 2018 13:39:57 +0200 Subject: Switched widget to JobIntentService --- .../core/service/playback/PlaybackService.java | 24 ++++------------------ .../antennapod/core/util/playback/Playable.java | 18 ++++++++++++++++ .../core/util/playback/PlaybackController.java | 15 ++------------ 3 files changed, 24 insertions(+), 33 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 5801ee3d5..a34ce4943 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 @@ -77,8 +77,6 @@ import de.greenrobot.event.EventBus; * Controls the MediaPlayer that plays a FeedMedia-file */ public class PlaybackService extends MediaBrowserServiceCompat { - public static final String FORCE_WIDGET_UPDATE = "de.danoeh.antennapod.FORCE_WIDGET_UPDATE"; - public static final String STOP_WIDGET_UPDATE = "de.danoeh.antennapod.STOP_WIDGET_UPDATE"; /** * Logging tag */ @@ -321,11 +319,8 @@ public class PlaybackService extends MediaBrowserServiceCompat { startForeground(NOTIFICATION_ID, notificationBuilder.build()); EventBus.getDefault().post(new ServiceEvent(ServiceEvent.Action.SERVICE_STARTED)); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - long currentlyPlayingMedia = PlaybackPreferences.getCurrentlyPlayingMedia(); - Playable lastPlayable = Playable.PlayableUtils.createInstanceFromPreferences( - getApplicationContext(), (int) currentlyPlayingMedia, prefs); - setupNotification(lastPlayable); + + setupNotification(Playable.PlayableUtils.createInstanceFromPreferences(getApplicationContext())); } private NotificationCompat.Builder createBasicNotification() { @@ -635,7 +630,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { @Override public void onWidgetUpdaterTick() { - updateWidget(); + //PlayerWidgetJobService.updateWidget(getBaseContext()); // TODO: Not accessible from core module } @Override @@ -697,7 +692,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { Intent statusUpdate = new Intent(ACTION_PLAYER_STATUS_CHANGED); // statusUpdate.putExtra(EXTRA_NEW_PLAYER_STATUS, newInfo.playerStatus.ordinal()); sendBroadcast(statusUpdate); - updateWidget(); + //PlayerWidgetJobService.updateWidget(getBaseContext()); // TODO: Not accessible from core module bluetoothNotifyChange(newInfo, AVRCP_ACTION_PLAYER_STATUS_CHANGED); bluetoothNotifyChange(newInfo, AVRCP_ACTION_META_CHANGED); } @@ -855,7 +850,6 @@ public class PlaybackService extends MediaBrowserServiceCompat { if (!isCasting) { stopForeground(true); } - stopWidgetUpdater(); } if (mediaType == null) { sendNotificationBroadcast(NOTIFICATION_TYPE_PLAYBACK_END, 0); @@ -1402,16 +1396,6 @@ public class PlaybackService extends MediaBrowserServiceCompat { } } - private void stopWidgetUpdater() { - taskManager.cancelWidgetUpdater(); - sendBroadcast(new Intent(STOP_WIDGET_UPDATE)); - } - - private void updateWidget() { - PlaybackService.this.sendBroadcast(new Intent( - FORCE_WIDGET_UPDATE)); - } - public boolean sleepTimerActive() { return taskManager.isSleepTimerActive(); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java index 279c56338..bb9896f25 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java @@ -3,6 +3,7 @@ package de.danoeh.antennapod.core.util.playback; import android.content.Context; import android.content.SharedPreferences; import android.os.Parcelable; +import android.preference.PreferenceManager; import android.util.Log; import java.util.List; @@ -11,6 +12,7 @@ import de.danoeh.antennapod.core.asynctask.ImageResource; import de.danoeh.antennapod.core.feed.Chapter; import de.danoeh.antennapod.core.feed.FeedMedia; import de.danoeh.antennapod.core.feed.MediaType; +import de.danoeh.antennapod.core.preferences.PlaybackPreferences; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.util.ShownotesProvider; @@ -175,6 +177,22 @@ public interface Playable extends Parcelable, class PlayableUtils { private static final String TAG = "PlayableUtils"; + /** + * Restores a playable object from a sharedPreferences file. This method might load data from the database, + * depending on the type of playable that was restored. + * + * @return The restored Playable object + */ + public static Playable createInstanceFromPreferences(Context context) { + long currentlyPlayingMedia = PlaybackPreferences.getCurrentlyPlayingMedia(); + if (currentlyPlayingMedia != PlaybackPreferences.NO_MEDIA_PLAYING) { + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()); + return PlayableUtils.createInstanceFromPreferences(context, + (int) currentlyPlayingMedia, prefs); + } + return null; + } + /** * Restores a playable object from a sharedPreferences file. This method might load data from the database, * depending on the type of playable that was restored. 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 0b874be1f..d1d6b5c63 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 @@ -208,24 +208,13 @@ public abstract class PlaybackController { }, error -> Log.e(TAG, Log.getStackTraceString(error))); } - private Playable getMediaFromPreferences() { - long currentlyPlayingMedia = PlaybackPreferences.getCurrentlyPlayingMedia(); - if (currentlyPlayingMedia != PlaybackPreferences.NO_MEDIA_PLAYING) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( - activity.getApplicationContext()); - return PlayableUtils.createInstanceFromPreferences(activity, - (int) currentlyPlayingMedia, prefs); - } - return null; - } - /** * Returns an intent that starts the PlaybackService and plays the last * played media or null if no last played media could be found. */ private Intent getPlayLastPlayedMediaIntent() { Log.d(TAG, "Trying to restore last played media"); - Playable media = getMediaFromPreferences(); + Playable media = PlayableUtils.createInstanceFromPreferences(activity); if (media != null) { Intent serviceIntent = new Intent(activity, PlaybackService.class); serviceIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); @@ -648,7 +637,7 @@ public abstract class PlaybackController { public Playable getMedia() { if (media == null) { - media = getMediaFromPreferences(); + media = PlayableUtils.createInstanceFromPreferences(activity); } return media; } -- cgit v1.2.3 From 7107819a6aa61c6f171e43fe582133302d5f260b Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 5 May 2018 14:04:12 +0200 Subject: Moved widget from app to core --- .../antennapod/core/receiver/PlayerWidget.java | 56 +++++++ .../core/service/PlayerWidgetJobService.java | 179 +++++++++++++++++++++ .../core/service/playback/PlaybackService.java | 5 +- 3 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/de/danoeh/antennapod/core/receiver/PlayerWidget.java create mode 100644 core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/PlayerWidget.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/PlayerWidget.java new file mode 100644 index 000000000..edc2ea3e0 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/PlayerWidget.java @@ -0,0 +1,56 @@ +package de.danoeh.antennapod.core.receiver; + +import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetProvider; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.util.Log; +import de.danoeh.antennapod.core.service.PlayerWidgetJobService; + +import java.util.Arrays; + + +public class PlayerWidget extends AppWidgetProvider { + private static final String TAG = "PlayerWidget"; + private static final String PREFS_NAME = "PlayerWidgetPrefs"; + private static final String KEY_ENABLED = "WidgetEnabled"; + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "onReceive"); + super.onReceive(context, intent); + PlayerWidgetJobService.updateWidget(context); + } + + @Override + public void onEnabled(Context context) { + super.onEnabled(context); + Log.d(TAG, "Widget enabled"); + setEnabled(context, true); + PlayerWidgetJobService.updateWidget(context); + } + + @Override + public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { + Log.d(TAG, "onUpdate() called with: " + "context = [" + context + "], appWidgetManager = [" + appWidgetManager + "], appWidgetIds = [" + Arrays.toString(appWidgetIds) + "]"); + PlayerWidgetJobService.updateWidget(context); + } + + @Override + public void onDisabled(Context context) { + super.onDisabled(context); + Log.d(TAG, "Widget disabled"); + setEnabled(context, false); + } + + public static boolean isEnabled(Context context) { + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + return prefs.getBoolean(KEY_ENABLED, false); + } + + private void setEnabled(Context context, boolean enabled) { + SharedPreferences prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + prefs.edit().putBoolean(KEY_ENABLED, enabled).apply(); + } +} 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 new file mode 100644 index 000000000..49f3058ef --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java @@ -0,0 +1,179 @@ +package de.danoeh.antennapod.core.service; + +import android.app.PendingIntent; +import android.appwidget.AppWidgetManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Build; +import android.os.IBinder; +import android.support.annotation.NonNull; +import android.support.v4.app.JobIntentService; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.widget.RemoteViews; +import de.danoeh.antennapod.core.R; +import de.danoeh.antennapod.core.receiver.MediaButtonReceiver; +import de.danoeh.antennapod.core.service.playback.PlaybackService; +import de.danoeh.antennapod.core.service.playback.PlayerStatus; +import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.playback.Playable; +import de.danoeh.antennapod.core.receiver.PlayerWidget; + +/** + * Updates the state of the player widget + */ +public class PlayerWidgetJobService extends JobIntentService { + private static final String TAG = "PlayerWidgetJobService"; + + private PlaybackService playbackService; + private final Object waitForService = new Object(); + + public PlayerWidgetJobService() { + } + + public static void updateWidget(Context context) { + enqueueWork(context, PlayerWidgetJobService.class, 0, new Intent(context, PlayerWidgetJobService.class)); + } + + @Override + protected void onHandleWork(@NonNull Intent intent) { + if (!PlayerWidget.isEnabled(getApplicationContext())) { + return; + } + + if (PlaybackService.isRunning && playbackService == null) { + synchronized (waitForService) { + bindService(new Intent(this, PlaybackService.class), mConnection, 0); + while (playbackService == null) { + try { + waitForService.wait(); + } catch (InterruptedException e) { + return; + } + } + } + } + + updateViews(); + + if (playbackService != null) { + try { + unbindService(mConnection); + } catch (IllegalArgumentException e) { + Log.w(TAG, "IllegalArgumentException when trying to unbind service"); + } + } + } + + private void updateViews() { + + ComponentName playerWidget = new ComponentName(this, PlayerWidget.class); + AppWidgetManager manager = AppWidgetManager.getInstance(this); + 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); + + boolean nothingPlaying = false; + Playable media; + PlayerStatus status; + if (playbackService != null) { + media = playbackService.getPlayable(); + status = playbackService.getStatus(); + } else { + media = Playable.PlayableUtils.createInstanceFromPreferences(getApplicationContext()); + status = PlayerStatus.STOPPED; + } + + if (media != null) { + views.setOnClickPendingIntent(R.id.layout_left, startMediaplayer); + + views.setTextViewText(R.id.txtvTitle, media.getEpisodeTitle()); + + String progressString; + if (playbackService != null) { + progressString = getProgressString(playbackService.getCurrentPosition(), playbackService.getDuration()); + } else { + progressString = getProgressString(media.getPosition(), media.getDuration()); + } + + if (progressString != null) { + views.setViewVisibility(R.id.txtvProgress, View.VISIBLE); + views.setTextViewText(R.id.txtvProgress, progressString); + } + + if (status == PlayerStatus.PLAYING) { + views.setImageViewResource(R.id.butPlay, R.drawable.ic_pause_white_24dp); + if (Build.VERSION.SDK_INT >= 15) { + views.setContentDescription(R.id.butPlay, getString(R.string.pause_label)); + } + } else { + views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp); + if (Build.VERSION.SDK_INT >= 15) { + views.setContentDescription(R.id.butPlay, getString(R.string.play_label)); + } + } + views.setOnClickPendingIntent(R.id.butPlay, createMediaButtonIntent()); + } else { + nothingPlaying = true; + } + + if (nothingPlaying) { + // start the app if they click anything + views.setOnClickPendingIntent(R.id.layout_left, startAppPending); + views.setOnClickPendingIntent(R.id.butPlay, startAppPending); + views.setViewVisibility(R.id.txtvProgress, View.INVISIBLE); + views.setTextViewText(R.id.txtvTitle, + this.getString(R.string.no_media_playing_label)); + views.setImageViewResource(R.id.butPlay, R.drawable.ic_play_arrow_white_24dp); + } + + manager.updateAppWidget(playerWidget, views); + } + + /** + * Creates an intent which fakes a mediabutton press + */ + private PendingIntent createMediaButtonIntent() { + KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); + Intent startingIntent = new Intent(getBaseContext(), MediaButtonReceiver.class); + startingIntent.setAction(MediaButtonReceiver.NOTIFY_BUTTON_RECEIVER); + startingIntent.putExtra(Intent.EXTRA_KEY_EVENT, event); + + return PendingIntent.getBroadcast(this, 0, startingIntent, 0); + } + + private String getProgressString(int position, int duration) { + if (position > 0 && duration > 0) { + return Converter.getDurationStringLong(position) + " / " + + Converter.getDurationStringLong(duration); + } else { + return null; + } + } + + private final ServiceConnection mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + Log.d(TAG, "Connection to service established"); + if (service instanceof PlaybackService.LocalBinder) { + synchronized (waitForService) { + playbackService = ((PlaybackService.LocalBinder) service).getService(); + waitForService.notifyAll(); + } + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + playbackService = null; + Log.d(TAG, "Disconnected from service"); + } + + }; +} 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 a34ce4943..9643b9cd3 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 @@ -62,6 +62,7 @@ import de.danoeh.antennapod.core.preferences.PlaybackPreferences; import de.danoeh.antennapod.core.preferences.SleepTimerPreferences; import de.danoeh.antennapod.core.preferences.UserPreferences; import de.danoeh.antennapod.core.receiver.MediaButtonReceiver; +import de.danoeh.antennapod.core.service.PlayerWidgetJobService; import de.danoeh.antennapod.core.storage.DBReader; import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; @@ -630,7 +631,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { @Override public void onWidgetUpdaterTick() { - //PlayerWidgetJobService.updateWidget(getBaseContext()); // TODO: Not accessible from core module + PlayerWidgetJobService.updateWidget(getBaseContext()); } @Override @@ -692,7 +693,7 @@ public class PlaybackService extends MediaBrowserServiceCompat { Intent statusUpdate = new Intent(ACTION_PLAYER_STATUS_CHANGED); // statusUpdate.putExtra(EXTRA_NEW_PLAYER_STATUS, newInfo.playerStatus.ordinal()); sendBroadcast(statusUpdate); - //PlayerWidgetJobService.updateWidget(getBaseContext()); // TODO: Not accessible from core module + PlayerWidgetJobService.updateWidget(getBaseContext()); bluetoothNotifyChange(newInfo, AVRCP_ACTION_PLAYER_STATUS_CHANGED); bluetoothNotifyChange(newInfo, AVRCP_ACTION_META_CHANGED); } -- cgit v1.2.3 From 7a768e9809dafc7e6f5944e26ebf2f1cb0e786aa Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 5 May 2018 14:32:04 +0200 Subject: Fixed widget if service is not running --- .../antennapod/core/service/playback/PlaybackService.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 9643b9cd3..dc67c0758 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 @@ -515,6 +515,8 @@ public class PlaybackService extends MediaBrowserServiceCompat { } else if (status == PlayerStatus.INITIALIZED) { mediaPlayer.setStartWhenPrepared(true); mediaPlayer.prepare(); + } else if (mediaPlayer.getPlayable() == null) { + startPlayingFromPreferences(); } return true; case KeyEvent.KEYCODE_MEDIA_PLAY: @@ -523,6 +525,8 @@ public class PlaybackService extends MediaBrowserServiceCompat { } else if (status == PlayerStatus.INITIALIZED) { mediaPlayer.setStartWhenPrepared(true); mediaPlayer.prepare(); + } else if (mediaPlayer.getPlayable() == null) { + startPlayingFromPreferences(); } return true; case KeyEvent.KEYCODE_MEDIA_PAUSE: @@ -576,6 +580,15 @@ public class PlaybackService extends MediaBrowserServiceCompat { return false; } + private void startPlayingFromPreferences() { + Playable playable = Playable.PlayableUtils.createInstanceFromPreferences(getApplicationContext()); + if (playable != null) { + mediaPlayer.playMediaObject(playable, false, true, true); + started = true; + PlaybackService.this.updateMediaSessionMetadata(playable); + } + } + /** * Called by a mediaplayer Activity as soon as it has prepared its * mediaplayer. -- cgit v1.2.3 From a270d4fc031caba89909fcd710849a6ba18f326b Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 5 May 2018 15:10:08 +0200 Subject: Migrated Gpodnet to JobIntentService, so it does not need notification --- .../core/service/GpodnetSyncService.java | 116 ++++----------------- 1 file changed, 23 insertions(+), 93 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java index 48398e0c5..8a18d93b9 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java @@ -3,10 +3,10 @@ package de.danoeh.antennapod.core.service; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; -import android.app.Service; import android.content.Context; import android.content.Intent; -import android.os.IBinder; +import android.support.annotation.NonNull; +import android.support.v4.app.JobIntentService; import android.support.v4.app.NotificationCompat; import android.support.v4.content.ContextCompat; import android.support.v4.util.ArrayMap; @@ -16,6 +16,7 @@ import android.util.Pair; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import de.danoeh.antennapod.core.ClientConfig; import de.danoeh.antennapod.core.R; @@ -44,7 +45,7 @@ import de.danoeh.antennapod.core.util.NotificationUtils; * Synchronizes local subscriptions with gpodder.net service. The service should be started with ACTION_SYNC as an action argument. * This class also provides static methods for starting the GpodnetSyncService. */ -public class GpodnetSyncService extends Service { +public class GpodnetSyncService extends JobIntentService { private static final String TAG = "GpodnetSyncService"; private static final long WAIT_INTERVAL = 5000L; @@ -55,26 +56,19 @@ public class GpodnetSyncService extends Service { private static final String ACTION_SYNC_SUBSCRIPTIONS = "de.danoeh.antennapod.intent.action.sync_subscriptions"; private static final String ACTION_SYNC_ACTIONS = "de.danoeh.antennapod.intent.action.sync_ACTIONS"; - private GpodnetService service; + private static final AtomicInteger syncActionCount = new AtomicInteger(0); + private GpodnetService service; private boolean syncSubscriptions = false; private boolean syncActions = false; - private static final int NOTIFICATION_ID = 2; - @Override - public void onCreate() { - super.onCreate(); - startForeground(NOTIFICATION_ID, - new NotificationCompat.Builder(this, NotificationUtils.CHANNEL_ID_GPODNET) - .setSmallIcon(R.drawable.stat_notify_sync) - .setContentTitle(getString(R.string.gpodnet_main_label)) - .setContentText(getString(R.string.synchronizing)) - .build()); + public static void enqueueWork(Context context, Intent intent) { + enqueueWork(context, GpodnetSyncService.class, 0, intent); } @Override - public int onStartCommand(Intent intent, int flags, int startId) { - final String action = (intent != null) ? intent.getStringExtra(ARG_ACTION) : null; + protected void onHandleWork(@NonNull Intent intent) { + final String action = intent.getStringExtra(ARG_ACTION); if (action != null) { switch(action) { case ACTION_SYNC: @@ -92,24 +86,20 @@ public class GpodnetSyncService extends Service { } if(syncSubscriptions || syncActions) { Log.d(TAG, String.format("Waiting %d milliseconds before uploading changes", WAIT_INTERVAL)); - syncWaiterThread.restart(); + int syncActionId = syncActionCount.incrementAndGet(); + try { + Thread.sleep(WAIT_INTERVAL); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if (syncActionId == syncActionCount.get()) { + // onHandleWork was not called again in the meantime + sync(); + } } } else { Log.e(TAG, "Received invalid intent: action argument is null"); } - return START_STICKY; - } - - @Override - public void onDestroy() { - super.onDestroy(); - Log.d(TAG, "onDestroy"); - syncWaiterThread.interrupt(); - } - - @Override - public IBinder onBind(Intent intent) { - return null; } private synchronized GpodnetService tryLogin() throws GpodnetServiceException { @@ -140,8 +130,6 @@ public class GpodnetSyncService extends Service { } syncActions = false; } - stopForeground(true); - stopSelf(); } private synchronized void syncSubscriptionChanges() { @@ -347,69 +335,11 @@ public class GpodnetSyncService extends Service { nm.notify(id, notification); } - private final WaiterThread syncWaiterThread = new WaiterThread(WAIT_INTERVAL) { - @Override - public void onWaitCompleted() { - sync(); - } - }; - - private abstract class WaiterThread { - private final long waitInterval; - private Thread thread; - - private WaiterThread(long waitInterval) { - this.waitInterval = waitInterval; - reinit(); - } - - public abstract void onWaitCompleted(); - - public void exec() { - if (!thread.isAlive()) { - thread.start(); - } - } - - private void reinit() { - if (thread != null && thread.isAlive()) { - Log.d(TAG, "Interrupting waiter thread"); - thread.interrupt(); - } - thread = new Thread() { - @Override - public void run() { - try { - Thread.sleep(waitInterval); - } catch (InterruptedException e) { - e.printStackTrace(); - } - if (!isInterrupted()) { - synchronized (this) { - onWaitCompleted(); - } - } - } - }; - } - - public void restart() { - reinit(); - exec(); - } - - public void interrupt() { - if (thread != null && thread.isAlive()) { - thread.interrupt(); - } - } - } - public static void sendSyncIntent(Context context) { if (GpodnetPreferences.loggedIn()) { Intent intent = new Intent(context, GpodnetSyncService.class); intent.putExtra(ARG_ACTION, ACTION_SYNC); - ContextCompat.startForegroundService(context, intent); + enqueueWork(context, intent); } } @@ -417,7 +347,7 @@ public class GpodnetSyncService extends Service { if (GpodnetPreferences.loggedIn()) { Intent intent = new Intent(context, GpodnetSyncService.class); intent.putExtra(ARG_ACTION, ACTION_SYNC_SUBSCRIPTIONS); - ContextCompat.startForegroundService(context, intent); + enqueueWork(context, intent); } } @@ -425,7 +355,7 @@ public class GpodnetSyncService extends Service { if (GpodnetPreferences.loggedIn()) { Intent intent = new Intent(context, GpodnetSyncService.class); intent.putExtra(ARG_ACTION, ACTION_SYNC_ACTIONS); - ContextCompat.startForegroundService(context, intent); + enqueueWork(context, intent); } } } -- cgit v1.2.3 From 304696d59e985ddd396685f9be22256f2c3f9aec Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 5 May 2018 18:23:29 +0200 Subject: Stop playback service when item of deleted feed is played Closes #2425 --- .../java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java | 3 +++ core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java | 3 +++ 2 files changed, 6 insertions(+) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java index af735aefd..0e64f484f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java @@ -609,6 +609,9 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer { public void shutdown() { executor.shutdown(); if (mediaPlayer != null) { + try { + mediaPlayer.stop(); + } catch (Exception ignore) { } mediaPlayer.release(); } releaseWifiLockIfNecessary(); diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java index 49de7ffe7..8cdf82e15 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java @@ -188,6 +188,9 @@ public class DBWriter { if(queue.remove(item)) { removed.add(item); } + if (item.getState() == FeedItem.State.PLAYING && PlaybackService.isRunning) { + context.stopService(new Intent(context, PlaybackService.class)); + } if (item.getMedia() != null && item.getMedia().isDownloaded()) { File mediaFile = new File(item.getMedia() -- cgit v1.2.3 From 61f8000352d80eef4687a66e0d6174637469adc2 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 6 May 2018 18:52:16 +0200 Subject: Using callback instead of sync/async methods --- .../core/receiver/FeedUpdateReceiver.java | 2 +- .../core/service/FeedUpdateJobService.java | 5 +- .../de/danoeh/antennapod/core/storage/DBTasks.java | 64 ++++++++++------------ .../antennapod/core/util/FeedUpdateUtils.java | 8 +-- 4 files changed, 35 insertions(+), 44 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java index 67f6d9348..05e12f6df 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java +++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java @@ -20,7 +20,7 @@ public class FeedUpdateReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { Log.d(TAG, "Received intent"); ClientConfig.initialize(context); - FeedUpdateUtils.startAutoUpdate(context, false); + FeedUpdateUtils.startAutoUpdate(context, null); UserPreferences.restartUpdateAlarm(false); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java index 3fc3551ee..55a8d6b86 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateJobService.java @@ -18,11 +18,10 @@ public class FeedUpdateJobService extends JobService { Log.d(TAG, "Job started"); ClientConfig.initialize(getApplicationContext()); - new Thread(() -> { - FeedUpdateUtils.startAutoUpdate(getApplicationContext(), true); + FeedUpdateUtils.startAutoUpdate(getApplicationContext(), () -> { UserPreferences.restartUpdateAlarm(false); jobFinished(params, false); // needsReschedule = false - }).start(); + }); return true; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java index b1937985f..d1713ff99 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java @@ -148,45 +148,41 @@ public final class DBTasks { * Refreshes a given list of Feeds in a separate Thread. This method might ignore subsequent calls if it is still * enqueuing Feeds for download from a previous call * - * @param context Might be used for accessing the database - * @param feeds List of Feeds that should be refreshed. + * @param context Might be used for accessing the database + * @param feeds List of Feeds that should be refreshed. + * @param callback Called after everything was added enqueued for download */ - public static void refreshAllFeeds(final Context context, final List feeds) { - new Thread(() -> refreshAllFeedsSynchronously(context, feeds)).start(); - } - - /** - * Refreshes a given list of Feeds in the current Thread. This method might ignore subsequent calls if it is still - * enqueuing Feeds for download from a previous call. MUST NOT be executed from main thread. - * - * @param context Might be used for accessing the database - * @param feeds List of Feeds that should be refreshed. - */ - public static void refreshAllFeedsSynchronously(final Context context, final List feeds) { + public static void refreshAllFeeds(final Context context, final List feeds, Runnable callback) { if (isRefreshing.compareAndSet(false, true)) { - if (feeds != null) { - refreshFeeds(context, feeds); - } else { - refreshFeeds(context, DBReader.getFeedList()); - } - isRefreshing.set(false); + new Thread(() -> { + if (feeds != null) { + refreshFeeds(context, feeds); + } else { + refreshFeeds(context, DBReader.getFeedList()); + } + isRefreshing.set(false); - SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE); - prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply(); + SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE); + prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply(); - if (FlattrUtils.hasToken()) { - Log.d(TAG, "Flattring all pending things."); - new FlattrClickWorker(context).executeAsync(); // flattr pending things + if (FlattrUtils.hasToken()) { + Log.d(TAG, "Flattring all pending things."); + new FlattrClickWorker(context).executeAsync(); // flattr pending things - Log.d(TAG, "Fetching flattr status."); - new FlattrStatusFetcher(context).start(); + Log.d(TAG, "Fetching flattr status."); + new FlattrStatusFetcher(context).start(); - } - if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { - GpodnetSyncService.sendSyncIntent(context); - } - Log.d(TAG, "refreshAllFeeds autodownload"); - autodownloadUndownloadedItems(context); + } + if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { + GpodnetSyncService.sendSyncIntent(context); + } + Log.d(TAG, "refreshAllFeeds autodownload"); + autodownloadUndownloadedItems(context); + + if (callback != null) { + callback.run(); + } + }).start(); } else { Log.d(TAG, "Ignoring request to refresh all feeds: Refresh lock is locked"); } @@ -344,7 +340,7 @@ public final class DBTasks { Log.d(TAG, "last refresh: " + Converter.getDurationStringLocalized(context, System.currentTimeMillis() - lastRefresh) + " ago"); if(lastRefresh <= System.currentTimeMillis() - interval) { - DBTasks.refreshAllFeeds(context, null); + DBTasks.refreshAllFeeds(context, null, null); } } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java index a57ab2ce6..24e0da9ed 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/FeedUpdateUtils.java @@ -11,13 +11,9 @@ public class FeedUpdateUtils { } - public static void startAutoUpdate(Context context, boolean synchronously) { + public static void startAutoUpdate(Context context, Runnable callback) { if (NetworkUtils.networkAvailable() && NetworkUtils.isDownloadAllowed()) { - if (synchronously) { - DBTasks.refreshAllFeedsSynchronously(context, null); - } else { - DBTasks.refreshAllFeeds(context, null); - } + DBTasks.refreshAllFeeds(context, null, callback); } else { Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed"); } -- cgit v1.2.3 From 22f791e05f58b03bfa84ca206cbc113ec002ef82 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 6 May 2018 19:07:25 +0200 Subject: Moved auto update handling to new class --- .../core/preferences/UserPreferences.java | 100 +++--------------- .../core/util/download/AutoUpdateManager.java | 113 +++++++++++++++++++++ 2 files changed, 127 insertions(+), 86 deletions(-) create mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java (limited to 'core/src/main/java/de/danoeh/antennapod') 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 07a62b743..48efdc84c 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 @@ -1,24 +1,22 @@ package de.danoeh.antennapod.core.preferences; -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.job.JobInfo; -import android.app.job.JobScheduler; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; -import android.os.SystemClock; import android.preference.PreferenceManager; import android.support.annotation.IntRange; import android.support.annotation.NonNull; -import android.support.annotation.RequiresApi; import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import android.util.Log; - -import de.danoeh.antennapod.core.service.FeedUpdateJobService; +import de.danoeh.antennapod.core.R; +import de.danoeh.antennapod.core.service.download.ProxyConfig; +import de.danoeh.antennapod.core.storage.APCleanupAlgorithm; +import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm; +import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm; +import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm; +import de.danoeh.antennapod.core.util.Converter; +import de.danoeh.antennapod.core.util.download.AutoUpdateManager; import org.json.JSONArray; import org.json.JSONException; @@ -31,15 +29,6 @@ import java.util.Calendar; import java.util.List; import java.util.concurrent.TimeUnit; -import de.danoeh.antennapod.core.R; -import de.danoeh.antennapod.core.receiver.FeedUpdateReceiver; -import de.danoeh.antennapod.core.service.download.ProxyConfig; -import de.danoeh.antennapod.core.storage.APCleanupAlgorithm; -import de.danoeh.antennapod.core.storage.APNullCleanupAlgorithm; -import de.danoeh.antennapod.core.storage.APQueueCleanupAlgorithm; -import de.danoeh.antennapod.core.storage.EpisodeCleanupAlgorithm; -import de.danoeh.antennapod.core.util.Converter; - /** * Provides access to preferences set by the user in the settings screen. A * private instance of this class must first be instantiated via @@ -109,9 +98,6 @@ public class UserPreferences { private static final String PREF_DATA_FOLDER = "prefDataFolder"; public static final String PREF_IMAGE_CACHE_SIZE = "prefImageCacheSize"; - // JobScheduler - private static final int JOB_ID_FEED_UPDATE = 42; - // Mediaplayer private static final String PREF_PLAYBACK_SPEED = "prefPlaybackSpeed"; private static final String PREF_FAST_FORWARD_SECS = "prefFastForwardSecs"; @@ -808,42 +794,10 @@ public class UserPreferences { Log.d(TAG, "Restarting update alarm."); if (Build.VERSION.SDK_INT >= 24) { - JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); - if (jobScheduler != null) { - JobInfo oldJob = jobScheduler.getPendingJob(JOB_ID_FEED_UPDATE); - if (oldJob == null || oldJob.getIntervalMillis() != intervalMillis) { - JobInfo.Builder builder = getFeedUpdateJobBuilder(); - builder.setPeriodic(intervalMillis); - jobScheduler.cancel(JOB_ID_FEED_UPDATE); - - if (intervalMillis <= 0) { - Log.d(TAG, "Automatic update was deactivated"); - return; - } - - jobScheduler.schedule(builder.build()); - Log.d(TAG, "JobScheduler was set at interval " + intervalMillis); - } else { - Log.d(TAG, "JobScheduler was already set at interval " + intervalMillis + ", ignoring."); - } - } - return; - } - - AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - Intent intent = new Intent(context, FeedUpdateReceiver.class); - PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, intent, 0); - alarmManager.cancel(updateIntent); - - if (intervalMillis <= 0) { - Log.d(TAG, "Automatic update was deactivated"); - return; + AutoUpdateManager.restartJobServiceInterval(context, intervalMillis); + } else { + AutoUpdateManager.restartAlarmManagerInterval(context, triggerAtMillis, intervalMillis); } - - alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + triggerAtMillis, - updateIntent); - Log.d(TAG, "Changed alarm to new interval " + TimeUnit.MILLISECONDS.toHours(intervalMillis) + " h"); } /** @@ -861,37 +815,11 @@ public class UserPreferences { } if (Build.VERSION.SDK_INT >= 24) { - JobInfo.Builder builder = getFeedUpdateJobBuilder(); long triggerAtMillis = alarm.getTimeInMillis() - now.getTimeInMillis(); - builder.setMinimumLatency(triggerAtMillis); - JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); - if (jobScheduler != null) { - jobScheduler.cancel(JOB_ID_FEED_UPDATE); - jobScheduler.schedule(builder.build()); - Log.d(TAG, "JobScheduler was set for " + triggerAtMillis); - } - return; + AutoUpdateManager.restartJobServiceTriggerAt(context, triggerAtMillis); + } else { + AutoUpdateManager.restartAlarmManagerTimeOfDay(context, alarm); } - - AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, - new Intent(context, FeedUpdateReceiver.class), 0); - alarmManager.cancel(updateIntent); - - Log.d(TAG, "Alarm set for: " + alarm.toString() + " : " + alarm.getTimeInMillis()); - alarmManager.set(AlarmManager.RTC_WAKEUP, - alarm.getTimeInMillis(), - updateIntent); - Log.d(TAG, "Changed alarm to new time of day " + hoursOfDay + ":" + minute); - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - private static JobInfo.Builder getFeedUpdateJobBuilder() { - ComponentName serviceComponent = new ComponentName(context, FeedUpdateJobService.class); - JobInfo.Builder builder = new JobInfo.Builder(JOB_ID_FEED_UPDATE, serviceComponent); - builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); - builder.setPersisted(true); - return builder; } /** 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 new file mode 100644 index 000000000..ec9fcae4e --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java @@ -0,0 +1,113 @@ +package de.danoeh.antennapod.core.util.download; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.app.job.JobInfo; +import android.app.job.JobScheduler; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.SystemClock; +import android.support.annotation.RequiresApi; +import android.util.Log; +import de.danoeh.antennapod.core.receiver.FeedUpdateReceiver; +import de.danoeh.antennapod.core.service.FeedUpdateJobService; + +import java.util.Calendar; +import java.util.concurrent.TimeUnit; + +public class AutoUpdateManager { + private static final int JOB_ID_FEED_UPDATE = 42; + private static final String TAG = "AutoUpdateManager"; + + private AutoUpdateManager() { + + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private static JobInfo.Builder getFeedUpdateJobBuilder(Context context) { + ComponentName serviceComponent = new ComponentName(context, FeedUpdateJobService.class); + JobInfo.Builder builder = new JobInfo.Builder(JOB_ID_FEED_UPDATE, serviceComponent); + builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); + builder.setPersisted(true); + return builder; + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static void restartJobServiceInterval(Context context, long intervalMillis) { + JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); + if (jobScheduler != null) { + JobInfo oldJob = jobScheduler.getPendingJob(JOB_ID_FEED_UPDATE); + if (oldJob == null || oldJob.getIntervalMillis() != intervalMillis) { + JobInfo.Builder builder = getFeedUpdateJobBuilder(context); + builder.setPeriodic(intervalMillis); + jobScheduler.cancel(JOB_ID_FEED_UPDATE); + + if (intervalMillis <= 0) { + Log.d(TAG, "Automatic update was deactivated"); + return; + } + + jobScheduler.schedule(builder.build()); + Log.d(TAG, "JobScheduler was set at interval " + intervalMillis); + } else { + Log.d(TAG, "JobScheduler was already set at interval " + intervalMillis + ", ignoring."); + } + } + } + + public static void restartAlarmManagerInterval(Context context, long triggerAtMillis, long intervalMillis) { + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + + if (alarmManager == null) { + Log.d(TAG, "AlarmManager was null"); + return; + } + + Intent intent = new Intent(context, FeedUpdateReceiver.class); + PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, intent, 0); + alarmManager.cancel(updateIntent); + + if (intervalMillis <= 0) { + Log.d(TAG, "Automatic update was deactivated"); + return; + } + + alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + triggerAtMillis, + updateIntent); + Log.d(TAG, "Changed alarm to new interval " + TimeUnit.MILLISECONDS.toHours(intervalMillis) + " h"); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + public static void restartJobServiceTriggerAt(Context context, long triggerAtMillis) { + JobInfo.Builder builder = getFeedUpdateJobBuilder(context); + builder.setMinimumLatency(triggerAtMillis); + JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); + if (jobScheduler != null) { + jobScheduler.cancel(JOB_ID_FEED_UPDATE); + jobScheduler.schedule(builder.build()); + Log.d(TAG, "JobScheduler was set for " + triggerAtMillis); + } + } + + public static void restartAlarmManagerTimeOfDay(Context context, Calendar alarm) { + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, + new Intent(context, FeedUpdateReceiver.class), 0); + + if (alarmManager == null) { + Log.d(TAG, "AlarmManager was null"); + return; + } + + alarmManager.cancel(updateIntent); + + Log.d(TAG, "Alarm set for: " + alarm.toString() + " : " + alarm.getTimeInMillis()); + alarmManager.set(AlarmManager.RTC_WAKEUP, + alarm.getTimeInMillis(), + updateIntent); + Log.d(TAG, "Changed alarm to new time of day " + alarm.get(Calendar.HOUR_OF_DAY) + ":" + alarm.get(Calendar.MINUTE)); + } +} -- cgit v1.2.3 From cb70aeb3cfe1cdf81937ee98c79cee324024048a Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 6 May 2018 19:15:40 +0200 Subject: Code style improvements --- .../core/service/PlayerWidgetJobService.java | 3 -- .../de/danoeh/antennapod/core/storage/DBTasks.java | 62 +++++++++++----------- .../antennapod/core/util/playback/Playable.java | 2 + .../core/util/playback/PlaybackController.java | 34 ++++++------ 4 files changed, 52 insertions(+), 49 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 49f3058ef..2fd790ac7 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 @@ -31,9 +31,6 @@ public class PlayerWidgetJobService extends JobIntentService { private PlaybackService playbackService; private final Object waitForService = new Object(); - public PlayerWidgetJobService() { - } - public static void updateWidget(Context context) { enqueueWork(context, PlayerWidgetJobService.class, 0, new Intent(context, PlayerWidgetJobService.class)); } diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java index d1713ff99..02098e9ed 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; +import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.util.Log; @@ -150,42 +151,43 @@ public final class DBTasks { * * @param context Might be used for accessing the database * @param feeds List of Feeds that should be refreshed. - * @param callback Called after everything was added enqueued for download + * @param callback Called after everything was added enqueued for download. Might be null. */ - public static void refreshAllFeeds(final Context context, final List feeds, Runnable callback) { - if (isRefreshing.compareAndSet(false, true)) { - new Thread(() -> { - if (feeds != null) { - refreshFeeds(context, feeds); - } else { - refreshFeeds(context, DBReader.getFeedList()); - } - isRefreshing.set(false); + public static void refreshAllFeeds(final Context context, final List feeds, @Nullable Runnable callback) { + if (!isRefreshing.compareAndSet(false, true)) { + Log.d(TAG, "Ignoring request to refresh all feeds: Refresh lock is locked"); + return; + } - SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE); - prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply(); + new Thread(() -> { + if (feeds != null) { + refreshFeeds(context, feeds); + } else { + refreshFeeds(context, DBReader.getFeedList()); + } + isRefreshing.set(false); - if (FlattrUtils.hasToken()) { - Log.d(TAG, "Flattring all pending things."); - new FlattrClickWorker(context).executeAsync(); // flattr pending things + SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE); + prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply(); - Log.d(TAG, "Fetching flattr status."); - new FlattrStatusFetcher(context).start(); + if (FlattrUtils.hasToken()) { + Log.d(TAG, "Flattring all pending things."); + new FlattrClickWorker(context).executeAsync(); // flattr pending things - } - if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { - GpodnetSyncService.sendSyncIntent(context); - } - Log.d(TAG, "refreshAllFeeds autodownload"); - autodownloadUndownloadedItems(context); + Log.d(TAG, "Fetching flattr status."); + new FlattrStatusFetcher(context).start(); - if (callback != null) { - callback.run(); - } - }).start(); - } else { - Log.d(TAG, "Ignoring request to refresh all feeds: Refresh lock is locked"); - } + } + if (ClientConfig.gpodnetCallbacks.gpodnetEnabled()) { + GpodnetSyncService.sendSyncIntent(context); + } + Log.d(TAG, "refreshAllFeeds autodownload"); + autodownloadUndownloadedItems(context); + + if (callback != null) { + callback.run(); + } + }).start(); } /** diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java index bb9896f25..ff7f5b79d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.Parcelable; import android.preference.PreferenceManager; +import android.support.annotation.Nullable; import android.util.Log; import java.util.List; @@ -183,6 +184,7 @@ public interface Playable extends Parcelable, * * @return The restored Playable object */ + @Nullable public static Playable createInstanceFromPreferences(Context context) { long currentlyPlayingMedia = PlaybackPreferences.getCurrentlyPlayingMedia(); if (currentlyPlayingMedia != PlaybackPreferences.NO_MEDIA_PLAYING) { 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 d1d6b5c63..7c930a8e2 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 @@ -14,6 +14,7 @@ import android.os.Build; import android.os.IBinder; import android.preference.PreferenceManager; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.text.TextUtils; import android.util.Log; @@ -212,25 +213,26 @@ public abstract class PlaybackController { * Returns an intent that starts the PlaybackService and plays the last * played media or null if no last played media could be found. */ - private Intent getPlayLastPlayedMediaIntent() { + @Nullable private Intent getPlayLastPlayedMediaIntent() { Log.d(TAG, "Trying to restore last played media"); Playable media = PlayableUtils.createInstanceFromPreferences(activity); - if (media != null) { - Intent serviceIntent = new Intent(activity, PlaybackService.class); - serviceIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); - serviceIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, false); - serviceIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, true); - boolean fileExists = media.localFileAvailable(); - boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream(); - if (!fileExists && !lastIsStream && media instanceof FeedMedia) { - DBTasks.notifyMissingFeedMediaFile(activity, (FeedMedia) media); - } - serviceIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, - lastIsStream || !fileExists); - return serviceIntent; + if (media == null) { + Log.d(TAG, "No last played media found"); + return null; } - Log.d(TAG, "No last played media found"); - return null; + + Intent serviceIntent = new Intent(activity, PlaybackService.class); + serviceIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); + serviceIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, false); + serviceIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, true); + boolean fileExists = media.localFileAvailable(); + boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream(); + if (!fileExists && !lastIsStream && media instanceof FeedMedia) { + DBTasks.notifyMissingFeedMediaFile(activity, (FeedMedia) media); + } + serviceIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, + lastIsStream || !fileExists); + return serviceIntent; } -- cgit v1.2.3 From 4411b0ffaa34aede5c42ad3cbc401b63db40a371 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 6 May 2018 19:21:02 +0200 Subject: Fix possible missing sync calls --- .../de/danoeh/antennapod/core/service/GpodnetSyncService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java index 8a18d93b9..94fadae02 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java @@ -56,13 +56,13 @@ public class GpodnetSyncService extends JobIntentService { private static final String ACTION_SYNC_SUBSCRIPTIONS = "de.danoeh.antennapod.intent.action.sync_subscriptions"; private static final String ACTION_SYNC_ACTIONS = "de.danoeh.antennapod.intent.action.sync_ACTIONS"; - private static final AtomicInteger syncActionCount = new AtomicInteger(0); - private GpodnetService service; - private boolean syncSubscriptions = false; - private boolean syncActions = false; - public static void enqueueWork(Context context, Intent intent) { + private static final AtomicInteger syncActionCount = new AtomicInteger(0); + private static boolean syncSubscriptions = false; + private static boolean syncActions = false; + + private static void enqueueWork(Context context, Intent intent) { enqueueWork(context, GpodnetSyncService.class, 0, intent); } -- cgit v1.2.3 From f6082f58088d79a8b46556fc68c7bbbf30008c82 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sun, 6 May 2018 19:44:07 +0200 Subject: Using builder to call PlaybackService --- .../core/service/playback/PlaybackService.java | 15 ----- .../de/danoeh/antennapod/core/storage/DBTasks.java | 10 ++- .../core/util/playback/PlaybackController.java | 17 ++--- .../core/util/playback/PlaybackServiceStarter.java | 76 ++++++++++++++++++++++ 4 files changed, 93 insertions(+), 25 deletions(-) create mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java (limited to 'core/src/main/java/de/danoeh/antennapod') 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 dc67c0758..c1d3b6f1f 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 @@ -804,21 +804,6 @@ public class PlaybackService extends MediaBrowserServiceCompat { } }; - public static void startIfNotRunning(final Context context, final Playable media, boolean startWhenPrepared, boolean shouldStream) { - if (!isRunning) { - startService(context, media, startWhenPrepared, shouldStream); - } - } - - public static void startService(final Context context, final Playable media, boolean startWhenPrepared, boolean shouldStream) { - Intent launchIntent = new Intent(context, PlaybackService.class); - launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); - launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, startWhenPrepared); - launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, shouldStream); - launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, true); - ContextCompat.startForegroundService(context, launchIntent); - } - private Playable getNextInQueue(final Playable currentMedia) { if (!(currentMedia instanceof FeedMedia)) { Log.d(TAG, "getNextInQueue(), but playable not an instance of FeedMedia, so not proceeding"); diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java index 02098e9ed..22a7b64fe 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java @@ -40,6 +40,7 @@ import de.danoeh.antennapod.core.util.LongList; import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator; import de.danoeh.antennapod.core.util.exception.MediaFileNotFoundException; import de.danoeh.antennapod.core.util.flattr.FlattrUtils; +import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter; import static android.content.Context.MODE_PRIVATE; @@ -125,8 +126,13 @@ public final class DBTasks { media); } } - // Needs to be called even if the service is already running to deliver the new media intent - PlaybackService.startService(context, media, startWhenPrepared, shouldStream); + + new PlaybackServiceStarter(context, media) + .callEvenIfRunning(true) + .startWhenPrepared(startWhenPrepared) + .shouldStream(shouldStream) + .start(); + if (showPlayer) { // Launch media player context.startActivity(PlaybackService.getPlayerActivityIntent( 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 7c930a8e2..a3f02d5cc 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 @@ -221,18 +221,16 @@ public abstract class PlaybackController { return null; } - Intent serviceIntent = new Intent(activity, PlaybackService.class); - serviceIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); - serviceIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, false); - serviceIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, true); boolean fileExists = media.localFileAvailable(); boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream(); if (!fileExists && !lastIsStream && media instanceof FeedMedia) { DBTasks.notifyMissingFeedMediaFile(activity, (FeedMedia) media); } - serviceIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, - lastIsStream || !fileExists); - return serviceIntent; + + return new PlaybackServiceStarter(activity, media) + .startWhenPrepared(false) + .shouldStream(lastIsStream || !fileExists) + .getIntent(); } @@ -586,7 +584,10 @@ public abstract class PlaybackController { public void playPause() { if (playbackService == null) { - PlaybackService.startService(activity, media, true, false); + new PlaybackServiceStarter(activity, media) + .startWhenPrepared(true) + .streamIfLastWasStream() + .start(); Log.w(TAG, "Play/Pause button was pressed, but playbackservice was null!"); return; } diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java new file mode 100644 index 000000000..3ba553d12 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java @@ -0,0 +1,76 @@ +package de.danoeh.antennapod.core.util.playback; + +import android.content.Context; +import android.content.Intent; +import android.media.MediaPlayer; +import android.support.v4.content.ContextCompat; +import de.danoeh.antennapod.core.preferences.PlaybackPreferences; +import de.danoeh.antennapod.core.service.playback.PlaybackService; + +public class PlaybackServiceStarter { + private final Context context; + private final Playable media; + private boolean startWhenPrepared = false; + private boolean shouldStream = false; + private boolean callEvenIfRunning = false; + private boolean prepareImmediately = true; + + public PlaybackServiceStarter(Context context, Playable media) { + this.context = context; + this.media = media; + } + + /** + * Default value: false + */ + public PlaybackServiceStarter shouldStream(boolean shouldStream) { + this.shouldStream = shouldStream; + return this; + } + + public PlaybackServiceStarter streamIfLastWasStream() { + boolean lastIsStream = PlaybackPreferences.getCurrentEpisodeIsStream(); + return shouldStream(lastIsStream); + } + + /** + * Default value: false + */ + public PlaybackServiceStarter startWhenPrepared(boolean startWhenPrepared) { + this.startWhenPrepared = startWhenPrepared; + return this; + } + + /** + * Default value: false + */ + public PlaybackServiceStarter callEvenIfRunning(boolean callEvenIfRunning) { + this.callEvenIfRunning = callEvenIfRunning; + return this; + } + + /** + * Default value: true + */ + public PlaybackServiceStarter prepareImmediately(boolean prepareImmediately) { + this.prepareImmediately = prepareImmediately; + return this; + } + + public Intent getIntent() { + Intent launchIntent = new Intent(context, PlaybackService.class); + launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media); + launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED, startWhenPrepared); + launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, shouldStream); + launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY, prepareImmediately); + + return launchIntent; + } + + public void start() { + if (PlaybackService.isRunning && !callEvenIfRunning) { + return; + } + ContextCompat.startForegroundService(context, getIntent()); + } +} -- cgit v1.2.3 From 6bda6405b8102a1111e6d0521584fedf8ebc3a07 Mon Sep 17 00:00:00 2001 From: brad Date: Sun, 20 May 2018 23:01:14 -0700 Subject: avoid unused context parameter --- .../antennapod/core/storage/DownloadRequester.java | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 a8fd79fda..1f429d189 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 @@ -176,8 +176,8 @@ public class DownloadRequester { args.putInt(REQUEST_ARG_PAGE_NR, feed.getPageNr()); args.putBoolean(REQUEST_ARG_LOAD_ALL_PAGES, loadAllPages); - download(context, feed, null, new File(getFeedfilePath(context), - getFeedfileName(feed)), true, username, password, lastModified, true, args); + download(context, feed, null, new File(getFeedfilePath(), getFeedfileName(feed)), + true, username, password, lastModified, true, args); } } @@ -203,8 +203,7 @@ public class DownloadRequester { if (feedmedia.getFile_url() != null) { dest = new File(feedmedia.getFile_url()); } else { - dest = new File(getMediafilePath(context, feedmedia), - getMediafilename(feedmedia)); + dest = new File(getMediafilePath(feedmedia), getMediafilename(feedmedia)); } download(context, feedmedia, feed, dest, false, username, password, null, false, null); @@ -305,10 +304,8 @@ public class DownloadRequester { return downloads.size(); } - private synchronized String getFeedfilePath(Context context) - throws DownloadRequestException { - return getExternalFilesDirOrThrowException(context, FEED_DOWNLOADPATH) - .toString() + "/"; + private synchronized String getFeedfilePath() throws DownloadRequestException { + return getExternalFilesDirOrThrowException(FEED_DOWNLOADPATH).toString() + "/"; } private synchronized String getFeedfileName(Feed feed) { @@ -319,10 +316,8 @@ public class DownloadRequester { return "feed-" + FileNameGenerator.generateFileName(filename); } - private synchronized String getMediafilePath(Context context, FeedMedia media) - throws DownloadRequestException { + private synchronized String getMediafilePath(FeedMedia media) throws DownloadRequestException { File externalStorage = getExternalFilesDirOrThrowException( - context, MEDIA_DOWNLOADPATH + FileNameGenerator.generateFileName(media.getItem() .getFeed().getTitle()) + "/" @@ -330,8 +325,7 @@ public class DownloadRequester { return externalStorage.toString(); } - private File getExternalFilesDirOrThrowException(Context context, - String type) throws DownloadRequestException { + private File getExternalFilesDirOrThrowException(String type) throws DownloadRequestException { File result = UserPreferences.getDataFolder(type); if (result == null) { throw new DownloadRequestException( -- cgit v1.2.3 From 3edbbe8c5356f00cd12824b5819ec9b42a347eca Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 26 May 2018 23:13:16 +0200 Subject: Moved notification utils to other package --- .../core/asynctask/FlattrClickWorker.java | 2 +- .../core/service/GpodnetSyncService.java | 3 +- .../core/service/download/DownloadService.java | 4 +- .../core/service/playback/PlaybackService.java | 5 +- .../antennapod/core/util/NotificationUtils.java | 72 ---------------------- .../core/util/gui/NotificationUtils.java | 72 ++++++++++++++++++++++ 6 files changed, 76 insertions(+), 82 deletions(-) delete mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/NotificationUtils.java create mode 100644 core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java index 627e601bd..f4c99011a 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java +++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/FlattrClickWorker.java @@ -10,7 +10,7 @@ import android.support.v4.app.NotificationCompat; import android.util.Log; import android.widget.Toast; -import de.danoeh.antennapod.core.util.NotificationUtils; +import de.danoeh.antennapod.core.util.gui.NotificationUtils; import org.shredzone.flattr4j.exception.FlattrException; import java.util.LinkedList; diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java index 94fadae02..de040603d 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java @@ -8,7 +8,6 @@ import android.content.Intent; import android.support.annotation.NonNull; import android.support.v4.app.JobIntentService; import android.support.v4.app.NotificationCompat; -import android.support.v4.content.ContextCompat; import android.support.v4.util.ArrayMap; import android.util.Log; import android.util.Pair; @@ -39,7 +38,7 @@ import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.DownloadRequestException; import de.danoeh.antennapod.core.storage.DownloadRequester; import de.danoeh.antennapod.core.util.NetworkUtils; -import de.danoeh.antennapod.core.util.NotificationUtils; +import de.danoeh.antennapod.core.util.gui.NotificationUtils; /** * Synchronizes local subscriptions with gpodder.net service. The service should be started with ACTION_SYNC as an action argument. 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 34cabf564..e3b8a505b 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 @@ -7,8 +7,6 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.media.MediaMetadataRetriever; import android.os.Binder; import android.os.Build; @@ -22,7 +20,7 @@ import android.util.Log; import android.util.Pair; import android.webkit.URLUtil; -import de.danoeh.antennapod.core.util.NotificationUtils; +import de.danoeh.antennapod.core.util.gui.NotificationUtils; import org.apache.commons.io.FileUtils; import org.xml.sax.SAXException; 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 c1d23c626..be6cb346d 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 @@ -24,19 +24,16 @@ import android.os.Vibrator; import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.StringRes; -import android.support.v4.content.ContextCompat; import android.support.v4.media.MediaBrowserCompat; import android.support.v4.media.MediaBrowserServiceCompat; import android.support.v4.media.MediaDescriptionCompat; import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; -import android.support.v4.view.InputDeviceCompat; import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import android.util.Log; import android.util.Pair; -import android.view.InputDevice; import android.view.KeyEvent; import android.view.SurfaceHolder; import android.widget.Toast; @@ -68,7 +65,7 @@ import de.danoeh.antennapod.core.storage.DBTasks; import de.danoeh.antennapod.core.storage.DBWriter; import de.danoeh.antennapod.core.storage.FeedSearcher; import de.danoeh.antennapod.core.util.IntList; -import de.danoeh.antennapod.core.util.NotificationUtils; +import de.danoeh.antennapod.core.util.gui.NotificationUtils; import de.danoeh.antennapod.core.util.QueueAccess; import de.danoeh.antennapod.core.util.playback.ExternalMedia; import de.danoeh.antennapod.core.util.playback.Playable; diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/NotificationUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/NotificationUtils.java deleted file mode 100644 index e81b03d77..000000000 --- a/core/src/main/java/de/danoeh/antennapod/core/util/NotificationUtils.java +++ /dev/null @@ -1,72 +0,0 @@ -package de.danoeh.antennapod.core.util; - - -import android.app.NotificationChannel; -import android.app.NotificationManager; -import android.content.Context; -import android.os.Build; -import android.support.annotation.RequiresApi; -import de.danoeh.antennapod.core.R; - -public class NotificationUtils { - public static final String CHANNEL_ID_USER_ACTION = "user_action"; - public static final String CHANNEL_ID_DOWNLOADING = "downloading"; - public static final String CHANNEL_ID_PLAYING = "playing"; - public static final String CHANNEL_ID_ERROR = "error"; - public static final String CHANNEL_ID_GPODNET = "gpodnet"; - - public static void createChannels(Context context) { - if (android.os.Build.VERSION.SDK_INT < 26) { - return; - } - NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - - if (mNotificationManager != null) { - mNotificationManager.createNotificationChannel(createChannelUserAction(context)); - mNotificationManager.createNotificationChannel(createChannelDownloading(context)); - mNotificationManager.createNotificationChannel(createChannelPlaying(context)); - mNotificationManager.createNotificationChannel(createChannelError(context)); - mNotificationManager.createNotificationChannel(createChannelGpodnet(context)); - } - } - - @RequiresApi(api = Build.VERSION_CODES.O) - private static NotificationChannel createChannelUserAction(Context c) { - NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_USER_ACTION, - c.getString(R.string.notification_channel_user_action), NotificationManager.IMPORTANCE_HIGH); - mChannel.setDescription(c.getString(R.string.notification_channel_user_action_description)); - return mChannel; - } - - @RequiresApi(api = Build.VERSION_CODES.O) - private static NotificationChannel createChannelDownloading(Context c) { - NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_DOWNLOADING, - c.getString(R.string.notification_channel_downloading), NotificationManager.IMPORTANCE_LOW); - mChannel.setDescription(c.getString(R.string.notification_channel_downloading_description)); - return mChannel; - } - - @RequiresApi(api = Build.VERSION_CODES.O) - private static NotificationChannel createChannelPlaying(Context c) { - NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_PLAYING, - c.getString(R.string.notification_channel_playing), NotificationManager.IMPORTANCE_LOW); - mChannel.setDescription(c.getString(R.string.notification_channel_playing_description)); - return mChannel; - } - - @RequiresApi(api = Build.VERSION_CODES.O) - private static NotificationChannel createChannelError(Context c) { - NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_ERROR, - c.getString(R.string.notification_channel_error), NotificationManager.IMPORTANCE_HIGH); - mChannel.setDescription(c.getString(R.string.notification_channel_error_description)); - return mChannel; - } - - @RequiresApi(api = Build.VERSION_CODES.O) - private static NotificationChannel createChannelGpodnet(Context c) { - NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_GPODNET, - c.getString(R.string.notification_channel_gpodnet), NotificationManager.IMPORTANCE_MIN); - mChannel.setDescription(c.getString(R.string.notification_channel_gpodnet_description)); - return mChannel; - } -} diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java new file mode 100644 index 000000000..39e4d8335 --- /dev/null +++ b/core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java @@ -0,0 +1,72 @@ +package de.danoeh.antennapod.core.util.gui; + + +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.content.Context; +import android.os.Build; +import android.support.annotation.RequiresApi; +import de.danoeh.antennapod.core.R; + +public class NotificationUtils { + public static final String CHANNEL_ID_USER_ACTION = "user_action"; + public static final String CHANNEL_ID_DOWNLOADING = "downloading"; + public static final String CHANNEL_ID_PLAYING = "playing"; + public static final String CHANNEL_ID_ERROR = "error"; + public static final String CHANNEL_ID_GPODNET = "gpodnet"; + + public static void createChannels(Context context) { + if (android.os.Build.VERSION.SDK_INT < 26) { + return; + } + NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + if (mNotificationManager != null) { + mNotificationManager.createNotificationChannel(createChannelUserAction(context)); + mNotificationManager.createNotificationChannel(createChannelDownloading(context)); + mNotificationManager.createNotificationChannel(createChannelPlaying(context)); + mNotificationManager.createNotificationChannel(createChannelError(context)); + mNotificationManager.createNotificationChannel(createChannelGpodnet(context)); + } + } + + @RequiresApi(api = Build.VERSION_CODES.O) + private static NotificationChannel createChannelUserAction(Context c) { + NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_USER_ACTION, + c.getString(R.string.notification_channel_user_action), NotificationManager.IMPORTANCE_HIGH); + mChannel.setDescription(c.getString(R.string.notification_channel_user_action_description)); + return mChannel; + } + + @RequiresApi(api = Build.VERSION_CODES.O) + private static NotificationChannel createChannelDownloading(Context c) { + NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_DOWNLOADING, + c.getString(R.string.notification_channel_downloading), NotificationManager.IMPORTANCE_LOW); + mChannel.setDescription(c.getString(R.string.notification_channel_downloading_description)); + return mChannel; + } + + @RequiresApi(api = Build.VERSION_CODES.O) + private static NotificationChannel createChannelPlaying(Context c) { + NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_PLAYING, + c.getString(R.string.notification_channel_playing), NotificationManager.IMPORTANCE_LOW); + mChannel.setDescription(c.getString(R.string.notification_channel_playing_description)); + return mChannel; + } + + @RequiresApi(api = Build.VERSION_CODES.O) + private static NotificationChannel createChannelError(Context c) { + NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_ERROR, + c.getString(R.string.notification_channel_error), NotificationManager.IMPORTANCE_HIGH); + mChannel.setDescription(c.getString(R.string.notification_channel_error_description)); + return mChannel; + } + + @RequiresApi(api = Build.VERSION_CODES.O) + private static NotificationChannel createChannelGpodnet(Context c) { + NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_GPODNET, + c.getString(R.string.notification_channel_gpodnet), NotificationManager.IMPORTANCE_MIN); + mChannel.setDescription(c.getString(R.string.notification_channel_gpodnet_description)); + return mChannel; + } +} -- cgit v1.2.3 From badc8398049314451a7c2f51a632e323786d6c7b Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 26 May 2018 23:14:07 +0200 Subject: Gpodder sync does not need a notification anymore --- .../de/danoeh/antennapod/core/util/gui/NotificationUtils.java | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java index 39e4d8335..1c42364ea 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java +++ b/core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java @@ -13,7 +13,6 @@ public class NotificationUtils { public static final String CHANNEL_ID_DOWNLOADING = "downloading"; public static final String CHANNEL_ID_PLAYING = "playing"; public static final String CHANNEL_ID_ERROR = "error"; - public static final String CHANNEL_ID_GPODNET = "gpodnet"; public static void createChannels(Context context) { if (android.os.Build.VERSION.SDK_INT < 26) { @@ -26,7 +25,6 @@ public class NotificationUtils { mNotificationManager.createNotificationChannel(createChannelDownloading(context)); mNotificationManager.createNotificationChannel(createChannelPlaying(context)); mNotificationManager.createNotificationChannel(createChannelError(context)); - mNotificationManager.createNotificationChannel(createChannelGpodnet(context)); } } @@ -61,12 +59,4 @@ public class NotificationUtils { mChannel.setDescription(c.getString(R.string.notification_channel_error_description)); return mChannel; } - - @RequiresApi(api = Build.VERSION_CODES.O) - private static NotificationChannel createChannelGpodnet(Context c) { - NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID_GPODNET, - c.getString(R.string.notification_channel_gpodnet), NotificationManager.IMPORTANCE_MIN); - mChannel.setDescription(c.getString(R.string.notification_channel_gpodnet_description)); - return mChannel; - } } -- cgit v1.2.3 From 9ce48bd86bc5f32f197f2f5b0d3a78596b9c15fe Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 26 May 2018 23:20:47 +0200 Subject: Added a refreshAllFeeds method without callback --- .../java/de/danoeh/antennapod/core/storage/DBTasks.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'core/src/main/java/de/danoeh/antennapod') diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java index 22a7b64fe..da500fd3e 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java @@ -151,6 +151,17 @@ public final class DBTasks { private static final AtomicBoolean isRefreshing = new AtomicBoolean(false); + /** + * Refreshes a given list of Feeds in a separate Thread. This method might ignore subsequent calls if it is still + * enqueuing Feeds for download from a previous call + * + * @param context Might be used for accessing the database + * @param feeds List of Feeds that should be refreshed. + */ + public static void refreshAllFeeds(final Context context, final List feeds) { + refreshAllFeeds(context, feeds, null); + } + /** * Refreshes a given list of Feeds in a separate Thread. This method might ignore subsequent calls if it is still * enqueuing Feeds for download from a previous call @@ -348,7 +359,7 @@ public final class DBTasks { Log.d(TAG, "last refresh: " + Converter.getDurationStringLocalized(context, System.currentTimeMillis() - lastRefresh) + " ago"); if(lastRefresh <= System.currentTimeMillis() - interval) { - DBTasks.refreshAllFeeds(context, null, null); + DBTasks.refreshAllFeeds(context, null); } } -- cgit v1.2.3 From b3e02e215cadafa3d76120f92a022d5f714bcd7e Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 26 May 2018 23:25:18 +0200 Subject: Simplified AutoUpdateManager --- .../core/util/download/AutoUpdateManager.java | 61 ++++++++++++---------- 1 file changed, 34 insertions(+), 27 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 ec9fcae4e..83fe8f137 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 @@ -37,24 +37,28 @@ public class AutoUpdateManager { @RequiresApi(api = Build.VERSION_CODES.N) public static void restartJobServiceInterval(Context context, long intervalMillis) { JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); - if (jobScheduler != null) { - JobInfo oldJob = jobScheduler.getPendingJob(JOB_ID_FEED_UPDATE); - if (oldJob == null || oldJob.getIntervalMillis() != intervalMillis) { - JobInfo.Builder builder = getFeedUpdateJobBuilder(context); - builder.setPeriodic(intervalMillis); - jobScheduler.cancel(JOB_ID_FEED_UPDATE); - - if (intervalMillis <= 0) { - Log.d(TAG, "Automatic update was deactivated"); - return; - } - - jobScheduler.schedule(builder.build()); - Log.d(TAG, "JobScheduler was set at interval " + intervalMillis); - } else { - Log.d(TAG, "JobScheduler was already set at interval " + intervalMillis + ", ignoring."); - } + if (jobScheduler == null) { + Log.d(TAG, "JobScheduler was null."); + return; + } + + JobInfo oldJob = jobScheduler.getPendingJob(JOB_ID_FEED_UPDATE); + if (oldJob != null && oldJob.getIntervalMillis() == intervalMillis) { + Log.d(TAG, "JobScheduler was already set at interval " + intervalMillis + ", ignoring."); + return; + } + + JobInfo.Builder builder = getFeedUpdateJobBuilder(context); + builder.setPeriodic(intervalMillis); + jobScheduler.cancel(JOB_ID_FEED_UPDATE); + + if (intervalMillis <= 0) { + Log.d(TAG, "Automatic update was deactivated"); + return; } + + jobScheduler.schedule(builder.build()); + Log.d(TAG, "JobScheduler was set at interval " + intervalMillis); } public static void restartAlarmManagerInterval(Context context, long triggerAtMillis, long intervalMillis) { @@ -65,8 +69,8 @@ public class AutoUpdateManager { return; } - Intent intent = new Intent(context, FeedUpdateReceiver.class); - PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, intent, 0); + PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, + new Intent(context, FeedUpdateReceiver.class), 0); alarmManager.cancel(updateIntent); if (intervalMillis <= 0) { @@ -82,26 +86,29 @@ public class AutoUpdateManager { @RequiresApi(api = Build.VERSION_CODES.N) public static void restartJobServiceTriggerAt(Context context, long triggerAtMillis) { - JobInfo.Builder builder = getFeedUpdateJobBuilder(context); - builder.setMinimumLatency(triggerAtMillis); JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); - if (jobScheduler != null) { - jobScheduler.cancel(JOB_ID_FEED_UPDATE); - jobScheduler.schedule(builder.build()); - Log.d(TAG, "JobScheduler was set for " + triggerAtMillis); + if (jobScheduler == null) { + Log.d(TAG, "JobScheduler was null."); + return; } + + JobInfo.Builder builder = getFeedUpdateJobBuilder(context); + builder.setMinimumLatency(triggerAtMillis); + jobScheduler.cancel(JOB_ID_FEED_UPDATE); + jobScheduler.schedule(builder.build()); + Log.d(TAG, "JobScheduler was set for " + triggerAtMillis); } public static void restartAlarmManagerTimeOfDay(Context context, Calendar alarm) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, - new Intent(context, FeedUpdateReceiver.class), 0); if (alarmManager == null) { Log.d(TAG, "AlarmManager was null"); return; } + PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0, + new Intent(context, FeedUpdateReceiver.class), 0); alarmManager.cancel(updateIntent); Log.d(TAG, "Alarm set for: " + alarm.toString() + " : " + alarm.getTimeInMillis()); -- cgit v1.2.3 From 443f6315fa2935c413dcfdf2c6cbc96a7a330f84 Mon Sep 17 00:00:00 2001 From: ByteHamster Date: Sat, 26 May 2018 23:30:06 +0200 Subject: Moved methods into AutoUpdateManager --- .../core/preferences/UserPreferences.java | 41 +-------------------- .../core/util/download/AutoUpdateManager.java | 43 ++++++++++++++++++++-- 2 files changed, 41 insertions(+), 43 deletions(-) (limited to 'core/src/main/java/de/danoeh/antennapod') 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 48efdc84c..44b2fa2b2 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 @@ -2,7 +2,6 @@ package de.danoeh.antennapod.core.preferences; import android.content.Context; import android.content.SharedPreferences; -import android.os.Build; import android.preference.PreferenceManager; import android.support.annotation.IntRange; import android.support.annotation.NonNull; @@ -25,7 +24,6 @@ import java.io.IOException; import java.net.Proxy; import java.util.ArrayList; import java.util.Arrays; -import java.util.Calendar; import java.util.List; import java.util.concurrent.TimeUnit; @@ -776,49 +774,14 @@ public class UserPreferences { int[] timeOfDay = getUpdateTimeOfDay(); Log.d(TAG, "timeOfDay: " + Arrays.toString(timeOfDay)); if (timeOfDay.length == 2) { - restartUpdateTimeOfDayAlarm(timeOfDay[0], timeOfDay[1]); + AutoUpdateManager.restartUpdateTimeOfDayAlarm(context, timeOfDay[0], timeOfDay[1]); } else { long milliseconds = getUpdateInterval(); long startTrigger = milliseconds; if (now) { startTrigger = TimeUnit.SECONDS.toMillis(10); } - restartUpdateIntervalAlarm(startTrigger, milliseconds); - } - } - - /** - * Sets the interval in which the feeds are refreshed automatically - */ - private static void restartUpdateIntervalAlarm(long triggerAtMillis, long intervalMillis) { - Log.d(TAG, "Restarting update alarm."); - - if (Build.VERSION.SDK_INT >= 24) { - AutoUpdateManager.restartJobServiceInterval(context, intervalMillis); - } else { - AutoUpdateManager.restartAlarmManagerInterval(context, triggerAtMillis, intervalMillis); - } - } - - /** - * Sets time of day the feeds are refreshed automatically - */ - private static void restartUpdateTimeOfDayAlarm(int hoursOfDay, int minute) { - Log.d(TAG, "Restarting update alarm."); - - Calendar now = Calendar.getInstance(); - Calendar alarm = (Calendar)now.clone(); - alarm.set(Calendar.HOUR_OF_DAY, hoursOfDay); - alarm.set(Calendar.MINUTE, minute); - if (alarm.before(now) || alarm.equals(now)) { - alarm.add(Calendar.DATE, 1); - } - - if (Build.VERSION.SDK_INT >= 24) { - long triggerAtMillis = alarm.getTimeInMillis() - now.getTimeInMillis(); - AutoUpdateManager.restartJobServiceTriggerAt(context, triggerAtMillis); - } else { - AutoUpdateManager.restartAlarmManagerTimeOfDay(context, alarm); + AutoUpdateManager.restartUpdateIntervalAlarm(context, startTrigger, milliseconds); } } 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 83fe8f137..ad723c685 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 @@ -25,6 +25,41 @@ public class AutoUpdateManager { } + /** + * Sets the interval in which the feeds are refreshed automatically + */ + public static void restartUpdateIntervalAlarm(Context context, long triggerAtMillis, long intervalMillis) { + Log.d(TAG, "Restarting update alarm."); + + if (Build.VERSION.SDK_INT >= 24) { + restartJobServiceInterval(context, intervalMillis); + } else { + restartAlarmManagerInterval(context, triggerAtMillis, intervalMillis); + } + } + + /** + * Sets time of day the feeds are refreshed automatically + */ + public static void restartUpdateTimeOfDayAlarm(Context context, int hoursOfDay, int minute) { + Log.d(TAG, "Restarting update alarm."); + + Calendar now = Calendar.getInstance(); + Calendar alarm = (Calendar)now.clone(); + alarm.set(Calendar.HOUR_OF_DAY, hoursOfDay); + alarm.set(Calendar.MINUTE, minute); + if (alarm.before(now) || alarm.equals(now)) { + alarm.add(Calendar.DATE, 1); + } + + if (Build.VERSION.SDK_INT >= 24) { + long triggerAtMillis = alarm.getTimeInMillis() - now.getTimeInMillis(); + restartJobServiceTriggerAt(context, triggerAtMillis); + } else { + restartAlarmManagerTimeOfDay(context, alarm); + } + } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private static JobInfo.Builder getFeedUpdateJobBuilder(Context context) { ComponentName serviceComponent = new ComponentName(context, FeedUpdateJobService.class); @@ -35,7 +70,7 @@ public class AutoUpdateManager { } @RequiresApi(api = Build.VERSION_CODES.N) - public static void restartJobServiceInterval(Context context, long intervalMillis) { + private static void restartJobServiceInterval(Context context, long intervalMillis) { JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); if (jobScheduler == null) { Log.d(TAG, "JobScheduler was null."); @@ -61,7 +96,7 @@ public class AutoUpdateManager { Log.d(TAG, "JobScheduler was set at interval " + intervalMillis); } - public static void restartAlarmManagerInterval(Context context, long triggerAtMillis, long intervalMillis) { + private static void restartAlarmManagerInterval(Context context, long triggerAtMillis, long intervalMillis) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); if (alarmManager == null) { @@ -85,7 +120,7 @@ public class AutoUpdateManager { } @RequiresApi(api = Build.VERSION_CODES.N) - public static void restartJobServiceTriggerAt(Context context, long triggerAtMillis) { + private static void restartJobServiceTriggerAt(Context context, long triggerAtMillis) { JobScheduler jobScheduler = context.getSystemService(JobScheduler.class); if (jobScheduler == null) { Log.d(TAG, "JobScheduler was null."); @@ -99,7 +134,7 @@ public class AutoUpdateManager { Log.d(TAG, "JobScheduler was set for " + triggerAtMillis); } - public static void restartAlarmManagerTimeOfDay(Context context, Calendar alarm) { + private static void restartAlarmManagerTimeOfDay(Context context, Calendar alarm) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); if (alarmManager == null) { -- cgit v1.2.3