diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index ed72f0d47..4fe28a14b 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -29,6 +29,7 @@ import de.danoeh.antennapod.storage.PodDBAdapter; import de.danoeh.antennapod.util.DownloadError; import de.danoeh.antennapod.util.EpisodeFilter; import de.danoeh.antennapod.util.FeedtitleComparator; +import de.danoeh.antennapod.util.NetworkUtils; import de.danoeh.antennapod.util.comparator.DownloadStatusComparator; import de.danoeh.antennapod.util.comparator.FeedItemPubdateComparator; import de.danoeh.antennapod.util.comparator.PlaybackCompletionDateComparator; @@ -573,10 +574,26 @@ public class FeedManager { } } - /** Downloads FeedItems if they have not been downloaded yet. */ public void downloadFeedItem(final Context context, FeedItem... items) throws DownloadRequestException { + downloadFeedItem(true, context, items); + } + /** Downloads FeedItems if they have not been downloaded yet. */ + private void downloadFeedItem(boolean performAutoCleanup, + final Context context, final FeedItem... items) + throws DownloadRequestException { + if (performAutoCleanup) { + new Thread() { + + @Override + public void run() { + performAutoCleanup(context, + getPerformAutoCleanupArgs(items.length)); + } + + }.start(); + } for (FeedItem item : items) { if (item.getMedia() != null && !requester.isDownloadingFile(item.getMedia()) @@ -600,6 +617,167 @@ public class FeedManager { } } + /** + * This method will try to download undownloaded items in the queue or the + * unread items list. If not enough space is available, an episode cleanup + * will be performed first. + */ + public void autodownloadUndownloadedItems(Context context) { + if (AppConfig.DEBUG) + Log.d(TAG, "Performing auto-dl of undownloaded episodes"); + if (NetworkUtils.autodownloadNetworkAvailable(context)) { + int undownloadedEpisodes = getNumberOfUndownloadedEpisodes(); + if (undownloadedEpisodes > 0) { + int downloadedEpisodes = getNumberOfDownloadedEpisodes(); + int deletedEpisodes = performAutoCleanup(context, + getPerformAutoCleanupArgs(undownloadedEpisodes)); + int episodeSpaceLeft = undownloadedEpisodes; + if (UserPreferences.getEpisodeCacheSize() < downloadedEpisodes + + undownloadedEpisodes) { + episodeSpaceLeft = UserPreferences.getEpisodeCacheSize() + - (downloadedEpisodes - deletedEpisodes); + } + + List itemsToDownload = new ArrayList(); + if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) { + for (FeedItem item : queue) { + if (item.hasMedia() && !item.getMedia().isDownloaded()) { + itemsToDownload.add(item); + episodeSpaceLeft--; + undownloadedEpisodes--; + if (episodeSpaceLeft == 0 + || undownloadedEpisodes == 0) { + break; + } + } + } + } + if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) { + for (FeedItem item : unreadItems) { + if (item.hasMedia() && !item.getMedia().isDownloaded()) { + itemsToDownload.add(item); + episodeSpaceLeft--; + undownloadedEpisodes--; + if (episodeSpaceLeft == 0 + || undownloadedEpisodes == 0) { + break; + } + } + } + } + if (AppConfig.DEBUG) + Log.d(TAG, "Enqueueing " + itemsToDownload.size() + + " items for download"); + + try { + downloadFeedItem(false, context, + itemsToDownload + .toArray(new FeedItem[itemsToDownload + .size()])); + } catch (DownloadRequestException e) { + e.printStackTrace(); + } + + } + + } + } + + /** + * This method will determine the number of episodes that have to be deleted + * depending on a given number of episodes. + * + * @return The argument that has to be passed to performAutoCleanup() so + * that the number of episodes fits into the episode cache. + * */ + private int getPerformAutoCleanupArgs(final int episodeNumber) { + if (episodeNumber >= 0) { + int downloadedEpisodes = getNumberOfDownloadedEpisodes(); + if (downloadedEpisodes + episodeNumber >= UserPreferences + .getEpisodeCacheSize()) { + + return downloadedEpisodes + episodeNumber + - UserPreferences.getEpisodeCacheSize(); + } + } + return 0; + } + + /** + * Performs an auto-cleanup so that the number of downloaded episodes is + * below or equal to the episode cache size. The method will be executed in + * the caller's thread. + */ + public void performAutoCleanup(Context context) { + performAutoCleanup(context, getPerformAutoCleanupArgs(0)); + } + + /** + * This method will try to delete a given number of episodes. An episode + * will only be deleted if it is not in the queue. + * + * @return The number of episodes that were actually deleted + * */ + private int performAutoCleanup(Context context, final int episodeNumber) { + int counter = 0; + int episodesLeft = episodeNumber; + feedloop: for (Feed feed : feeds) { + for (FeedItem item : feed.getItems()) { + if (item.hasMedia() && item.getMedia().isDownloaded()) { + if (!isInQueue(item) && item.isRead()) { + deleteFeedMedia(context, item.getMedia()); + counter++; + episodesLeft--; + if (episodesLeft == 0) { + break feedloop; + } + } + } + } + } + if (AppConfig.DEBUG) + Log.d(TAG, String.format( + "Auto-delete deleted %d episodes (%d requested)", counter, + episodeNumber)); + + return counter; + } + + /** + * Counts items in the queue and the unread items list which haven't been + * downloaded yet. + */ + private int getNumberOfUndownloadedEpisodes() { + int counter = 0; + for (FeedItem item : queue) { + if (item.hasMedia() && !item.getMedia().isDownloaded()) { + counter++; + } + } + for (FeedItem item : unreadItems) { + if (item.hasMedia() && !item.getMedia().isDownloaded()) { + counter++; + } + } + return counter; + + } + + /** Counts all downloaded items. */ + private int getNumberOfDownloadedEpisodes() { + int counter = 0; + for (Feed feed : feeds) { + for (FeedItem item : feed.getItems()) { + if (item.hasMedia() && item.getMedia().isDownloaded()) { + counter++; + } + } + } + if (AppConfig.DEBUG) + Log.d(TAG, "Number of downloaded episodes: " + counter); + return counter; + } + /** * Enqueues all items that are currently in the unreadItems list and marks * them as 'read'. diff --git a/src/de/danoeh/antennapod/util/NetworkUtils.java b/src/de/danoeh/antennapod/util/NetworkUtils.java new file mode 100644 index 000000000..6064f3f91 --- /dev/null +++ b/src/de/danoeh/antennapod/util/NetworkUtils.java @@ -0,0 +1,63 @@ +package de.danoeh.antennapod.util; + +import java.util.Arrays; +import java.util.List; + +import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.preferences.UserPreferences; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.util.Log; + +public class NetworkUtils { + private static final String TAG = "NetworkUtils"; + + private NetworkUtils() { + + } + + /** + * Returns true if the device is connected to Wi-Fi and the Wi-Fi filter for + * automatic downloads is disabled or the device is connected to a Wi-Fi + * network that is on the 'selected networks' list of the Wi-Fi filter for + * automatic downloads and false otherwise. + * */ + public static boolean autodownloadNetworkAvailable(Context context) { + ConnectivityManager cm = (ConnectivityManager) context + .getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = cm.getActiveNetworkInfo(); + if (networkInfo != null) { + if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { + if (AppConfig.DEBUG) + Log.d(TAG, "Device is connected to Wi-Fi"); + if (networkInfo.isConnected()) { + if (!UserPreferences.isEnableAutodownloadWifiFilter()) { + if (AppConfig.DEBUG) + Log.d(TAG, "Auto-dl filter is disabled"); + return true; + } else { + WifiManager wm = (WifiManager) context + .getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wm.getConnectionInfo(); + List selectedNetworks = Arrays + .asList(UserPreferences + .getAutodownloadSelectedNetworks()); + if (selectedNetworks.contains(Integer.toString(wifiInfo + .getNetworkId()))) { + if (AppConfig.DEBUG) + Log.d(TAG, + "Current network is on the selected networks list"); + return true; + } + } + } + } + } + if (AppConfig.DEBUG) + Log.d(TAG, "Network for auto-dl is not available"); + return false; + } +}