Refactoring: Remove ClientConfig.automaticDownloadAlgorithm (#4924)
This commit is contained in:
parent
ded779d0c9
commit
60968089ae
|
@ -3,13 +3,13 @@ package de.test.antennapod.storage;
|
|||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.core.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.storage.AutomaticDownloadAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.DBReader;
|
||||
import de.danoeh.antennapod.core.storage.DBTasks;
|
||||
import de.danoeh.antennapod.core.util.playback.PlaybackServiceStarter;
|
||||
import de.test.antennapod.EspressoTestUtils;
|
||||
import de.test.antennapod.ui.UITestUtils;
|
||||
|
@ -29,8 +29,7 @@ public class AutoDownloadTest {
|
|||
|
||||
private Context context;
|
||||
private UITestUtils stubFeedsServer;
|
||||
|
||||
private AutomaticDownloadAlgorithm automaticDownloadAlgorithmOrig;
|
||||
private StubDownloadAlgorithm stubDownloadAlgorithm;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
@ -39,16 +38,19 @@ public class AutoDownloadTest {
|
|||
stubFeedsServer = new UITestUtils(context);
|
||||
stubFeedsServer.setup();
|
||||
|
||||
automaticDownloadAlgorithmOrig = ClientConfig.automaticDownloadAlgorithm;
|
||||
|
||||
EspressoTestUtils.clearPreferences();
|
||||
EspressoTestUtils.clearDatabase();
|
||||
UserPreferences.setAllowMobileStreaming(true);
|
||||
|
||||
// Setup: enable automatic download
|
||||
// it is not needed, as the actual automatic download is stubbed.
|
||||
stubDownloadAlgorithm = new StubDownloadAlgorithm();
|
||||
DBTasks.setDownloadAlgorithm(stubDownloadAlgorithm);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
ClientConfig.automaticDownloadAlgorithm = automaticDownloadAlgorithmOrig;
|
||||
DBTasks.setDownloadAlgorithm(new AutomaticDownloadAlgorithm());
|
||||
EspressoTestUtils.tryKillPlaybackService();
|
||||
stubFeedsServer.tearDown();
|
||||
}
|
||||
|
@ -74,11 +76,6 @@ public class AutoDownloadTest {
|
|||
FeedItem item0 = queue.get(0);
|
||||
FeedItem item1 = queue.get(1);
|
||||
|
||||
// Setup: enable automatic download
|
||||
// it is not needed, as the actual automatic download is stubbed.
|
||||
StubDownloadAlgorithm stubDownloadAlgorithm = new StubDownloadAlgorithm();
|
||||
ClientConfig.automaticDownloadAlgorithm = stubDownloadAlgorithm;
|
||||
|
||||
// Actual test
|
||||
// Play the first one in the queue
|
||||
playEpisode(item0);
|
||||
|
@ -92,11 +89,10 @@ public class AutoDownloadTest {
|
|||
} catch (ConditionTimeoutException cte) {
|
||||
long actual = stubDownloadAlgorithm.getCurrentlyPlayingAtDownload();
|
||||
fail("when auto download is triggered, the next episode should be playing: ("
|
||||
+ item1.getId() + ", " + item1.getTitle() + ") . "
|
||||
+ item1.getId() + ", " + item1.getTitle() + ") . "
|
||||
+ "Actual playing: (" + actual + ")"
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void playEpisode(@NonNull FeedItem item) {
|
||||
|
@ -111,7 +107,7 @@ public class AutoDownloadTest {
|
|||
.until(() -> item.getMedia().getId() == PlaybackPreferences.getCurrentlyPlayingFeedMediaId());
|
||||
}
|
||||
|
||||
private static class StubDownloadAlgorithm implements AutomaticDownloadAlgorithm {
|
||||
private static class StubDownloadAlgorithm extends AutomaticDownloadAlgorithm {
|
||||
private long currentlyPlaying = -1;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,21 +2,20 @@ package de.danoeh.antennapod.config;
|
|||
|
||||
import de.danoeh.antennapod.BuildConfig;
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
import de.danoeh.antennapod.core.storage.APDownloadAlgorithm;
|
||||
|
||||
/**
|
||||
* Configures the ClientConfig class of the core package.
|
||||
*/
|
||||
class ClientConfigurator {
|
||||
|
||||
private ClientConfigurator(){}
|
||||
private ClientConfigurator() {
|
||||
}
|
||||
|
||||
static {
|
||||
ClientConfig.USER_AGENT = "AntennaPod/" + BuildConfig.VERSION_NAME;
|
||||
ClientConfig.applicationCallbacks = new ApplicationCallbacksImpl();
|
||||
ClientConfig.downloadServiceCallbacks = new DownloadServiceCallbacksImpl();
|
||||
ClientConfig.playbackServiceCallbacks = new PlaybackServiceCallbacksImpl();
|
||||
ClientConfig.automaticDownloadAlgorithm = new APDownloadAlgorithm();
|
||||
ClientConfig.castCallbacks = new CastCallbackImpl();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
|
|||
import de.danoeh.antennapod.core.preferences.UsageStatistics;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.core.storage.AutomaticDownloadAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||
|
@ -33,8 +32,6 @@ public class ClientConfig {
|
|||
|
||||
public static PlaybackServiceCallbacks playbackServiceCallbacks;
|
||||
|
||||
public static AutomaticDownloadAlgorithm automaticDownloadAlgorithm;
|
||||
|
||||
public static CastCallbacks castCallbacks;
|
||||
|
||||
private static boolean initialized = false;
|
||||
|
|
|
@ -1,103 +0,0 @@
|
|||
package de.danoeh.antennapod.core.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.FeedFilter;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedPreferences;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.PowerUtils;
|
||||
|
||||
/**
|
||||
* Implements the automatic download algorithm used by AntennaPod. This class assumes that
|
||||
* the client uses the APEpisodeCleanupAlgorithm.
|
||||
*/
|
||||
public class APDownloadAlgorithm implements AutomaticDownloadAlgorithm {
|
||||
private static final String TAG = "APDownloadAlgorithm";
|
||||
|
||||
/**
|
||||
* Looks for undownloaded episodes in the queue or list of new items and request a download if
|
||||
* 1. Network is available
|
||||
* 2. The device is charging or the user allows auto download on battery
|
||||
* 3. There is free space in the episode cache
|
||||
* This method is executed on an internal single thread executor.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
* @return A Runnable that will be submitted to an ExecutorService.
|
||||
*/
|
||||
@Override
|
||||
public Runnable autoDownloadUndownloadedItems(final Context context) {
|
||||
return () -> {
|
||||
|
||||
// true if we should auto download based on network status
|
||||
boolean networkShouldAutoDl = NetworkUtils.autodownloadNetworkAvailable()
|
||||
&& UserPreferences.isEnableAutodownload();
|
||||
|
||||
// true if we should auto download based on power status
|
||||
boolean powerShouldAutoDl = PowerUtils.deviceCharging(context)
|
||||
|| UserPreferences.isEnableAutodownloadOnBattery();
|
||||
|
||||
// we should only auto download if both network AND power are happy
|
||||
if (networkShouldAutoDl && powerShouldAutoDl) {
|
||||
|
||||
Log.d(TAG, "Performing auto-dl of undownloaded episodes");
|
||||
|
||||
List<FeedItem> candidates;
|
||||
final List<FeedItem> queue = DBReader.getQueue();
|
||||
final List<FeedItem> newItems = DBReader.getNewItemsList(0, Integer.MAX_VALUE);
|
||||
candidates = new ArrayList<>(queue.size() + newItems.size());
|
||||
candidates.addAll(queue);
|
||||
for (FeedItem newItem : newItems) {
|
||||
FeedPreferences feedPrefs = newItem.getFeed().getPreferences();
|
||||
FeedFilter feedFilter = feedPrefs.getFilter();
|
||||
if (!candidates.contains(newItem) && feedFilter.shouldAutoDownload(newItem)) {
|
||||
candidates.add(newItem);
|
||||
}
|
||||
}
|
||||
|
||||
// filter items that are not auto downloadable
|
||||
Iterator<FeedItem> it = candidates.iterator();
|
||||
while (it.hasNext()) {
|
||||
FeedItem item = it.next();
|
||||
if (!item.isAutoDownloadable() || item.getFeed().isLocalFeed()) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
int autoDownloadableEpisodes = candidates.size();
|
||||
int downloadedEpisodes = DBReader.getNumberOfDownloadedEpisodes();
|
||||
int deletedEpisodes = UserPreferences.getEpisodeCleanupAlgorithm()
|
||||
.makeRoomForEpisodes(context, autoDownloadableEpisodes);
|
||||
boolean cacheIsUnlimited =
|
||||
UserPreferences.getEpisodeCacheSize() == UserPreferences.getEpisodeCacheSizeUnlimited();
|
||||
int episodeCacheSize = UserPreferences.getEpisodeCacheSize();
|
||||
|
||||
int episodeSpaceLeft;
|
||||
if (cacheIsUnlimited || episodeCacheSize >= downloadedEpisodes + autoDownloadableEpisodes) {
|
||||
episodeSpaceLeft = autoDownloadableEpisodes;
|
||||
} else {
|
||||
episodeSpaceLeft = episodeCacheSize - (downloadedEpisodes - deletedEpisodes);
|
||||
}
|
||||
|
||||
FeedItem[] itemsToDownload = candidates.subList(0, episodeSpaceLeft)
|
||||
.toArray(new FeedItem[episodeSpaceLeft]);
|
||||
|
||||
if (itemsToDownload.length > 0) {
|
||||
Log.d(TAG, "Enqueueing " + itemsToDownload.length + " items for download");
|
||||
|
||||
try {
|
||||
DownloadRequester.getInstance().downloadMedia(false, context, false, itemsToDownload);
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,11 +1,28 @@
|
|||
package de.danoeh.antennapod.core.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
public interface AutomaticDownloadAlgorithm {
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.core.feed.FeedFilter;
|
||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||
import de.danoeh.antennapod.core.feed.FeedPreferences;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.PowerUtils;
|
||||
|
||||
/**
|
||||
* Implements the automatic download algorithm used by AntennaPod. This class assumes that
|
||||
* the client uses the {@link EpisodeCleanupAlgorithm}.
|
||||
*/
|
||||
public class AutomaticDownloadAlgorithm {
|
||||
private static final String TAG = "DownloadAlgorithm";
|
||||
|
||||
/**
|
||||
* Looks for undownloaded episodes and request a download if
|
||||
* Looks for undownloaded episodes in the queue or list of new items and request a download if
|
||||
* 1. Network is available
|
||||
* 2. The device is charging or the user allows auto download on battery
|
||||
* 3. There is free space in the episode cache
|
||||
|
@ -14,5 +31,72 @@ public interface AutomaticDownloadAlgorithm {
|
|||
* @param context Used for accessing the DB.
|
||||
* @return A Runnable that will be submitted to an ExecutorService.
|
||||
*/
|
||||
Runnable autoDownloadUndownloadedItems(Context context);
|
||||
public Runnable autoDownloadUndownloadedItems(final Context context) {
|
||||
return () -> {
|
||||
|
||||
// true if we should auto download based on network status
|
||||
boolean networkShouldAutoDl = NetworkUtils.autodownloadNetworkAvailable()
|
||||
&& UserPreferences.isEnableAutodownload();
|
||||
|
||||
// true if we should auto download based on power status
|
||||
boolean powerShouldAutoDl = PowerUtils.deviceCharging(context)
|
||||
|| UserPreferences.isEnableAutodownloadOnBattery();
|
||||
|
||||
// we should only auto download if both network AND power are happy
|
||||
if (networkShouldAutoDl && powerShouldAutoDl) {
|
||||
|
||||
Log.d(TAG, "Performing auto-dl of undownloaded episodes");
|
||||
|
||||
List<FeedItem> candidates;
|
||||
final List<FeedItem> queue = DBReader.getQueue();
|
||||
final List<FeedItem> newItems = DBReader.getNewItemsList(0, Integer.MAX_VALUE);
|
||||
candidates = new ArrayList<>(queue.size() + newItems.size());
|
||||
candidates.addAll(queue);
|
||||
for (FeedItem newItem : newItems) {
|
||||
FeedPreferences feedPrefs = newItem.getFeed().getPreferences();
|
||||
FeedFilter feedFilter = feedPrefs.getFilter();
|
||||
if (!candidates.contains(newItem) && feedFilter.shouldAutoDownload(newItem)) {
|
||||
candidates.add(newItem);
|
||||
}
|
||||
}
|
||||
|
||||
// filter items that are not auto downloadable
|
||||
Iterator<FeedItem> it = candidates.iterator();
|
||||
while (it.hasNext()) {
|
||||
FeedItem item = it.next();
|
||||
if (!item.isAutoDownloadable() || item.getFeed().isLocalFeed()) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
int autoDownloadableEpisodes = candidates.size();
|
||||
int downloadedEpisodes = DBReader.getNumberOfDownloadedEpisodes();
|
||||
int deletedEpisodes = UserPreferences.getEpisodeCleanupAlgorithm()
|
||||
.makeRoomForEpisodes(context, autoDownloadableEpisodes);
|
||||
boolean cacheIsUnlimited =
|
||||
UserPreferences.getEpisodeCacheSize() == UserPreferences.getEpisodeCacheSizeUnlimited();
|
||||
int episodeCacheSize = UserPreferences.getEpisodeCacheSize();
|
||||
|
||||
int episodeSpaceLeft;
|
||||
if (cacheIsUnlimited || episodeCacheSize >= downloadedEpisodes + autoDownloadableEpisodes) {
|
||||
episodeSpaceLeft = autoDownloadableEpisodes;
|
||||
} else {
|
||||
episodeSpaceLeft = episodeCacheSize - (downloadedEpisodes - deletedEpisodes);
|
||||
}
|
||||
|
||||
FeedItem[] itemsToDownload = candidates.subList(0, episodeSpaceLeft)
|
||||
.toArray(new FeedItem[episodeSpaceLeft]);
|
||||
|
||||
if (itemsToDownload.length > 0) {
|
||||
Log.d(TAG, "Enqueueing " + itemsToDownload.length + " items for download");
|
||||
|
||||
try {
|
||||
DownloadRequester.getInstance().downloadMedia(false, context, false, itemsToDownload);
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,9 @@ import android.database.Cursor;
|
|||
import android.os.Looper;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.core.ClientConfig;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import de.danoeh.antennapod.core.R;
|
||||
import de.danoeh.antennapod.core.event.FeedItemEvent;
|
||||
import de.danoeh.antennapod.core.event.FeedListUpdateEvent;
|
||||
|
@ -53,6 +55,8 @@ public final class DBTasks {
|
|||
*/
|
||||
private static final ExecutorService autodownloadExec;
|
||||
|
||||
private static AutomaticDownloadAlgorithm downloadAlgorithm = new AutomaticDownloadAlgorithm();
|
||||
|
||||
static {
|
||||
autodownloadExec = Executors.newSingleThreadExecutor(r -> {
|
||||
Thread t = new Thread(r);
|
||||
|
@ -278,7 +282,7 @@ public final class DBTasks {
|
|||
}
|
||||
|
||||
/**
|
||||
* Looks for undownloaded episodes in the queue or list of unread items and request a download if
|
||||
* Looks for non-downloaded episodes in the queue or list of unread items and request a download if
|
||||
* 1. Network is available
|
||||
* 2. The device is charging or the user allows auto download on battery
|
||||
* 3. There is free space in the episode cache
|
||||
|
@ -289,9 +293,15 @@ public final class DBTasks {
|
|||
*/
|
||||
public static Future<?> autodownloadUndownloadedItems(final Context context) {
|
||||
Log.d(TAG, "autodownloadUndownloadedItems");
|
||||
return autodownloadExec.submit(ClientConfig.automaticDownloadAlgorithm
|
||||
.autoDownloadUndownloadedItems(context));
|
||||
return autodownloadExec.submit(downloadAlgorithm.autoDownloadUndownloadedItems(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing purpose only.
|
||||
*/
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
|
||||
public static void setDownloadAlgorithm(AutomaticDownloadAlgorithm newDownloadAlgorithm) {
|
||||
downloadAlgorithm = newDownloadAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -12,7 +12,6 @@ import de.danoeh.antennapod.core.preferences.SleepTimerPreferences;
|
|||
import de.danoeh.antennapod.core.preferences.UsageStatistics;
|
||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
|
||||
import de.danoeh.antennapod.core.storage.AutomaticDownloadAlgorithm;
|
||||
import de.danoeh.antennapod.core.storage.PodDBAdapter;
|
||||
import de.danoeh.antennapod.core.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
|
||||
|
@ -39,8 +38,6 @@ public class ClientConfig {
|
|||
|
||||
public static PlaybackServiceCallbacks playbackServiceCallbacks;
|
||||
|
||||
public static AutomaticDownloadAlgorithm automaticDownloadAlgorithm;
|
||||
|
||||
public static CastCallbacks castCallbacks;
|
||||
|
||||
private static boolean initialized = false;
|
||||
|
|
Loading…
Reference in New Issue