summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.java58
-rw-r--r--app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java28
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java48
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/FeedRefreshIntervalDialog.java117
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java15
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java5
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java21
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java46
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java65
-rw-r--r--app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java13
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java7
-rw-r--r--app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java20
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/TimePicker.java31
-rw-r--r--app/src/main/res/layout/feed_refresh_dialog.xml40
-rw-r--r--app/src/main/res/layout/scrollable_dialog.xml37
-rw-r--r--app/src/main/res/xml/preferences_network.xml7
-rw-r--r--core/build.gradle1
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java11
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/FeedUpdateWorker.java166
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java139
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceInterfaceImpl.java6
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java14
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java101
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java10
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java20
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java167
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/download/FeedUpdateManager.java112
-rw-r--r--core/src/main/res/values/arrays.xml22
-rw-r--r--core/src/main/res/values/ids.xml1
-rw-r--r--event/src/main/java/de/danoeh/antennapod/event/FeedUpdateRunningEvent.java9
-rw-r--r--net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequest.java6
-rw-r--r--storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java7
-rw-r--r--storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java72
-rw-r--r--ui/i18n/src/main/res/values/strings.xml17
40 files changed, 525 insertions, 964 deletions
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.java b/app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.java
index f3cd99b2c..861c62f1b 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/FeedSettingsTest.java
@@ -2,13 +2,11 @@ package de.test.antennapod.ui;
import android.content.Intent;
import androidx.test.espresso.intent.rule.IntentsTestRule;
-import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.model.feed.Feed;
-import de.danoeh.antennapod.model.feed.FeedPreferences;
import de.test.antennapod.EspressoTestUtils;
import org.junit.After;
import org.junit.Before;
@@ -18,8 +16,6 @@ import org.junit.runner.RunWith;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
-import static androidx.test.espresso.action.ViewActions.pressBack;
-import static androidx.test.espresso.action.ViewActions.typeText;
import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
@@ -28,10 +24,6 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static de.test.antennapod.EspressoTestUtils.clickPreference;
import static de.test.antennapod.EspressoTestUtils.waitForView;
import static org.hamcrest.Matchers.allOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import java.io.IOException;
@RunWith(AndroidJUnit4.class)
public class FeedSettingsTest {
@@ -84,52 +76,4 @@ public class FeedSettingsTest {
clickPreference(R.string.feed_volume_reduction);
onView(withText(R.string.cancel_label)).perform(click());
}
-
- /**
- * Test that modifying a feed's authentication settings results in proper behavior.
- * Expect:
- * - Feed is refreshed automatically
- * - Database has updated username and password
- */
- @Test
- public void testAuthenticationSettingsUpdate() throws IOException {
- onView(isRoot()).perform(waitForView(allOf(isDescendantOfA(withId(R.id.appBar)),
- withText(feed.getTitle()), isDisplayed()), 1000));
-
- String updatedTitle = "modified episode title";
- String username = "username";
- String password = "password";
-
- // update feed hosted on server
- feed.getItems().get(0).setTitle(updatedTitle);
- uiTestUtils.hostFeed(feed);
-
- // interact with UI to update authentication settings
- updateAuthenticationSettings(username, password);
-
- // expect feed to have refreshed and be showing new episode title
- onView(isRoot()).perform(waitForView(withText(updatedTitle), 5000));
-
- // expect database to be updated with correct username and password
- Feed updatedFeed = DBReader.getFeed(feed.getId());
- assertNotNull(updatedFeed);
-
- FeedPreferences updatedFeedPreferences = updatedFeed.getPreferences();
- assertNotNull(updatedFeedPreferences);
-
- assertEquals("database updated with username", username, updatedFeedPreferences.getUsername());
- assertEquals("database updated with password", password, updatedFeedPreferences.getPassword());
- }
-
- private void updateAuthenticationSettings(String username, String password) {
- onView(withId(R.id.butShowSettings)).perform(click());
-
- clickPreference(R.string.authentication_label);
- onView(withId(R.id.usernameEditText)).perform(typeText(username));
- onView(withId(R.id.passwordEditText)).perform(typeText(password));
- onView(withText(R.string.confirm_label)).perform(click());
-
- onView(isRoot()).perform(pressBack());
- }
-
}
diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
index b790bc005..1b8100392 100644
--- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
+++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java
@@ -5,7 +5,6 @@ import android.content.SharedPreferences;
import android.content.res.Resources;
import androidx.annotation.StringRes;
import androidx.preference.PreferenceManager;
-import androidx.test.espresso.matcher.RootMatchers;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import de.danoeh.antennapod.R;
@@ -25,9 +24,7 @@ import org.junit.Rule;
import org.junit.Test;
import java.util.Arrays;
-import java.util.concurrent.TimeUnit;
-import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
@@ -46,7 +43,6 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static de.test.antennapod.EspressoTestUtils.clickPreference;
import static de.test.antennapod.EspressoTestUtils.waitForView;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.hamcrest.Matchers.anything;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertTrue;
@@ -227,30 +223,6 @@ public class PreferencesTest {
}
@Test
- public void testDisableUpdateInterval() {
- clickPreference(R.string.network_pref);
- clickPreference(R.string.feed_refresh_title);
- onView(withText(R.string.feed_refresh_never)).perform(click());
- onView(withId(R.id.disableRadioButton)).perform(click());
- onView(withText(R.string.confirm_label)).perform(click());
- Awaitility.await().atMost(1000, MILLISECONDS)
- .until(() -> UserPreferences.getUpdateInterval() == 0);
- }
-
- @Test
- public void testSetUpdateInterval() {
- clickPreference(R.string.network_pref);
- clickPreference(R.string.feed_refresh_title);
- onView(withId(R.id.intervalRadioButton)).perform(click());
- onView(withId(R.id.spinner)).perform(click());
- int position = 1; // an arbitrary position
- onData(anything()).inRoot(RootMatchers.isPlatformPopup()).atPosition(position).perform(click());
- onView(withText(R.string.confirm_label)).perform(click());
- Awaitility.await().atMost(1000, MILLISECONDS)
- .until(() -> UserPreferences.getUpdateInterval() == TimeUnit.HOURS.toMillis(2));
- }
-
- @Test
public void testSetSequentialDownload() {
clickPreference(R.string.network_pref);
clickPreference(R.string.pref_parallel_downloads_title);
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
index 9c771f161..7851e5b9a 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java
@@ -22,36 +22,31 @@ import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
-import com.google.android.material.appbar.MaterialToolbar;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentContainerView;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.RecyclerView;
+import androidx.work.WorkInfo;
+import androidx.work.WorkManager;
import com.bumptech.glide.Glide;
+import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.snackbar.Snackbar;
-
-import de.danoeh.antennapod.core.preferences.ThemeSwitcher;
-import de.danoeh.antennapod.fragment.AllEpisodesFragment;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.Validate;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
+import de.danoeh.antennapod.core.preferences.ThemeSwitcher;
import de.danoeh.antennapod.core.receiver.MediaButtonReceiver;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.dialog.RatingDialog;
+import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
import de.danoeh.antennapod.event.MessageEvent;
import de.danoeh.antennapod.fragment.AddFeedFragment;
+import de.danoeh.antennapod.fragment.AllEpisodesFragment;
import de.danoeh.antennapod.fragment.AudioPlayerFragment;
import de.danoeh.antennapod.fragment.CompletedDownloadsFragment;
-import de.danoeh.antennapod.fragment.InboxFragment;
import de.danoeh.antennapod.fragment.FeedItemlistFragment;
+import de.danoeh.antennapod.fragment.InboxFragment;
import de.danoeh.antennapod.fragment.NavDrawerFragment;
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
import de.danoeh.antennapod.fragment.QueueFragment;
@@ -60,10 +55,16 @@ import de.danoeh.antennapod.fragment.SubscriptionFragment;
import de.danoeh.antennapod.fragment.TransitionEffect;
import de.danoeh.antennapod.playback.cast.CastEnabledActivity;
import de.danoeh.antennapod.preferences.PreferenceUpgrader;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.ui.appstartintent.MainActivityStarter;
import de.danoeh.antennapod.ui.common.ThemeUtils;
import de.danoeh.antennapod.ui.home.HomeFragment;
import de.danoeh.antennapod.view.LockableBottomSheetBehavior;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.Validate;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
/**
* The activity that is shown when the user launches the app.
@@ -157,6 +158,21 @@ public class MainActivity extends CastEnabledActivity {
sheetBehavior = (LockableBottomSheetBehavior) BottomSheetBehavior.from(bottomSheet);
sheetBehavior.setHideable(false);
sheetBehavior.setBottomSheetCallback(bottomSheetCallback);
+
+ FeedUpdateManager.restartUpdateAlarm(this, false);
+ WorkManager.getInstance(this)
+ .getWorkInfosByTagLiveData(FeedUpdateManager.WORK_TAG_FEED_UPDATE)
+ .observe(this, workInfos -> {
+ boolean isRefreshingFeeds = false;
+ for (WorkInfo workInfo : workInfos) {
+ if (workInfo.getState() == WorkInfo.State.RUNNING) {
+ isRefreshingFeeds = true;
+ } else if (workInfo.getState() == WorkInfo.State.ENQUEUED) {
+ isRefreshingFeeds = true;
+ }
+ }
+ EventBus.getDefault().postSticky(new FeedUpdateRunningEvent(isRefreshingFeeds));
+ });
}
@Override
@@ -241,9 +257,7 @@ public class MainActivity extends CastEnabledActivity {
private void checkFirstLaunch() {
SharedPreferences prefs = getSharedPreferences(PREF_NAME, MODE_PRIVATE);
if (prefs.getBoolean(PREF_IS_FIRST_LAUNCH, true)) {
- // for backward compatibility, we only change defaults for fresh installs
- UserPreferences.setUpdateInterval(12);
- AutoUpdateManager.restartUpdateAlarm(this);
+ FeedUpdateManager.restartUpdateAlarm(this, true);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(PREF_IS_FIRST_LAUNCH, false);
@@ -553,7 +567,7 @@ public class MainActivity extends CastEnabledActivity {
drawerLayout.open();
}
if (intent.getBooleanExtra(EXTRA_REFRESH_ON_START, false)) {
- AutoUpdateManager.runImmediate(this);
+ FeedUpdateManager.runOnceOrAsk(this);
}
// to avoid handling the intent twice when the configuration changes
setIntent(new Intent(MainActivity.this, MainActivity.class));
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
index 50aabbd01..f5f3d28f6 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -36,7 +36,7 @@ import de.danoeh.antennapod.core.preferences.ThemeSwitcher;
import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.service.download.DownloadRequestCreator;
import de.danoeh.antennapod.core.feed.FeedUrlNotFoundException;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
+import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.service.playback.PlaybackServiceInterface;
import de.danoeh.antennapod.core.util.DownloadErrorLabel;
import de.danoeh.antennapod.event.FeedListUpdateEvent;
@@ -455,10 +455,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
if (feedInFeedlist()) {
openFeed();
} else {
- Feed f = new Feed(selectedDownloadUrl, null, feed.getTitle());
- DownloadServiceInterface.get().download(this, false, DownloadRequestCreator.create(f)
- .withAuthentication(username, password)
- .build());
+ DBTasks.updateFeed(this, feed, false);
didPressSubscribe = true;
handleUpdatedFeedStatus();
}
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
index 64a6b6632..10a41057c 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
@@ -29,7 +29,7 @@ import de.danoeh.antennapod.core.export.opml.OpmlReader;
import de.danoeh.antennapod.core.preferences.ThemeSwitcher;
import de.danoeh.antennapod.core.storage.DBTasks;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.databinding.OpmlSelectionBinding;
import de.danoeh.antennapod.model.feed.Feed;
import io.reactivex.Completable;
@@ -101,7 +101,7 @@ public class OpmlImportActivity extends AppCompatActivity {
feed.setItems(Collections.emptyList());
DBTasks.updateFeed(this, feed, false);
}
- DownloadServiceInterface.get().refreshAllFeeds(this, true);
+ FeedUpdateManager.runOnce(this);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/FeedRefreshIntervalDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/FeedRefreshIntervalDialog.java
deleted file mode 100644
index 3d92fd979..000000000
--- a/app/src/main/java/de/danoeh/antennapod/dialog/FeedRefreshIntervalDialog.java
+++ /dev/null
@@ -1,117 +0,0 @@
-package de.danoeh.antennapod.dialog;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.os.Build;
-import android.text.format.DateFormat;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import androidx.appcompat.app.AlertDialog;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
-import de.danoeh.antennapod.databinding.FeedRefreshDialogBinding;
-import de.danoeh.antennapod.databinding.ScrollableDialogBinding;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import java.util.concurrent.TimeUnit;
-import org.apache.commons.lang3.ArrayUtils;
-
-public class FeedRefreshIntervalDialog {
- private static final int[] INTERVAL_VALUES_HOURS = {1, 2, 4, 8, 12, 24, 72};
- private final Context context;
- private FeedRefreshDialogBinding viewBinding;
-
- public FeedRefreshIntervalDialog(Context context) {
- this.context = context;
- }
-
- public void show() {
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context);
- builder.setTitle(R.string.feed_refresh_title);
- builder.setMessage(R.string.feed_refresh_sum);
- ScrollableDialogBinding scrollableDialogBinding = ScrollableDialogBinding.inflate(LayoutInflater.from(context));
- builder.setView(scrollableDialogBinding.getRoot());
- viewBinding = FeedRefreshDialogBinding.inflate(LayoutInflater.from(context));
- scrollableDialogBinding.content.addView(viewBinding.getRoot());
-
- ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(context,
- android.R.layout.simple_spinner_item, buildSpinnerEntries());
- spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
- viewBinding.spinner.setAdapter(spinnerArrayAdapter);
- viewBinding.timePicker.setIs24HourView(DateFormat.is24HourFormat(context));
- viewBinding.spinner.setSelection(ArrayUtils.indexOf(INTERVAL_VALUES_HOURS, 24));
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- viewBinding.timePicker.setHour(8);
- viewBinding.timePicker.setMinute(0);
- } else {
- viewBinding.timePicker.setCurrentHour(8);
- viewBinding.timePicker.setCurrentMinute(0);
- }
-
- long currInterval = UserPreferences.getUpdateInterval();
- int[] updateTime = UserPreferences.getUpdateTimeOfDay();
- if (currInterval > 0) {
- viewBinding.spinner.setSelection(ArrayUtils.indexOf(INTERVAL_VALUES_HOURS,
- (int) TimeUnit.MILLISECONDS.toHours(currInterval)));
- viewBinding.intervalRadioButton.setChecked(true);
- } else if (updateTime.length == 2 && updateTime[0] >= 0) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- viewBinding.timePicker.setHour(updateTime[0]);
- viewBinding.timePicker.setMinute(updateTime[1]);
- } else {
- viewBinding.timePicker.setCurrentHour(updateTime[0]);
- viewBinding.timePicker.setCurrentMinute(updateTime[1]);
- }
- viewBinding.timeRadioButton.setChecked(true);
- } else {
- viewBinding.disableRadioButton.setChecked(true);
- }
- updateVisibility();
-
- viewBinding.radioGroup.setOnCheckedChangeListener((radioGroup, i) -> updateVisibility());
-
- AlertDialog dialog = builder.show();
-
- scrollableDialogBinding.positiveButton.setText(R.string.confirm_label);
- scrollableDialogBinding.positiveButton.setOnClickListener(v -> {
- dialog.dismiss();
- if (viewBinding.intervalRadioButton.isChecked()) {
- UserPreferences.setUpdateInterval(INTERVAL_VALUES_HOURS[viewBinding.spinner.getSelectedItemPosition()]);
- AutoUpdateManager.restartUpdateAlarm(context);
- } else if (viewBinding.timeRadioButton.isChecked()) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- UserPreferences.setUpdateTimeOfDay(viewBinding.timePicker.getHour(),
- viewBinding.timePicker.getMinute());
- } else {
- UserPreferences.setUpdateTimeOfDay(viewBinding.timePicker.getCurrentHour(),
- viewBinding.timePicker.getCurrentMinute());
- }
- AutoUpdateManager.restartUpdateAlarm(context);
- } else if (viewBinding.disableRadioButton.isChecked()) {
- UserPreferences.disableAutoUpdate();
- AutoUpdateManager.disableAutoUpdate(context);
- } else {
- throw new IllegalStateException("Unexpected error.");
- }
- });
-
- scrollableDialogBinding.negativeButton.setText(R.string.cancel_label);
- scrollableDialogBinding.negativeButton.setOnClickListener((v) -> dialog.dismiss());
- }
-
- private String[] buildSpinnerEntries() {
- final Resources res = context.getResources();
- String[] entries = new String[INTERVAL_VALUES_HOURS.length];
- for (int i = 0; i < INTERVAL_VALUES_HOURS.length; i++) {
- int hours = INTERVAL_VALUES_HOURS[i];
- entries[i] = res.getQuantityString(R.plurals.feed_refresh_every_x_hours, hours, hours);
- }
- return entries;
- }
-
- private void updateVisibility() {
- viewBinding.spinner.setVisibility(viewBinding.intervalRadioButton.isChecked() ? View.VISIBLE : View.GONE);
- viewBinding.timePicker.setVisibility(viewBinding.timeRadioButton.isChecked() ? View.VISIBLE : View.GONE);
- }
-}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
index dbc453301..737975389 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/CompletedDownloadsFragment.java
@@ -25,7 +25,7 @@ import de.danoeh.antennapod.core.event.DownloadLogEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.util.FeedItemUtil;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.event.FeedItemEvent;
import de.danoeh.antennapod.event.PlayerStatusEvent;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
@@ -193,7 +193,7 @@ public class CompletedDownloadsFragment extends Fragment
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.refresh_item) {
- AutoUpdateManager.runImmediate(requireContext());
+ FeedUpdateManager.runOnceOrAsk(requireContext());
return true;
} else if (item.getItemId() == R.id.action_download_logs) {
new DownloadLogFragment().show(getChildFragmentManager(), null);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
index 5ba323372..18bec12ca 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/EpisodesListFragment.java
@@ -30,11 +30,11 @@ import de.danoeh.antennapod.core.dialog.ConfirmationDialog;
import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.util.FeedItemUtil;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.event.FeedItemEvent;
import de.danoeh.antennapod.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
import de.danoeh.antennapod.event.PlayerStatusEvent;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.event.playback.PlaybackPositionEvent;
@@ -123,7 +123,7 @@ public abstract class EpisodesListFragment extends Fragment
}
final int itemId = item.getItemId();
if (itemId == R.id.refresh_item) {
- AutoUpdateManager.runImmediate(requireContext());
+ FeedUpdateManager.runOnceOrAsk(requireContext());
return true;
} else if (itemId == R.id.action_search) {
((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance());
@@ -184,7 +184,7 @@ public abstract class EpisodesListFragment extends Fragment
SwipeRefreshLayout swipeRefreshLayout = root.findViewById(R.id.swipeRefresh);
swipeRefreshLayout.setDistanceToTriggerSync(getResources().getInteger(R.integer.swipe_refresh_distance));
swipeRefreshLayout.setOnRefreshListener(() -> {
- AutoUpdateManager.runImmediate(requireContext());
+ FeedUpdateManager.runOnceOrAsk(requireContext());
new Handler(Looper.getMainLooper()).postDelayed(() -> swipeRefreshLayout.setRefreshing(false),
getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms));
});
@@ -455,9 +455,12 @@ public abstract class EpisodesListFragment extends Fragment
protected abstract String getPrefName();
protected void updateToolbar() {
+ }
+
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(FeedUpdateRunningEvent event) {
if (toolbar.getMenu().findItem(R.id.refresh_item) != null) {
- MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(), R.id.refresh_item,
- DownloadService.isRunning && DownloadService.isDownloadingFeeds());
+ MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(), R.id.refresh_item, event.isFeedUpdateRunning);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
index 0b264b5a3..ecc60c411 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
@@ -33,11 +33,11 @@ import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.feed.FeedEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.util.FeedItemPermutors;
import de.danoeh.antennapod.core.util.FeedItemUtil;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.core.util.gui.MoreContentListFooterUtil;
import de.danoeh.antennapod.databinding.FeedItemListFragmentBinding;
import de.danoeh.antennapod.databinding.MultiSelectSpeedDialBinding;
@@ -48,6 +48,7 @@ import de.danoeh.antennapod.dialog.RenameItemDialog;
import de.danoeh.antennapod.event.FavoritesEvent;
import de.danoeh.antennapod.event.FeedItemEvent;
import de.danoeh.antennapod.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
import de.danoeh.antennapod.event.PlayerStatusEvent;
import de.danoeh.antennapod.event.QueueEvent;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
@@ -164,7 +165,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
nextPageLoader = new MoreContentListFooterUtil(viewBinding.moreContent.moreContentListFooter);
nextPageLoader.setClickListener(() -> {
if (feed != null) {
- DBTasks.loadNextPageOfFeed(getActivity(), feed, false);
+ FeedUpdateManager.runOnce(getContext(), feed, true);
}
});
viewBinding.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@@ -241,8 +242,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
}
viewBinding.toolbar.getMenu().findItem(R.id.visit_website_item).setVisible(feed.getLink() != null);
- MenuItemUtils.updateRefreshMenuItem(viewBinding.toolbar.getMenu(), R.id.refresh_item,
- DownloadService.isRunning && DownloadService.isDownloadingFile(feed.getDownload_url()));
FeedMenuHandler.onPrepareOptionsMenu(viewBinding.toolbar.getMenu(), feed);
}
@@ -384,7 +383,6 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
private void updateUi() {
loadItems();
- updateSyncProgressBarVisibility();
}
@Subscribe(threadMode = ThreadMode.MAIN)
@@ -404,12 +402,14 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
}
}
- private void updateSyncProgressBarVisibility() {
- updateToolbar();
- if (!DownloadService.isDownloadingFeeds()) {
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(FeedUpdateRunningEvent event) {
+ nextPageLoader.setLoadingState(event.isFeedUpdateRunning);
+ if (!event.isFeedUpdateRunning) {
nextPageLoader.getRoot().setVisibility(View.GONE);
}
- nextPageLoader.setLoadingState(DownloadService.isDownloadingFeeds());
+ MenuItemUtils.updateRefreshMenuItem(viewBinding.toolbar.getMenu(),
+ R.id.refresh_item, event.isFeedUpdateRunning);
}
private void refreshHeaderView() {
@@ -534,14 +534,12 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
adapter.setDummyViews(0);
adapter.updateItems(feed.getItems());
updateToolbar();
- updateSyncProgressBarVisibility();
}, error -> {
feed = null;
refreshHeaderView();
adapter.setDummyViews(0);
adapter.updateItems(Collections.emptyList());
updateToolbar();
- updateSyncProgressBarVisibility();
Log.e(TAG, Log.getStackTraceString(error));
});
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
index b4195ba01..ae9e003d5 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedSettingsFragment.java
@@ -16,7 +16,7 @@ import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreferenceCompat;
import androidx.recyclerview.widget.RecyclerView;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.event.settings.SkipIntroEndingChangedEvent;
import de.danoeh.antennapod.event.settings.SpeedPresetChangedEvent;
import de.danoeh.antennapod.event.settings.VolumeAdaptionChangedEvent;
@@ -270,8 +270,7 @@ public class FeedSettingsFragment extends Fragment {
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
-
- DBTasks.forceRefreshFeed(requireContext(), feed, true);
+ FeedUpdateManager.runOnce(getContext(), feed);
}, "RefreshAfterCredentialChange").start();
}
}.show();
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
index bb22c5652..6681df4c1 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/QueueFragment.java
@@ -18,13 +18,13 @@ import android.widget.CheckBox;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import com.google.android.material.appbar.MaterialToolbar;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+import com.google.android.material.appbar.MaterialToolbar;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
import com.leinardi.android.speeddial.SpeedDialView;
import de.danoeh.antennapod.R;
@@ -36,14 +36,13 @@ import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.event.DownloaderUpdate;
import de.danoeh.antennapod.core.feed.util.PlaybackSpeedUtils;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.Converter;
import de.danoeh.antennapod.core.util.FeedItemUtil;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.event.FeedItemEvent;
+import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
import de.danoeh.antennapod.event.PlayerStatusEvent;
import de.danoeh.antennapod.event.QueueEvent;
import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
@@ -54,6 +53,7 @@ import de.danoeh.antennapod.menuhandler.FeedItemMenuHandler;
import de.danoeh.antennapod.model.feed.FeedItem;
import de.danoeh.antennapod.model.feed.FeedItemFilter;
import de.danoeh.antennapod.model.feed.SortOrder;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.view.EmptyViewHandler;
import de.danoeh.antennapod.view.EpisodeItemListRecyclerView;
import de.danoeh.antennapod.view.LiftOnScrollListener;
@@ -263,8 +263,11 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte
toolbar.getMenu().findItem(R.id.queue_lock).setVisible(!keepSorted);
toolbar.getMenu().findItem(R.id.sort_random).setVisible(!keepSorted);
toolbar.getMenu().findItem(R.id.keep_sorted).setChecked(keepSorted);
- MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(),
- R.id.refresh_item, DownloadService.isRunning && DownloadService.isDownloadingFeeds());
+ }
+
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(FeedUpdateRunningEvent event) {
+ MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(), R.id.refresh_item, event.isFeedUpdateRunning);
}
@Override
@@ -274,7 +277,7 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte
toggleQueueLock();
return true;
} else if (itemId == R.id.refresh_item) {
- AutoUpdateManager.runImmediate(requireContext());
+ FeedUpdateManager.runOnceOrAsk(requireContext());
return true;
} else if (itemId == R.id.clear_queue) {
// make sure the user really wants to clear the queue
@@ -457,7 +460,7 @@ public class QueueFragment extends Fragment implements MaterialToolbar.OnMenuIte
SwipeRefreshLayout swipeRefreshLayout = root.findViewById(R.id.swipeRefresh);
swipeRefreshLayout.setDistanceToTriggerSync(getResources().getInteger(R.integer.swipe_refresh_distance));
swipeRefreshLayout.setOnRefreshListener(() -> {
- AutoUpdateManager.runImmediate(requireContext());
+ FeedUpdateManager.runOnceOrAsk(requireContext());
new Handler(Looper.getMainLooper()).postDelayed(() -> swipeRefreshLayout.setRefreshing(false),
getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms));
});
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
index cc13f4ce3..a0698229a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/SubscriptionFragment.java
@@ -13,51 +13,47 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
-
import androidx.annotation.NonNull;
-import com.google.android.material.appbar.MaterialToolbar;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
-
+import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.joanzapata.iconify.Iconify;
import com.leinardi.android.speeddial.SpeedDialView;
-
-import de.danoeh.antennapod.ui.statistics.StatisticsFragment;
-import de.danoeh.antennapod.view.LiftOnScrollListener;
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-import org.greenrobot.eventbus.ThreadMode;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
import de.danoeh.antennapod.adapter.SubscriptionsRecyclerAdapter;
import de.danoeh.antennapod.core.event.DownloadEvent;
-import de.danoeh.antennapod.event.FeedListUpdateEvent;
-import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBReader;
import de.danoeh.antennapod.core.storage.NavDrawerData;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.dialog.FeedSortDialog;
import de.danoeh.antennapod.dialog.RenameItemDialog;
import de.danoeh.antennapod.dialog.SubscriptionsFilterDialog;
+import de.danoeh.antennapod.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
+import de.danoeh.antennapod.event.UnreadItemsUpdateEvent;
import de.danoeh.antennapod.fragment.actions.FeedMultiSelectActionHandler;
+import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
+import de.danoeh.antennapod.ui.statistics.StatisticsFragment;
import de.danoeh.antennapod.view.EmptyViewHandler;
-import de.danoeh.antennapod.menuhandler.FeedMenuHandler;
+import de.danoeh.antennapod.view.LiftOnScrollListener;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
/**
* Fragment for displaying feed subscriptions
@@ -173,7 +169,7 @@ public class SubscriptionFragment extends Fragment
SwipeRefreshLayout swipeRefreshLayout = root.findViewById(R.id.swipeRefresh);
swipeRefreshLayout.setDistanceToTriggerSync(getResources().getInteger(R.integer.swipe_refresh_distance));
swipeRefreshLayout.setOnRefreshListener(() -> {
- AutoUpdateManager.runImmediate(requireContext());
+ FeedUpdateManager.runOnceOrAsk(requireContext());
new Handler(Looper.getMainLooper()).postDelayed(() -> swipeRefreshLayout.setRefreshing(false),
getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms));
});
@@ -209,16 +205,18 @@ public class SubscriptionFragment extends Fragment
private void refreshToolbarState() {
int columns = prefs.getInt(PREF_NUM_COLUMNS, getDefaultNumOfColumns());
toolbar.getMenu().findItem(COLUMN_CHECKBOX_IDS[columns - MIN_NUM_COLUMNS]).setChecked(true);
+ }
- MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(), R.id.refresh_item,
- DownloadService.isRunning && DownloadService.isDownloadingFeeds());
+ @Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
+ public void onEventMainThread(FeedUpdateRunningEvent event) {
+ MenuItemUtils.updateRefreshMenuItem(toolbar.getMenu(), R.id.refresh_item, event.isFeedUpdateRunning);
}
@Override
public boolean onMenuItemClick(MenuItem item) {
final int itemId = item.getItemId();
if (itemId == R.id.refresh_item) {
- AutoUpdateManager.runImmediate(requireContext());
+ FeedUpdateManager.runOnceOrAsk(requireContext());
return true;
} else if (itemId == R.id.subscriptions_filter) {
SubscriptionsFilterDialog.showDialog(requireContext());
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
index 50de1e3c4..94c85abfe 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/NetworkPreferencesFragment.java
@@ -1,21 +1,15 @@
package de.danoeh.antennapod.fragment.preferences;
-import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
-import android.text.format.DateFormat;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.PreferenceActivity;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.dialog.FeedRefreshIntervalDialog;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.dialog.ProxyDialog;
-
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.concurrent.TimeUnit;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
public class NetworkPreferencesFragment extends PreferenceFragmentCompat
@@ -45,7 +39,6 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat
@Override
public void onResume() {
super.onResume();
- setUpdateIntervalText();
setParallelDownloadsText(UserPreferences.getParallelDownloads());
}
@@ -54,21 +47,12 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat
((PreferenceActivity) getActivity()).openScreen(R.xml.preferences_autodownload);
return true;
});
- findPreference(UserPreferences.PREF_UPDATE_INTERVAL)
- .setOnPreferenceClickListener(preference -> {
- new FeedRefreshIntervalDialog(getContext()).show();
- return true;
- });
-
- findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS)
- .setOnPreferenceChangeListener(
- (preference, o) -> {
- if (o instanceof Integer) {
- setParallelDownloadsText((Integer) o);
- }
- return true;
- }
- );
+ findPreference(UserPreferences.PREF_PARALLEL_DOWNLOADS).setOnPreferenceChangeListener((preference, o) -> {
+ if (o instanceof Integer) {
+ setParallelDownloadsText((Integer) o);
+ }
+ return true;
+ });
// validate and set correct value: number of downloads between 1 and 50 (inclusive)
findPreference(PREF_PROXY).setOnPreferenceClickListener(preference -> {
ProxyDialog dialog = new ProxyDialog(getActivity());
@@ -77,35 +61,6 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat
});
}
- /**
- * Used to init and handle changes to view
- */
- private void setUpdateIntervalText() {
- Context context = getActivity().getApplicationContext();
- String val;
- long interval = UserPreferences.getUpdateInterval();
- if (interval > 0) {
- int hours = (int) TimeUnit.MILLISECONDS.toHours(interval);
- val = context.getResources().getQuantityString(
- R.plurals.feed_refresh_every_x_hours, hours, hours);
- } else {
- int[] timeOfDay = UserPreferences.getUpdateTimeOfDay();
- if (timeOfDay.length == 2) {
- Calendar cal = new GregorianCalendar();
- cal.set(Calendar.HOUR_OF_DAY, timeOfDay[0]);
- cal.set(Calendar.MINUTE, timeOfDay[1]);
- String timeOfDayStr = DateFormat.getTimeFormat(context).format(cal.getTime());
- val = String.format(context.getString(R.string.feed_refresh_interval_at),
- timeOfDayStr);
- } else {
- val = context.getString(R.string.feed_refresh_never);
- }
- }
- String summary = context.getString(R.string.feed_refresh_sum) + "\n"
- + String.format(context.getString(R.string.pref_current_value), val);
- findPreference(UserPreferences.PREF_UPDATE_INTERVAL).setSummary(summary);
- }
-
private void setParallelDownloadsText(int downloads) {
final Resources res = getActivity().getResources();
String s = res.getString(R.string.parallel_downloads, downloads);
@@ -115,9 +70,7 @@ public class NetworkPreferencesFragment extends PreferenceFragmentCompat
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (UserPreferences.PREF_UPDATE_INTERVAL.equals(key)) {
- setUpdateIntervalText();
+ FeedUpdateManager.restartUpdateAlarm(getContext(), true);
}
}
}
-
-
diff --git a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
index 7aee499da..e9b0c0b19 100644
--- a/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
+++ b/app/src/main/java/de/danoeh/antennapod/menuhandler/FeedMenuHandler.java
@@ -10,6 +10,7 @@ import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.IntentUtils;
import de.danoeh.antennapod.core.util.ShareUtils;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.dialog.IntraFeedSortDialog;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.model.feed.SortOrder;
@@ -26,6 +27,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import java.util.Collections;
import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
@@ -64,7 +66,16 @@ public class FeedMenuHandler {
if (itemId == R.id.refresh_item) {
DBTasks.forceRefreshFeed(context, selectedFeed, true);
} else if (itemId == R.id.refresh_complete_item) {
- DBTasks.forceRefreshCompleteFeed(context, selectedFeed);
+ new Thread(() -> {
+ selectedFeed.setNextPageLink(selectedFeed.getDownload_url());
+ selectedFeed.setPageNr(0);
+ try {
+ DBWriter.resetPagedFeedPage(selectedFeed).get();
+ FeedUpdateManager.runOnce(context, selectedFeed);
+ } catch (ExecutionException | InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }).start();
} else if (itemId == R.id.sort_items) {
showSortDialog(context, selectedFeed);
} else if (itemId == R.id.visit_website_item) {
diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
index 875ed347e..80e7fdb1e 100644
--- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
+++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceUpgrader.java
@@ -13,7 +13,7 @@ import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
import de.danoeh.antennapod.error.CrashReportWriter;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.storage.preferences.UserPreferences.EnqueueLocation;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.fragment.QueueFragment;
import de.danoeh.antennapod.fragment.swipeactions.SwipeAction;
import de.danoeh.antennapod.fragment.swipeactions.SwipeActions;
@@ -31,7 +31,7 @@ public class PreferenceUpgrader {
int newVersion = BuildConfig.VERSION_CODE;
if (oldVersion != newVersion) {
- AutoUpdateManager.restartUpdateAlarm(context);
+ FeedUpdateManager.restartUpdateAlarm(context, true);
CrashReportWriter.getFile().delete();
upgrade(oldVersion, context);
@@ -138,6 +138,9 @@ public class PreferenceUpgrader {
.apply();
}
UserPreferences.setAllowMobileSync(true);
+ if (prefs.getString(UserPreferences.PREF_UPDATE_INTERVAL, ":").contains(":")) { // Unset or "time of day"
+ prefs.edit().putString(UserPreferences.PREF_UPDATE_INTERVAL, "12").apply();
+ }
}
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
index c566a1fd2..788359a4e 100644
--- a/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
+++ b/app/src/main/java/de/danoeh/antennapod/receiver/SPAReceiver.java
@@ -8,11 +8,12 @@ import android.util.Log;
import android.widget.Toast;
import java.util.Arrays;
+import java.util.Collections;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.ClientConfigurator;
-import de.danoeh.antennapod.core.service.download.DownloadRequestCreator;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.model.feed.Feed;
/**
@@ -43,9 +44,11 @@ public class SPAReceiver extends BroadcastReceiver{
Log.d(TAG, "Received feeds list: " + Arrays.toString(feedUrls));
ClientConfigurator.initialize(context);
for (String url : feedUrls) {
- Feed f = new Feed(url, null);
- DownloadServiceInterface.get().download(context, false, DownloadRequestCreator.create(f).build());
+ Feed feed = new Feed(url, null, "Unknown podcast");
+ feed.setItems(Collections.emptyList());
+ DBTasks.updateFeed(context, feed, false);
}
Toast.makeText(context, R.string.sp_apps_importing_feeds_msg, Toast.LENGTH_LONG).show();
+ FeedUpdateManager.runOnce(context);
}
}
diff --git a/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java b/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java
index da3fd7b05..778b57c8c 100644
--- a/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/ui/home/HomeFragment.java
@@ -17,13 +17,12 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentContainerView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.MainActivity;
-import de.danoeh.antennapod.core.event.DownloadEvent;
import de.danoeh.antennapod.core.menuhandler.MenuItemUtils;
-import de.danoeh.antennapod.core.service.download.DownloadService;
import de.danoeh.antennapod.core.storage.DBReader;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.databinding.HomeFragmentBinding;
import de.danoeh.antennapod.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
import de.danoeh.antennapod.fragment.SearchFragment;
import de.danoeh.antennapod.ui.home.sections.DownloadsSection;
import de.danoeh.antennapod.ui.home.sections.EpisodesSurpriseSection;
@@ -69,13 +68,12 @@ public class HomeFragment extends Fragment implements Toolbar.OnMenuItemClickLis
}
viewBinding.homeScrollView.setOnScrollChangeListener(new LiftOnScrollListener(viewBinding.appbar));
((MainActivity) requireActivity()).setupToolbarToggle(viewBinding.toolbar, displayUpArrow);
- refreshToolbarState();
populateSectionList();
updateWelcomeScreenVisibility();
viewBinding.swipeRefresh.setDistanceToTriggerSync(getResources().getInteger(R.integer.swipe_refresh_distance));
viewBinding.swipeRefresh.setOnRefreshListener(() -> {
- AutoUpdateManager.runImmediate(requireContext());
+ FeedUpdateManager.runOnceOrAsk(requireContext());
new Handler(Looper.getMainLooper()).postDelayed(() -> viewBinding.swipeRefresh.setRefreshing(false),
getResources().getInteger(R.integer.swipe_to_refresh_duration_in_ms));
});
@@ -126,14 +124,10 @@ public class HomeFragment extends Fragment implements Toolbar.OnMenuItemClickLis
return new ArrayList<>(Arrays.asList(TextUtils.split(hiddenSectionsString, ",")));
}
- private void refreshToolbarState() {
- MenuItemUtils.updateRefreshMenuItem(viewBinding.toolbar.getMenu(),
- R.id.refresh_item, DownloadService.isRunning && DownloadService.isDownloadingFeeds());
- }
-
@Subscribe(sticky = true, threadMode = ThreadMode.MAIN)
- public void onEventMainThread(DownloadEvent event) {
- refreshToolbarState();
+ public void onEventMainThread(FeedUpdateRunningEvent event) {
+ MenuItemUtils.updateRefreshMenuItem(viewBinding.toolbar.getMenu(),
+ R.id.refresh_item, event.isFeedUpdateRunning);
}
@Override
@@ -142,7 +136,7 @@ public class HomeFragment extends Fragment implements Toolbar.OnMenuItemClickLis
HomeSectionsSettingsDialog.open(getContext(), (dialogInterface, i) -> populateSectionList());
return true;
} else if (item.getItemId() == R.id.refresh_item) {
- AutoUpdateManager.runImmediate(requireContext());
+ FeedUpdateManager.runOnceOrAsk(requireContext());
return true;
} else if (item.getItemId() == R.id.action_search) {
((MainActivity) getActivity()).loadChildFragment(SearchFragment.newInstance());
diff --git a/app/src/main/java/de/danoeh/antennapod/view/TimePicker.java b/app/src/main/java/de/danoeh/antennapod/view/TimePicker.java
deleted file mode 100644
index 191f72d2e..000000000
--- a/app/src/main/java/de/danoeh/antennapod/view/TimePicker.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package de.danoeh.antennapod.view;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-/**
- * Samsung's Android 6.0.1 has a bug that crashes the app when inflating a time picker.
- * This class serves as a workaround for affected devices.
- */
-public class TimePicker extends android.widget.TimePicker {
- public TimePicker(Context context) {
- super(context);
- }
-
- public TimePicker(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public TimePicker(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- public void onRtlPropertiesChanged(int layoutDirection) {
- try {
- super.onRtlPropertiesChanged(layoutDirection);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-}
diff --git a/app/src/main/res/layout/feed_refresh_dialog.xml b/app/src/main/res/layout/feed_refresh_dialog.xml
deleted file mode 100644
index 5a6770a80..000000000
--- a/app/src/main/res/layout/feed_refresh_dialog.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RadioGroup
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/radioGroup"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="16dp">
-
- <RadioButton
- android:id="@+id/intervalRadioButton"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/feed_refresh_interval" />
-
- <Spinner
- android:id="@+id/spinner"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone" />
-
- <RadioButton
- android:id="@+id/timeRadioButton"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/feed_refresh_time" />
-
- <de.danoeh.antennapod.view.TimePicker
- android:id="@+id/timePicker"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:timePickerMode="spinner"
- android:visibility="gone" />
-
- <RadioButton
- android:id="@+id/disableRadioButton"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/feed_refresh_never" />
-
-</RadioGroup>
diff --git a/app/src/main/res/layout/scrollable_dialog.xml b/app/src/main/res/layout/scrollable_dialog.xml
deleted file mode 100644
index 29b84ee4b..000000000
--- a/app/src/main/res/layout/scrollable_dialog.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <ScrollView
- android:id="@+id/content"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_weight="1" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="end"
- android:orientation="horizontal"
- android:paddingHorizontal="32dp"
- android:paddingVertical="16dp"
- style="?android:attr/buttonBarStyle">
-
- <Button
- android:id="@+id/negativeButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="?android:attr/buttonBarButtonStyle" />
-
- <Button
- android:id="@+id/positiveButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="?android:attr/buttonBarButtonStyle" />
-
- </LinearLayout>
-
-</LinearLayout>
diff --git a/app/src/main/res/xml/preferences_network.xml b/app/src/main/res/xml/preferences_network.xml
index 83929bb70..f9cd15e68 100644
--- a/app/src/main/res/xml/preferences_network.xml
+++ b/app/src/main/res/xml/preferences_network.xml
@@ -4,10 +4,13 @@
xmlns:numberpicker="http://schemas.android.com/apk/de.danoeh.antennapod"
xmlns:search="http://schemas.android.com/apk/com.bytehamster.lib.preferencesearch">
<PreferenceCategory android:title="@string/automation">
- <Preference
+ <de.danoeh.antennapod.preferences.MaterialListPreference
+ android:entryValues="@array/feed_refresh_interval_values"
+ android:entries="@array/feed_refresh_interval_entries"
android:key="prefAutoUpdateIntervall"
+ android:title="@string/feed_refresh_title"
android:summary="@string/feed_refresh_sum"
- android:title="@string/feed_refresh_title"/>
+ android:defaultValue="12"/>
<Preference
android:summary="@string/pref_automatic_download_sum"
android:key="prefAutoDownloadSettings"
diff --git a/core/build.gradle b/core/build.gradle
index a70a1e1c0..02c273db1 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -62,6 +62,7 @@ dependencies {
annotationProcessor "org.greenrobot:eventbus-annotation-processor:$eventbusVersion"
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
+ implementation 'com.annimon:stream:1.2.2'
implementation "com.google.android.exoplayer:exoplayer-core:$exoPlayerVersion"
implementation "com.google.android.exoplayer:exoplayer-ui:$exoPlayerVersion"
diff --git a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java
index 9046b7165..79c6dd6bc 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/backup/OpmlBackupAgent.java
@@ -8,9 +8,8 @@ import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.util.Log;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequest;
-import de.danoeh.antennapod.core.service.download.DownloadRequestCreator;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import org.apache.commons.io.IOUtils;
import org.xmlpull.v1.XmlPullParserException;
@@ -30,6 +29,7 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import de.danoeh.antennapod.core.export.opml.OpmlElement;
import de.danoeh.antennapod.core.export.opml.OpmlReader;
@@ -144,9 +144,10 @@ public class OpmlBackupAgent extends BackupAgentHelper {
mChecksum = digester == null ? null : digester.digest();
for (OpmlElement opmlElem : opmlElements) {
Feed feed = new Feed(opmlElem.getXmlUrl(), null, opmlElem.getText());
- DownloadRequest request = DownloadRequestCreator.create(feed).build();
- DownloadServiceInterface.get().download(mContext, false, request);
+ feed.setItems(Collections.emptyList());
+ DBTasks.updateFeed(mContext, feed, false);
}
+ FeedUpdateManager.runOnce(mContext);
} catch (XmlPullParserException e) {
Log.e(TAG, "Error while parsing the OPML file", e);
} catch (IOException e) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java
index 9ce89ebe2..e30b49280 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/receiver/FeedUpdateReceiver.java
@@ -6,7 +6,7 @@ import android.content.Intent;
import android.util.Log;
import de.danoeh.antennapod.core.ClientConfigurator;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
/**
* Refreshes all feeds when it receives an intent
@@ -20,7 +20,7 @@ public class FeedUpdateReceiver extends BroadcastReceiver {
Log.d(TAG, "Received intent");
ClientConfigurator.initialize(context);
- AutoUpdateManager.runOnce(context);
+ FeedUpdateManager.runOnce(context);
}
}
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 49c5211b0..bbf0dc357 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,47 +1,177 @@
package de.danoeh.antennapod.core.service;
+import android.app.Notification;
import android.content.Context;
-import androidx.annotation.NonNull;
import android.util.Log;
-
+import androidx.annotation.NonNull;
+import androidx.core.app.NotificationCompat;
+import androidx.work.ForegroundInfo;
+import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
-
+import com.annimon.stream.Collectors;
+import com.annimon.stream.Stream;
import de.danoeh.antennapod.core.ClientConfigurator;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.R;
+import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
+import de.danoeh.antennapod.core.service.download.DefaultDownloaderFactory;
+import de.danoeh.antennapod.core.service.download.DownloadRequestCreator;
+import de.danoeh.antennapod.core.service.download.Downloader;
+import de.danoeh.antennapod.core.service.download.NewEpisodesNotification;
+import de.danoeh.antennapod.core.service.download.handler.FeedSyncTask;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBWriter;
import de.danoeh.antennapod.core.util.NetworkUtils;
-import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
+import de.danoeh.antennapod.core.util.gui.NotificationUtils;
+import de.danoeh.antennapod.model.download.DownloadError;
+import de.danoeh.antennapod.model.download.DownloadStatus;
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequest;
-public class FeedUpdateWorker extends Worker {
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+public class FeedUpdateWorker extends Worker {
private static final String TAG = "FeedUpdateWorker";
- public static final String PARAM_RUN_ONCE = "runOnce";
+ private final NewEpisodesNotification newEpisodesNotification;
public FeedUpdateWorker(@NonNull Context context, @NonNull WorkerParameters params) {
super(context, params);
+ newEpisodesNotification = new NewEpisodesNotification();
}
@Override
@NonNull
public Result doWork() {
- final boolean isRunOnce = getInputData().getBoolean(PARAM_RUN_ONCE, false);
- Log.d(TAG, "doWork() : isRunOnce = " + isRunOnce);
ClientConfigurator.initialize(getApplicationContext());
+ newEpisodesNotification.loadCountersBeforeRefresh();
- if (NetworkUtils.networkAvailable() && NetworkUtils.isFeedRefreshAllowed()) {
- DBTasks.refreshAllFeeds(getApplicationContext(), false);
- } else {
+ if (!NetworkUtils.networkAvailable() || !NetworkUtils.isFeedRefreshAllowed()) {
Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed");
+ return Result.retry();
}
- if (!isRunOnce && UserPreferences.isAutoUpdateTimeOfDay()) {
- // WorkManager does not allow to set specific time for repeated tasks.
- // We repeatedly schedule a OneTimeWorkRequest instead.
- AutoUpdateManager.restartUpdateAlarm(getApplicationContext());
+ List<Feed> toUpdate;
+ long feedId = getInputData().getLong(FeedUpdateManager.EXTRA_FEED_ID, -1);
+ if (feedId == -1) { // Update all
+ toUpdate = DBReader.getFeedList();
+ Iterator<Feed> itr = toUpdate.iterator();
+ while (itr.hasNext()) {
+ Feed feed = itr.next();
+ if (!feed.getPreferences().getKeepUpdated()) {
+ itr.remove();
+ }
+ }
+ Collections.shuffle(toUpdate); // If the worker gets cancelled early, every feed has a chance to be updated
+ refreshFeeds(toUpdate, false);
+ } else {
+ toUpdate = new ArrayList<>();
+ Feed feed = DBReader.getFeed(feedId);
+ if (feed == null) {
+ return Result.success();
+ }
+ toUpdate.add(feed);
+ refreshFeeds(toUpdate, true);
}
-
return Result.success();
}
+
+ @NonNull
+ private ForegroundInfo createForegroundInfo(List<Feed> toUpdate) {
+ Context context = getApplicationContext();
+ String contentText = context.getResources().getQuantityString(R.plurals.downloads_left,
+ toUpdate.size(), toUpdate.size());
+ String bigText = Stream.of(toUpdate).map(feed -> "• " + feed.getTitle()).collect(Collectors.joining("\n"));
+ Notification notification = new NotificationCompat.Builder(context, NotificationUtils.CHANNEL_ID_DOWNLOADING)
+ .setContentTitle(context.getString(R.string.download_notification_title_feeds))
+ .setContentText(contentText)
+ .setStyle(new NotificationCompat.BigTextStyle().bigText(bigText))
+ .setSmallIcon(R.drawable.ic_notification_sync)
+ .setOngoing(true)
+ .addAction(R.drawable.ic_cancel, context.getString(R.string.cancel_label),
+ WorkManager.getInstance(context).createCancelPendingIntent(getId()))
+ .build();
+ return new ForegroundInfo(R.id.notification_updating_feeds, notification);
+ }
+
+ private void refreshFeeds(List<Feed> toUpdate, boolean force) {
+ while (!toUpdate.isEmpty()) {
+ if (isStopped()) {
+ return;
+ }
+ setForegroundAsync(createForegroundInfo(toUpdate));
+ Feed feed = toUpdate.get(0);
+ try {
+ if (feed.isLocalFeed()) {
+ LocalFeedUpdater.updateFeed(feed, getApplicationContext(), null);
+ } else {
+ refreshFeed(feed, force);
+ }
+ } catch (Exception e) {
+ DBWriter.setFeedLastUpdateFailed(feed.getId(), true);
+ DownloadStatus status = new DownloadStatus(feed, feed.getTitle(),
+ DownloadError.ERROR_IO_ERROR, false, e.getMessage(), true);
+ DBWriter.addDownloadStatus(status);
+ }
+ toUpdate.remove(0);
+ }
+ }
+
+ void refreshFeed(Feed feed, boolean force) throws Exception {
+ boolean nextPage = getInputData().getBoolean(FeedUpdateManager.EXTRA_NEXT_PAGE, false)
+ && feed.getNextPageLink() != null;
+ if (nextPage) {
+ feed.setPageNr(feed.getPageNr() + 1);
+ }
+ DownloadRequest.Builder builder = DownloadRequestCreator.create(feed);
+ builder.setForce(force || feed.hasLastUpdateFailed());
+ if (nextPage) {
+ builder.setSource(feed.getNextPageLink());
+ }
+ DownloadRequest request = builder.build();
+
+ Downloader downloader = new DefaultDownloaderFactory().create(request);
+ if (downloader == null) {
+ throw new Exception("Unable to create downloader");
+ }
+
+ downloader.call();
+
+ if (!downloader.getResult().isSuccessful()) {
+ if (downloader.getResult().isCancelled()) {
+ return;
+ }
+ DBWriter.setFeedLastUpdateFailed(request.getFeedfileId(), true);
+ DBWriter.addDownloadStatus(downloader.getResult());
+ return;
+ }
+
+ FeedSyncTask feedSyncTask = new FeedSyncTask(getApplicationContext(), request);
+ boolean success = feedSyncTask.run();
+
+ if (!success) {
+ DBWriter.setFeedLastUpdateFailed(request.getFeedfileId(), true);
+ DBWriter.addDownloadStatus(feedSyncTask.getDownloadStatus());
+ return;
+ }
+
+ if (request.getFeedfileId() == 0) {
+ return; // No download logs for new subscriptions
+ }
+ // we create a 'successful' download log if the feed's last refresh failed
+ List<DownloadStatus> log = DBReader.getFeedDownloadLog(request.getFeedfileId());
+ if (log.size() > 0 && !log.get(0).isSuccessful()) {
+ DBWriter.addDownloadStatus(feedSyncTask.getDownloadStatus());
+ }
+ newEpisodesNotification.showIfNeeded(getApplicationContext(), feedSyncTask.getSavedFeed());
+ if (downloader.permanentRedirectUrl != null) {
+ DBWriter.updateFeedDownloadURL(request.getSource(), downloader.permanentRedirectUrl);
+ } else if (feedSyncTask.getRedirectUrl() != null) {
+ DBWriter.updateFeedDownloadURL(request.getSource(), feedSyncTask.getRedirectUrl());
+ }
+ }
}
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 0e55e9a36..9c238137e 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
@@ -10,19 +10,29 @@ import android.content.IntentFilter;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.Log;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.app.ServiceCompat;
-
import de.danoeh.antennapod.core.R;
-import de.danoeh.antennapod.core.feed.LocalFeedUpdater;
+import de.danoeh.antennapod.core.event.DownloadEvent;
+import de.danoeh.antennapod.core.service.download.handler.FailedDownloadHandler;
+import de.danoeh.antennapod.core.service.download.handler.MediaDownloadedHandler;
+import de.danoeh.antennapod.core.service.download.handler.PostDownloaderTask;
+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.EpisodeCleanupAlgorithmFactory;
+import de.danoeh.antennapod.core.util.download.ConnectionStateMonitor;
+import de.danoeh.antennapod.event.FeedItemEvent;
+import de.danoeh.antennapod.model.download.DownloadError;
import de.danoeh.antennapod.model.download.DownloadStatus;
+import de.danoeh.antennapod.model.feed.FeedItem;
+import de.danoeh.antennapod.model.feed.FeedMedia;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequest;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
import org.apache.commons.io.FileUtils;
import org.greenrobot.eventbus.EventBus;
@@ -39,22 +49,6 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import de.danoeh.antennapod.core.event.DownloadEvent;
-import de.danoeh.antennapod.core.util.download.ConnectionStateMonitor;
-import de.danoeh.antennapod.event.FeedItemEvent;
-import de.danoeh.antennapod.model.feed.Feed;
-import de.danoeh.antennapod.model.feed.FeedItem;
-import de.danoeh.antennapod.model.feed.FeedMedia;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.download.handler.FailedDownloadHandler;
-import de.danoeh.antennapod.core.service.download.handler.FeedSyncTask;
-import de.danoeh.antennapod.core.service.download.handler.MediaDownloadedHandler;
-import de.danoeh.antennapod.core.service.download.handler.PostDownloaderTask;
-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.model.download.DownloadError;
-
/**
* Manages the download of feedfiles in the app. Downloads can be enqueued via the startService intent.
* The argument of the intent is an instance of DownloadRequest in the EXTRA_REQUESTS field of
@@ -69,7 +63,6 @@ public class DownloadService extends Service {
public static final String ACTION_CANCEL_ALL_DOWNLOADS = "action.de.danoeh.antennapod.core.service.cancelAll";
public static final String EXTRA_DOWNLOAD_URL = "downloadUrl";
public static final String EXTRA_REQUESTS = "downloadRequests";
- public static final String EXTRA_REFRESH_ALL = "refreshAll";
public static final String EXTRA_INITIATED_BY_USER = "initiatedByUser";
public static final String EXTRA_CLEANUP_MEDIA = "cleanupMedia";
@@ -85,7 +78,6 @@ public class DownloadService extends Service {
private final List<DownloadStatus> reportQueue = new ArrayList<>();
private final List<DownloadRequest> failedRequestsForReport = new ArrayList<>();
private DownloadServiceNotification notificationManager;
- private final NewEpisodesNotification newEpisodesNotification;
private NotificationUpdater notificationUpdater;
private ScheduledFuture<?> notificationUpdaterFuture;
private ScheduledFuture<?> downloadPostFuture;
@@ -99,16 +91,12 @@ public class DownloadService extends Service {
}
public DownloadService() {
- newEpisodesNotification = new NewEpisodesNotification();
downloadEnqueueExecutor = Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r, "EnqueueThread");
t.setPriority(Thread.MIN_PRIORITY);
return t;
});
- // Must be the first runnable in syncExecutor
- downloadEnqueueExecutor.execute(newEpisodesNotification::loadCountersBeforeRefresh);
-
Log.d(TAG, "parallel downloads: " + UserPreferences.getParallelDownloads());
downloadHandleExecutor = Executors.newFixedThreadPool(UserPreferences.getParallelDownloads(),
r -> {
@@ -140,18 +128,6 @@ public class DownloadService extends Service {
connectionMonitor.enable(getApplicationContext());
}
- public static boolean isDownloadingFeeds() {
- if (!isRunning) {
- return false;
- }
- for (Downloader downloader : downloads) {
- if (downloader.request.getFeedfileType() == Feed.FEEDFILETYPE_FEED && !downloader.cancelled) {
- return true;
- }
- }
- return false;
- }
-
public static boolean isDownloadingFile(String downloadUrl) {
if (!isRunning) {
return false;
@@ -182,13 +158,6 @@ public class DownloadService extends Service {
NotificationManagerCompat.from(this).cancel(R.id.notification_auto_download_report);
setupNotificationUpdaterIfNecessary();
downloadEnqueueExecutor.execute(() -> onDownloadQueued(intent));
- } else if (intent != null && intent.getBooleanExtra(EXTRA_REFRESH_ALL, false)) {
- Notification notification = notificationManager.updateNotifications(downloads);
- startForeground(R.id.notification_downloading, notification);
- NotificationManagerCompat.from(this).cancel(R.id.notification_download_report);
- NotificationManagerCompat.from(this).cancel(R.id.notification_auto_download_report);
- setupNotificationUpdaterIfNecessary();
- downloadEnqueueExecutor.execute(() -> enqueueAll(intent));
} else if (downloads.size() == 0) {
shutdown();
} else {
@@ -251,61 +220,12 @@ public class DownloadService extends Service {
});
}
- /**
- * This method MUST NOT, in any case, throw an exception.
- * Otherwise, it hangs up the refresh thread pool.
- */
- private void performLocalFeedRefresh(Downloader downloader, DownloadRequest request) {
- try {
- Feed feed = DBReader.getFeed(request.getFeedfileId());
- LocalFeedUpdater.updateFeed(feed, DownloadService.this, (scanned, totalFiles) -> {
- request.setSize(totalFiles);
- request.setSoFar(scanned);
- request.setProgressPercent((int) (100.0 * scanned / totalFiles));
- });
- } catch (Exception e) {
- e.printStackTrace();
- }
- downloadEnqueueExecutor.submit(() -> {
- downloads.remove(downloader);
- stopServiceIfEverythingDone();
- });
- }
-
-
private void handleSuccessfulDownload(Downloader downloader) {
DownloadRequest request = downloader.getDownloadRequest();
DownloadStatus status = downloader.getResult();
final int type = status.getFeedfileType();
- if (type == Feed.FEEDFILETYPE_FEED) {
- Log.d(TAG, "Handling completed Feed Download");
- FeedSyncTask feedSyncTask = new FeedSyncTask(DownloadService.this, request);
- boolean success = feedSyncTask.run();
-
- if (success) {
- if (request.getFeedfileId() == 0) {
- return; // No download logs for new subscriptions
- }
- // we create a 'successful' download log if the feed's last refresh failed
- List<DownloadStatus> log = DBReader.getFeedDownloadLog(request.getFeedfileId());
- if (log.size() > 0 && !log.get(0).isSuccessful()) {
- saveDownloadStatus(feedSyncTask.getDownloadStatus(), downloader.getDownloadRequest());
- }
- if (!request.isInitiatedByUser()) {
- // Was stored in the database before and not initiated manually
- newEpisodesNotification.showIfNeeded(DownloadService.this, feedSyncTask.getSavedFeed());
- }
- if (downloader.permanentRedirectUrl != null) {
- DBWriter.updateFeedDownloadURL(request.getSource(), downloader.permanentRedirectUrl);
- } else if (feedSyncTask.getRedirectUrl() != null) {
- DBWriter.updateFeedDownloadURL(request.getSource(), feedSyncTask.getRedirectUrl());
- }
- } else {
- DBWriter.setFeedLastUpdateFailed(request.getFeedfileId(), true);
- saveDownloadStatus(feedSyncTask.getDownloadStatus(), downloader.getDownloadRequest());
- }
- } else if (type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
+ if (type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
Log.d(TAG, "Handling completed FeedMedia Download");
MediaDownloadedHandler handler = new MediaDownloadedHandler(DownloadService.this, status, request);
handler.run();
@@ -461,23 +381,6 @@ public class DownloadService extends Service {
}
}
- private void enqueueAll(Intent intent) {
- boolean initiatedByUser = intent.getBooleanExtra(EXTRA_INITIATED_BY_USER, false);
- List<Feed> feeds = DBReader.getFeedList();
- for (Feed feed : feeds) {
- if (feed.getPreferences().getKeepUpdated()) {
- DownloadRequest.Builder builder = DownloadRequestCreator.create(feed);
- builder.withInitiatedByUser(initiatedByUser);
- if (feed.hasLastUpdateFailed()) {
- builder.setForce(true);
- }
- addNewRequest(builder.build());
- }
- }
- postDownloaders();
- stopServiceIfEverythingDone();
- }
-
private void addNewRequest(@NonNull DownloadRequest request) {
if (isDownloadingFile(request.getSource())) {
Log.d(TAG, "Skipped enqueueing request. Already running.");
@@ -487,17 +390,11 @@ public class DownloadService extends Service {
return;
}
Log.d(TAG, "Add new request: " + request.getSource());
- if (request.getSource().startsWith(Feed.PREFIX_LOCAL_FOLDER)) {
- Downloader downloader = new LocalFeedStubDownloader(request);
+ writeFileUrl(request);
+ Downloader downloader = downloaderFactory.create(request);
+ if (downloader != null) {
downloads.add(downloader);
- downloadHandleExecutor.submit(() -> performLocalFeedRefresh(downloader, request));
- } else {
- writeFileUrl(request);
- Downloader downloader = downloaderFactory.create(request);
- if (downloader != null) {
- downloads.add(downloader);
- downloadHandleExecutor.submit(() -> performDownload(downloader));
- }
+ downloadHandleExecutor.submit(() -> performDownload(downloader));
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceInterfaceImpl.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceInterfaceImpl.java
index 7b7e52e0e..976d8255f 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceInterfaceImpl.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadServiceInterfaceImpl.java
@@ -5,6 +5,7 @@ import android.content.Intent;
import androidx.core.content.ContextCompat;
import com.google.android.exoplayer2.util.Log;
import de.danoeh.antennapod.core.BuildConfig;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequest;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
@@ -49,10 +50,7 @@ public class DownloadServiceInterfaceImpl extends DownloadServiceInterface {
}
public void refreshAllFeeds(Context context, boolean initiatedByUser) {
- Intent launchIntent = new Intent(context, DownloadService.class);
- launchIntent.putExtra(DownloadService.EXTRA_REFRESH_ALL, true);
- launchIntent.putExtra(DownloadService.EXTRA_INITIATED_BY_USER, initiatedByUser);
- ContextCompat.startForegroundService(context, launchIntent);
+ FeedUpdateManager.runOnce(context);
}
public void cancel(Context context, String url) {
diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java
index e3010fe24..9cb1166b4 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/service/download/handler/FeedSyncTask.java
@@ -1,23 +1,20 @@
package de.danoeh.antennapod.core.service.download.handler;
import android.content.Context;
-
import androidx.annotation.NonNull;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.model.download.DownloadStatus;
import de.danoeh.antennapod.model.feed.Feed;
import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequest;
-import de.danoeh.antennapod.model.download.DownloadStatus;
-import de.danoeh.antennapod.core.storage.DBTasks;
import de.danoeh.antennapod.parser.feed.FeedHandlerResult;
public class FeedSyncTask {
- private final DownloadRequest request;
private final Context context;
private Feed savedFeed;
private final FeedParserTask task;
private FeedHandlerResult feedHandlerResult;
public FeedSyncTask(Context context, DownloadRequest request) {
- this.request = request;
this.context = context;
this.task = new FeedParserTask(request);
}
@@ -29,13 +26,6 @@ public class FeedSyncTask {
}
savedFeed = DBTasks.updateFeed(context, feedHandlerResult.feed, false);
- // If loadAllPages=true, check if another page is available and queue it for download
- final boolean loadAllPages = request.getArguments().getBoolean(DownloadRequest.REQUEST_ARG_LOAD_ALL_PAGES);
- final Feed feed = feedHandlerResult.feed;
- if (loadAllPages && feed.getNextPageLink() != null) {
- feed.setId(savedFeed.getId());
- DBTasks.loadNextPageOfFeed(context, feed, true);
- }
return true;
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
index 18f157908..8b79d594c 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBTasks.java
@@ -1,20 +1,28 @@
package de.danoeh.antennapod.core.storage;
-import static android.content.Context.MODE_PRIVATE;
-
import android.content.Context;
-import android.content.SharedPreferences;
import android.database.Cursor;
import android.text.TextUtils;
import android.util.Log;
-
import androidx.annotation.VisibleForTesting;
-
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequest;
-import de.danoeh.antennapod.core.service.download.DownloadRequestCreator;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
+import de.danoeh.antennapod.core.R;
+import de.danoeh.antennapod.core.sync.queue.SynchronizationQueueSink;
+import de.danoeh.antennapod.core.util.LongList;
+import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
+import de.danoeh.antennapod.event.FeedItemEvent;
+import de.danoeh.antennapod.event.FeedListUpdateEvent;
+import de.danoeh.antennapod.event.MessageEvent;
+import de.danoeh.antennapod.model.download.DownloadError;
+import de.danoeh.antennapod.model.download.DownloadStatus;
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.model.feed.FeedItem;
+import de.danoeh.antennapod.model.feed.FeedMedia;
+import de.danoeh.antennapod.model.feed.FeedPreferences;
+import de.danoeh.antennapod.net.sync.model.EpisodeAction;
import de.danoeh.antennapod.storage.database.PodDBAdapter;
import de.danoeh.antennapod.storage.database.mapper.FeedCursorMapper;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
import org.greenrobot.eventbus.EventBus;
import java.util.ArrayList;
@@ -29,31 +37,12 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
-import de.danoeh.antennapod.core.R;
-import de.danoeh.antennapod.event.FeedItemEvent;
-import de.danoeh.antennapod.event.FeedListUpdateEvent;
-import de.danoeh.antennapod.event.MessageEvent;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.model.download.DownloadStatus;
-import de.danoeh.antennapod.core.sync.queue.SynchronizationQueueSink;
-import de.danoeh.antennapod.model.download.DownloadError;
-import de.danoeh.antennapod.core.util.LongList;
-import de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator;
-import de.danoeh.antennapod.model.feed.Feed;
-import de.danoeh.antennapod.model.feed.FeedItem;
-import de.danoeh.antennapod.model.feed.FeedMedia;
-import de.danoeh.antennapod.model.feed.FeedPreferences;
-import de.danoeh.antennapod.net.sync.model.EpisodeAction;
-
/**
* Provides methods for doing common tasks that use DBReader and DBWriter.
*/
public final class DBTasks {
private static final String TAG = "DBTasks";
- private static final String PREF_NAME = "dbtasks";
- private static final String PREF_LAST_REFRESH = "last_refresh";
-
/**
* Executor service used by the autodownloadUndownloadedEpisodes method.
*/
@@ -104,68 +93,12 @@ public final class DBTasks {
}
}
- /**
- * Refreshes all feeds.
- * It must not be from the main thread.
- * This method might ignore subsequent calls if it is still
- * enqueuing Feeds for download from a previous call
- *
- * @param context Might be used for accessing the database
- * @param initiatedByUser a boolean indicating if the refresh was triggered by user action.
- */
- public static void refreshAllFeeds(final Context context, boolean initiatedByUser) {
- DownloadServiceInterface.get().refreshAllFeeds(context, initiatedByUser);
-
- SharedPreferences prefs = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE);
- prefs.edit().putLong(PREF_LAST_REFRESH, System.currentTimeMillis()).apply();
-
- SynchronizationQueueSink.syncNow();
- // Note: automatic download of episodes will be done but not here.
- // Instead it is done after all feeds have been refreshed (asynchronously),
- // in DownloadService.onDestroy()
- // See Issue #2577 for the details of the rationale
- }
-
-
-
- /**
- * Queues the next page of this Feed for download. The given Feed has to be a paged
- * Feed (isPaged()=true) and must contain a nextPageLink.
- *
- * @param context Used for requesting the download.
- * @param feed The feed whose next page should be loaded.
- * @param loadAllPages True if any subsequent pages should also be loaded, false otherwise.
- */
- public static void loadNextPageOfFeed(final Context context, Feed feed, boolean loadAllPages) {
- if (feed.isPaged() && feed.getNextPageLink() != null) {
- int pageNr = feed.getPageNr() + 1;
- Feed nextFeed = new Feed(feed.getNextPageLink(), null, feed.getTitle() + "(" + pageNr + ")");
- nextFeed.setPageNr(pageNr);
- nextFeed.setPaged(true);
- nextFeed.setId(feed.getId());
-
- DownloadRequest.Builder builder = DownloadRequestCreator.create(nextFeed);
- builder.loadAllPages(loadAllPages);
- DownloadServiceInterface.get().download(context, false, builder.build());
- } else {
- Log.e(TAG, "loadNextPageOfFeed: Feed was either not paged or contained no nextPageLink");
- }
- }
-
public static void forceRefreshFeed(Context context, Feed feed, boolean initiatedByUser) {
forceRefreshFeed(context, feed, false, initiatedByUser);
}
- public static void forceRefreshCompleteFeed(final Context context, final Feed feed) {
- forceRefreshFeed(context, feed, true, true);
- }
-
private static void forceRefreshFeed(Context context, Feed feed, boolean loadAllPages, boolean initiatedByUser) {
- DownloadRequest.Builder builder = DownloadRequestCreator.create(feed);
- builder.withInitiatedByUser(initiatedByUser);
- builder.setForce(true);
- builder.loadAllPages(loadAllPages);
- DownloadServiceInterface.get().download(context, false, builder.build());
+ FeedUpdateManager.runOnce(context, feed);
}
/**
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 9b4146f15..dcee8a45a 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
@@ -665,6 +665,15 @@ public class DBWriter {
adapter.close();
}
+ public static Future<?> resetPagedFeedPage(Feed feed) {
+ return dbExec.submit(() -> {
+ final PodDBAdapter adapter = PodDBAdapter.getInstance();
+ adapter.open();
+ adapter.resetPagedFeedPage(feed);
+ adapter.close();
+ });
+ }
+
/*
* Sets the 'read'-attribute of all specified FeedItems
*
@@ -698,7 +707,6 @@ public class DBWriter {
});
}
-
/**
* Sets the 'read'-attribute of a FeedItem to the specified value.
*
diff --git a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java
index 73f467154..2fd492cbd 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/sync/SyncService.java
@@ -20,16 +20,15 @@ import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
+import de.danoeh.antennapod.core.util.download.FeedUpdateManager;
+import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
import de.danoeh.antennapod.model.feed.FeedItemFilter;
import de.danoeh.antennapod.model.feed.SortOrder;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadRequest;
-import de.danoeh.antennapod.core.service.download.DownloadService;
-import de.danoeh.antennapod.core.service.download.DownloadRequestCreator;
-import de.danoeh.antennapod.net.download.serviceinterface.DownloadServiceInterface;
import org.apache.commons.lang3.StringUtils;
import org.greenrobot.eventbus.EventBus;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -153,9 +152,10 @@ public class SyncService extends Worker {
continue;
}
if (!UrlChecker.containsUrl(localSubscriptions, downloadUrl) && !queuedRemovedFeeds.contains(downloadUrl)) {
- Feed feed = new Feed(downloadUrl, null);
- DownloadRequest.Builder builder = DownloadRequestCreator.create(feed);
- DownloadServiceInterface.get().download(getApplicationContext(), false, builder.build());
+ Feed feed = new Feed(downloadUrl, null, "Unknown podcast");
+ feed.setItems(Collections.emptyList());
+ Feed newFeed = DBTasks.updateFeed(getApplicationContext(), feed, false);
+ FeedUpdateManager.runOnce(getApplicationContext(), newFeed);
}
}
@@ -193,9 +193,13 @@ public class SyncService extends Worker {
private void waitForDownloadServiceCompleted() {
EventBus.getDefault().postSticky(new SyncServiceEvent(R.string.sync_status_wait_for_downloads));
try {
- while (DownloadService.isRunning) {
+ while (true) {
//noinspection BusyWait
Thread.sleep(1000);
+ FeedUpdateRunningEvent event = EventBus.getDefault().getStickyEvent(FeedUpdateRunningEvent.class);
+ if (event == null || !event.isFeedUpdateRunning) {
+ return;
+ }
}
} catch (InterruptedException e) {
e.printStackTrace();
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
deleted file mode 100644
index 0602fc4fe..000000000
--- a/core/src/main/java/de/danoeh/antennapod/core/util/download/AutoUpdateManager.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package de.danoeh.antennapod.core.util.download;
-
-import android.content.Context;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-import androidx.work.Constraints;
-import androidx.work.Data;
-import androidx.work.ExistingPeriodicWorkPolicy;
-import androidx.work.ExistingWorkPolicy;
-import androidx.work.NetworkType;
-import androidx.work.OneTimeWorkRequest;
-import androidx.work.PeriodicWorkRequest;
-import androidx.work.WorkManager;
-
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.concurrent.TimeUnit;
-
-import de.danoeh.antennapod.core.R;
-import de.danoeh.antennapod.storage.preferences.UserPreferences;
-import de.danoeh.antennapod.core.service.FeedUpdateWorker;
-import de.danoeh.antennapod.core.storage.DBTasks;
-import de.danoeh.antennapod.core.util.NetworkUtils;
-
-public class AutoUpdateManager {
- private static final String WORK_ID_FEED_UPDATE = "de.danoeh.antennapod.core.service.FeedUpdateWorker";
- private static final String WORK_ID_FEED_UPDATE_ONCE = WORK_ID_FEED_UPDATE + "Once";
- private static final String TAG = "AutoUpdateManager";
-
- private AutoUpdateManager() {
-
- }
-
- /**
- * Start / restart periodic auto feed refresh
- * @param context Context
- */
- public static void restartUpdateAlarm(Context context) {
- if (UserPreferences.isAutoUpdateDisabled()) {
- disableAutoUpdate(context);
- } else if (UserPreferences.isAutoUpdateTimeOfDay()) {
- int[] timeOfDay = UserPreferences.getUpdateTimeOfDay();
- Log.d(TAG, "timeOfDay: " + Arrays.toString(timeOfDay));
- restartUpdateTimeOfDayAlarm(timeOfDay[0], timeOfDay[1], context);
- } else {
- long milliseconds = UserPreferences.getUpdateInterval();
- restartUpdateIntervalAlarm(milliseconds, context);
- }
- }
-
- /**
- * Sets the interval in which the feeds are refreshed automatically
- */
- private static void restartUpdateIntervalAlarm(long intervalMillis, Context context) {
- Log.d(TAG, "Restarting update alarm.");
-
- PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(FeedUpdateWorker.class,
- intervalMillis, TimeUnit.MILLISECONDS)
- .setConstraints(getConstraints())
- .build();
-
- WorkManager.getInstance(context).enqueueUniquePeriodicWork(
- WORK_ID_FEED_UPDATE, ExistingPeriodicWorkPolicy.REPLACE, workRequest);
- }
-
- /**
- * Sets time of day the feeds are refreshed automatically
- */
- private static void restartUpdateTimeOfDayAlarm(int hoursOfDay, int minute, Context context) {
- Log.d(TAG, "Restarting update alarm.");
-
- Calendar now = Calendar.getInstance();
- Calendar alarm = (Calendar) now.clone();
- alarm.set(Calendar.HOUR_OF_DAY, hoursOfDay);
- alarm.set(Calendar.MINUTE, minute);
- if (alarm.before(now) || alarm.equals(now)) {
- alarm.add(Calendar.DATE, 1);
- }
- long triggerAtMillis = alarm.getTimeInMillis() - now.getTimeInMillis();
-
- OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(FeedUpdateWorker.class)
- .setConstraints(getConstraints())
- .setInitialDelay(triggerAtMillis, TimeUnit.MILLISECONDS)
- .build();
-
- WorkManager.getInstance(context).enqueueUniqueWork(WORK_ID_FEED_UPDATE,
- ExistingWorkPolicy.REPLACE, workRequest);
- }
-
- /**
- * Run auto feed refresh once in background, as soon as what OS scheduling allows.
- *
- * Callers from UI should use {@link #runImmediate(Context)}, as it will guarantee
- * the refresh be run immediately.
- * @param context Context
- */
- public static void runOnce(Context context) {
- Log.d(TAG, "Run auto update once, as soon as OS allows.");
-
- OneTimeWorkRequest workRequest = new OneTimeWorkRequest.Builder(FeedUpdateWorker.class)
- .setConstraints(getConstraints())
- .setInitialDelay(0L, TimeUnit.MILLISECONDS)
- .setInputData(new Data.Builder()
- .putBoolean(FeedUpdateWorker.PARAM_RUN_ONCE, true)
- .build()
- )
- .build();
-
- WorkManager.getInstance(context).enqueueUniqueWork(WORK_ID_FEED_UPDATE_ONCE,
- ExistingWorkPolicy.REPLACE, workRequest);
-
- }
-
- /**
- /**
- * Run auto feed refresh once in background immediately, using its own thread.
- *
- * Callers where the additional threads is not suitable should use {@link #runOnce(Context)}
- */
- public static void runImmediate(@NonNull Context context) {
- Log.d(TAG, "Run auto update immediately in background.");
- if (!NetworkUtils.networkAvailable()) {
- Log.d(TAG, "Ignoring: No network connection.");
- } else if (NetworkUtils.isFeedRefreshAllowed()) {
- startRefreshAllFeeds(context);
- } else {
- confirmMobileAllFeedsRefresh(context);
- }
- }
-
- private static void confirmMobileAllFeedsRefresh(final Context context) {
- MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context)
- .setTitle(R.string.feed_refresh_title)
- .setMessage(R.string.confirm_mobile_feed_refresh_dialog_message)
- .setPositiveButton(R.string.confirm_mobile_streaming_button_once,
- (dialog, which) -> startRefreshAllFeeds(context))
- .setNeutralButton(R.string.confirm_mobile_streaming_button_always, (dialog, which) -> {
- UserPreferences.setAllowMobileFeedRefresh(true);
- startRefreshAllFeeds(context);
- })
- .setNegativeButton(R.string.no, null);
- builder.show();
- }
-
- private static void startRefreshAllFeeds(final Context context) {
- new Thread(() -> DBTasks.refreshAllFeeds(
- context.getApplicationContext(), true), "ManualRefreshAllFeeds").start();
- }
-
- public static void disableAutoUpdate(Context context) {
- WorkManager.getInstance(context).cancelUniqueWork(WORK_ID_FEED_UPDATE);
- }
-
- private static Constraints getConstraints() {
- Constraints.Builder constraints = new Constraints.Builder();
-
- if (UserPreferences.isAllowMobileFeedRefresh()) {
- constraints.setRequiredNetworkType(NetworkType.CONNECTED);
- } else {
- constraints.setRequiredNetworkType(NetworkType.UNMETERED);
- }
- return constraints.build();
- }
-
-}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/download/FeedUpdateManager.java b/core/src/main/java/de/danoeh/antennapod/core/util/download/FeedUpdateManager.java
new file mode 100644
index 000000000..d1a273d4e
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/download/FeedUpdateManager.java
@@ -0,0 +1,112 @@
+package de.danoeh.antennapod.core.util.download;
+
+import android.content.Context;
+import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.work.Constraints;
+import androidx.work.Data;
+import androidx.work.ExistingPeriodicWorkPolicy;
+import androidx.work.ExistingWorkPolicy;
+import androidx.work.NetworkType;
+import androidx.work.OneTimeWorkRequest;
+import androidx.work.OutOfQuotaPolicy;
+import androidx.work.PeriodicWorkRequest;
+import androidx.work.WorkManager;
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+import de.danoeh.antennapod.core.R;
+import de.danoeh.antennapod.core.service.FeedUpdateWorker;
+import de.danoeh.antennapod.core.util.NetworkUtils;
+import de.danoeh.antennapod.model.feed.Feed;
+import de.danoeh.antennapod.storage.preferences.UserPreferences;
+
+import java.util.concurrent.TimeUnit;
+
+public class FeedUpdateManager {
+ public static final String WORK_TAG_FEED_UPDATE = "feedUpdate";
+ private static final String WORK_ID_FEED_UPDATE = "de.danoeh.antennapod.core.service.FeedUpdateWorker";
+ private static final String WORK_ID_FEED_UPDATE_MANUAL = "feedUpdateManual";
+ public static final String EXTRA_FEED_ID = "feed_id";
+ public static final String EXTRA_NEXT_PAGE = "next_page";
+ private static final String TAG = "AutoUpdateManager";
+
+ private FeedUpdateManager() {
+
+ }
+
+ /**
+ * Start / restart periodic auto feed refresh
+ * @param context Context
+ */
+ public static void restartUpdateAlarm(Context context, boolean replace) {
+ if (UserPreferences.isAutoUpdateDisabled()) {
+ WorkManager.getInstance(context).cancelUniqueWork(WORK_ID_FEED_UPDATE);
+ } else {
+ PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(
+ FeedUpdateWorker.class, UserPreferences.getUpdateInterval(), TimeUnit.HOURS)
+ .setConstraints(getConstraints())
+ .build();
+ WorkManager.getInstance(context).enqueueUniquePeriodicWork(WORK_ID_FEED_UPDATE,
+ replace ? ExistingPeriodicWorkPolicy.REPLACE : ExistingPeriodicWorkPolicy.KEEP, workRequest);
+ }
+ }
+
+ public static void runOnce(Context context) {
+ runOnce(context, null, false);
+ }
+
+ public static void runOnce(Context context, Feed feed) {
+ runOnce(context, feed, false);
+ }
+
+ public static void runOnce(Context context, Feed feed, boolean nextPage) {
+ OneTimeWorkRequest.Builder workRequest = new OneTimeWorkRequest.Builder(FeedUpdateWorker.class)
+ .setInitialDelay(0L, TimeUnit.MILLISECONDS)
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+ .addTag(WORK_TAG_FEED_UPDATE);
+ if (feed != null) {
+ Data.Builder builder = new Data.Builder();
+ builder.putLong(EXTRA_FEED_ID, feed.getId());
+ builder.putBoolean(EXTRA_NEXT_PAGE, nextPage);
+ workRequest.setInputData(builder.build());
+ }
+ WorkManager.getInstance(context).enqueueUniqueWork(WORK_ID_FEED_UPDATE_MANUAL,
+ ExistingWorkPolicy.REPLACE, workRequest.build());
+ }
+
+ public static void runOnceOrAsk(@NonNull Context context) {
+ Log.d(TAG, "Run auto update immediately in background.");
+ if (!NetworkUtils.networkAvailable()) {
+ Log.d(TAG, "Ignoring: No network connection.");
+ } else if (NetworkUtils.isFeedRefreshAllowed()) {
+ runOnce(context);
+ } else {
+ confirmMobileAllFeedsRefresh(context);
+ }
+ }
+
+ private static void confirmMobileAllFeedsRefresh(final Context context) {
+ MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context)
+ .setTitle(R.string.feed_refresh_title)
+ .setMessage(R.string.confirm_mobile_feed_refresh_dialog_message)
+ .setPositiveButton(R.string.confirm_mobile_streaming_button_once,
+ (dialog, which) -> runOnce(context))
+ .setNeutralButton(R.string.confirm_mobile_streaming_button_always, (dialog, which) -> {
+ UserPreferences.setAllowMobileFeedRefresh(true);
+ runOnce(context);
+ })
+ .setNegativeButton(R.string.no, null);
+ builder.show();
+ }
+
+ private static Constraints getConstraints() {
+ Constraints.Builder constraints = new Constraints.Builder();
+
+ if (UserPreferences.isAllowMobileFeedRefresh()) {
+ constraints.setRequiredNetworkType(NetworkType.CONNECTED);
+ } else {
+ constraints.setRequiredNetworkType(NetworkType.UNMETERED);
+ }
+ return constraints.build();
+ }
+
+}
diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml
index 39f62a5d7..f3c0a0a3c 100644
--- a/core/src/main/res/values/arrays.xml
+++ b/core/src/main/res/values/arrays.xml
@@ -25,6 +25,28 @@
<item>heavy</item>
</string-array>
+ <string-array name="feed_refresh_interval_entries">
+ <item>@string/feed_refresh_never</item>
+ <item>@string/feed_every_hour</item>
+ <item>@string/feed_every_2_hours</item>
+ <item>@string/feed_every_4_hours</item>
+ <item>@string/feed_every_8_hours</item>
+ <item>@string/feed_every_12_hours</item>
+ <item>@string/feed_every_24_hours</item>
+ <item>@string/feed_every_72_hours</item>
+ </string-array>
+
+ <string-array name="feed_refresh_interval_values">
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ <item>4</item>
+ <item>8</item>
+ <item>12</item>
+ <item>24</item>
+ <item>72</item>
+ </string-array>
+
<string-array name="globalNewEpisodesActionItems">
<item>@string/feed_new_episodes_action_add_to_inbox</item>
<item>@string/feed_new_episodes_action_nothing</item>
diff --git a/core/src/main/res/values/ids.xml b/core/src/main/res/values/ids.xml
index 87046cc0f..90d143d38 100644
--- a/core/src/main/res/values/ids.xml
+++ b/core/src/main/res/values/ids.xml
@@ -19,6 +19,7 @@
<item name="notification_gpodnet_sync_error" type="id"/>
<item name="notification_gpodnet_sync_autherror" type="id"/>
<item name="notification_downloading" type="id"/>
+ <item name="notification_updating_feeds" type="id"/>
<item name="notification_download_report" type="id"/>
<item name="notification_auto_download_report" type="id"/>
<item name="notification_playing" type="id"/>
diff --git a/event/src/main/java/de/danoeh/antennapod/event/FeedUpdateRunningEvent.java b/event/src/main/java/de/danoeh/antennapod/event/FeedUpdateRunningEvent.java
new file mode 100644
index 000000000..4c14c1647
--- /dev/null
+++ b/event/src/main/java/de/danoeh/antennapod/event/FeedUpdateRunningEvent.java
@@ -0,0 +1,9 @@
+package de.danoeh.antennapod.event;
+
+public class FeedUpdateRunningEvent {
+ public final boolean isFeedUpdateRunning;
+
+ public FeedUpdateRunningEvent(boolean isRunning) {
+ this.isFeedUpdateRunning = isRunning;
+ }
+}
diff --git a/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequest.java b/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequest.java
index e5c6662eb..9f9737edc 100644
--- a/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequest.java
+++ b/net/download/service-interface/src/main/java/de/danoeh/antennapod/net/download/serviceinterface/DownloadRequest.java
@@ -263,7 +263,7 @@ public class DownloadRequest implements Parcelable {
public static class Builder {
private final String destination;
- private final String source;
+ private String source;
private final String title;
private String username;
private String password;
@@ -296,6 +296,10 @@ public class DownloadRequest implements Parcelable {
return this;
}
+ public void setSource(String source) {
+ this.source = source;
+ }
+
public void setForce(boolean force) {
if (force) {
lastModified = null;
diff --git a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java
index 6802dfcc3..1de47f769 100644
--- a/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java
+++ b/storage/database/src/main/java/de/danoeh/antennapod/storage/database/PodDBAdapter.java
@@ -734,6 +734,13 @@ public class PodDBAdapter {
}
}
+ public void resetPagedFeedPage(Feed feed) {
+ final String sql = "UPDATE " + TABLE_NAME_FEEDS
+ + " SET " + KEY_NEXT_PAGE_LINK + "=" + KEY_DOWNLOAD_URL
+ + " WHERE " + KEY_ID + "=" + feed.getId();
+ db.execSQL(sql);
+ }
+
public void setFeedLastUpdateFailed(long feedId, boolean failed) {
final String sql = "UPDATE " + TABLE_NAME_FEEDS
+ " SET " + KEY_LAST_UPDATE_FAILED + "=" + (failed ? "1" : "0")
diff --git a/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java b/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java
index 92acb6319..8a4d248ee 100644
--- a/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java
+++ b/storage/preferences/src/main/java/de/danoeh/antennapod/storage/preferences/UserPreferences.java
@@ -6,14 +6,17 @@ import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.app.NotificationCompat;
import androidx.preference.PreferenceManager;
-
+import de.danoeh.antennapod.model.download.ProxyConfig;
+import de.danoeh.antennapod.model.feed.FeedCounter;
import de.danoeh.antennapod.model.feed.FeedPreferences;
+import de.danoeh.antennapod.model.feed.SortOrder;
+import de.danoeh.antennapod.model.feed.SubscriptionsFilter;
+import de.danoeh.antennapod.model.playback.MediaType;
import org.json.JSONArray;
import org.json.JSONException;
@@ -28,13 +31,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import de.danoeh.antennapod.model.feed.FeedCounter;
-import de.danoeh.antennapod.model.playback.MediaType;
-import de.danoeh.antennapod.model.feed.SubscriptionsFilter;
-import de.danoeh.antennapod.model.download.ProxyConfig;
-import de.danoeh.antennapod.model.feed.SortOrder;
/**
* Provides access to preferences set by the user in the settings screen. A
@@ -463,34 +459,12 @@ public class UserPreferences {
return prefs.getBoolean(PREF_PAUSE_PLAYBACK_FOR_FOCUS_LOSS, true);
}
-
- /*
- * Returns update interval in milliseconds; value 0 means that auto update is disabled
- * or feeds are updated at a certain time of day
- */
public static long getUpdateInterval() {
- String updateInterval = prefs.getString(PREF_UPDATE_INTERVAL, "0");
- if(!updateInterval.contains(":")) {
- return readUpdateInterval(updateInterval);
- } else {
- return 0;
- }
- }
-
- public static int[] getUpdateTimeOfDay() {
- String datetime = prefs.getString(PREF_UPDATE_INTERVAL, "");
- if(datetime.length() >= 3 && datetime.contains(":")) {
- String[] parts = datetime.split(":");
- int hourOfDay = Integer.parseInt(parts[0]);
- int minute = Integer.parseInt(parts[1]);
- return new int[] { hourOfDay, minute };
- } else {
- return new int[0];
- }
+ return Integer.parseInt(prefs.getString(PREF_UPDATE_INTERVAL, "12"));
}
public static boolean isAutoUpdateDisabled() {
- return prefs.getString(PREF_UPDATE_INTERVAL, "").equals("0");
+ return getUpdateInterval() == 0;
}
private static boolean isAllowMobileFor(String type) {
@@ -696,24 +670,6 @@ public class UserPreferences {
.apply();
}
- public static void setUpdateInterval(long hours) {
- prefs.edit()
- .putString(PREF_UPDATE_INTERVAL, String.valueOf(hours))
- .apply();
- }
-
- public static void setUpdateTimeOfDay(int hourOfDay, int minute) {
- prefs.edit()
- .putString(PREF_UPDATE_INTERVAL, hourOfDay + ":" + minute)
- .apply();
- }
-
- public static void disableAutoUpdate() {
- prefs.edit()
- .putString(PREF_UPDATE_INTERVAL, "0")
- .apply();
- }
-
public static boolean gpodnetNotificationsEnabled() {
if (Build.VERSION.SDK_INT >= 26) {
return true; // System handles notification preferences
@@ -754,11 +710,6 @@ public class UserPreferences {
.apply();
}
- private static long readUpdateInterval(String valueFromPrefs) {
- int hours = Integer.parseInt(valueFromPrefs);
- return TimeUnit.HOURS.toMillis(hours);
- }
-
private static List<Float> readPlaybackSpeedArray(String valueFromPrefs) {
if (valueFromPrefs != null) {
try {
@@ -851,15 +802,6 @@ public class UserPreferences {
}
}
- /**
- *
- * @return true if auto update is set to a specific time
- * false if auto update is set to interval
- */
- public static boolean isAutoUpdateTimeOfDay() {
- return getUpdateTimeOfDay().length == 2;
- }
-
public static String getDefaultPage() {
return prefs.getString(PREF_DEFAULT_PAGE, "HomeFragment");
}
diff --git a/ui/i18n/src/main/res/values/strings.xml b/ui/i18n/src/main/res/values/strings.xml
index f9b61de08..32db0dcac 100644
--- a/ui/i18n/src/main/res/values/strings.xml
+++ b/ui/i18n/src/main/res/values/strings.xml
@@ -412,15 +412,15 @@
<string name="network_pref">Network</string>
<string name="network_pref_sum">Update interval, Download controls, Mobile data</string>
<string name="feed_refresh_title">Refresh podcasts</string>
- <string name="feed_refresh_sum">Specify an interval or a specific time to look for new episodes automatically</string>
- <string name="feed_refresh_interval">Interval</string>
- <string name="feed_refresh_time">Time</string>
+ <string name="feed_refresh_sum">Specify an interval at which AntennaPod looks for new episodes automatically</string>
<string name="feed_refresh_never">Never</string>
- <string name="feed_refresh_interval_at">at %1$s</string>
- <plurals name="feed_refresh_every_x_hours">
- <item quantity="one">Every hour</item>
- <item quantity="other">Every %d hours</item>
- </plurals>
+ <string name="feed_every_hour">Every hour</string>
+ <string name="feed_every_2_hours">Every 2 hours</string>
+ <string name="feed_every_4_hours">Every 4 hours</string>
+ <string name="feed_every_8_hours">Every 8 hours</string>
+ <string name="feed_every_12_hours">Every 12 hours</string>
+ <string name="feed_every_24_hours">Every day</string>
+ <string name="feed_every_72_hours">Every 3 days</string>
<string name="pref_followQueue_title">Continuous Playback</string>
<string name="pref_pauseOnHeadsetDisconnect_title">Headphones or Bluetooth disconnect</string>
<string name="pref_unpauseOnHeadsetReconnect_title">Headphones Reconnect</string>
@@ -499,7 +499,6 @@
<string name="open_bug_tracker">Open bug tracker</string>
<string name="copy_to_clipboard">Copy to clipboard</string>
<string name="copied_to_clipboard">Copied to clipboard</string>
- <string name="pref_current_value">Current value: %1$s</string>
<string name="pref_proxy_title">Proxy</string>
<string name="pref_proxy_sum">Set a network proxy</string>
<string name="pref_no_browser_found">No web browser found.</string>