summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/main/java/de/danoeh/antennapod/preferences/PreferenceController.java53
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/feed/FeedItem.java44
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java13
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBWriter.java27
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java2
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSITunes.java8
-rw-r--r--core/src/main/res/values/arrays.xml3
-rw-r--r--core/src/main/res/values/strings.xml19
8 files changed, 140 insertions, 29 deletions
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 ecbec4edc..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;
@@ -410,6 +415,7 @@ public class PreferenceController implements SharedPreferences.OnSharedPreferenc
public void onResume() {
checkItemVisibility();
+ setUpdateIntervalText();
setParallelDownloadsText(UserPreferences.getParallelDownloads());
setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize());
setDataFolderText();
@@ -502,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);
@@ -548,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();
@@ -767,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();
@@ -789,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));
@@ -798,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/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/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..0371d99bc 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -75,7 +75,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&#8230;</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 +87,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&#8230;</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 +112,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&#8230;</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 +299,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 +376,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 +405,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&#8230;</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&#8230;</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 +497,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&#8230;</string>
<!-- Content descriptions for image buttons -->
<string name="show_chapters_label">Show chapters</string>
@@ -529,7 +532,7 @@
<string name="sp_apps_importing_feeds_msg">Importing subscriptions from single-purpose apps&#8230;</string>
<string name="search_itunes_label">Search iTunes</string>
- <string name="select_label"><b>Select ...</b></string>
+ <string name="select_label"><b>Select&#8230;</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 +545,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&#8230;</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>