diff options
18 files changed, 222 insertions, 74 deletions
diff --git a/app/build.gradle b/app/build.gradle index 2fe94d576..d957d9833 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -31,8 +31,8 @@ dependencies { compile "io.reactivex:rxjava:$rxJavaVersion" // And ProGuard rules for RxJava! compile "com.artemzin.rxjava:proguard-rules:$rxJavaRulesVersion" - compile "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyFontawesomeVersion" - compile "com.joanzapata.iconify:android-iconify-material:$iconifyFontawesomeVersion" + compile "com.joanzapata.iconify:android-iconify-fontawesome:$iconifyVersion" + compile "com.joanzapata.iconify:android-iconify-material:$iconifyVersion" compile("com.github.afollestad.material-dialogs:commons:$materialDialogsVersion") { transitive = true } diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java index d65925703..d4994fb1a 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackSonicTest.java @@ -49,10 +49,11 @@ public class PlaybackSonicTest extends ActivityInstrumentationTestCase2<MainActi public void setUp() throws Exception { super.setUp(); - PodDBAdapter.deleteDatabase(); - context = getInstrumentation().getTargetContext(); + PodDBAdapter.init(context); + PodDBAdapter.deleteDatabase(); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); prefs.edit() .clear() diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java index 016c868b4..5ce495f9a 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java @@ -46,10 +46,11 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2<MainActivity> public void setUp() throws Exception { super.setUp(); - PodDBAdapter.deleteDatabase(); - context = getInstrumentation().getTargetContext(); + PodDBAdapter.init(context); + PodDBAdapter.deleteDatabase(); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); prefs.edit() .clear() 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 fabc399ba..b70336a30 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/PreferencesTest.java @@ -3,17 +3,10 @@ package de.test.antennapod.ui; import android.content.Context; import android.content.res.Resources; import android.test.ActivityInstrumentationTestCase2; -import android.test.FlakyTest; -import com.robotium.solo.Condition; import com.robotium.solo.Solo; import com.robotium.solo.Timeout; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.util.List; import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.R; @@ -230,6 +223,8 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference String[] values = res.getStringArray(R.array.episode_cache_size_values); String entry = entries[entries.length/2]; final int value = Integer.valueOf(values[values.length/2]); + solo.clickOnText(solo.getString(R.string.pref_automatic_download_title)); + solo.waitForText(solo.getString(R.string.pref_automatic_download_title)); solo.clickOnText(solo.getString(R.string.pref_episode_cache_title)); solo.waitForDialogToOpen(); solo.clickOnText(entry); @@ -241,6 +236,11 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference String[] values = res.getStringArray(R.array.episode_cache_size_values); String minEntry = entries[0]; final int minValue = Integer.valueOf(values[0]); + solo.clickOnText(solo.getString(R.string.pref_automatic_download_title)); + solo.waitForText(solo.getString(R.string.pref_automatic_download_title)); + if(!UserPreferences.isEnableAutodownload()) { + solo.clickOnText(solo.getString(R.string.pref_automatic_download_title)); + } solo.clickOnText(solo.getString(R.string.pref_episode_cache_title)); solo.waitForDialogToOpen(1000); solo.scrollUp(); @@ -248,12 +248,16 @@ public class PreferencesTest extends ActivityInstrumentationTestCase2<Preference assertTrue(solo.waitForCondition(() -> UserPreferences.getEpisodeCacheSize() == minValue, Timeout.getLargeTimeout())); } - public void testSetEpisodeCacheMax() { String[] entries = res.getStringArray(R.array.episode_cache_size_entries); String[] values = res.getStringArray(R.array.episode_cache_size_values); String maxEntry = entries[entries.length-1]; final int maxValue = Integer.valueOf(values[values.length-1]); + solo.clickOnText(solo.getString(R.string.pref_automatic_download_title)); + solo.waitForText(solo.getString(R.string.pref_automatic_download_title)); + if(!UserPreferences.isEnableAutodownload()) { + solo.clickOnText(solo.getString(R.string.pref_automatic_download_title)); + } solo.clickOnText(solo.getString(R.string.pref_episode_cache_title)); solo.waitForDialogToOpen(); solo.clickOnText(maxEntry); diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java index 442515010..835ac29cd 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java @@ -842,6 +842,11 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc } @Override + public int getNumberOfDownloadedItems() { + return (navDrawerData != null) ? navDrawerData.numDownloadedItems : 0; + } + + @Override public int getFeedCounter(long feedId) { return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0; } 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 17cd5ace3..2181e7d2d 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MainActivity.java @@ -636,6 +636,11 @@ public class MainActivity extends AppCompatActivity implements NavDrawerActivity } @Override + public int getNumberOfDownloadedItems() { + return (navDrawerData != null) ? navDrawerData.numDownloadedItems : 0; + } + + @Override public int getFeedCounter(long feedId) { return navDrawerData != null ? navDrawerData.feedCounters.get(feedId) : 0; } diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java index 183c1a44e..d43e30d8f 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/NavListAdapter.java @@ -6,6 +6,7 @@ import android.content.res.TypedArray; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.preference.PreferenceManager; +import android.support.v7.app.AlertDialog; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -15,7 +16,7 @@ import android.widget.RelativeLayout; import android.widget.TextView; import com.bumptech.glide.Glide; -import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.widget.IconTextView; import org.apache.commons.lang3.ArrayUtils; @@ -208,7 +209,8 @@ public class NavListAdapter extends BaseAdapter holder.title.setText(title); - if (tags.get(position).equals(QueueFragment.TAG)) { + String tag = tags.get(position); + if (tag.equals(QueueFragment.TAG)) { int queueSize = itemAccess.getQueueSize(); if (queueSize > 0) { holder.count.setVisibility(View.VISIBLE); @@ -216,7 +218,7 @@ public class NavListAdapter extends BaseAdapter } else { holder.count.setVisibility(View.GONE); } - } else if (tags.get(position).equals(EpisodesFragment.TAG)) { + } else if (tag.equals(EpisodesFragment.TAG)) { int unreadItems = itemAccess.getNumberOfNewItems(); if (unreadItems > 0) { holder.count.setVisibility(View.VISIBLE); @@ -224,6 +226,22 @@ public class NavListAdapter extends BaseAdapter } else { holder.count.setVisibility(View.GONE); } + } else if(tag.equals(DownloadsFragment.TAG) && UserPreferences.isEnableAutodownload()) { + int epCacheSize = UserPreferences.getEpisodeCacheSize(); + if(itemAccess.getNumberOfDownloadedItems() >= epCacheSize) { + holder.count.setText("{md-disc-full 150%}"); + Iconify.addIcons(holder.count); + holder.count.setVisibility(View.VISIBLE); + holder.count.setOnClickListener(v -> { + new AlertDialog.Builder(context) + .setTitle(R.string.episode_cache_full_title) + .setMessage(R.string.episode_cache_full_message) + .setPositiveButton(android.R.string.ok, (dialog, which) -> {}) + .show(); + }); + } else { + holder.count.setVisibility(View.GONE); + } } else { holder.count.setVisibility(View.GONE); } @@ -316,6 +334,7 @@ public class NavListAdapter extends BaseAdapter int getSelectedItemIndex(); int getQueueSize(); int getNumberOfNewItems(); + int getNumberOfDownloadedItems(); int getFeedCounter(long feedId); } diff --git a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java index a872039f9..083ac5202 100644 --- a/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java +++ b/app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java @@ -30,10 +30,15 @@ import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; +import org.apache.commons.lang3.ArrayUtils; + import java.io.File; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; +import java.util.GregorianCalendar; import java.util.List; +import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.CrashReportWriter; import de.danoeh.antennapod.R; @@ -216,17 +221,16 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc } }); - ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL) - .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (newValue instanceof Boolean) { - ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled((Boolean) newValue); - setSelectedNetworksEnabled((Boolean) newValue && UserPreferences.isEnableAutodownloadWifiFilter()); - ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY).setEnabled((Boolean) newValue); - } - return true; + ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL).setOnPreferenceChangeListener( + (preference, newValue) -> { + if (newValue instanceof Boolean) { + boolean enabled = (Boolean) newValue; + ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setEnabled(enabled); + ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY).setEnabled(enabled); + ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled(enabled); + setSelectedNetworksEnabled(enabled && UserPreferences.isEnableAutodownloadWifiFilter()); } + return true; }); ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER) .setOnPreferenceChangeListener( @@ -411,6 +415,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc public void onResume() { checkItemVisibility(); + setUpdateIntervalText(); setParallelDownloadsText(UserPreferences.getParallelDownloads()); setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize()); setDataFolderText(); @@ -503,15 +508,19 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc final Resources res = ui.getActivity().getResources(); ListPreference pref = (ListPreference) ui.findPreference(UserPreferences.PREF_SMART_MARK_AS_PLAYED_SECS); - String[] values = res.getStringArray( - R.array.smart_mark_as_played_values); + String[] values = res.getStringArray(R.array.smart_mark_as_played_values); String[] entries = new String[values.length]; for (int x = 0; x < values.length; x++) { if(x == 0) { entries[x] = res.getString(R.string.pref_smart_mark_as_played_disabled); } else { Integer v = Integer.parseInt(values[x]); - entries[x] = res.getQuantityString(R.plurals.time_seconds_quantified, v, v); + if(v < 60) { + entries[x] = res.getQuantityString(R.plurals.time_seconds_quantified, v, v); + } else { + v /= 60; + entries[x] = res.getQuantityString(R.plurals.time_minutes_quantified, v, v); + } } } pref.setEntries(entries); @@ -527,21 +536,17 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc @SuppressWarnings("deprecation") private void checkItemVisibility() { - boolean hasFlattrToken = FlattrUtils.hasToken(); - ui.findPreference(PreferenceController.PREF_FLATTR_SETTINGS).setEnabled(FlattrUtils.hasAPICredentials()); ui.findPreference(PreferenceController.PREF_FLATTR_AUTH).setEnabled(!hasFlattrToken); ui.findPreference(PreferenceController.PREF_FLATTR_REVOKE).setEnabled(hasFlattrToken); ui.findPreference(PreferenceController.PREF_AUTO_FLATTR_PREFS).setEnabled(hasFlattrToken); - ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER) - .setEnabled(UserPreferences.isEnableAutodownload()); - setSelectedNetworksEnabled(UserPreferences.isEnableAutodownload() - && UserPreferences.isEnableAutodownloadWifiFilter()); - - ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY) - .setEnabled(UserPreferences.isEnableAutodownload()); + boolean autoDownload = UserPreferences.isEnableAutodownload(); + ui.findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setEnabled(autoDownload); + ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_ON_BATTERY).setEnabled(autoDownload); + ui.findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER).setEnabled(autoDownload); + setSelectedNetworksEnabled(autoDownload && UserPreferences.isEnableAutodownloadWifiFilter()); ui.findPreference("prefSendCrashReport").setEnabled(CrashReportWriter.getFile().exists()); @@ -553,6 +558,32 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc } } + private void setUpdateIntervalText() { + Context context = ui.getActivity().getApplicationContext(); + String val; + long interval = UserPreferences.getUpdateInterval(); + if(interval > 0) { + int hours = (int) TimeUnit.MILLISECONDS.toHours(interval); + String hoursStr = context.getResources().getQuantityString(R.plurals.time_hours_quantified, hours, hours); + val = String.format(context.getString(R.string.pref_autoUpdateIntervallOrTime_every), hoursStr); + } 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.pref_autoUpdateIntervallOrTime_at), + timeOfDayStr); + } else { + val = context.getString(R.string.pref_smart_mark_as_played_disabled); + } + } + String summary = context.getString(R.string.pref_autoUpdateIntervallOrTime_sum) + "\n" + + String.format(context.getString(R.string.pref_current_value), val); + ui.findPreference(UserPreferences.PREF_UPDATE_INTERVAL).setSummary(summary); + } + private void setParallelDownloadsText(int downloads) { final Resources res = ui.getActivity().getResources(); @@ -772,10 +803,17 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc builder.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_Interval)); final String[] values = context.getResources().getStringArray(R.array.update_intervall_values); final String[] entries = getUpdateIntervalEntries(values); - builder.setSingleChoiceItems(entries, -1, (dialog1, which) -> { + long currInterval = UserPreferences.getUpdateInterval(); + int checkedItem = -1; + if(currInterval > 0) { + String currIntervalStr = String.valueOf(TimeUnit.MILLISECONDS.toHours(currInterval)); + checkedItem = ArrayUtils.indexOf(values, currIntervalStr); + } + builder.setSingleChoiceItems(entries, checkedItem, (dialog1, which) -> { int hours = Integer.valueOf(values[which]); UserPreferences.setUpdateInterval(hours); dialog1.dismiss(); + setUpdateIntervalText(); }); builder.setNegativeButton(context.getString(R.string.cancel_label), null); builder.show(); @@ -794,6 +832,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc if (view.getTag() == null) { // onTimeSet() may get called twice! view.setTag("TAGGED"); UserPreferences.setUpdateTimeOfDay(selectedHourOfDay, selectedMinute); + setUpdateIntervalText(); } }, hourOfDay, minute, DateFormat.is24HourFormat(context)); timePickerDialog.setTitle(context.getString(R.string.pref_autoUpdateIntervallOrTime_TimeOfDay)); @@ -803,6 +842,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc @Override public void onNeutral(MaterialDialog dialog) { UserPreferences.setUpdateInterval(0); + setUpdateIntervalText(); } }); builder.forceStacking(true); diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index cdb582898..b2a28e871 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -170,13 +170,6 @@ android:key="prefParallelDownloads" android:title="@string/pref_parallel_downloads_title" app:useStockLayout="true"/> - <com.afollestad.materialdialogs.prefs.MaterialListPreference - android:defaultValue="20" - android:entries="@array/episode_cache_size_entries" - android:key="prefEpisodeCacheSize" - android:title="@string/pref_episode_cache_title" - android:entryValues="@array/episode_cache_size_values" - app:useStockLayout="true"/> <PreferenceScreen android:summary="@string/pref_automatic_download_sum" android:key="prefAutoDownloadSettings" @@ -185,6 +178,13 @@ android:key="prefEnableAutoDl" android:title="@string/pref_automatic_download_title" android:defaultValue="false"/> + <com.afollestad.materialdialogs.prefs.MaterialListPreference + android:defaultValue="20" + android:entries="@array/episode_cache_size_entries" + android:key="prefEpisodeCacheSize" + android:title="@string/pref_episode_cache_title" + android:entryValues="@array/episode_cache_size_values" + app:useStockLayout="true"/> <de.danoeh.antennapod.preferences.SwitchCompatPreference android:key="prefEnableAutoDownloadOnBattery" android:title="@string/pref_automatic_download_on_battery_title" diff --git a/build.gradle b/build.gradle index 79cf2e3c5..aa2251121 100644 --- a/build.gradle +++ b/build.gradle @@ -47,8 +47,8 @@ project.ext { eventbusVersion = "2.4.0" flattr4jVersion = "2.12" glideVersion = "3.6.1" + iconifyVersion = "2.1.1" jsoupVersion = "1.7.3" - iconifyFontawesomeVersion = "2.1.1" materialDialogsVersion = "0.8.5.3@aar" recyclerviewFlexibledividerVersion = "1.2.6" rxAndroidVersion = "1.1.0" diff --git a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java index c54cc1d5b..00b32de5f 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java +++ b/core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java @@ -11,6 +11,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; import de.danoeh.antennapod.core.asynctask.ImageResource; import de.danoeh.antennapod.core.storage.DBReader; @@ -75,7 +76,13 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr private List<Chapter> chapters; private FeedImage image; - private boolean autoDownload = true; + /* + * 0: auto download disabled + * 1: auto download enabled + * > 1: auto download enabled, (approx.) timestamp of the last failed attempt + * where last digit denotes the number of failed attempts + */ + private long autoDownload = 0; /** * Any tags assigned to this item @@ -93,7 +100,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr * */ public FeedItem(long id, String title, String link, Date pubDate, String paymentLink, long feedId, FlattrStatus flattrStatus, boolean hasChapters, FeedImage image, int state, - String itemIdentifier, boolean autoDownload) { + String itemIdentifier, long autoDownload) { this.id = id; this.title = title; this.link = link; @@ -162,7 +169,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr FlattrStatus flattrStatus = new FlattrStatus(cursor.getLong(indexFlattrStatus)); int state = cursor.getInt(indexRead); String itemIdentifier = cursor.getString(indexItemIdentifier); - boolean autoDownload = cursor.getInt(indexAutoDownload) > 0; + long autoDownload = cursor.getLong(indexAutoDownload); FeedItem item = new FeedItem(id, title, link, pubDate, paymentLink, feedId, flattrStatus, hasChapters, null, state, itemIdentifier, autoDownload); @@ -449,18 +456,37 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr } public void setAutoDownload(boolean autoDownload) { - this.autoDownload = autoDownload; + this.autoDownload = autoDownload ? 1 : 0; } public boolean getAutoDownload() { - return this.autoDownload; + return this.autoDownload > 0; + } + + public int getFailedAutoDownloadAttempts() { + if (autoDownload <= 1) { + return 0; + } + int failedAttempts = (int)(autoDownload % 10); + if (failedAttempts == 0) { + failedAttempts = 10; + } + return failedAttempts; } public boolean isAutoDownloadable() { - return this.hasMedia() && - false == this.getMedia().isPlaying() && - false == this.getMedia().isDownloaded() && - this.getAutoDownload(); + if (media == null || media.isPlaying() || media.isDownloaded() || autoDownload == 0) { + return false; + } + if (autoDownload == 1) { + return true; + } + int failedAttempts = getFailedAutoDownloadAttempts(); + double magicValue = 1.767; // 1.767^(10[=#maxNumAttempts]-1) = 168 hours / 7 days + int millisecondsInHour = 3600000; + long waitingTime = (long) (Math.pow(magicValue, failedAttempts - 1) * millisecondsInHour); + long grace = TimeUnit.MINUTES.toMillis(5); + return System.currentTimeMillis() > (autoDownload + waitingTime - grace); } /** 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 29c44207d..c3afff276 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 @@ -26,6 +26,7 @@ import org.xml.sax.SAXException; import java.io.File; import java.io.IOException; +import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -196,11 +197,19 @@ public class DownloadService extends Service { saveDownloadStatus(status); handleFailedDownload(status, downloader.getDownloadRequest()); - // to make lists reload the failed item, we fake an item update if(type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) { long id = status.getFeedfileId(); FeedMedia media = DBReader.getFeedMedia(id); - EventBus.getDefault().post(FeedItemEvent.updated(media.getItem())); + if(media == null || media.getItem() == null) { + return; + } + FeedItem item = media.getItem(); + if (status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR && + Integer.valueOf(status.getReasonDetailed()) == HttpURLConnection.HTTP_NOT_FOUND) { + DBWriter.saveFeedItemAutoDownloadFailed(item).get(); + } + // to make lists reload the failed item, we fake an item update + EventBus.getDefault().post(FeedItemEvent.updated(item)); } } } else { diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java index fe5b177ab..16e65f9f3 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java @@ -1015,7 +1015,9 @@ public final class DBReader { Collections.sort(feeds, comparator); int queueSize = adapter.getQueueSize(); int numNewItems = adapter.getNumberOfNewItems(); - NavDrawerData result = new NavDrawerData(feeds, queueSize, numNewItems, feedCounters); + int numDownloadedItems = adapter.getNumberOfDownloadedEpisodes(); + + NavDrawerData result = new NavDrawerData(feeds, queueSize, numNewItems, numDownloadedItems, feedCounters); adapter.close(); return result; } @@ -1024,15 +1026,18 @@ public final class DBReader { public List<Feed> feeds; public int queueSize; public int numNewItems; + public int numDownloadedItems; public LongIntMap feedCounters; public NavDrawerData(List<Feed> feeds, int queueSize, int numNewItems, + int numDownloadedItems, LongIntMap feedIndicatorValues) { this.feeds = feeds; this.queueSize = queueSize; this.numNewItems = numNewItems; + this.numDownloadedItems = numDownloadedItems; this.feedCounters = feedIndicatorValues; } } 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 f74064cfc..d1d6bd750 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 @@ -977,13 +977,35 @@ public class DBWriter { * Sets the 'auto_download'-attribute of specific FeedItem. * * @param feedItem FeedItem. + * @param autoDownload true enables auto download, false disables it */ public static Future<?> setFeedItemAutoDownload(final FeedItem feedItem, final boolean autoDownload) { - Log.d(TAG, "FeedItem[id=" + feedItem.getId() + "] SET auto_download " + autoDownload); return dbExec.submit(() -> { final PodDBAdapter adapter = PodDBAdapter.getInstance(); adapter.open(); + adapter.setFeedItemAutoDownload(feedItem, autoDownload ? 1 : 0); + adapter.close(); + EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); + }); + } + + public static Future<?> saveFeedItemAutoDownloadFailed(final FeedItem feedItem) { + return dbExec.submit(() -> { + int failedAttempts = feedItem.getFailedAutoDownloadAttempts() + 1; + Log.d(TAG, "failedAttempts: " + failedAttempts); + long autoDownload; + if(!feedItem.getAutoDownload() || failedAttempts >= 10) { + autoDownload = 0; // giving up, disable auto download + feedItem.setAutoDownload(false); + } else { + long now = System.currentTimeMillis(); + autoDownload = (now / 10) * 10 + failedAttempts; + Log.d(TAG, "now: " + now); + Log.d(TAG, "autoDownload: " + autoDownload); + } + final PodDBAdapter adapter = PodDBAdapter.getInstance(); + adapter.open(); adapter.setFeedItemAutoDownload(feedItem, autoDownload); adapter.close(); EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); @@ -992,7 +1014,8 @@ public class DBWriter { /** * Sets the 'auto_download'-attribute of specific FeedItem. - * @param feed This feed's episodes will be processed. + * + * @param feed This feed's episodes will be processed. * @param autoDownload If true, auto download will be enabled for the feed's episodes. Else, */ public static Future<?> setFeedsItemsAutoDownload(final Feed feed, diff --git a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java index 629b73668..915ca14c7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java +++ b/core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java @@ -794,7 +794,7 @@ public class PodDBAdapter { return status.getId(); } - public void setFeedItemAutoDownload(FeedItem feedItem, boolean autoDownload) { + public void setFeedItemAutoDownload(FeedItem feedItem, long autoDownload) { ContentValues values = new ContentValues(); values.put(KEY_AUTO_DOWNLOAD, autoDownload); db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?", diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java index 6406295c1..9b9849c49 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java +++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java @@ -1,5 +1,7 @@ package de.danoeh.antennapod.core.syndication.namespace; +import android.text.TextUtils; + import org.xml.sax.Attributes; import java.util.concurrent.TimeUnit; @@ -36,8 +38,10 @@ public class NSITunes extends Namespace { } else { // this is the feed image // prefer to all other images - image.setOwner(state.getFeed()); - state.getFeed().setImage(image); + if(!TextUtils.isEmpty(image.getDownload_url())) { + image.setOwner(state.getFeed()); + state.getFeed().setImage(image); + } } } diff --git a/core/src/main/res/values/arrays.xml b/core/src/main/res/values/arrays.xml index 341a7e520..6e885c0bb 100644 --- a/core/src/main/res/values/arrays.xml +++ b/core/src/main/res/values/arrays.xml @@ -11,8 +11,9 @@ <item>0</item> <item>15</item> <item>30</item> - <item>45</item> <item>60</item> + <item>120</item> + <item>300</item> </string-array> diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml index 69acdcc4a..726697602 100644 --- a/core/src/main/res/values/strings.xml +++ b/core/src/main/res/values/strings.xml @@ -26,6 +26,8 @@ <string name="gpodnet_main_label">gpodder.net</string> <string name="gpodnet_auth_label">gpodder.net Login</string> <string name="free_space_label">%1$s free</string> + <string name="episode_cache_full_title">Episode cache full</string> + <string name="episode_cache_full_message">The episode cache limit has been reached. You can increase the cache size in the Settings.</string> <!-- New episodes fragment --> <string name="recently_published_episodes_label">Recently published</string> @@ -75,7 +77,7 @@ <string name="length_prefix">Length:\u0020</string> <string name="size_prefix">Size:\u0020</string> <string name="processing_label">Processing</string> - <string name="loading_label">Loading...</string> + <string name="loading_label">Loading…</string> <string name="save_username_password_label">Save username and password</string> <string name="close_label">Close</string> <string name="retry_label">Retry</string> @@ -87,7 +89,7 @@ <string name="feed_auto_download_global">Global</string> <string name="feed_auto_download_always">Always</string> <string name="feed_auto_download_never">Never</string> - <string name="send_label">Send...</string> + <string name="send_label">Send…</string> <string name="episode_cleanup_never">Never</string> <string name="episode_cleanup_queue_removal">When not in queue</string> <string name="episode_cleanup_after_listening">After finishing</string> @@ -112,7 +114,7 @@ <string name="mark_all_seen_label">Mark all as seen</string> <string name="show_info_label">Show information</string> <string name="remove_feed_label">Remove Podcast</string> - <string name="share_label">Share...</string> + <string name="share_label">Share…</string> <string name="share_link_label">Share Link</string> <string name="share_link_with_position_label">Share Link with Position</string> <string name="share_feed_url_label">Share Feed URL</string> @@ -299,6 +301,8 @@ <string name="pref_autoUpdateIntervallOrTime_Disable">Disable</string> <string name="pref_autoUpdateIntervallOrTime_Interval">Set Interval</string> <string name="pref_autoUpdateIntervallOrTime_TimeOfDay">Set Time of Day</string> + <string name="pref_autoUpdateIntervallOrTime_every">every %1$s</string> + <string name="pref_autoUpdateIntervallOrTime_at">at %1$s</string> <string name="pref_downloadMediaOnWifiOnly_sum">Download media files only over WiFi</string> <string name="pref_followQueue_title">Continuous Playback</string> <string name="pref_downloadMediaOnWifiOnly_title">WiFi media download</string> @@ -374,6 +378,7 @@ <string name="experimental_pref">Experimental</string> <string name="pref_sonic_title">Sonic media player</string> <string name="pref_sonic_message">Use built-in sonic media player as a replacement for Prestissimo</string> + <string name="pref_current_value">Current value: %1$s</string> <!-- Auto-Flattr dialog --> <string name="auto_flattr_enable">Enable automatic flattring</string> @@ -402,11 +407,11 @@ <string name="opml_import_error_dir_empty">The import directory is empty.</string> <string name="select_all_label">Select all</string> <string name="deselect_all_label">Deselect all</string> - <string name="select_options_label">Select ...</string> + <string name="select_options_label">Select…</string> <string name="choose_file_from_filesystem">From local filesystem</string> <string name="choose_file_from_external_application">Use external application</string> <string name="opml_export_label">OPML export</string> - <string name="exporting_label">Exporting...</string> + <string name="exporting_label">Exporting…</string> <string name="export_error_label">Export error</string> <string name="opml_export_success_title">OPML Export successful.</string> <string name="opml_export_success_sum">The .opml file was written to:\u0020</string> @@ -494,7 +499,7 @@ <!-- Online feed view --> <string name="subscribe_label">Subscribe</string> <string name="subscribed_label">Subscribed</string> - <string name="downloading_label">Downloading...</string> + <string name="downloading_label">Downloading…</string> <!-- Content descriptions for image buttons --> <string name="show_chapters_label">Show chapters</string> @@ -529,7 +534,7 @@ <string name="sp_apps_importing_feeds_msg">Importing subscriptions from single-purpose apps…</string> <string name="search_itunes_label">Search iTunes</string> - <string name="select_label"><b>Select ...</b></string> + <string name="select_label"><b>Select…</b></string> <string name="all_label">All</string> <string name="selected_all_label">Selected all Episodes</string> <string name="none_label">None</string> @@ -542,7 +547,7 @@ <string name="selected_downloaded_label">Selected downloaded Episodes</string> <string name="not_downloaded_label">Not downloaded</string> <string name="selected_not_downloaded_label">Selected not downloaded Episodes</string> - <string name="sort_title"><b>Sort by ...</b></string> + <string name="sort_title"><b>Sort by…</b></string> <string name="sort_title_a_z">Title (A \u2192 Z)</string> <string name="sort_title_z_a">Title (Z \u2192 A)</string> <string name="sort_date_new_old">Date (New \u2192 Old)</string> |