summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorMax Bechtold <max.bechtold@andrena.de>2019-10-17 12:36:45 +0200
committerMax Bechtold <max.bechtold@andrena.de>2019-10-17 13:13:19 +0200
commit87cca61dcd8337facf695f03f1330c55bfa85168 (patch)
tree630888c57de93856f33184ec475f01716812deff /core
parentcc9c8bb63a27deb35f0e234d252e22a73ef6c117 (diff)
parent2ffdc275b8dd127f15506556d1b7ba9fb9108b47 (diff)
downloadAntennaPod-87cca61dcd8337facf695f03f1330c55bfa85168.zip
Merge remote-tracking branch 'origin/develop' into feat/simple-adjust-volume-per-feed
Diffstat (limited to 'core')
-rw-r--r--core/build.gradle18
-rw-r--r--core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java2
-rw-r--r--core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java2
-rw-r--r--core/src/main/java/androidx/core/app/SafeJobIntentService.java (renamed from core/src/main/java/android/support/v4/app/SafeJobIntentService.java)4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/MessageEvent.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedMedia.java3
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java22
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java25
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackSpeedHelper.java41
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/SleepTimerPreferences.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/preferences/UserPreferences.java23
-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/FeedUpdateWorker.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/GpodnetSyncService.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/PlayerWidgetJobService.java11
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java8
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/LocalPSMP.java11
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java121
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceNotificationBuilder.java169
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java20
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java77
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DownloadRequester.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java31
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/ShareUtils.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/gui/NotificationUtils.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java461
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/Playable.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackController.java21
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/PlaybackServiceStarter.java5
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java2
-rw-r--r--core/src/main/res/drawable/notification_default_large_icon.xml15
-rw-r--r--core/src/main/res/values/strings.xml3
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/CastCallbacks.java4
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java10
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/cast/RemoteMedia.java2
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/cast/SwitchableMediaRouteActionProvider.java12
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java6
-rw-r--r--core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java2
78 files changed, 728 insertions, 534 deletions
diff --git a/core/build.gradle b/core/build.gradle
index 8614d5589..fe6ed824a 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -10,7 +10,7 @@ android {
versionCode 1
versionName "1.0"
testApplicationId "de.danoeh.antennapod.core.tests"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions {
annotationProcessorOptions {
@@ -56,11 +56,11 @@ android {
}
dependencies {
- implementation "com.android.support:support-v4:$supportVersion"
- implementation "com.android.support:appcompat-v7:$supportVersion"
- implementation "com.android.support:preference-v14:$supportVersion"
+ implementation "androidx.appcompat:appcompat:1.1.0"
+ implementation "androidx.preference:preference:1.1.0"
+ annotationProcessor "androidx.annotation:annotation:1.1.0"
implementation "android.arch.work:work-runtime:$workManagerVersion"
-
+ implementation "androidx.media:media:1.1.0"
implementation "org.apache.commons:commons-lang3:$commonslangVersion"
implementation "org.apache.commons:commons-text:$commonstextVersion"
implementation "commons-io:commons-io:$commonsioVersion"
@@ -84,7 +84,7 @@ dependencies {
// free build hack: skip some dependencies
if (!doFreeBuild()) {
playApi "com.google.android.libraries.cast.companionlibrary:ccl:$castCompanionLibVer"
- api "com.android.support:mediarouter-v7:$supportVersion"
+ api "androidx.mediarouter:mediarouter:1.0.0"
playApi "com.google.android.gms:play-services-cast:$playServicesVersion"
api "com.google.android.support:wearable:$wearableSupportVersion"
} else {
@@ -94,9 +94,9 @@ dependencies {
testImplementation "org.awaitility:awaitility:$awaitilityVersion"
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:1.10.19'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test:rules:1.0.2'
+ androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test:rules:1.2.0'
}
diff --git a/core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java b/core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java
index ffba4e479..5d98f133c 100644
--- a/core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java
+++ b/core/src/androidTest/java/de/danoeh/antennapod/core/util/DateUtilsTest.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.util;
-import android.support.test.filters.SmallTest;
+import androidx.test.filters.SmallTest;
import org.junit.Test;
import java.util.Calendar;
diff --git a/core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java b/core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
index 37109ddca..837cb1bd0 100644
--- a/core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
+++ b/core/src/free/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.service.playback;
import android.content.Context;
-import android.support.annotation.StringRes;
+import androidx.annotation.StringRes;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
diff --git a/core/src/main/java/android/support/v4/app/SafeJobIntentService.java b/core/src/main/java/androidx/core/app/SafeJobIntentService.java
index c07c409ee..aedc9418b 100644
--- a/core/src/main/java/android/support/v4/app/SafeJobIntentService.java
+++ b/core/src/main/java/androidx/core/app/SafeJobIntentService.java
@@ -1,4 +1,4 @@
-package android.support.v4.app;
+package androidx.core.app;
import android.app.job.JobParameters;
import android.app.job.JobServiceEngine;
@@ -6,7 +6,7 @@ import android.app.job.JobWorkItem;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
-import android.support.annotation.RequiresApi;
+import androidx.annotation.RequiresApi;
import android.util.Log;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java b/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java
index c626a8189..c9fe886fb 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/dialog/ConfirmationDialog.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.dialog;
import android.content.Context;
import android.content.DialogInterface;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import android.util.Log;
import de.danoeh.antennapod.core.R;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java b/core/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java
index b1beac315..e38abb990 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/dialog/DownloadRequestErrorDialogCreator.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.dialog;
import android.content.Context;
-import android.support.v7.app.AlertDialog;
+import androidx.appcompat.app.AlertDialog;
import de.danoeh.antennapod.core.R;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
index 7ca6f78de..9acd7728a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/DownloaderUpdate.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.event;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.List;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
index 9db262857..89ecf271b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/FeedItemEvent.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.event;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/MessageEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/MessageEvent.java
index 9fc488fbc..9fb22b8ea 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/MessageEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/MessageEvent.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.event;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
public class MessageEvent {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java b/core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java
index a84e8456f..209dcba4d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/event/QueueEvent.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.event;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
index 2a535b2c4..61a09565f 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/Feed.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.feed;
import android.database.Cursor;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.text.TextUtils;
import java.util.ArrayList;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
index 744e9b924..ecd34acff 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.feed;
import android.database.Cursor;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.text.TextUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
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 218570632..b1c2ff15a 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
@@ -7,7 +7,7 @@ import android.database.Cursor;
import android.media.MediaMetadataRetriever;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaDescriptionCompat;
@@ -21,7 +21,6 @@ import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.ChapterUtils;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
index eaafab322..cb5a59a3b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedPreferences.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.feed;
import android.content.Context;
import android.database.Cursor;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.text.TextUtils;
import de.danoeh.antennapod.core.preferences.UserPreferences;
@@ -14,6 +14,8 @@ import de.danoeh.antennapod.core.storage.PodDBAdapter;
*/
public class FeedPreferences {
+ public static final float SPEED_USE_GLOBAL = -1;
+
@NonNull
private FeedFilter filter;
private long feedID;
@@ -31,12 +33,13 @@ public class FeedPreferences {
private String username;
private String password;
+ private float feedPlaybackSpeed;
public FeedPreferences(long feedID, boolean autoDownload, AutoDeleteAction auto_delete_action, VolumeReductionSetting volumeReductionSetting, String username, String password) {
- this(feedID, autoDownload, true, auto_delete_action, volumeReductionSetting, username, password, new FeedFilter());
+ this(feedID, autoDownload, true, auto_delete_action, volumeReductionSetting, username, password, new FeedFilter(), SPEED_USE_GLOBAL);
}
- private FeedPreferences(long feedID, boolean autoDownload, boolean keepUpdated, AutoDeleteAction auto_delete_action, VolumeReductionSetting volumeReductionSetting, String username, String password, @NonNull FeedFilter filter) {
+ private FeedPreferences(long feedID, boolean autoDownload, boolean keepUpdated, AutoDeleteAction auto_delete_action, VolumeReductionSetting volumeReductionSetting, String username, String password, @NonNull FeedFilter filter, float feedPlaybackSpeed) {
this.feedID = feedID;
this.autoDownload = autoDownload;
this.keepUpdated = keepUpdated;
@@ -45,6 +48,7 @@ public class FeedPreferences {
this.username = username;
this.password = password;
this.filter = filter;
+ this.feedPlaybackSpeed = feedPlaybackSpeed;
}
public static FeedPreferences fromCursor(Cursor cursor) {
@@ -57,6 +61,7 @@ public class FeedPreferences {
int indexPassword = cursor.getColumnIndex(PodDBAdapter.KEY_PASSWORD);
int indexIncludeFilter = cursor.getColumnIndex(PodDBAdapter.KEY_INCLUDE_FILTER);
int indexExcludeFilter = cursor.getColumnIndex(PodDBAdapter.KEY_EXCLUDE_FILTER);
+ int indexFeedPlaybackSpeed = cursor.getColumnIndex(PodDBAdapter.KEY_FEED_PLAYBACK_SPEED);
long feedId = cursor.getLong(indexId);
boolean autoDownload = cursor.getInt(indexAutoDownload) > 0;
@@ -69,7 +74,8 @@ public class FeedPreferences {
String password = cursor.getString(indexPassword);
String includeFilter = cursor.getString(indexIncludeFilter);
String excludeFilter = cursor.getString(indexExcludeFilter);
- return new FeedPreferences(feedId, autoDownload, autoRefresh, autoDeleteAction, volumeReductionSetting, username, password, new FeedFilter(includeFilter, excludeFilter));
+ float feedPlaybackSpeed = cursor.getFloat(indexFeedPlaybackSpeed);
+ return new FeedPreferences(feedId, autoDownload, autoRefresh, autoDeleteAction, volumeReductionSetting, username, password, new FeedFilter(includeFilter, excludeFilter), feedPlaybackSpeed);
}
/**
@@ -190,4 +196,12 @@ public class FeedPreferences {
public void setPassword(String password) {
this.password = password;
}
+
+ public float getFeedPlaybackSpeed() {
+ return feedPlaybackSpeed;
+ }
+
+ public void setFeedPlaybackSpeed(float playbackSpeed) {
+ feedPlaybackSpeed = playbackSpeed;
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java
index 552c1b691..b2c809e90 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ApGlideModule.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.glide;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.Registry;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java b/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java
index 3dd87cc0b..f02334af5 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/ApOkHttpUrlLoader.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.glide;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java b/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java
index 479846655..6a237573b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/AudioCoverFetcher.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.glide;
import android.media.MediaMetadataRetriever;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.data.DataFetcher;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
index a740782d6..cbd22ceb0 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/glide/FastBlurTransformation.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.glide;
import android.graphics.Bitmap;
import android.media.ThumbnailUtils;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
index 2588cfdee..9ee8c0fc1 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/GpodnetService.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import org.json.JSONArray;
import org.json.JSONException;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java
index faf4264e5..e86b74164 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetDevice.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
public class GpodnetDevice {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java
index 1e21efcda..7b28bba49 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionGetResponse.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.List;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java
index b6efab016..10ea4cd9b 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetEpisodeActionPostResponse.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.v4.util.ArrayMap;
+import androidx.collection.ArrayMap;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java
index 680dc1042..2c2d759c9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetPodcast.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
public class GpodnetPodcast {
private final String url;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java
index 0f1961bef..56a64053f 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetSubscriptionChange.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.List;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java
index 40543592e..dec3be7f2 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetTag.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.gpoddernet.model;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
public class GpodnetTag implements Parcelable {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java
index 9f9c3bd74..ba3db8412 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/gpoddernet/model/GpodnetUploadChangesResponse.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.gpoddernet.model;
-import android.support.v4.util.ArrayMap;
+import androidx.collection.ArrayMap;
import org.json.JSONArray;
import org.json.JSONException;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
index f2c0c8fe3..192674f0d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackPreferences.java
@@ -11,6 +11,8 @@ import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.service.playback.PlayerStatus;
import de.danoeh.antennapod.core.util.playback.Playable;
+import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
+
/**
* Provides access to preferences set by the playback service. A private
* instance of this class must first be instantiated via createInstance() or
@@ -55,6 +57,13 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
private static final String PREF_CURRENT_PLAYER_STATUS = "de.danoeh.antennapod.preferences.currentPlayerStatus";
/**
+ * A temporary playback speed which overrides the per-feed playback speed for the currently playing
+ * media. Considered unset if set to SPEED_USE_GLOBAL;
+ */
+ private static final String PREF_CURRENTLY_PLAYING_TEMPORARY_PLAYBACK_SPEED = "de.danoeh.antennapod.preferences.temporaryPlaybackSpeed";
+
+
+ /**
* Value of PREF_CURRENTLY_PLAYING_MEDIA if no media is playing.
*/
public static final long NO_MEDIA_PLAYING = -1;
@@ -112,6 +121,10 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
return prefs.getInt(PREF_CURRENT_PLAYER_STATUS, PLAYER_STATUS_OTHER);
}
+ public static float getCurrentlyPlayingTemporaryPlaybackSpeed() {
+ return prefs.getFloat(PREF_CURRENTLY_PLAYING_TEMPORARY_PLAYBACK_SPEED, SPEED_USE_GLOBAL);
+ }
+
public static void writeNoMediaPlaying() {
SharedPreferences.Editor editor = prefs.edit();
editor.putLong(PREF_CURRENTLY_PLAYING_MEDIA, NO_MEDIA_PLAYING);
@@ -154,6 +167,18 @@ public class PlaybackPreferences implements SharedPreferences.OnSharedPreference
editor.apply();
}
+ public static void setCurrentlyPlayingTemporaryPlaybackSpeed(float speed) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putFloat(PREF_CURRENTLY_PLAYING_TEMPORARY_PLAYBACK_SPEED, speed);
+ editor.apply();
+ }
+
+ public static void clearCurrentlyPlayingTemporaryPlaybackSpeed() {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.remove(PREF_CURRENTLY_PLAYING_TEMPORARY_PLAYBACK_SPEED);
+ editor.apply();
+ }
+
private static int getCurrentPlayerStatusAsInt(PlayerStatus playerStatus) {
int playerStatusAsInt;
switch (playerStatus) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackSpeedHelper.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackSpeedHelper.java
new file mode 100644
index 000000000..d48e41c3b
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/PlaybackSpeedHelper.java
@@ -0,0 +1,41 @@
+package de.danoeh.antennapod.core.preferences;
+
+import de.danoeh.antennapod.core.feed.Feed;
+import de.danoeh.antennapod.core.feed.FeedItem;
+import de.danoeh.antennapod.core.feed.FeedMedia;
+import de.danoeh.antennapod.core.feed.MediaType;
+import de.danoeh.antennapod.core.util.playback.Playable;
+
+import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
+
+public class PlaybackSpeedHelper {
+
+ /**
+ * Returns the currently configured playback speed for the specified media.
+ */
+ public static float getCurrentPlaybackSpeed(Playable media) {
+ float playbackSpeed = SPEED_USE_GLOBAL;
+ MediaType mediaType = null;
+
+ if (media != null) {
+ mediaType = media.getMediaType();
+ playbackSpeed = PlaybackPreferences.getCurrentlyPlayingTemporaryPlaybackSpeed();
+
+ if (playbackSpeed == SPEED_USE_GLOBAL && media instanceof FeedMedia) {
+ FeedItem item = ((FeedMedia) media).getItem();
+ if (item != null) {
+ Feed feed = item.getFeed();
+ if (feed != null) {
+ playbackSpeed = feed.getPreferences().getFeedPlaybackSpeed();
+ }
+ }
+ }
+ }
+
+ if (playbackSpeed == SPEED_USE_GLOBAL) {
+ playbackSpeed = UserPreferences.getPlaybackSpeed(mediaType);
+ }
+
+ return playbackSpeed;
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/preferences/SleepTimerPreferences.java b/core/src/main/java/de/danoeh/antennapod/core/preferences/SleepTimerPreferences.java
index 0f3a9fcb3..eb87acb5f 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/preferences/SleepTimerPreferences.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/preferences/SleepTimerPreferences.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.preferences;
import android.content.Context;
import android.content.SharedPreferences;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import java.util.concurrent.TimeUnit;
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 787e32ccc..ba02a9b8c 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
@@ -4,9 +4,9 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.preference.PreferenceManager;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.v4.app.NotificationCompat;
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.core.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.service.download.ProxyConfig;
import de.danoeh.antennapod.core.storage.APCleanupAlgorithm;
@@ -71,7 +72,7 @@ public class UserPreferences {
private static final String PREF_HARDWARE_FOWARD_BUTTON_SKIPS = "prefHardwareForwardButtonSkips";
private static final String PREF_HARDWARE_PREVIOUS_BUTTON_RESTARTS = "prefHardwarePreviousButtonRestarts";
public static final String PREF_FOLLOW_QUEUE = "prefFollowQueue";
- private static final String PREF_SKIP_KEEPS_EPISODE = "prefSkipKeepsEpisode";
+ public static final String PREF_SKIP_KEEPS_EPISODE = "prefSkipKeepsEpisode";
private static final String PREF_FAVORITE_KEEPS_EPISODE = "prefFavoriteKeepsEpisode";
private static final String PREF_AUTO_DELETE = "prefAutoDelete";
public static final String PREF_SMART_MARK_AS_PLAYED_SECS = "prefSmartMarkAsPlayedSecs";
@@ -321,7 +322,15 @@ public class UserPreferences {
return prefs.getBoolean(PREF_DELETE_REMOVES_FROM_QUEUE, false);
}
- public static float getPlaybackSpeed() {
+ public static float getPlaybackSpeed(MediaType mediaType) {
+ if (mediaType == MediaType.VIDEO) {
+ return getVideoPlaybackSpeed();
+ } else {
+ return getAudioPlaybackSpeed();
+ }
+ }
+
+ private static float getAudioPlaybackSpeed() {
try {
return Float.parseFloat(prefs.getString(PREF_PLAYBACK_SPEED, "1.00"));
} catch (NumberFormatException e) {
@@ -331,7 +340,7 @@ public class UserPreferences {
}
}
- public static float getVideoPlaybackSpeed() {
+ private static float getVideoPlaybackSpeed() {
try {
return Float.parseFloat(prefs.getString(PREF_VIDEO_PLAYBACK_SPEED, "1.00"));
} catch (NumberFormatException e) {
@@ -706,7 +715,7 @@ public class UserPreferences {
String[] selectedSpeeds = null;
// If this preference hasn't been set yet, return the default options
if (valueFromPrefs == null) {
- selectedSpeeds = new String[] { "1.00", "1.25", "1.50", "1.75", "2.00" };
+ selectedSpeeds = new String[] { "0.75", "1.00", "1.25", "1.50", "1.75", "2.00" };
} else {
try {
JSONArray jsonArray = new JSONArray(valueFromPrefs);
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 b191dbf8b..b683f849c 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,7 +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 androidx.core.content.ContextCompat;
import android.util.Log;
import android.view.KeyEvent;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java
index 87c18227b..4443319e9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.service;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import androidx.work.Worker;
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 5584991ca..b254cfc59 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
@@ -5,10 +5,10 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.support.annotation.NonNull;
-import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.SafeJobIntentService;
-import android.support.v4.util.ArrayMap;
+import androidx.annotation.NonNull;
+import androidx.core.app.NotificationCompat;
+import androidx.core.app.SafeJobIntentService;
+import androidx.collection.ArrayMap;
import android.util.Log;
import android.util.Pair;
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 abb1d0c0b..a34a1e2c3 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
@@ -10,8 +10,8 @@ import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
-import android.support.annotation.NonNull;
-import android.support.v4.app.SafeJobIntentService;
+import androidx.annotation.NonNull;
+import androidx.core.app.SafeJobIntentService;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
@@ -23,9 +23,8 @@ import com.bumptech.glide.request.RequestOptions;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.R;
-import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
-import de.danoeh.antennapod.core.preferences.UserPreferences;
+import de.danoeh.antennapod.core.preferences.PlaybackSpeedHelper;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
import de.danoeh.antennapod.core.receiver.PlayerWidget;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
@@ -148,9 +147,7 @@ public class PlayerWidgetJobService extends SafeJobIntentService {
progressString = getProgressString(playbackService.getCurrentPosition(),
playbackService.getDuration(), playbackService.getCurrentPlaybackSpeed());
} else {
- float speed = media.getMediaType() == MediaType.VIDEO ?
- UserPreferences.getVideoPlaybackSpeed() : UserPreferences.getPlaybackSpeed();
- progressString = getProgressString(media.getPosition(), media.getDuration(), speed);
+ progressString = getProgressString(media.getPosition(), media.getDuration(), PlaybackSpeedHelper.getCurrentPlaybackSpeed(media));
}
if (progressString != null) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
index 04a6d5882..2082b95d1 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/AntennapodHttpClient.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.service.download;
import android.os.Build;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
index 48234c387..60591899d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadRequest.java
@@ -3,8 +3,8 @@ package de.danoeh.antennapod.core.service.download;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import de.danoeh.antennapod.core.feed.FeedFile;
import de.danoeh.antennapod.core.util.URLChecker;
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 e9b4c5d1e..b6e5de254 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
@@ -12,10 +12,10 @@ import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.app.NotificationCompat;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.core.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java
index d88eb63f4..675115bc7 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadStatus.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.service.download;
import android.database.Cursor;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.Date;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java
index 38b93eab8..02dc17301 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/Downloader.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.service.download;
import android.content.Context;
import android.net.wifi.WifiManager;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.concurrent.Callable;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
index c27cefc10..8abfa3da3 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/HttpDownloader.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.service.download;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java
index c4096c3da..0d59a1b7e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/ProxyConfig.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.service.download;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import java.net.Proxy;
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 e5dd292f0..8ac2721b6 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
@@ -6,7 +6,7 @@ import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.os.Build;
import android.os.PowerManager;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.Pair;
@@ -29,6 +29,7 @@ import java.util.concurrent.locks.ReentrantLock;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.feed.FeedPreferences;
import de.danoeh.antennapod.core.feed.MediaType;
+import de.danoeh.antennapod.core.preferences.PlaybackSpeedHelper;
import de.danoeh.antennapod.core.feed.VolumeReductionSetting;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.RewindAfterPauseUtils;
@@ -246,6 +247,7 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
try {
media.loadMetadata();
callback.onMediaChanged(false);
+ setPlaybackParams(PlaybackSpeedHelper.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence());
if (stream) {
mediaPlayer.setDataSource(media.getStreamUrl());
} else if (media.getLocalMediaUrl() != null && new File(media.getLocalMediaUrl()).canRead()) {
@@ -308,11 +310,8 @@ public class LocalPSMP extends PlaybackServiceMediaPlayer {
Log.d(TAG, "Audiofocus successfully requested");
Log.d(TAG, "Resuming/Starting playback");
acquireWifiLockIfNecessary();
- if (media.getMediaType() == MediaType.VIDEO) {
- setPlaybackParams(UserPreferences.getVideoPlaybackSpeed(), UserPreferences.isSkipSilence());
- } else {
- setPlaybackParams(UserPreferences.getPlaybackSpeed(), UserPreferences.isSkipSilence());
- }
+
+ setPlaybackParams(PlaybackSpeedHelper.getCurrentPlaybackSpeed(media), UserPreferences.isSkipSilence());
float leftVolume = UserPreferences.getLeftVolume();
float rightVolume = UserPreferences.getRightVolume();
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 d444875ad..eb38a02d9 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
@@ -21,12 +21,12 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Vibrator;
import android.preference.PreferenceManager;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
-import android.support.v4.app.NotificationCompat;
-import android.support.v4.app.NotificationManagerCompat;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+import androidx.core.app.NotificationCompat;
+import androidx.core.app.NotificationManagerCompat;
import android.support.v4.media.MediaBrowserCompat;
-import android.support.v4.media.MediaBrowserServiceCompat;
+import androidx.media.MediaBrowserServiceCompat;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
@@ -225,6 +225,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
private PlaybackServiceFlavorHelper flavorHelper;
private PlaybackServiceStateManager stateManager;
private Disposable positionEventTimer;
+ private PlaybackServiceNotificationBuilder notificationBuilder;
/**
* Used for Lollipop notifications, Android Wear, and Android Auto.
@@ -280,7 +281,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
isRunning = true;
stateManager = new PlaybackServiceStateManager(this);
- PlaybackServiceNotificationBuilder notificationBuilder = new PlaybackServiceNotificationBuilder(this);
+ notificationBuilder = new PlaybackServiceNotificationBuilder(this);
stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build());
registerReceiver(autoStateUpdated, new IntentFilter("com.google.android.gms.car.media.STATUS"));
@@ -454,20 +455,9 @@ public class PlaybackService extends MediaBrowserServiceCompat {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
-
Log.d(TAG, "OnStartCommand called");
- if (!stateManager.isInForeground()) {
- PlaybackServiceNotificationBuilder notificationBuilder = new PlaybackServiceNotificationBuilder(this);
- if (mediaPlayer != null && getPlayable() != null) {
- notificationBuilder.addMetadata(getPlayable(), mediaSession.getSessionToken(), getStatus(), isCasting);
- if (notificationBuilder.isIconCached(getPlayable())) {
- notificationBuilder.loadIcon(getPlayable());
- }
- }
- stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build());
- }
-
+ stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build());
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.cancel(NOTIFICATION_ID_STREAMING);
@@ -847,6 +837,9 @@ public class PlaybackService extends MediaBrowserServiceCompat {
@Override
public void onPlaybackStart(@NonNull Playable playable, int position) {
+ if (taskManager.isSleepTimerActive()) {
+ taskManager.restartSleepTimer();
+ }
taskManager.startWidgetUpdater();
if (position != PlaybackServiceMediaPlayer.INVALID_TIME) {
playable.setPosition(position);
@@ -858,6 +851,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
@Override
public void onPlaybackPause(Playable playable, int position) {
taskManager.cancelPositionSaver();
+ cancelPositionObserver();
saveCurrentPosition(position == PlaybackServiceMediaPlayer.INVALID_TIME || playable == null,
playable, position);
taskManager.cancelWidgetUpdater();
@@ -934,6 +928,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
Log.d(TAG, "Playback ended");
if (stopPlaying) {
taskManager.cancelPositionSaver();
+ cancelPositionObserver();
PlaybackPreferences.writeNoMediaPlaying();
if (!isCasting) {
stateManager.stopForeground(true);
@@ -969,6 +964,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
*/
private void onPostPlayback(final Playable playable, boolean ended, boolean skipped,
boolean playingNext) {
+ PlaybackPreferences.clearCurrentlyPlayingTemporaryPlaybackSpeed();
if (playable == null) {
Log.e(TAG, "Cannot do post-playback processing: media was null");
return;
@@ -986,7 +982,7 @@ public class PlaybackService extends MediaBrowserServiceCompat {
}
FeedMedia media = (FeedMedia) playable;
FeedItem item = media.getItem();
- boolean smartMarkAsPlayed = playingNext && media.hasAlmostEnded();
+ boolean smartMarkAsPlayed = media.hasAlmostEnded();
if (!ended && smartMarkAsPlayed) {
Log.d(TAG, "smart mark as played");
}
@@ -1204,59 +1200,51 @@ public class PlaybackService extends MediaBrowserServiceCompat {
}
private synchronized void setupNotification(final Playable playable) {
+ Log.d(TAG, "setupNotification");
if (notificationSetupThread != null) {
notificationSetupThread.interrupt();
}
- if (playable == null) {
- Log.d(TAG, "setupNotification: playable is null" + Log.getStackTraceString(new Exception()));
+ if (playable == null || mediaPlayer == null) {
+ Log.d(TAG, "setupNotification: playable=" + playable);
+ Log.d(TAG, "setupNotification: mediaPlayer=" + mediaPlayer);
if (!stateManager.hasReceivedValidStartCommand()) {
stateManager.stopService();
}
return;
}
- Runnable notificationSetupTask = new Runnable() {
- @Override
- public void run() {
- Log.d(TAG, "Starting background work");
- if (mediaPlayer == null) {
- Log.d(TAG, "notificationSetupTask: mediaPlayer is null");
- if (!stateManager.hasReceivedValidStartCommand()) {
- stateManager.stopService();
- }
- return;
- }
- PlayerStatus playerStatus = mediaPlayer.getPlayerStatus();
- PlaybackServiceNotificationBuilder notificationBuilder =
- new PlaybackServiceNotificationBuilder(PlaybackService.this);
- notificationBuilder.addMetadata(playable, mediaSession.getSessionToken(), playerStatus, isCasting);
-
- if (!notificationBuilder.isIconCached(playable)) {
- // To make sure that the notification is shown instantly
- notificationBuilder.loadDefaultIcon();
- stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build());
- }
- notificationBuilder.loadIcon(playable);
-
- if (!Thread.currentThread().isInterrupted() && stateManager.hasReceivedValidStartCommand()) {
- Notification notification = notificationBuilder.build();
-
- if (playerStatus == PlayerStatus.PLAYING ||
- playerStatus == PlayerStatus.PREPARING ||
- playerStatus == PlayerStatus.SEEKING ||
- isCasting) {
- stateManager.startForeground(NOTIFICATION_ID, notification);
- } else {
- stateManager.stopForeground(false);
- NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- mNotificationManager.notify(NOTIFICATION_ID, notification);
- }
- Log.d(TAG, "Notification set up");
+ PlayerStatus playerStatus = mediaPlayer.getPlayerStatus();
+ notificationBuilder.setMetadata(playable, mediaSession.getSessionToken(), playerStatus, isCasting);
+ notificationBuilder.updatePosition(getCurrentPosition(), getCurrentPlaybackSpeed());
+
+ Log.d(TAG, "setupNotification: startForeground" + playerStatus);
+ NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
+ notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ startForegroundIfPlaying(playerStatus);
+
+ if (!notificationBuilder.isIconCached()) {
+ notificationSetupThread = new Thread(() -> {
+ Log.d(TAG, "Loading notification icon");
+ notificationBuilder.loadIcon();
+ if (!Thread.currentThread().isInterrupted()) {
+ notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
+ });
+ notificationSetupThread.start();
+ }
+ }
+
+ private void startForegroundIfPlaying(@NonNull PlayerStatus status) {
+ if (stateManager.hasReceivedValidStartCommand()) {
+ if (isCasting || status == PlayerStatus.PLAYING || status == PlayerStatus.PREPARING
+ || status == PlayerStatus.SEEKING) {
+ stateManager.startForeground(NOTIFICATION_ID, notificationBuilder.build());
+ } else {
+ stateManager.stopForeground(false);
+ NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
+ notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
- };
- notificationSetupThread = new Thread(notificationSetupTask);
- notificationSetupThread.start();
+ }
}
/**
@@ -1618,8 +1606,15 @@ public class PlaybackService extends MediaBrowserServiceCompat {
Log.d(TAG, "Setting up position observer");
positionEventTimer = Observable.interval(1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
- .subscribe(aLong ->
- EventBus.getDefault().post(new PlaybackPositionEvent(getCurrentPosition(), getDuration())));
+ .subscribe(number -> {
+ EventBus.getDefault().post(new PlaybackPositionEvent(getCurrentPosition(), getDuration()));
+ if (Build.VERSION.SDK_INT < 29) {
+ notificationBuilder.updatePosition(getCurrentPosition(), getCurrentPlaybackSpeed());
+ NotificationManager notificationManager = (NotificationManager)
+ getSystemService(NOTIFICATION_SERVICE);
+ notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
+ }
+ });
}
private void cancelPositionObserver() {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
index b8198fa63..bc009e2bc 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java
@@ -2,8 +2,8 @@ package de.danoeh.antennapod.core.service.playback;
import android.content.Context;
import android.net.wifi.WifiManager;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
import android.util.Log;
import android.util.Pair;
import android.view.SurfaceHolder;
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 1a13fe5a7..b277a6bc2 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
@@ -1,82 +1,77 @@
package de.danoeh.antennapod.core.service.playback;
+import android.annotation.TargetApi;
+import android.app.Notification;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.VectorDrawable;
import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.v4.app.NotificationCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.util.Log;
import android.view.KeyEvent;
+import androidx.annotation.NonNull;
+import androidx.core.app.NotificationCompat;
+import androidx.core.content.ContextCompat;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
-import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.core.R;
import de.danoeh.antennapod.core.glide.ApGlideSettings;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
+import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.IntList;
+import de.danoeh.antennapod.core.util.TimeSpeedConverter;
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
import de.danoeh.antennapod.core.util.playback.Playable;
-public class PlaybackServiceNotificationBuilder extends NotificationCompat.Builder {
+public class PlaybackServiceNotificationBuilder {
private static final String TAG = "PlaybackSrvNotification";
private static Bitmap defaultIcon = null;
private Context context;
+ private Playable playable;
+ private MediaSessionCompat.Token mediaSessionToken;
+ private PlayerStatus playerStatus;
+ private boolean isCasting;
+ private Bitmap icon;
+ private String position;
public PlaybackServiceNotificationBuilder(@NonNull Context context) {
- super(context, NotificationUtils.CHANNEL_ID_PLAYING);
this.context = context;
+ }
- final int smallIcon = ClientConfig.playbackServiceCallbacks.getNotificationIconResource(context);
+ public void setMetadata(Playable playable, MediaSessionCompat.Token mediaSessionToken,
+ PlayerStatus playerStatus, boolean isCasting) {
- final PendingIntent pIntent = PendingIntent.getActivity(context, 0,
- PlaybackService.getPlayerActivityIntent(context),
- PendingIntent.FLAG_UPDATE_CURRENT);
+ if (playable != this.playable) {
+ clearCache();
+ }
+ this.playable = playable;
+ this.mediaSessionToken = mediaSessionToken;
+ this.playerStatus = playerStatus;
+ this.isCasting = isCasting;
+ }
- setContentTitle(context.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);
+ private void clearCache() {
+ this.icon = null;
+ this.position = null;
}
- public void addMetadata(Playable playable, MediaSessionCompat.Token mediaSessionToken, PlayerStatus playerStatus, boolean isCasting) {
- Log.v(TAG, "notificationSetupTask: playerStatus=" + playerStatus);
- setContentTitle(playable.getFeedTitle());
- setContentText(playable.getEpisodeTitle());
- setPriority(UserPreferences.getNotifyPriority());
- addActions(mediaSessionToken, playerStatus, isCasting);
- setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
- setColor(NotificationCompat.COLOR_DEFAULT);
+ public void updatePosition(int position,float speed) {
+ TimeSpeedConverter converter = new TimeSpeedConverter(speed);
+ this.position = Converter.getDurationStringLong(converter.convert(position));
}
- public boolean isIconCached(Playable playable) {
- int iconSize = context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
- try {
- Bitmap icon = Glide.with(context)
- .asBitmap()
- .load(playable.getImageLocation())
- .apply(RequestOptions.diskCacheStrategyOf(ApGlideSettings.AP_DISK_CACHE_STRATEGY))
- .apply(new RequestOptions()
- .centerCrop()
- .onlyRetrieveFromCache(true))
- .submit(iconSize, iconSize)
- .get();
- return icon != null;
- } catch (Throwable tr) {
- return false;
- }
+ public boolean isIconCached() {
+ return icon != null;
}
- public void loadIcon(Playable playable) {
- Bitmap icon = null;
+ public void loadIcon() {
int iconSize = context.getResources().getDimensionPixelSize(android.R.dimen.notification_large_icon_width);
try {
icon = Glide.with(context)
@@ -89,23 +84,77 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
} catch (Throwable tr) {
Log.e(TAG, "Error loading the media icon for the notification", tr);
}
+ }
- if (icon == null) {
- loadDefaultIcon();
+ private Bitmap getDefaultIcon() {
+ if (defaultIcon == null) {
+ defaultIcon = getBitmap(context, R.drawable.notification_default_large_icon);
+ }
+ return defaultIcon;
+ }
+
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ private static Bitmap getBitmap(VectorDrawable vectorDrawable) {
+ Bitmap bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
+ vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ vectorDrawable.draw(canvas);
+ return bitmap;
+ }
+
+ private static Bitmap getBitmap(Context context, int drawableId) {
+ Drawable drawable = ContextCompat.getDrawable(context, drawableId);
+ if (drawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable) drawable).getBitmap();
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable) {
+ return getBitmap((VectorDrawable) drawable);
} else {
- setLargeIcon(icon);
+ return null;
}
}
- public void loadDefaultIcon() {
- if (defaultIcon == null) {
- defaultIcon = BitmapFactory.decodeResource(context.getResources(),
- ClientConfig.playbackServiceCallbacks.getNotificationIconResource(context));
+ public Notification build() {
+ NotificationCompat.Builder notification = new NotificationCompat.Builder(context,
+ NotificationUtils.CHANNEL_ID_PLAYING);
+
+ if (playable != null) {
+ notification.setContentTitle(playable.getFeedTitle());
+ notification.setContentText(playable.getEpisodeTitle());
+ addActions(notification, mediaSessionToken, playerStatus, isCasting);
+
+ if (icon != null) {
+ notification.setLargeIcon(icon);
+ } else {
+ notification.setLargeIcon(getDefaultIcon());
+ }
+
+ if (Build.VERSION.SDK_INT < 29) {
+ notification.setSubText(position);
+ }
+ } else {
+ notification.setContentTitle(context.getString(R.string.app_name));
+ notification.setContentText("Service is running");
}
- setLargeIcon(defaultIcon);
+
+ notification.setContentIntent(getPlayerActivityPendingIntent());
+ notification.setWhen(0);
+ notification.setSmallIcon(R.drawable.ic_antenna);
+ notification.setOngoing(false);
+ notification.setOnlyAlertOnce(true);
+ notification.setPriority(UserPreferences.getNotifyPriority());
+ notification.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
+ notification.setColor(NotificationCompat.COLOR_DEFAULT);
+ return notification.build();
+ }
+
+ private PendingIntent getPlayerActivityPendingIntent() {
+ return PendingIntent.getActivity(context, 0, PlaybackService.getPlayerActivityIntent(context),
+ PendingIntent.FLAG_UPDATE_CURRENT);
}
- private void addActions(MediaSessionCompat.Token mediaSessionToken, PlayerStatus playerStatus, boolean isCasting) {
+ private void addActions(NotificationCompat.Builder notification, MediaSessionCompat.Token mediaSessionToken,
+ PlayerStatus playerStatus, boolean isCasting) {
IntList compactActionList = new IntList();
int numActions = 0; // we start and 0 and then increment by 1 for each call to addAction
@@ -115,7 +164,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
stopCastingIntent.putExtra(PlaybackService.EXTRA_CAST_DISCONNECT, true);
PendingIntent stopCastingPendingIntent = PendingIntent.getService(context,
numActions, stopCastingIntent, PendingIntent.FLAG_UPDATE_CURRENT);
- addAction(R.drawable.ic_notification_cast_off,
+ notification.addAction(R.drawable.ic_notification_cast_off,
context.getString(R.string.cast_disconnect_label),
stopCastingPendingIntent);
numActions++;
@@ -124,7 +173,8 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
// always let them rewind
PendingIntent rewindButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_REWIND, numActions);
- addAction(R.drawable.ic_notification_fast_rewind, context.getString(R.string.rewind_label), rewindButtonPendingIntent);
+ notification.addAction(R.drawable.ic_notification_fast_rewind, context.getString(R.string.rewind_label),
+ rewindButtonPendingIntent);
if (UserPreferences.showRewindOnCompactNotification()) {
compactActionList.add(numActions);
}
@@ -133,14 +183,14 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
if (playerStatus == PlayerStatus.PLAYING) {
PendingIntent pauseButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_PAUSE, numActions);
- addAction(R.drawable.ic_notification_pause, //pause action
+ notification.addAction(R.drawable.ic_notification_pause, //pause action
context.getString(R.string.pause_label),
pauseButtonPendingIntent);
compactActionList.add(numActions++);
} else {
PendingIntent playButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_PLAY, numActions);
- addAction(R.drawable.ic_notification_play, //play action
+ notification.addAction(R.drawable.ic_notification_play, //play action
context.getString(R.string.play_label),
playButtonPendingIntent);
compactActionList.add(numActions++);
@@ -149,7 +199,8 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
// ff follows play, then we have skip (if it's present)
PendingIntent ffButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, numActions);
- addAction(R.drawable.ic_notification_fast_forward, context.getString(R.string.fast_forward_label), ffButtonPendingIntent);
+ notification.addAction(R.drawable.ic_notification_fast_forward, context.getString(R.string.fast_forward_label),
+ ffButtonPendingIntent);
if (UserPreferences.showFastForwardOnCompactNotification()) {
compactActionList.add(numActions);
}
@@ -158,7 +209,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
if (UserPreferences.isFollowQueue()) {
PendingIntent skipButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_NEXT, numActions);
- addAction(R.drawable.ic_notification_skip,
+ notification.addAction(R.drawable.ic_notification_skip,
context.getString(R.string.skip_episode_label),
skipButtonPendingIntent);
if (UserPreferences.showSkipOnCompactNotification()) {
@@ -169,7 +220,7 @@ public class PlaybackServiceNotificationBuilder extends NotificationCompat.Build
PendingIntent stopButtonPendingIntent = getPendingIntentForMediaAction(
KeyEvent.KEYCODE_MEDIA_STOP, numActions);
- setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
+ notification.setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
.setMediaSession(mediaSessionToken)
.setShowActionsInCompactView(compactActionList.toArray())
.setShowCancelButton(true)
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
index 1a13f9e9f..5647590b1 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceTaskManager.java
@@ -4,7 +4,7 @@ import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Vibrator;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import org.greenrobot.eventbus.EventBus;
@@ -249,6 +249,16 @@ public class PlaybackServiceTaskManager {
}
/**
+ * Restarts the sleep timer. If the sleep timer is not active, nothing will happen.
+ */
+ public synchronized void restartSleepTimer() {
+ if (isSleepTimerActive()) {
+ Log.d(TAG, "Restarting sleep timer");
+ sleepTimer.restart();
+ }
+ }
+
+ /**
* Returns the current sleep timer time or 0 if the sleep timer is not active.
*/
public synchronized long getSleepTimerTimeLeft() {
@@ -428,13 +438,15 @@ public class PlaybackServiceTaskManager {
return timeLeft;
}
- public void onShake() {
+ public void restart() {
postCallback(() -> {
setSleepTimer(waitingTime, shakeToReset, vibrate);
callback.onSleepTimerReset();
});
- shakeListener.pause();
- shakeListener = null;
+ if (shakeListener != null) {
+ shakeListener.pause();
+ shakeListener = null;
+ }
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java
index c0b1b3bc0..b0b6e164d 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/ShakeListener.java
@@ -52,7 +52,7 @@ class ShakeListener implements SensorEventListener
double gForce = Math.sqrt(gX*gX + gY*gY + gZ*gZ);
if (gForce > 2.25) {
Log.d(TAG, "Detected shake " + gForce);
- mSleepTimer.onShake();
+ mSleepTimer.restart();
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java
index c63ac4416..b88793e87 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APCleanupAlgorithm.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.core.storage;
import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.annotation.VisibleForTesting;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
import android.util.Log;
import java.util.ArrayList;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java b/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java
index 04b200699..dfe0b5201 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/APQueueCleanupAlgorithm.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.storage;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import java.util.ArrayList;
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 70d3ba9dd..948a21efc 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
@@ -1,9 +1,9 @@
package de.danoeh.antennapod.core.storage;
import android.database.Cursor;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.ArrayMap;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.collection.ArrayMap;
import android.text.TextUtils;
import android.util.Log;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java
index d9aec8649..148252902 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBUpgrader.java
@@ -8,6 +8,8 @@ import android.util.Log;
import de.danoeh.antennapod.core.feed.FeedItem;
+import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
+
class DBUpgrader {
/**
* Upgrades the given database to a new schema version
@@ -288,7 +290,10 @@ class DBUpgrader {
db.execSQL("DROP TABLE " + PodDBAdapter.TABLE_NAME_FEED_IMAGES);
}
- if (oldVersion < 1070296) {
+ if (oldVersion < 1070400) {
+ db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ + " ADD COLUMN " + PodDBAdapter.KEY_FEED_PLAYBACK_SPEED + " REAL DEFAULT " + SPEED_USE_GLOBAL);
+
db.execSQL("ALTER TABLE " + PodDBAdapter.TABLE_NAME_FEEDS
+ " ADD COLUMN " + PodDBAdapter.KEY_FEED_VOLUME_REDUCTION + " INTEGER DEFAULT 0");
}
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 4f0ee70ef..e0e15c1ff 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
@@ -2,12 +2,10 @@ package de.danoeh.antennapod.core.storage;
import android.app.backup.BackupManager;
import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-import android.support.annotation.NonNull;
import android.util.Log;
+import androidx.annotation.NonNull;
+
import org.greenrobot.eventbus.EventBus;
import java.io.File;
@@ -89,7 +87,8 @@ public class DBWriter {
});
}
- private static boolean deleteFeedMediaSynchronous(@NonNull Context context, @NonNull FeedMedia media) {
+ private static boolean deleteFeedMediaSynchronous(
+ @NonNull Context context, @NonNull FeedMedia media) {
Log.i(TAG, String.format("Requested to delete FeedMedia [id=%d, title=%s, downloaded=%s",
media.getId(), media.getEpisodeTitle(), String.valueOf(media.isDownloaded())));
if (media.isDownloaded()) {
@@ -114,7 +113,7 @@ public class DBWriter {
}
// Gpodder: queue delete action for synchronization
- if(GpodnetPreferences.loggedIn()) {
+ if (GpodnetPreferences.loggedIn()) {
FeedItem item = media.getItem();
GpodnetEpisodeAction action = new GpodnetEpisodeAction.Builder(item, GpodnetEpisodeAction.Action.DELETE)
.currentDeviceId()
@@ -162,7 +161,7 @@ public class DBWriter {
adapter.open();
if (removed.size() > 0) {
adapter.setQueue(queue);
- for(FeedItem item : removed) {
+ for (FeedItem item : removed) {
EventBus.getDefault().post(QueueEvent.irreversibleRemoved(item));
}
}
@@ -187,7 +186,6 @@ public class DBWriter {
/**
* Deletes the entire playback history.
- *
*/
public static Future<?> clearPlaybackHistory() {
return dbExec.submit(() -> {
@@ -218,7 +216,7 @@ public class DBWriter {
* its playback completion date is set to a non-null value. This method will set the playback completion date to the
* current date regardless of the current value.
*
- * @param media FeedMedia that should be added to the playback history.
+ * @param media FeedMedia that should be added to the playback history.
*/
public static Future<?> addItemToPlaybackHistory(final FeedMedia media) {
return dbExec.submit(() -> {
@@ -237,7 +235,7 @@ public class DBWriter {
/**
* Adds a Download status object to the download log.
*
- * @param status The DownloadStatus object.
+ * @param status The DownloadStatus object.
*/
public static Future<?> addDownloadStatus(final DownloadStatus status) {
return dbExec.submit(() -> {
@@ -307,9 +305,9 @@ public class DBWriter {
* Appends FeedItem objects to the end of the queue. The 'read'-attribute of all items will be set to true.
* If a FeedItem is already in the queue, the FeedItem will not change its position in the queue.
*
- * @param context A context that is used for opening a database connection.
+ * @param context A context that is used for opening a database connection.
* @param performAutoDownload true if an auto-download process should be started after the operation.
- * @param itemIds IDs of the FeedItem objects that should be added to the queue.
+ * @param itemIds IDs of the FeedItem objects that should be added to the queue.
*/
public static Future<?> addQueueItem(final Context context, final boolean performAutoDownload,
final long... itemIds) {
@@ -397,7 +395,6 @@ public class DBWriter {
/**
* Removes all FeedItem objects from the queue.
- *
*/
public static Future<?> clearQueue() {
return dbExec.submit(() -> {
@@ -412,7 +409,8 @@ public class DBWriter {
/**
* Removes a FeedItem object from the queue.
- * @param context A context that is used for opening a database connection.
+ *
+ * @param context A context that is used for opening a database connection.
* @param performAutoDownload true if an auto-download process should be started after the operation.
* @param item FeedItem that should be removed.
*/
@@ -500,14 +498,15 @@ public class DBWriter {
/**
* Moves the specified item to the top of the queue.
- * @param itemId The item to move to the top of the queue
+ *
+ * @param itemId The item to move to the top of the queue
* @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to
*/
public static Future<?> moveQueueItemToTop(final long itemId, final boolean broadcastUpdate) {
return dbExec.submit(() -> {
LongList queueIdList = DBReader.getQueueIDList();
int index = queueIdList.indexOf(itemId);
- if (index >=0) {
+ if (index >= 0) {
moveQueueItemHelper(index, 0, broadcastUpdate);
} else {
Log.e(TAG, "moveQueueItemToTop: item not found");
@@ -517,7 +516,8 @@ public class DBWriter {
/**
* Moves the specified item to the bottom of the queue.
- * @param itemId The item to move to the bottom of the queue
+ *
+ * @param itemId The item to move to the bottom of the queue
* @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to
*/
public static Future<?> moveQueueItemToBottom(final long itemId,
@@ -527,7 +527,7 @@ public class DBWriter {
int index = queueIdList.indexOf(itemId);
if (index >= 0) {
moveQueueItemHelper(index, queueIdList.size() - 1,
- broadcastUpdate);
+ broadcastUpdate);
} else {
Log.e(TAG, "moveQueueItemToBottom: item not found");
}
@@ -608,7 +608,7 @@ public class DBWriter {
adapter.open();
adapter.setFeedItemRead(played, itemIds);
adapter.close();
- if(broadcastUpdate) {
+ if (broadcastUpdate) {
EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
}
});
@@ -617,7 +617,8 @@ public class DBWriter {
/**
* Sets the 'read'-attribute of a FeedItem to the specified value.
- * @param item The FeedItem object
+ *
+ * @param item The FeedItem object
* @param played New value of the 'read'-attribute one of FeedItem.PLAYED,
* FeedItem.NEW, FeedItem.UNPLAYED
* @param resetMediaPosition true if this method should also reset the position of the FeedItem's FeedMedia object.
@@ -647,7 +648,7 @@ public class DBWriter {
/**
* Sets the 'read'-attribute of all NEW FeedItems of a specific Feed to UNPLAYED.
*
- * @param feedId ID of the Feed.
+ * @param feedId ID of the Feed.
*/
public static Future<?> removeFeedNewFlag(final long feedId) {
return dbExec.submit(() -> {
@@ -663,7 +664,7 @@ public class DBWriter {
/**
* Sets the 'read'-attribute of all FeedItems of a specific Feed to PLAYED.
*
- * @param feedId ID of the Feed.
+ * @param feedId ID of the Feed.
*/
public static Future<?> markFeedRead(final long feedId) {
return dbExec.submit(() -> {
@@ -735,7 +736,7 @@ public class DBWriter {
* Saves a FeedMedia object in the database. This method will save all attributes of the FeedMedia object. The
* contents of FeedComponent-attributes (e.g. the FeedMedia's 'item'-attribute) will not be saved.
*
- * @param media The FeedMedia object.
+ * @param media The FeedMedia object.
*/
public static Future<?> setFeedMedia(final FeedMedia media) {
return dbExec.submit(() -> {
@@ -749,7 +750,7 @@ public class DBWriter {
/**
* Saves the 'position', 'duration' and 'last played time' attributes of a FeedMedia object
*
- * @param media The FeedMedia object.
+ * @param media The FeedMedia object.
*/
public static Future<?> setFeedMediaPlaybackInformation(final FeedMedia media) {
return dbExec.submit(() -> {
@@ -764,7 +765,7 @@ public class DBWriter {
* Saves a FeedItem object in the database. This method will save all attributes of the FeedItem object including
* the content of FeedComponent-attributes.
*
- * @param item The FeedItem object.
+ * @param item The FeedItem object.
*/
public static Future<?> setFeedItem(final FeedItem item) {
return dbExec.submit(() -> {
@@ -780,7 +781,7 @@ public class DBWriter {
* Updates download URL of a feed
*/
public static Future<?> updateFeedDownloadURL(final String original, final String updated) {
- Log.d(TAG, "updateFeedDownloadURL(original: " + original + ", updated: " + updated +")");
+ Log.d(TAG, "updateFeedDownloadURL(original: " + original + ", updated: " + updated + ")");
return dbExec.submit(() -> {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
@@ -805,11 +806,11 @@ public class DBWriter {
}
private static boolean itemListContains(List<FeedItem> items, long itemId) {
- return indexInItemList(items, itemId) >= 0;
+ return indexInItemList(items, itemId) >= 0;
}
private static int indexInItemList(List<FeedItem> items, long itemId) {
- for (int i = 0; i < items.size(); i ++) {
+ for (int i = 0; i < items.size(); i++) {
FeedItem item = items.get(i);
if (item.getId() == itemId) {
return i;
@@ -873,7 +874,7 @@ public class DBWriter {
/**
* Sets the 'auto_download'-attribute of specific FeedItem.
*
- * @param feedItem FeedItem.
+ * @param feedItem FeedItem.
* @param autoDownload true enables auto download, false disables it
*/
public static Future<?> setFeedItemAutoDownload(final FeedItem feedItem,
@@ -891,7 +892,7 @@ public class DBWriter {
return dbExec.submit(() -> {
int failedAttempts = feedItem.getFailedAutoDownloadAttempts() + 1;
long autoDownload;
- if(!feedItem.getAutoDownload() || failedAttempts >= 10) {
+ if (!feedItem.getAutoDownload() || failedAttempts >= 10) {
autoDownload = 0; // giving up, disable auto download
feedItem.setAutoDownload(false);
} else {
@@ -927,7 +928,8 @@ public class DBWriter {
/**
* Set filter of the feed
- * @param feedId The feed's ID
+ *
+ * @param feedId The feed's ID
* @param filterValues Values that represent properties to filter by
*/
public static Future<?> setFeedItemsFilter(final long feedId,
@@ -942,4 +944,17 @@ public class DBWriter {
});
}
+
+ /**
+ * Reset the statistics in DB
+ */
+ @NonNull
+ public static Future<?> resetStatistics() {
+ return dbExec.submit(() -> {
+ PodDBAdapter adapter = PodDBAdapter.getInstance();
+ adapter.open();
+ adapter.resetAllMediaPlayedDuration();
+ adapter.close();
+ });
+ }
}
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 9c48f31dd..71f6845c5 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
@@ -3,8 +3,8 @@ package de.danoeh.antennapod.core.storage;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.URLUtil;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
index c6620a90e..0c8d20007 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/FeedSearcher.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.storage;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
index 04accecd0..fa72cd510 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java
@@ -12,10 +12,9 @@ import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
-import android.media.MediaMetadataRetriever;
import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
@@ -37,6 +36,8 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
import de.danoeh.antennapod.core.util.LongIntMap;
+import static de.danoeh.antennapod.core.feed.FeedPreferences.SPEED_USE_GLOBAL;
+
// TODO Remove media column from feeditem table
/**
@@ -106,6 +107,7 @@ public class PodDBAdapter {
public static final String KEY_LAST_PLAYED_TIME = "last_played_time";
public static final String KEY_INCLUDE_FILTER = "include_filter";
public static final String KEY_EXCLUDE_FILTER = "exclude_filter";
+ public static final String KEY_FEED_PLAYBACK_SPEED = "feed_playback_speed";
// Table names
static final String TABLE_NAME_FEEDS = "Feeds";
@@ -139,6 +141,7 @@ public class PodDBAdapter {
+ KEY_HIDE + " TEXT,"
+ KEY_LAST_UPDATE_FAILED + " INTEGER DEFAULT 0,"
+ KEY_AUTO_DELETE_ACTION + " INTEGER DEFAULT 0,"
+ + KEY_FEED_PLAYBACK_SPEED + " REAL DEFAULT " + SPEED_USE_GLOBAL + ","
+ KEY_FEED_VOLUME_REDUCTION + " INTEGER DEFAULT 0)";
private static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE "
@@ -160,7 +163,7 @@ public class PodDBAdapter {
+ KEY_FEEDITEM + " INTEGER,"
+ KEY_PLAYED_DURATION + " INTEGER,"
+ KEY_HAS_EMBEDDED_PICTURE + " INTEGER,"
- + KEY_LAST_PLAYED_TIME + " INTEGER)";
+ + KEY_LAST_PLAYED_TIME + " INTEGER" + ")";
private static final String CREATE_TABLE_DOWNLOAD_LOG = "CREATE TABLE "
+ TABLE_NAME_DOWNLOAD_LOG + " (" + TABLE_PRIMARY_KEY + KEY_FEEDFILE
@@ -237,7 +240,8 @@ public class PodDBAdapter {
TABLE_NAME_FEEDS + "." + KEY_AUTO_DELETE_ACTION,
TABLE_NAME_FEEDS + "." + KEY_FEED_VOLUME_REDUCTION,
TABLE_NAME_FEEDS + "." + KEY_INCLUDE_FILTER,
- TABLE_NAME_FEEDS + "." + KEY_EXCLUDE_FILTER
+ TABLE_NAME_FEEDS + "." + KEY_EXCLUDE_FILTER,
+ TABLE_NAME_FEEDS + "." + KEY_FEED_PLAYBACK_SPEED
};
/**
@@ -403,6 +407,7 @@ public class PodDBAdapter {
values.put(KEY_PASSWORD, prefs.getPassword());
values.put(KEY_INCLUDE_FILTER, prefs.getFilter().getIncludeFilter());
values.put(KEY_EXCLUDE_FILTER, prefs.getFilter().getExcludeFilter());
+ values.put(KEY_FEED_PLAYBACK_SPEED, prefs.getFeedPlaybackSpeed());
db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(prefs.getFeedID())});
}
@@ -475,6 +480,20 @@ public class PodDBAdapter {
}
}
+ public void resetAllMediaPlayedDuration() {
+ try {
+ db.beginTransactionNonExclusive();
+ ContentValues values = new ContentValues();
+ values.put(KEY_PLAYED_DURATION, 0);
+ db.update(TABLE_NAME_FEED_MEDIA, values, null, new String[0]);
+ db.setTransactionSuccessful();
+ } catch (SQLException e) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ } finally {
+ db.endTransaction();
+ }
+ }
+
/**
* Insert all FeedItems of a feed and the feed object itself in a single
* transaction
@@ -1440,7 +1459,7 @@ public class PodDBAdapter {
*/
private static class PodDBHelper extends SQLiteOpenHelper {
- private static final int VERSION = 1070296;
+ private static final int VERSION = 1070400;
private final Context context;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java
index 1cd05aa26..608cade88 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/handler/HandlerState.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.syndication.handler;
-import android.support.v4.util.ArrayMap;
+import androidx.collection.ArrayMap;
import java.util.ArrayList;
import java.util.Map;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
index e6d4ed6b7..300e0038a 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/ChapterUtils.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.util;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.util.Log;
import org.apache.commons.io.IOUtils;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java
index 90e0b0981..20af6415e 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/LangUtils.java
@@ -1,6 +1,6 @@
package de.danoeh.antennapod.core.util;
-import android.support.v4.util.ArrayMap;
+import androidx.collection.ArrayMap;
import java.nio.charset.Charset;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java
index ca48c9bc9..a9e46e42c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/NetworkUtils.java
@@ -5,7 +5,7 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
-import android.support.v4.net.ConnectivityManagerCompat;
+import androidx.core.net.ConnectivityManagerCompat;
import android.text.TextUtils;
import android.util.Log;
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 5ae00460e..3e9e8327e 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
@@ -6,7 +6,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
-import android.support.v4.content.FileProvider;
+import androidx.core.content.FileProvider;
import android.util.Log;
import java.io.File;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java
index 1da7a5c50..eabaaa828 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/ThemeUtils.java
@@ -1,8 +1,8 @@
package de.danoeh.antennapod.core.util;
import android.content.Context;
-import android.support.annotation.AttrRes;
-import android.support.annotation.ColorInt;
+import androidx.annotation.AttrRes;
+import androidx.annotation.ColorInt;
import android.util.TypedValue;
public class ThemeUtils {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
index ffc6a6e28..7e3870a20 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/URLChecker.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.util;
import android.net.Uri;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import de.danoeh.antennapod.core.BuildConfig;
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 ebeec058d..e093a7e00 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
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.util.download;
import android.content.Context;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import androidx.work.Constraints;
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 52a43aab2..02e98ba84 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
@@ -5,7 +5,7 @@ import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
-import android.support.annotation.RequiresApi;
+import androidx.annotation.RequiresApi;
import de.danoeh.antennapod.core.R;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java
index 9b644c3ba..b55091009 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/ExternalMedia.java
@@ -6,245 +6,252 @@ import android.content.SharedPreferences.Editor;
import android.media.MediaMetadataRetriever;
import android.os.Parcel;
import android.os.Parcelable;
-
-import java.util.List;
-import java.util.concurrent.Callable;
-
import de.danoeh.antennapod.core.feed.Chapter;
import de.danoeh.antennapod.core.feed.MediaType;
import de.danoeh.antennapod.core.util.ChapterUtils;
+import java.util.List;
+import java.util.concurrent.Callable;
+import org.apache.commons.io.FilenameUtils;
/** Represents a media file that is stored on the local storage device. */
public class ExternalMedia implements Playable {
+ public static final int PLAYABLE_TYPE_EXTERNAL_MEDIA = 2;
+ public static final String PREF_SOURCE_URL = "ExternalMedia.PrefSourceUrl";
+ public static final String PREF_POSITION = "ExternalMedia.PrefPosition";
+ public static final String PREF_MEDIA_TYPE = "ExternalMedia.PrefMediaType";
+ public static final String PREF_LAST_PLAYED_TIME = "ExternalMedia.PrefLastPlayedTime";
+
+ private final String source;
+ private String episodeTitle;
+ private String feedTitle;
+ private MediaType mediaType;
+ private List<Chapter> chapters;
+ private int duration;
+ private int position;
+ private long lastPlayedTime;
+
+ /**
+ * Creates a new playable for files on the sd card.
+ * @param source File path of the file
+ * @param mediaType Type of the file
+ */
+ public ExternalMedia(String source, MediaType mediaType) {
+ super();
+ this.source = source;
+ this.mediaType = mediaType;
+ }
- public static final int PLAYABLE_TYPE_EXTERNAL_MEDIA = 2;
- public static final String PREF_SOURCE_URL = "ExternalMedia.PrefSourceUrl";
- public static final String PREF_POSITION = "ExternalMedia.PrefPosition";
- public static final String PREF_MEDIA_TYPE = "ExternalMedia.PrefMediaType";
- public static final String PREF_LAST_PLAYED_TIME = "ExternalMedia.PrefLastPlayedTime";
-
- private final String source;
-
- private String episodeTitle;
- private String feedTitle;
- private MediaType mediaType = MediaType.AUDIO;
- private List<Chapter> chapters;
- private int duration;
- private int position;
- private long lastPlayedTime;
-
- public ExternalMedia(String source, MediaType mediaType) {
- super();
- this.source = source;
- this.mediaType = mediaType;
- }
-
- public ExternalMedia(String source, MediaType mediaType, int position, long lastPlayedTime) {
- this(source, mediaType);
- this.position = position;
- this.lastPlayedTime = lastPlayedTime;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(source);
- dest.writeString(mediaType.toString());
- dest.writeInt(position);
- dest.writeLong(lastPlayedTime);
- }
-
- @Override
- public void writeToPreferences(Editor prefEditor) {
- prefEditor.putString(PREF_SOURCE_URL, source);
- prefEditor.putString(PREF_MEDIA_TYPE, mediaType.toString());
- prefEditor.putInt(PREF_POSITION, position);
- prefEditor.putLong(PREF_LAST_PLAYED_TIME, lastPlayedTime);
- }
-
- @Override
- public void loadMetadata() throws PlayableException {
- MediaMetadataRetriever mmr = new MediaMetadataRetriever();
- try {
- mmr.setDataSource(source);
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- throw new PlayableException(
- "IllegalArgumentException when setting up MediaMetadataReceiver");
- } catch (RuntimeException e) {
- // http://code.google.com/p/android/issues/detail?id=39770
- e.printStackTrace();
- throw new PlayableException(
- "RuntimeException when setting up MediaMetadataRetriever");
- }
- episodeTitle = mmr
- .extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
- feedTitle = mmr
- .extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
+ /**
+ * Creates a new playable for files on the sd card.
+ * @param source File path of the file
+ * @param mediaType Type of the file
+ * @param position Position to start from
+ * @param lastPlayedTime Timestamp when it was played last
+ */
+ public ExternalMedia(String source, MediaType mediaType, int position, long lastPlayedTime) {
+ this(source, mediaType);
+ this.position = position;
+ this.lastPlayedTime = lastPlayedTime;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(source);
+ dest.writeString(mediaType.toString());
+ dest.writeInt(position);
+ dest.writeLong(lastPlayedTime);
+ }
+
+ @Override
+ public void writeToPreferences(Editor prefEditor) {
+ prefEditor.putString(PREF_SOURCE_URL, source);
+ prefEditor.putString(PREF_MEDIA_TYPE, mediaType.toString());
+ prefEditor.putInt(PREF_POSITION, position);
+ prefEditor.putLong(PREF_LAST_PLAYED_TIME, lastPlayedTime);
+ }
+
+ @Override
+ public void loadMetadata() throws PlayableException {
+ MediaMetadataRetriever mmr = new MediaMetadataRetriever();
try {
- duration = Integer.parseInt(mmr
- .extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
+ mmr.setDataSource(source);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ throw new PlayableException("IllegalArgumentException when setting up MediaMetadataReceiver");
+ } catch (RuntimeException e) {
+ // http://code.google.com/p/android/issues/detail?id=39770
+ e.printStackTrace();
+ throw new PlayableException("RuntimeException when setting up MediaMetadataRetriever");
+ }
+ episodeTitle = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
+ if (episodeTitle == null) {
+ episodeTitle = FilenameUtils.getName(source);
+ }
+ feedTitle = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
+ try {
+ duration = Integer.parseInt(mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
} catch (NumberFormatException e) {
e.printStackTrace();
throw new PlayableException("NumberFormatException when reading duration of media file");
}
- ChapterUtils.loadChaptersFromFileUrl(this);
- }
-
- @Override
- public void loadChapterMarks() {
-
- }
-
- @Override
- public String getEpisodeTitle() {
- return episodeTitle;
- }
-
- @Override
- public Callable<String> loadShownotes() {
- return () -> "";
- }
-
- @Override
- public List<Chapter> getChapters() {
- return chapters;
- }
-
- @Override
- public String getWebsiteLink() {
- return null;
- }
-
- @Override
- public String getPaymentLink() {
- return null;
- }
-
- @Override
- public String getFeedTitle() {
- return feedTitle;
- }
-
- @Override
- public Object getIdentifier() {
- return source;
- }
-
- @Override
- public int getDuration() {
- return duration;
- }
-
- @Override
- public int getPosition() {
- return position;
- }
-
- @Override
- public long getLastPlayedTime() {
- return lastPlayedTime;
- }
-
- @Override
- public MediaType getMediaType() {
- return mediaType;
- }
-
- @Override
- public String getLocalMediaUrl() {
- return source;
- }
-
- @Override
- public String getStreamUrl() {
- return null;
- }
-
- @Override
- public boolean localFileAvailable() {
- return true;
- }
-
- @Override
- public boolean streamAvailable() {
- return false;
- }
-
- @Override
- public void saveCurrentPosition(SharedPreferences pref, int newPosition, long timestamp) {
- SharedPreferences.Editor editor = pref.edit();
- editor.putInt(PREF_POSITION, newPosition);
- editor.putLong(PREF_LAST_PLAYED_TIME, timestamp);
- position = newPosition;
- lastPlayedTime = timestamp;
- editor.apply();
- }
-
- @Override
- public void setPosition(int newPosition) {
- position = newPosition;
- }
-
- @Override
- public void setDuration(int newDuration) {
- duration = newDuration;
- }
-
- @Override
- public void setLastPlayedTime(long lastPlayedTime) {
- this.lastPlayedTime = lastPlayedTime;
- }
-
- @Override
- public void onPlaybackStart() {
-
- }
-
- @Override
- public void onPlaybackPause(Context context) {
-
- }
-
- @Override
- public void onPlaybackCompleted(Context context) {
-
- }
-
- @Override
- public int getPlayableType() {
- return PLAYABLE_TYPE_EXTERNAL_MEDIA;
- }
-
- @Override
- public void setChapters(List<Chapter> chapters) {
- this.chapters = chapters;
- }
-
- public static final Parcelable.Creator<ExternalMedia> CREATOR = new Parcelable.Creator<ExternalMedia>() {
- public ExternalMedia createFromParcel(Parcel in) {
- String source = in.readString();
- MediaType type = MediaType.valueOf(in.readString());
- int position = 0;
- if (in.dataAvail() > 0) {
- position = in.readInt();
- }
- long lastPlayedTime = 0;
- if (in.dataAvail() > 0) {
- lastPlayedTime = in.readLong();
- }
-
- return new ExternalMedia(source, type, position, lastPlayedTime);
- }
-
- public ExternalMedia[] newArray(int size) {
- return new ExternalMedia[size];
- }
- };
+ ChapterUtils.loadChaptersFromFileUrl(this);
+ }
+
+ @Override
+ public void loadChapterMarks() {
+
+ }
+
+ @Override
+ public String getEpisodeTitle() {
+ return episodeTitle;
+ }
+
+ @Override
+ public Callable<String> loadShownotes() {
+ return () -> "";
+ }
+
+ @Override
+ public List<Chapter> getChapters() {
+ return chapters;
+ }
+
+ @Override
+ public String getWebsiteLink() {
+ return null;
+ }
+
+ @Override
+ public String getPaymentLink() {
+ return null;
+ }
+
+ @Override
+ public String getFeedTitle() {
+ return feedTitle;
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return source;
+ }
+
+ @Override
+ public int getDuration() {
+ return duration;
+ }
+
+ @Override
+ public int getPosition() {
+ return position;
+ }
+
+ @Override
+ public long getLastPlayedTime() {
+ return lastPlayedTime;
+ }
+
+ @Override
+ public MediaType getMediaType() {
+ return mediaType;
+ }
+
+ @Override
+ public String getLocalMediaUrl() {
+ return source;
+ }
+
+ @Override
+ public String getStreamUrl() {
+ return null;
+ }
+
+ @Override
+ public boolean localFileAvailable() {
+ return true;
+ }
+
+ @Override
+ public boolean streamAvailable() {
+ return false;
+ }
+
+ @Override
+ public void saveCurrentPosition(SharedPreferences pref, int newPosition, long timestamp) {
+ SharedPreferences.Editor editor = pref.edit();
+ editor.putInt(PREF_POSITION, newPosition);
+ editor.putLong(PREF_LAST_PLAYED_TIME, timestamp);
+ position = newPosition;
+ lastPlayedTime = timestamp;
+ editor.apply();
+ }
+
+ @Override
+ public void setPosition(int newPosition) {
+ position = newPosition;
+ }
+
+ @Override
+ public void setDuration(int newDuration) {
+ duration = newDuration;
+ }
+
+ @Override
+ public void setLastPlayedTime(long lastPlayedTime) {
+ this.lastPlayedTime = lastPlayedTime;
+ }
+
+ @Override
+ public void onPlaybackStart() {
+
+ }
+
+ @Override
+ public void onPlaybackPause(Context context) {
+
+ }
+
+ @Override
+ public void onPlaybackCompleted(Context context) {
+
+ }
+
+ @Override
+ public int getPlayableType() {
+ return PLAYABLE_TYPE_EXTERNAL_MEDIA;
+ }
+
+ @Override
+ public void setChapters(List<Chapter> chapters) {
+ this.chapters = chapters;
+ }
+
+ public static final Parcelable.Creator<ExternalMedia> CREATOR = new Parcelable.Creator<ExternalMedia>() {
+ public ExternalMedia createFromParcel(Parcel in) {
+ String source = in.readString();
+ MediaType type = MediaType.valueOf(in.readString());
+ int position = 0;
+ if (in.dataAvail() > 0) {
+ position = in.readInt();
+ }
+ long lastPlayedTime = 0;
+ if (in.dataAvail() > 0) {
+ lastPlayedTime = in.readLong();
+ }
+
+ return new ExternalMedia(source, type, position, lastPlayedTime);
+ }
+
+ public ExternalMedia[] newArray(int size) {
+ return new ExternalMedia[size];
+ }
+ };
@Override
public String getImageLocation() {
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 da9b96430..378c47faf 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,7 +4,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.os.Parcelable;
import android.preference.PreferenceManager;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.util.Log;
import java.util.List;
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 1456ebd8d..ba903eeb9 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
@@ -11,8 +11,8 @@ import android.content.res.TypedArray;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.IBinder;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
@@ -24,12 +24,12 @@ import android.widget.TextView;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import de.danoeh.antennapod.core.R;
-import de.danoeh.antennapod.core.event.PlaybackPositionEvent;
import de.danoeh.antennapod.core.event.ServiceEvent;
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.preferences.PlaybackSpeedHelper;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
import de.danoeh.antennapod.core.service.playback.PlaybackServiceMediaPlayer;
@@ -503,16 +503,6 @@ public class PlaybackController {
PlaybackServiceMediaPlayer.PSMPInfo info = playbackService.getPSMPInfo();
status = info.playerStatus;
media = info.playable;
- /*
- if (media == null) {
- Log.w(TAG,
- "PlaybackService has no media object. Trying to restore last played media.");
- Intent serviceIntent = getPlayLastPlayedMediaIntent();
- if (serviceIntent != null) {
- ContextCompat.startForegroundService(activity, serviceIntent);
- }
- }
- */
onServiceQueried();
setupGUI();
@@ -715,12 +705,13 @@ public class PlaybackController {
if (playbackService != null && canSetPlaybackSpeed()) {
return playbackService.getCurrentPlaybackSpeed();
} else {
- return -1;
+ return PlaybackSpeedHelper.getCurrentPlaybackSpeed(getMedia());
}
}
public boolean canDownmix() {
- return playbackService != null && playbackService.canDownmix();
+ return (playbackService != null && playbackService.canDownmix())
+ || UserPreferences.useSonic();
}
public void setDownmix(boolean enable) {
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
index f7d2ee409..01ca97134 100644
--- 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
@@ -2,9 +2,8 @@ package de.danoeh.antennapod.core.util.playback;
import android.content.Context;
import android.content.Intent;
-import android.media.MediaPlayer;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
+import androidx.annotation.NonNull;
+import androidx.core.content.ContextCompat;
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
import de.danoeh.antennapod.core.service.playback.PlaybackService;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
index 75229b9cf..0fe1f0036 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/playback/Timeline.java
@@ -3,11 +3,10 @@ package de.danoeh.antennapod.core.util.playback;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
-import android.support.annotation.ColorInt;
-import android.support.annotation.NonNull;
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
-import android.util.Pair;
import android.util.TypedValue;
import org.jsoup.Jsoup;
@@ -15,7 +14,6 @@ import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
-import java.util.ArrayList;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
index c5ad9cfd6..a474756e9 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/syndication/FeedDiscoverer.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core.util.syndication;
import android.net.Uri;
-import android.support.v4.util.ArrayMap;
+import androidx.collection.ArrayMap;
import android.text.TextUtils;
import org.jsoup.Jsoup;
diff --git a/core/src/main/res/drawable/notification_default_large_icon.xml b/core/src/main/res/drawable/notification_default_large_icon.xml
new file mode 100644
index 000000000..6da31b1bb
--- /dev/null
+++ b/core/src/main/res/drawable/notification_default_large_icon.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportHeight="12.7"
+ android:viewportWidth="12.7"
+ android:height="64dp"
+ android:width="64dp">
+
+ <path
+ android:fillColor="#ff007DBA"
+ android:pathData="M 0,0 L 12.7,0 12.7,12.7 0,12.7 z"/>
+
+ <path
+ android:fillColor="#ffffffff"
+ android:pathData="m5.7552,2.2412l0,0.2651c0.9377,0.0202 1.5471,0.342 2.1043,0.9059 0.5571,0.5639 0.8845,1.3798 0.9007,2.3678l0.2599,0C9.0264,4.6634 8.5918,3.7637 8.0502,3.2236 7.5085,2.6834 6.7902,2.2418 5.7552,2.2412ZM5.7552,3.0148l0,0.2796c0.6954,0.0292 1.0901,0.1719 1.5704,0.6542 0.4803,0.4823 0.6825,1.1066 0.6961,1.8314l0.2754,0c-0.0071,-0.9985 -0.4383,-1.6927 -0.7746,-2.0278 -0.3363,-0.3351 -0.8054,-0.734 -1.7673,-0.7374zM5.7547,3.8277 L5.7552,4.0845c0.3213,0.006 0.6726,0.1129 0.9788,0.4568 0.3061,0.3439 0.4008,0.8294 0.4129,1.2387l0.2635,0C7.4091,5.2384 7.1848,4.6554 6.9122,4.3656 6.6397,4.0758 6.3157,3.8296 5.7547,3.8277ZM5.7774,4.916c-0.3286,0.0001 -0.595,0.2667 -0.5948,0.5953 0.0001,0.2168 0.1181,0.4163 0.308,0.5209l-2.4371,5.0379 0.417,0.2713 0.4914,-1.0108 4.3574,1.2511 0.0672,0.1302 0.4641,-0.2031L6.0229,6.0523c0.2124,-0.0963 0.349,-0.3078 0.3493,-0.5411 0.0002,-0.3286 -0.2661,-0.5952 -0.5948,-0.5953zM5.7567,6.6053 L6.1841,7.4352 5.1278,7.9111zM6.2689,7.6001 L7.0047,9.0284 5.0054,8.1747zM4.9154,8.3514 L7.0083,9.2408 4.1103,10.0237zM7.1934,9.3948 L8.1985,11.3471 4.2054,10.203Z" />
+
+</vector>
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 2f3375fe0..c8a22eddb 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -37,6 +37,8 @@
<string name="statistics_mode_normal">Calculate duration that was actually played. Playing twice is counted twice, while marking as played is not counted</string>
<string name="statistics_mode_count_all">Sum up all podcasts marked as played</string>
<string name="statistics_speed_not_counted">Notice: Playback speed is never taken into account.</string>
+ <string name="statistics_reset_data">Reset statistics data</string>
+ <string name="statistics_reset_data_msg">This will erase the history of duration played for all episodes. Are you sure you want to proceed?</string>
<!-- Main activity -->
<string name="drawer_open">Open menu</string>
@@ -431,6 +433,7 @@
<string name="pref_gpodnet_notifications_sum">This setting does not apply to authentication errors.</string>
<string name="pref_playback_speed_title">Playback Speeds</string>
<string name="pref_playback_speed_sum">Customize the speeds available for variable speed audio playback</string>
+ <string name="pref_feed_playback_speed_sum">The speed to use when starting audio playback for episodes in this feed</string>
<string name="pref_playback_time_respects_speed_title">Adjust media info to playback speed</string>
<string name="pref_playback_time_respects_speed_sum">Displayed position and duration are adapted to playback speed</string>
<string name="pref_fast_forward">Fast Forward Skip Time</string>
diff --git a/core/src/play/java/de/danoeh/antennapod/core/CastCallbacks.java b/core/src/play/java/de/danoeh/antennapod/core/CastCallbacks.java
index 770fee9b9..27f985a4c 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/CastCallbacks.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/CastCallbacks.java
@@ -1,7 +1,7 @@
package de.danoeh.antennapod.core;
-import android.support.annotation.Nullable;
-import android.support.v7.app.MediaRouteDialogFactory;
+import androidx.annotation.Nullable;
+import androidx.mediarouter.app.MediaRouteDialogFactory;
/**
* Callbacks for Chromecast support on the core module
diff --git a/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java b/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java
index 414a7840c..bf9ef3f5b 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/cast/CastManager.java
@@ -24,10 +24,10 @@ package de.danoeh.antennapod.core.cast;
import android.content.Context;
import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.v4.view.ActionProvider;
-import android.support.v4.view.MenuItemCompat;
-import android.support.v7.media.MediaRouter;
+import androidx.annotation.NonNull;
+import androidx.core.view.ActionProvider;
+import androidx.core.view.MenuItemCompat;
+import androidx.mediarouter.media.MediaRouter;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MenuItem;
@@ -1735,7 +1735,7 @@ public class CastManager extends BaseCastManager implements OnFailedListener {
* {@link SwitchableMediaRouteActionProvider} associated with the button if the caller needs
* such reference. It is assumed that the enclosing
* {@link android.app.Activity} inherits (directly or indirectly) from
- * {@link android.support.v7.app.AppCompatActivity}.
+ * {@link androidx.appcompat.app.AppCompatActivity}.
*
* @param menuItem MenuItem of the Media Router cast button.
*/
diff --git a/core/src/play/java/de/danoeh/antennapod/core/cast/RemoteMedia.java b/core/src/play/java/de/danoeh/antennapod/core/cast/RemoteMedia.java
index 1c6dd30c4..0614e5952 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/cast/RemoteMedia.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/cast/RemoteMedia.java
@@ -5,7 +5,7 @@ import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
-import android.support.annotation.Nullable;
+import androidx.annotation.Nullable;
import android.text.TextUtils;
import com.google.android.gms.cast.MediaInfo;
diff --git a/core/src/play/java/de/danoeh/antennapod/core/cast/SwitchableMediaRouteActionProvider.java b/core/src/play/java/de/danoeh/antennapod/core/cast/SwitchableMediaRouteActionProvider.java
index f063cf5e3..5a6a0aa2b 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/cast/SwitchableMediaRouteActionProvider.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/cast/SwitchableMediaRouteActionProvider.java
@@ -3,12 +3,12 @@ package de.danoeh.antennapod.core.cast;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.FragmentManager;
-import android.support.v7.app.MediaRouteActionProvider;
-import android.support.v7.app.MediaRouteChooserDialogFragment;
-import android.support.v7.app.MediaRouteControllerDialogFragment;
-import android.support.v7.media.MediaRouter;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.mediarouter.app.MediaRouteActionProvider;
+import androidx.mediarouter.app.MediaRouteChooserDialogFragment;
+import androidx.mediarouter.app.MediaRouteControllerDialogFragment;
+import androidx.mediarouter.media.MediaRouter;
import android.util.Log;
/**
diff --git a/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java b/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
index 79c71f164..c32ba2385 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceFlavorHelper.java
@@ -7,11 +7,11 @@ import android.content.IntentFilter;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.StringRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
-import android.support.v7.media.MediaRouter;
+import androidx.mediarouter.media.MediaRouter;
import android.support.wearable.media.MediaControlConstants;
import android.util.Log;
import android.widget.Toast;
diff --git a/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java b/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java
index f91264c59..63fc05cb8 100644
--- a/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java
+++ b/core/src/play/java/de/danoeh/antennapod/core/service/playback/RemotePSMP.java
@@ -2,7 +2,7 @@ package de.danoeh.antennapod.core.service.playback;
import android.content.Context;
import android.media.MediaPlayer;
-import android.support.annotation.NonNull;
+import androidx.annotation.NonNull;
import android.util.Log;
import android.util.Pair;
import android.view.SurfaceHolder;