summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/src/debug/res/mipmap-hdpi/ic_launcher.pngbin8724 -> 0 bytes
-rw-r--r--core/src/debug/res/mipmap-hdpi/ic_launcher_background.pngbin0 -> 8672 bytes
-rw-r--r--core/src/debug/res/mipmap-hdpi/ic_launcher_foreground.pngbin0 -> 10705 bytes
-rw-r--r--core/src/debug/res/mipmap-mdpi/ic_launcher.pngbin4821 -> 0 bytes
-rw-r--r--core/src/debug/res/mipmap-mdpi/ic_launcher_background.pngbin0 -> 4187 bytes
-rw-r--r--core/src/debug/res/mipmap-mdpi/ic_launcher_foreground.pngbin0 -> 5235 bytes
-rw-r--r--core/src/debug/res/mipmap-xhdpi/ic_launcher.pngbin13548 -> 0 bytes
-rw-r--r--core/src/debug/res/mipmap-xhdpi/ic_launcher_background.pngbin0 -> 10040 bytes
-rw-r--r--core/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.pngbin0 -> 12181 bytes
-rw-r--r--core/src/debug/res/mipmap-xxhdpi/ic_launcher.pngbin25054 -> 0 bytes
-rw-r--r--core/src/debug/res/mipmap-xxhdpi/ic_launcher_background.pngbin0 -> 17155 bytes
-rw-r--r--core/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.pngbin0 -> 21041 bytes
-rw-r--r--core/src/debug/res/mipmap-xxxhdpi/ic_launcher.pngbin38151 -> 0 bytes
-rw-r--r--core/src/debug/res/mipmap-xxxhdpi/ic_launcher_background.pngbin0 -> 23926 bytes
-rw-r--r--core/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.pngbin0 -> 30166 bytes
-rw-r--r--core/src/debug/res/mipmap-xxxhdpi/ic_launcher_monochrome.pngbin0 -> 10269 bytes
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java18
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/receiver/MediaButtonReceiver.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java98
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java47
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java9
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/FeedItemDuplicateGuesser.java15
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java13
-rw-r--r--core/src/main/res/drawable/ic_disc_alert.xml13
-rw-r--r--core/src/main/res/drawable/ic_disc_full.xml9
-rw-r--r--core/src/main/res/drawable/ic_paperclip.xml16
-rw-r--r--core/src/main/res/drawable/ic_sliders.xml5
-rw-r--r--core/src/main/res/layout/refresh_action_view.xml8
-rw-r--r--core/src/main/res/values/arrays.xml48
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/feed/FeedItemTest.java35
-rw-r--r--core/src/test/java/de/danoeh/antennapod/core/storage/FeedItemDuplicateGuesserTest.java3
32 files changed, 179 insertions, 164 deletions
diff --git a/core/src/debug/res/mipmap-hdpi/ic_launcher.png b/core/src/debug/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index 6f8022e25..000000000
--- a/core/src/debug/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/core/src/debug/res/mipmap-hdpi/ic_launcher_background.png b/core/src/debug/res/mipmap-hdpi/ic_launcher_background.png
new file mode 100644
index 000000000..da2b8d47b
--- /dev/null
+++ b/core/src/debug/res/mipmap-hdpi/ic_launcher_background.png
Binary files differ
diff --git a/core/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png b/core/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 000000000..dd7c03e27
--- /dev/null
+++ b/core/src/debug/res/mipmap-hdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/core/src/debug/res/mipmap-mdpi/ic_launcher.png b/core/src/debug/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index d542d555f..000000000
--- a/core/src/debug/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/core/src/debug/res/mipmap-mdpi/ic_launcher_background.png b/core/src/debug/res/mipmap-mdpi/ic_launcher_background.png
new file mode 100644
index 000000000..701d43516
--- /dev/null
+++ b/core/src/debug/res/mipmap-mdpi/ic_launcher_background.png
Binary files differ
diff --git a/core/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png b/core/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 000000000..b7a85063f
--- /dev/null
+++ b/core/src/debug/res/mipmap-mdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/core/src/debug/res/mipmap-xhdpi/ic_launcher.png b/core/src/debug/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index a02ec4ca8..000000000
--- a/core/src/debug/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/core/src/debug/res/mipmap-xhdpi/ic_launcher_background.png b/core/src/debug/res/mipmap-xhdpi/ic_launcher_background.png
new file mode 100644
index 000000000..1adaed041
--- /dev/null
+++ b/core/src/debug/res/mipmap-xhdpi/ic_launcher_background.png
Binary files differ
diff --git a/core/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png b/core/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 000000000..4d5a15f39
--- /dev/null
+++ b/core/src/debug/res/mipmap-xhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/core/src/debug/res/mipmap-xxhdpi/ic_launcher.png b/core/src/debug/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 066f9e5a5..000000000
--- a/core/src/debug/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/core/src/debug/res/mipmap-xxhdpi/ic_launcher_background.png b/core/src/debug/res/mipmap-xxhdpi/ic_launcher_background.png
new file mode 100644
index 000000000..31d4b272e
--- /dev/null
+++ b/core/src/debug/res/mipmap-xxhdpi/ic_launcher_background.png
Binary files differ
diff --git a/core/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png b/core/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 000000000..75caa42c9
--- /dev/null
+++ b/core/src/debug/res/mipmap-xxhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/core/src/debug/res/mipmap-xxxhdpi/ic_launcher.png b/core/src/debug/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 7dbab284c..000000000
--- a/core/src/debug/res/mipmap-xxxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/core/src/debug/res/mipmap-xxxhdpi/ic_launcher_background.png b/core/src/debug/res/mipmap-xxxhdpi/ic_launcher_background.png
new file mode 100644
index 000000000..9edb9ab01
--- /dev/null
+++ b/core/src/debug/res/mipmap-xxxhdpi/ic_launcher_background.png
Binary files differ
diff --git a/core/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/core/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 000000000..630363954
--- /dev/null
+++ b/core/src/debug/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/core/src/debug/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/core/src/debug/res/mipmap-xxxhdpi/ic_launcher_monochrome.png
new file mode 100644
index 000000000..d7e12bda3
--- /dev/null
+++ b/core/src/debug/res/mipmap-xxxhdpi/ic_launcher_monochrome.png
Binary files differ
diff --git a/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java b/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java
index 3b9d6a08d..829add126 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/menuhandler/MenuItemUtils.java
@@ -3,30 +3,12 @@ package de.danoeh.antennapod.core.menuhandler;
import android.view.Menu;
import android.view.MenuItem;
-import de.danoeh.antennapod.core.R;
-
/**
* Utilities for menu items
*/
public class MenuItemUtils {
/**
- * @param menu The menu that the MenuItem belongs to
- * @param resId The id of the MenuItem
- */
- public static void updateRefreshMenuItem(Menu menu, int resId, boolean isRefreshing) {
- // expand actionview if feeds are being downloaded, collapse otherwise
- MenuItem refreshItem = menu.findItem(resId);
- if (isRefreshing) {
- if (refreshItem.getActionView() == null) {
- refreshItem.setActionView(R.layout.refresh_action_view);
- }
- } else {
- refreshItem.setActionView(null);
- }
- }
-
- /**
* When pressing a context menu item, Android calls onContextItemSelected
* for ALL fragments in arbitrary order, not just for the fragment that the
* context menu was created from. This assigns the listener to every menu item,
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 08bdd39bc..161af58e1 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
@@ -17,6 +17,8 @@ import de.danoeh.antennapod.core.ClientConfigurator;
public class MediaButtonReceiver extends BroadcastReceiver {
private static final String TAG = "MediaButtonReceiver";
public static final String EXTRA_KEYCODE = "de.danoeh.antennapod.core.service.extra.MediaButtonReceiver.KEYCODE";
+ public static final String EXTRA_CUSTOM_ACTION =
+ "de.danoeh.antennapod.core.service.extra.MediaButtonReceiver.CUSTOM_ACTION";
public static final String EXTRA_SOURCE = "de.danoeh.antennapod.core.service.extra.MediaButtonReceiver.SOURCE";
public static final String EXTRA_HARDWAREBUTTON
= "de.danoeh.antennapod.core.service.extra.MediaButtonReceiver.HARDWAREBUTTON";
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 5c8dead81..02102db14 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
@@ -63,10 +63,12 @@ import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
import de.danoeh.antennapod.core.service.QuickSettingsTileService;
+import de.danoeh.antennapod.core.service.playback.PlaybackServiceTaskManager.SleepTimer;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.FeedSearcher;
import de.danoeh.antennapod.core.sync.queue.SynchronizationQueueSink;
+import de.danoeh.antennapod.core.util.ChapterUtils;
import de.danoeh.antennapod.core.util.FeedItemUtil;
import de.danoeh.antennapod.core.util.FeedUtil;
import de.danoeh.antennapod.core.util.IntentUtils;
@@ -84,12 +86,12 @@ import de.danoeh.antennapod.event.playback.SleepTimerUpdatedEvent;
import de.danoeh.antennapod.event.settings.SkipIntroEndingChangedEvent;
import de.danoeh.antennapod.event.settings.SpeedPresetChangedEvent;
import de.danoeh.antennapod.event.settings.VolumeAdaptionChangedEvent;
+import de.danoeh.antennapod.model.feed.Chapter;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedItemFilter;
import de.danoeh.antennapod.model.feed.FeedMedia;
import de.danoeh.antennapod.model.feed.FeedPreferences;
-import de.danoeh.antennapod.model.feed.SortOrder;
import de.danoeh.antennapod.model.playback.MediaType;
import de.danoeh.antennapod.model.playback.Playable;
import de.danoeh.antennapod.playback.base.PlaybackServiceMediaPlayer;
@@ -127,6 +129,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
private static final String CUSTOM_ACTION_REWIND = "action.de.danoeh.antennapod.core.service.rewind";
private static final String CUSTOM_ACTION_CHANGE_PLAYBACK_SPEED =
"action.de.danoeh.antennapod.core.service.changePlaybackSpeed";
+ public static final String CUSTOM_ACTION_NEXT_CHAPTER = "action.de.danoeh.antennapod.core.service.next_chapter";
/**
* Set a max number of episodes to load for Android Auto, otherwise there could be performance issues
@@ -327,7 +330,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
if (rootHints != null && rootHints.getBoolean(BrowserRoot.EXTRA_RECENT)) {
Bundle extras = new Bundle();
extras.putBoolean(BrowserRoot.EXTRA_RECENT, true);
- return new BrowserRoot(getResources().getString(R.string.recently_played_episodes), extras);
+ Log.d(TAG, "OnGetRoot: Returning BrowserRoot " + R.string.current_playing_episode);
+ return new BrowserRoot(getResources().getString(R.string.current_playing_episode), extras);
}
// Name visible in Android Auto
@@ -408,6 +412,11 @@ public class PlaybackService extends MediaBrowserServiceCompat {
private List<MediaBrowserCompat.MediaItem> loadChildrenSynchronous(@NonNull String parentId) {
List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();
if (parentId.equals(getResources().getString(R.string.app_name))) {
+ long currentlyPlaying = PlaybackPreferences.getCurrentPlayerStatus();
+ if (currentlyPlaying == PlaybackPreferences.PLAYER_STATUS_PLAYING
+ || currentlyPlaying == PlaybackPreferences.PLAYER_STATUS_PAUSED) {
+ mediaItems.add(createBrowsableMediaItem(R.string.current_playing_episode, R.drawable.ic_play_48dp, 1));
+ }
mediaItems.add(createBrowsableMediaItem(R.string.queue_label, R.drawable.ic_playlist_play_black,
DBReader.getTotalEpisodeCount(new FeedItemFilter(FeedItemFilter.QUEUED))));
mediaItems.add(createBrowsableMediaItem(R.string.downloads_label, R.drawable.ic_download_black,
@@ -429,11 +438,12 @@ public class PlaybackService extends MediaBrowserServiceCompat {
new FeedItemFilter(FeedItemFilter.DOWNLOADED), UserPreferences.getDownloadsSortedOrder());
} else if (parentId.equals(getResources().getString(R.string.episodes_label))) {
feedItems = DBReader.getEpisodes(0, MAX_ANDROID_AUTO_EPISODES_PER_FEED,
- new FeedItemFilter(FeedItemFilter.UNPLAYED), SortOrder.DATE_NEW_OLD);
+ new FeedItemFilter(FeedItemFilter.UNPLAYED), UserPreferences.getAllEpisodesSortOrder());
} else if (parentId.startsWith("FeedId:")) {
long feedId = Long.parseLong(parentId.split(":")[1]);
- feedItems = DBReader.getFeedItemList(DBReader.getFeed(feedId));
- } else if (parentId.equals(getString(R.string.recently_played_episodes))) {
+ Feed feed = DBReader.getFeed(feedId);
+ feedItems = DBReader.getFeedItemList(feed, FeedItemFilter.unfiltered(), feed.getSortOrder());
+ } else if (parentId.equals(getString(R.string.current_playing_episode))) {
Playable playable = PlaybackPreferences.createInstanceFromPreferences(this);
if (playable instanceof FeedMedia) {
feedItems = Collections.singletonList(((FeedMedia) playable).getItem());
@@ -476,9 +486,10 @@ public class PlaybackService extends MediaBrowserServiceCompat {
notificationManager.cancel(R.id.notification_streaming_confirmation);
final int keycode = intent.getIntExtra(MediaButtonReceiver.EXTRA_KEYCODE, -1);
+ final String customAction = intent.getStringExtra(MediaButtonReceiver.EXTRA_CUSTOM_ACTION);
final boolean hardwareButton = intent.getBooleanExtra(MediaButtonReceiver.EXTRA_HARDWAREBUTTON, false);
Playable playable = intent.getParcelableExtra(PlaybackServiceInterface.EXTRA_PLAYABLE);
- if (keycode == -1 && playable == null) {
+ if (keycode == -1 && playable == null && customAction == null) {
Log.e(TAG, "PlaybackService was started with no arguments");
stateManager.stopService();
return Service.START_NOT_STICKY;
@@ -502,7 +513,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
stateManager.stopService();
return Service.START_NOT_STICKY;
}
- } else {
+ } else if (playable != null) {
stateManager.validStartCommandWasReceived();
boolean allowStreamThisTime = intent.getBooleanExtra(
PlaybackServiceInterface.EXTRA_ALLOW_STREAM_THIS_TIME, false);
@@ -530,6 +541,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
stateManager.stopService();
});
return Service.START_NOT_STICKY;
+ } else {
+ mediaSession.getController().getTransportControls().sendCustomAction(customAction, null);
}
}
@@ -777,6 +790,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
@Override
public void onChapterLoaded(Playable media) {
sendNotificationBroadcast(PlaybackServiceInterface.NOTIFICATION_TYPE_RELOAD, 0);
+ updateMediaSession(mediaPlayer.getPlayerStatus());
}
};
@@ -965,7 +979,10 @@ public class PlaybackService extends MediaBrowserServiceCompat {
if (event.isOver()) {
mediaPlayer.pause(true, true);
mediaPlayer.setVolume(1.0f, 1.0f);
- } else if (event.getTimeLeft() < PlaybackServiceTaskManager.SleepTimer.NOTIFICATION_THRESHOLD) {
+ int newPosition = mediaPlayer.getPosition() - (int) SleepTimer.NOTIFICATION_THRESHOLD / 2;
+ newPosition = Math.max(newPosition, 0);
+ seekTo(newPosition);
+ } else if (event.getTimeLeft() < SleepTimer.NOTIFICATION_THRESHOLD) {
final float[] multiplicators = {0.1f, 0.2f, 0.3f, 0.3f, 0.3f, 0.4f, 0.4f, 0.4f, 0.6f, 0.8f};
float multiplicator = multiplicators[Math.max(0, (int) event.getTimeLeft() / 1000)];
Log.d(TAG, "onSleepTimerAlmostExpired: " + multiplicator);
@@ -1244,20 +1261,35 @@ public class PlaybackService extends MediaBrowserServiceCompat {
WearMediaSession.addWearExtrasToAction(fastForwardBuilder);
sessionState.addCustomAction(fastForwardBuilder.build());
- sessionState.addCustomAction(
- new PlaybackStateCompat.CustomAction.Builder(
- CUSTOM_ACTION_CHANGE_PLAYBACK_SPEED,
- getString(R.string.playback_speed),
- R.drawable.ic_notification_playback_speed
+ if (UserPreferences.showPlaybackSpeedOnFullNotification()) {
+ sessionState.addCustomAction(
+ new PlaybackStateCompat.CustomAction.Builder(
+ CUSTOM_ACTION_CHANGE_PLAYBACK_SPEED,
+ getString(R.string.playback_speed),
+ R.drawable.ic_notification_playback_speed
).build()
- );
- sessionState.addCustomAction(
+ );
+ }
+
+ if (UserPreferences.showNextChapterOnFullNotification()) {
+ if (getPlayable() != null && getPlayable().getChapters() != null) {
+ sessionState.addCustomAction(
+ new PlaybackStateCompat.CustomAction.Builder(
+ CUSTOM_ACTION_NEXT_CHAPTER,
+ getString(R.string.next_chapter), R.drawable.ic_notification_next_chapter)
+ .build());
+ }
+ }
+
+ if (UserPreferences.showSkipOnFullNotification()) {
+ sessionState.addCustomAction(
new PlaybackStateCompat.CustomAction.Builder(
- CUSTOM_ACTION_SKIP_TO_NEXT,
- getString(R.string.skip_episode_label),
- R.drawable.ic_notification_skip
+ CUSTOM_ACTION_SKIP_TO_NEXT,
+ getString(R.string.skip_episode_label),
+ R.drawable.ic_notification_skip
).build()
- );
+ );
+ }
WearMediaSession.mediaSessionSetExtraForWear(mediaSession);
@@ -1765,6 +1797,12 @@ public class PlaybackService extends MediaBrowserServiceCompat {
public void onPlayFromSearch(String query, Bundle extras) {
Log.d(TAG, "onPlayFromSearch query=" + query + " extras=" + extras.toString());
+ if (query.equals("")) {
+ Log.d(TAG, "onPlayFromSearch called with empty query, resuming from the last position");
+ startPlayingFromPreferences();
+ return;
+ }
+
List<FeedItem> results = FeedSearcher.searchFeedItems(query, 0);
if (results.size() > 0 && results.get(0).getMedia() != null) {
FeedMedia media = results.get(0).getMedia();
@@ -1800,6 +1838,26 @@ public class PlaybackService extends MediaBrowserServiceCompat {
seekDelta(-UserPreferences.getRewindSecs() * 1000);
}
+ public void onNextChapter() {
+ List<Chapter> chapters = mediaPlayer.getPlayable().getChapters();
+ if (chapters == null) {
+ // No chapters, just fallback to next episode
+ mediaPlayer.skip();
+ return;
+ }
+
+ int nextChapter = ChapterUtils.getCurrentChapterIndex(
+ mediaPlayer.getPlayable(), mediaPlayer.getPosition()) + 1;
+
+ if (chapters.size() < nextChapter + 1) {
+ // We are on the last chapter, just fallback to the next episode
+ mediaPlayer.skip();
+ return;
+ }
+
+ mediaPlayer.seekTo((int) chapters.get(nextChapter).getStart());
+ }
+
@Override
public void onFastForward() {
Log.d(TAG, "onFastForward()");
@@ -1872,6 +1930,8 @@ public class PlaybackService extends MediaBrowserServiceCompat {
onRewind();
} else if (CUSTOM_ACTION_SKIP_TO_NEXT.equals(action)) {
mediaPlayer.skip();
+ } else if (CUSTOM_ACTION_NEXT_CHAPTER.equals(action)) {
+ onNextChapter();
} else if (CUSTOM_ACTION_CHANGE_PLAYBACK_SPEED.equals(action)) {
List<Float> selectedSpeeds = UserPreferences.getPlaybackSpeedArray();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
index fe98dbc8f..471dc7454 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java
@@ -175,14 +175,12 @@ public class PlaybackServiceNotificationBuilder {
ArrayList<Integer> compactActionList = new ArrayList<>();
int numActions = 0; // we start and 0 and then increment by 1 for each call to addAction
- // always let them rewind
+
PendingIntent rewindButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_REWIND, numActions);
notification.addAction(R.drawable.ic_notification_fast_rewind, context.getString(R.string.rewind_label),
rewindButtonPendingIntent);
- if (UserPreferences.showRewindOnCompactNotification()) {
- compactActionList.add(numActions);
- }
+ compactActionList.add(numActions);
numActions++;
if (playerStatus == PlayerStatus.PLAYING) {
@@ -205,19 +203,24 @@ public class PlaybackServiceNotificationBuilder {
KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, numActions);
notification.addAction(R.drawable.ic_notification_fast_forward, context.getString(R.string.fast_forward_label),
ffButtonPendingIntent);
- if (UserPreferences.showFastForwardOnCompactNotification()) {
- compactActionList.add(numActions);
- }
+ compactActionList.add(numActions);
numActions++;
- PendingIntent skipButtonPendingIntent = getPendingIntentForMediaAction(
- KeyEvent.KEYCODE_MEDIA_NEXT, numActions);
- notification.addAction(R.drawable.ic_notification_skip, context.getString(R.string.skip_episode_label),
- skipButtonPendingIntent);
- if (UserPreferences.showSkipOnCompactNotification()) {
- compactActionList.add(numActions);
+ if (UserPreferences.showNextChapterOnFullNotification() && playable.getChapters() != null) {
+ PendingIntent nextChapterPendingIntent = getPendingIntentForCustomMediaAction(
+ PlaybackService.CUSTOM_ACTION_NEXT_CHAPTER, numActions);
+ notification.addAction(R.drawable.ic_notification_next_chapter, context.getString(R.string.next_chapter),
+ nextChapterPendingIntent);
+ numActions++;
+ }
+
+ if (UserPreferences.showSkipOnFullNotification()) {
+ PendingIntent skipButtonPendingIntent = getPendingIntentForMediaAction(
+ KeyEvent.KEYCODE_MEDIA_NEXT, numActions);
+ notification.addAction(R.drawable.ic_notification_skip, context.getString(R.string.skip_episode_label),
+ skipButtonPendingIntent);
+ numActions++;
}
- numActions++;
PendingIntent stopButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_STOP, numActions);
@@ -242,6 +245,20 @@ public class PlaybackServiceNotificationBuilder {
}
}
+ private PendingIntent getPendingIntentForCustomMediaAction(String action, int requestCode) {
+ Intent intent = new Intent(context, PlaybackService.class);
+ intent.setAction("MediaAction" + action);
+ intent.putExtra(MediaButtonReceiver.EXTRA_CUSTOM_ACTION, action);
+
+ if (Build.VERSION.SDK_INT >= 26) {
+ return PendingIntent.getForegroundService(context, requestCode, intent,
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+ } else {
+ return PendingIntent.getService(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT
+ | (Build.VERSION.SDK_INT >= 23 ? PendingIntent.FLAG_IMMUTABLE : 0));
+ }
+ }
+
public void setMediaSessionToken(MediaSessionCompat.Token mediaSessionToken) {
this.mediaSessionToken = mediaSessionToken;
}
@@ -253,4 +270,4 @@ public class PlaybackServiceNotificationBuilder {
public PlayerStatus getPlayerStatus() {
return playerStatus;
}
-} \ No newline at end of file
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java
index dbbfba379..ecfe5f4dd 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/AutomaticDownloadAlgorithm.java
@@ -69,7 +69,9 @@ public class AutomaticDownloadAlgorithm {
Iterator<FeedItem> it = candidates.iterator();
while (it.hasNext()) {
FeedItem item = it.next();
- if (!item.isAutoDownloadable(System.currentTimeMillis())
+ if (!item.isAutoDownloadEnabled()
+ || item.isDownloaded()
+ || !item.hasMedia()
|| PlaybackStatus.isPlaying(item.getMedia())
|| item.getFeed().isLocalFeed()) {
it.remove();
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
index 084b3a7ad..492dff759 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java
@@ -15,9 +15,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import de.danoeh.antennapod.core.util.FeedItemPermutors;
import de.danoeh.antennapod.core.util.LongList;
import de.danoeh.antennapod.core.util.comparator.DownloadResultComparator;
-import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
import de.danoeh.antennapod.core.util.comparator.PlaybackCompletionDateComparator;
import de.danoeh.antennapod.model.feed.Chapter;
import de.danoeh.antennapod.model.feed.Feed;
@@ -170,13 +170,18 @@ public final class DBReader {
}
public static List<FeedItem> getFeedItemList(final Feed feed, final FeedItemFilter filter) {
+ return getFeedItemList(feed, filter, SortOrder.DATE_NEW_OLD);
+ }
+
+ public static List<FeedItem> getFeedItemList(final Feed feed, final FeedItemFilter filter, SortOrder sortOrder) {
Log.d(TAG, "getFeedItemList() called with: " + "feed = [" + feed + "]");
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
try (Cursor cursor = adapter.getItemsOfFeedCursor(feed, filter)) {
List<FeedItem> items = extractItemlistFromCursor(adapter, cursor);
- Collections.sort(items, new FeedItemPubdateComparator());
+ FeedItemPermutors.getPermutor(sortOrder).reorder(items);
+ feed.setItems(items);
for (FeedItem item : items) {
item.setFeed(feed);
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedItemDuplicateGuesser.java b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedItemDuplicateGuesser.java
index 35d77ae4a..2ff9d8848 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedItemDuplicateGuesser.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedItemDuplicateGuesser.java
@@ -28,7 +28,7 @@ public class FeedItemDuplicateGuesser {
return titlesLookSimilar(item1, item2)
&& datesLookSimilar(item1, item2)
&& durationsLookSimilar(media1, media2)
- && TextUtils.equals(media1.getMime_type(), media2.getMime_type());
+ && mimeTypeLooksSimilar(media1, media2);
}
private static boolean sameAndNotEmpty(String string1, String string2) {
@@ -52,6 +52,19 @@ public class FeedItemDuplicateGuesser {
return Math.abs(media1.getDuration() - media2.getDuration()) < 10 * 60L * 1000L;
}
+ private static boolean mimeTypeLooksSimilar(FeedMedia media1, FeedMedia media2) {
+ String mimeType1 = media1.getMime_type();
+ String mimeType2 = media2.getMime_type();
+ if (mimeType1 == null || mimeType2 == null) {
+ return true;
+ }
+ if (mimeType1.contains("/") && mimeType2.contains("/")) {
+ mimeType1 = mimeType1.substring(0, mimeType1.indexOf("/"));
+ mimeType2 = mimeType2.substring(0, mimeType2.indexOf("/"));
+ }
+ return TextUtils.equals(mimeType1, mimeType2);
+ }
+
private static boolean titlesLookSimilar(FeedItem item1, FeedItem item2) {
return sameAndNotEmpty(canonicalizeTitle(item1.getTitle()), canonicalizeTitle(item2.getTitle()));
}
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 13f2af762..630507487 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
@@ -10,6 +10,7 @@ import androidx.core.app.ShareCompat;
import androidx.core.content.FileProvider;
import java.io.File;
+import java.net.URLEncoder;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.model.feed.Feed;
@@ -33,12 +34,12 @@ public class ShareUtils {
}
public static void shareFeedLink(Context context, Feed feed) {
- String text = feed.getTitle();
- if (feed.getLink() != null) {
- text += "\n" + feed.getLink();
- }
- text += "\n\n" + context.getResources().getString(R.string.share_rss_address_label)
- + " " + feed.getDownload_url();
+ String text = feed.getTitle()
+ + "\n\n"
+ + "https://antennapod.org/deeplink/subscribe/?url="
+ + URLEncoder.encode(feed.getDownload_url())
+ + "&title="
+ + URLEncoder.encode(feed.getTitle());
shareLink(context, text);
}
diff --git a/core/src/main/res/drawable/ic_disc_alert.xml b/core/src/main/res/drawable/ic_disc_alert.xml
new file mode 100644
index 000000000..6a2c11187
--- /dev/null
+++ b/core/src/main/res/drawable/ic_disc_alert.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="?attr/action_icon_color"
+ android:pathData="M10 14C8.9 14 8 13.1 8 12C8 10.9 8.9 10 10 10C11.1 10 12 10.9 12 12S11.1 14 10 14M10 4C5.6 4 2 7.6 2 12S5.6 20 10 20 18 16.4 18 12 14.4 4 10 4M20 13H22V7H20M20 17H22V15H20V17Z" />
+
+</vector>
diff --git a/core/src/main/res/drawable/ic_disc_full.xml b/core/src/main/res/drawable/ic_disc_full.xml
deleted file mode 100644
index 2aba1bc53..000000000
--- a/core/src/main/res/drawable/ic_disc_full.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="20dp"
- android:height="16dp"
- android:viewportWidth="20"
- android:viewportHeight="16">
- <path
- android:pathData="M17.1 11.5s0-1.7 0-1.7s1.8 0 1.8 0s0 1.7 0 1.7s-1.8 0-1.8 0zm0-8s1.8 0 1.8 0s0 4.5 0 4.5s-1.8 0-1.8 0s0-4.5 0-4.5zm-8.9-2.6c2 0 3.6 0.7 5 2.1s2.1 3 2.1 5s-0.7 3.7-2.1 5s-3 2.1-5 2.1c-1.9 0-3.6-0.7-5-2.1s-2.1-3-2.1-5s0.7-3.6 2.1-5s3.1-2.1 5-2.1zm0 8.9c0.5 0 0.9-0.2 1.3-0.5s0.5-0.8 0.5-1.3s-0.2-0.9-0.5-1.3s-0.8-0.5-1.3-0.5s-0.9 0.2-1.2 0.5s-0.6 0.8-0.6 1.3s0.2 0.9 0.6 1.3s0.7 0.5 1.2 0.5z"
- android:fillColor="?android:attr/textColorPrimary" />
-</vector> \ No newline at end of file
diff --git a/core/src/main/res/drawable/ic_paperclip.xml b/core/src/main/res/drawable/ic_paperclip.xml
new file mode 100644
index 000000000..dd6673c13
--- /dev/null
+++ b/core/src/main/res/drawable/ic_paperclip.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="12dp"
+ android:width="12dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <group>
+ <path
+ android:fillColor="?attr/action_icon_color"
+ android:pathData="M16.5,6V17.5A4,4 0 0,1 12.5,21.5A4,4 0 0,1 8.5,17.5V5A2.5,2.5 0 0,1 11,2.5A2.5,2.5 0 0,1 13.5,5V15.5A1,1 0 0,1 12.5,16.5A1,1 0 0,1 11.5,15.5V6H10V15.5A2.5,2.5 0 0,0 12.5,18A2.5,2.5 0 0,0 15,15.5V5A4,4 0 0,0 11,1A4,4 0 0,0 7,5V17.5A5.5,5.5 0 0,0 12.5,23A5.5,5.5 0 0,0 18,17.5V6H16.5Z" />
+
+ </group>
+
+</vector>
diff --git a/core/src/main/res/drawable/ic_sliders.xml b/core/src/main/res/drawable/ic_sliders.xml
deleted file mode 100644
index c6f3de7b4..000000000
--- a/core/src/main/res/drawable/ic_sliders.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<vector android:height="24dp"
- android:viewportHeight="24.0" android:viewportWidth="24.0"
- android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
- <path android:fillColor="?attr/action_icon_color" android:pathData="M3,17V19H9V17H3M3,5V7H13V5H3M13,21V19H21V17H13V15H11V21H13M7,9V11H3V13H7V15H9V9H7M21,13V11H11V13H21M15,9H17V7H21V5H17V3H15V9Z"/>
-</vector>
diff --git a/core/src/main/res/layout/refresh_action_view.xml b/core/src/main/res/layout/refresh_action_view.xml
deleted file mode 100644
index d5b88922e..000000000
--- a/core/src/main/res/layout/refresh_action_view.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<ProgressBar
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_gravity="end"
- android:padding="8dp"
- android:indeterminateOnly="true"/>
diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml
index 50afe630b..7eeab886a 100644
--- a/core/src/main/res/values/arrays.xml
+++ b/core/src/main/res/values/arrays.xml
@@ -246,52 +246,10 @@
<item>DownloadsSection</item>
</string-array>
- <!-- sort for podcast screen, not for queue -->
- <string-array name="feed_episodes_sort_options">
- <item>@string/sort_date_new_old</item>
- <item>@string/sort_date_old_new</item>
- <item>@string/sort_title_a_z</item>
- <item>@string/sort_title_z_a</item>
- <item>@string/sort_duration_short_long</item>
- <item>@string/sort_duration_long_short</item>
- </string-array>
-
- <!-- sort for local feed screen -->
- <string-array name="local_feed_episodes_sort_options">
- <item>@string/sort_date_new_old</item>
- <item>@string/sort_date_old_new</item>
- <item>@string/sort_title_a_z</item>
- <item>@string/sort_title_z_a</item>
- <item>@string/sort_duration_short_long</item>
- <item>@string/sort_duration_long_short</item>
- <item>@string/sort_filename_a_z</item>
- <item>@string/sort_filename_z_a</item>
- </string-array>
-
- <string-array name="feed_episodes_sort_values">
- <item>DATE_NEW_OLD</item>
- <item>DATE_OLD_NEW</item>
- <item>EPISODE_TITLE_A_Z</item>
- <item>EPISODE_TITLE_Z_A</item>
- <item>DURATION_SHORT_LONG</item>
- <item>DURATION_LONG_SHORT</item>
- </string-array>
-
- <string-array name="local_feed_episodes_sort_values">
- <item>DATE_NEW_OLD</item>
- <item>DATE_OLD_NEW</item>
- <item>EPISODE_TITLE_A_Z</item>
- <item>EPISODE_TITLE_Z_A</item>
- <item>DURATION_SHORT_LONG</item>
- <item>DURATION_LONG_SHORT</item>
- <item>EPISODE_FILENAME_A_Z</item>
- <item>EPISODE_FILENAME_Z_A</item>
- </string-array>
-
- <string-array name="compact_notification_buttons_options">
- <item>@string/rewind_label</item>
- <item>@string/fast_forward_label</item>
+ <string-array name="full_notification_buttons_options">
<item>@string/skip_episode_label</item>
+ <item>@string/next_chapter</item>
+ <item>@string/playback_speed</item>
</string-array>
<string-array name="default_page_values">
diff --git a/core/src/test/java/de/danoeh/antennapod/core/feed/FeedItemTest.java b/core/src/test/java/de/danoeh/antennapod/core/feed/FeedItemTest.java
index a08d0897d..62775b84b 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/feed/FeedItemTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/feed/FeedItemTest.java
@@ -1,7 +1,6 @@
package de.danoeh.antennapod.core.feed;
import de.danoeh.antennapod.model.feed.FeedItem;
-import de.danoeh.antennapod.model.feed.FeedMedia;
import org.junit.Before;
import org.junit.Test;
@@ -11,13 +10,11 @@ import java.util.Date;
import static de.danoeh.antennapod.core.feed.FeedItemMother.anyFeedItemWithImage;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
public class FeedItemTest {
private static final String TEXT_LONG = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
private static final String TEXT_SHORT = "Lorem ipsum";
- private static final long ONE_HOUR = 1000L * 3600L;
private FeedItem original;
private FeedItem changedFeedItem;
@@ -139,36 +136,4 @@ public class FeedItemTest {
item.setDescriptionIfLonger(contentEncoded);
assertEquals(TEXT_LONG, item.getDescription());
}
-
- @Test
- public void testAutoDownloadBackoff() {
- FeedItem item = new FeedItem();
- item.setMedia(new FeedMedia(item, "https://example.com/file.mp3", 0, "audio/mpeg"));
-
- long now = ONE_HOUR; // In reality, this is System.currentTimeMillis()
- assertTrue(item.isAutoDownloadable(now));
- item.increaseFailedAutoDownloadAttempts(now);
- assertFalse(item.isAutoDownloadable(now));
-
- now += ONE_HOUR;
- assertTrue(item.isAutoDownloadable(now));
- item.increaseFailedAutoDownloadAttempts(now);
- assertFalse(item.isAutoDownloadable(now));
-
- now += ONE_HOUR;
- assertFalse(item.isAutoDownloadable(now)); // Should backoff, so more than 1 hour needed
-
- now += ONE_HOUR;
- assertTrue(item.isAutoDownloadable(now)); // Now it's enough
- item.increaseFailedAutoDownloadAttempts(now);
- item.increaseFailedAutoDownloadAttempts(now);
- item.increaseFailedAutoDownloadAttempts(now);
-
- now += 1000L * ONE_HOUR;
- assertFalse(item.isAutoDownloadable(now)); // Should have given up
- item.increaseFailedAutoDownloadAttempts(now);
-
- now += 1000L * ONE_HOUR;
- assertFalse(item.isAutoDownloadable(now)); // Still given up
- }
}
diff --git a/core/src/test/java/de/danoeh/antennapod/core/storage/FeedItemDuplicateGuesserTest.java b/core/src/test/java/de/danoeh/antennapod/core/storage/FeedItemDuplicateGuesserTest.java
index ac7cdee1f..f3c993066 100644
--- a/core/src/test/java/de/danoeh/antennapod/core/storage/FeedItemDuplicateGuesserTest.java
+++ b/core/src/test/java/de/danoeh/antennapod/core/storage/FeedItemDuplicateGuesserTest.java
@@ -44,6 +44,9 @@ public class FeedItemDuplicateGuesserTest {
assertFalse(FeedItemDuplicateGuesser.seemDuplicates(
item("id1", "Title", "example.com/episode1", 10, 5 * MINUTES, "audio/*"),
item("id2", "Title", "example.com/episode2", 10, 5 * MINUTES, "video/*")));
+ assertTrue(FeedItemDuplicateGuesser.seemDuplicates(
+ item("id1", "Title", "example.com/episode1", 10, 5 * MINUTES, "audio/mpeg"),
+ item("id2", "Title", "example.com/episode2", 10, 5 * MINUTES, "audio/mp3")));
assertFalse(FeedItemDuplicateGuesser.seemDuplicates(
item("id1", "Title", "example.com/episode1", 5 * DAYS, 5 * MINUTES, "audio/*"),
item("id2", "Title", "example.com/episode2", 2 * DAYS, 5 * MINUTES, "audio/*")));