summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Hennen <TomHennen@users.noreply.github.com>2015-05-02 08:25:18 -0400
committerTom Hennen <TomHennen@users.noreply.github.com>2015-05-02 08:25:18 -0400
commit252f80de787feba0acf29cb6ca75d3128d4fbdac (patch)
treefae2382561bf1dc0991fcf7ccdd788d8564edf5c
parent68305498759df9a432019cf692676a9260512ce0 (diff)
parent8050372ba0c0d0ee9f03535866a7ddf0e7c4e744 (diff)
downloadAntennaPod-252f80de787feba0acf29cb6ca75d3128d4fbdac.zip
Merge pull request #777 from mfietz/feature/download-log-retry
Retry failed downloads in the download log
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java102
-rw-r--r--app/src/main/res/layout/downloadlog_item.xml120
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/service/download/DownloadService.java7
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/DBReader.java91
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/storage/PodDBAdapter.java8
5 files changed, 239 insertions, 89 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
index f982e86ce..f29cfdf2f 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -2,20 +2,34 @@ package de.danoeh.antennapod.adapter;
import android.content.Context;
import android.text.format.DateUtils;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import android.widget.Button;
import android.widget.TextView;
+import android.widget.Toast;
+
+import com.joanzapata.android.iconify.Iconify;
+
+import java.util.Date;
+
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.core.feed.Feed;
import de.danoeh.antennapod.core.feed.FeedImage;
import de.danoeh.antennapod.core.feed.FeedMedia;
import de.danoeh.antennapod.core.service.download.DownloadStatus;
+import de.danoeh.antennapod.core.storage.DBReader;
+import de.danoeh.antennapod.core.storage.DBTasks;
+import de.danoeh.antennapod.core.storage.DownloadRequestException;
/** Displays a list of DownloadStatus entries. */
public class DownloadLogAdapter extends BaseAdapter {
+ private final String TAG = "DownloadLogAdapter";
+
private Context context;
private ItemAccess itemAccess;
@@ -35,11 +49,11 @@ public class DownloadLogAdapter extends BaseAdapter {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.downloadlog_item, parent, false);
+ holder.icon = (TextView) convertView.findViewById(R.id.txtvIcon);
+ holder.retry = (Button) convertView.findViewById(R.id.btnRetry);
+ holder.date = (TextView) convertView.findViewById(R.id.txtvDate);
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
holder.type = (TextView) convertView.findViewById(R.id.txtvType);
- holder.date = (TextView) convertView.findViewById(R.id.txtvDate);
- holder.successful = (TextView) convertView
- .findViewById(R.id.txtvStatus);
holder.reason = (TextView) convertView
.findViewById(R.id.txtvReason);
convertView.setTag(holder);
@@ -62,33 +76,99 @@ public class DownloadLogAdapter extends BaseAdapter {
status.getCompletionDate().getTime(),
System.currentTimeMillis(), 0, 0));
if (status.isSuccessful()) {
- holder.successful.setTextColor(convertView.getResources().getColor(
+ holder.icon.setTextColor(convertView.getResources().getColor(
R.color.download_success_green));
- holder.successful.setText(R.string.download_successful);
+ holder.icon.setText("{fa-check-circle}");
+ Iconify.addIcons(holder.icon);
+ holder.retry.setVisibility(View.GONE);
holder.reason.setVisibility(View.GONE);
} else {
- holder.successful.setTextColor(convertView.getResources().getColor(
+ holder.icon.setTextColor(convertView.getResources().getColor(
R.color.download_failed_red));
- holder.successful.setText(R.string.download_failed);
+ holder.icon.setText("{fa-times-circle}");
+ Iconify.addIcons(holder.icon);
String reasonText = status.getReason().getErrorString(context);
if (status.getReasonDetailed() != null) {
reasonText += ": " + status.getReasonDetailed();
}
holder.reason.setText(reasonText);
holder.reason.setVisibility(View.VISIBLE);
+ if(status.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE &&
+ !newerWasSuccessful(position, status.getFeedfileType(), status.getFeedfileId())) {
+ holder.retry.setVisibility(View.VISIBLE);
+ holder.retry.setText("{fa-repeat}");
+ Iconify.addIcons(holder.retry);
+ holder.retry.setOnClickListener(clickListener);
+ ButtonHolder btnHolder;
+ if(holder.retry.getTag() != null) {
+ btnHolder = (ButtonHolder) holder.retry.getTag();
+ } else {
+ btnHolder = new ButtonHolder();
+ }
+ btnHolder.typeId = status.getFeedfileType();
+ btnHolder.id = status.getFeedfileId();
+ holder.retry.setTag(btnHolder);
+ } else {
+ holder.retry.setVisibility(View.GONE);
+ holder.retry.setOnClickListener(null);
+ holder.retry.setTag(null);
+ }
}
return convertView;
}
+ private final View.OnClickListener clickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ ButtonHolder holder = (ButtonHolder) v.getTag();
+ if(holder.typeId == Feed.FEEDFILETYPE_FEED) {
+ Feed feed = DBReader.getFeed(context, holder.id);
+ feed.setLastUpdate(new Date(0)); // force refresh
+ try {
+ DBTasks.refreshFeed(context, feed);
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ }
+ } else if(holder.typeId == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
+ FeedMedia media = DBReader.getFeedMedia(context, holder.id);
+ try {
+ DBTasks.downloadFeedItems(context, media.getItem());
+ Toast.makeText(context, R.string.status_downloading_label, Toast.LENGTH_SHORT).show();
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DownloadRequestErrorDialogCreator.newRequestErrorDialog(context, e.getMessage());
+ }
+ } else {
+ Log.wtf(TAG, "Unexpected type id: " + holder.typeId);
+ }
+ v.setVisibility(View.GONE);
+ }
+ };
+
+ private boolean newerWasSuccessful(int position, int feedTypeId, long id) {
+ for (int i = 0; i < position; i++) {
+ DownloadStatus status = getItem(i);
+ if (status.getFeedfileType() == feedTypeId && status.getFeedfileId() == id &&
+ status.isSuccessful()) return true;
+ }
+ return false;
+ }
+
static class Holder {
+ TextView icon;
+ Button retry;
TextView title;
TextView type;
TextView date;
- TextView successful;
TextView reason;
}
+ static class ButtonHolder {
+ int typeId;
+ long id;
+ }
+
@Override
public int getCount() {
return itemAccess.getCount();
@@ -104,9 +184,9 @@ public class DownloadLogAdapter extends BaseAdapter {
return position;
}
- public static interface ItemAccess {
- public int getCount();
- public DownloadStatus getItem(int position);
+ public interface ItemAccess {
+ int getCount();
+ DownloadStatus getItem(int position);
}
}
diff --git a/app/src/main/res/layout/downloadlog_item.xml b/app/src/main/res/layout/downloadlog_item.xml
index df1501222..c6a34a517 100644
--- a/app/src/main/res/layout/downloadlog_item.xml
+++ b/app/src/main/res/layout/downloadlog_item.xml
@@ -1,78 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
+ android:paddingTop="8dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingBottom="8dp"
tools:background="@android:color/darker_gray">
- <RelativeLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
- android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
- android:layout_marginTop="@dimen/listitem_threeline_verticalpadding">
-
- <TextView
- android:id="@+id/txtvType"
- style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="@dimen/listitem_threeline_textleftpadding"
- tools:text="Media file"
- tools:background="@android:color/holo_green_dark" />
-
- <TextView
- android:id="@+id/txtvTitle"
- style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:layout_toLeftOf="@id/txtvType"
- tools:text="Download item title"
- tools:background="@android:color/holo_blue_light" />
- </RelativeLayout>
+ <TextView
+ android:id="@+id/txtvIcon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentLeft="true"
+ android:textSize="48sp"
+ tools:text="[Icon]"
+ android:gravity="center" />
- <RelativeLayout
- android:layout_width="match_parent"
+ <Button
+ android:id="@+id/btnRetry"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
- android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
- android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding">
+ android:layout_below="@id/txtvIcon"
+ android:layout_alignLeft="@id/txtvIcon"
+ android:layout_alignRight="@id/txtvIcon"
+ android:layout_marginTop="8dp"
+ tools:text="↻" />
- <TextView
- android:id="@+id/txtvDate"
- style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_marginRight="8dp"
- tools:text="January 23"
- tools:background="@android:color/holo_green_dark" />
+ <TextView
+ android:id="@+id/txtvType"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_alignParentRight="true"
+ android:layout_marginLeft="8dp"
+ android:layout_marginBottom="8dp"
+ tools:text="Media file"
+ tools:background="@android:color/holo_green_dark" />
- <TextView
- android:id="@+id/txtvStatus"
- style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- tools:text="successful"
- tools:background="@android:color/holo_green_dark" />
+ <TextView
+ android:id="@+id/txtvTitle"
+ style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_toRightOf="@id/txtvIcon"
+ android:layout_toLeftOf="@id/txtvType"
+ android:layout_marginLeft="8dp"
+ android:layout_marginBottom="8dp"
+ android:minLines="1"
+ android:maxLines="2"
+ tools:text="Download item title"
+ tools:background="@android:color/holo_blue_light" />
- </RelativeLayout>
+ <TextView
+ android:id="@+id/txtvDate"
+ style="@style/AntennaPod.TextView.ListItemSecondaryTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/txtvIcon"
+ android:layout_below="@id/txtvTitle"
+ android:layout_marginLeft="8dp"
+ android:layout_marginBottom="8dp"
+ tools:text="January 23"
+ tools:background="@android:color/holo_green_dark" />
<TextView
android:id="@+id/txtvReason"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="@dimen/listitem_threeline_verticalpadding"
- android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
- android:layout_marginRight="@dimen/listitem_threeline_horizontalpadding"
+ android:layout_below="@id/txtvDate"
+ android:layout_toRightOf="@id/txtvIcon"
+ android:layout_marginLeft="8dp"
android:textColor="?android:attr/textColorTertiary"
android:textSize="@dimen/text_size_micro"
tools:text="@string/design_time_downloaded_log_failure_reason"
tools:background="@android:color/holo_green_dark" />
-</LinearLayout> \ No newline at end of file
+</RelativeLayout> \ No newline at end of file
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 d5f17c099..84822666c 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
@@ -939,6 +939,13 @@ public class DownloadService extends Service {
if (successful) {
+ // we create a 'successful' download log if the feed's last refresh failed
+ List<DownloadStatus> log = DBReader.getFeedDownloadLog(DownloadService.this, feed);
+ if(log.size() > 0 && log.get(0).isSuccessful() == false) {
+ saveDownloadStatus(new DownloadStatus(feed,
+ feed.getHumanReadableIdentifier(), DownloadError.SUCCESS, successful,
+ reasonDetailed));
+ }
return Pair.create(request, result);
} else {
numberOfDownloads.decrementAndGet();
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 aafe4071a..94fb6f0a7 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
@@ -327,6 +327,21 @@ public final class DBReader {
return feed;
}
+ private static DownloadStatus extractDownloadStatusFromCursorRow(final Cursor cursor) {
+ long id = cursor.getLong(PodDBAdapter.KEY_ID_INDEX);
+ long feedfileId = cursor.getLong(PodDBAdapter.KEY_FEEDFILE_INDEX);
+ int feedfileType = cursor.getInt(PodDBAdapter.KEY_FEEDFILETYPE_INDEX);
+ boolean successful = cursor.getInt(PodDBAdapter.KEY_SUCCESSFUL_INDEX) > 0;
+ int reason = cursor.getInt(PodDBAdapter.KEY_REASON_INDEX);
+ String reasonDetailed = cursor.getString(PodDBAdapter.KEY_REASON_DETAILED_INDEX);
+ String title = cursor.getString(PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE_INDEX);
+ Date completionDate = new Date(cursor.getLong(PodDBAdapter.KEY_COMPLETION_DATE_INDEX));
+
+ return new DownloadStatus(id, title, feedfileId,
+ feedfileType, successful, DownloadError.fromCode(reason), completionDate,
+ reasonDetailed);
+ }
+
private static FeedItem getMatchingItemForMedia(long itemId,
List<FeedItem> items) {
@@ -565,27 +580,7 @@ public final class DBReader {
if (logCursor.moveToFirst()) {
do {
- long id = logCursor.getLong(PodDBAdapter.KEY_ID_INDEX);
-
- long feedfileId = logCursor
- .getLong(PodDBAdapter.KEY_FEEDFILE_INDEX);
- int feedfileType = logCursor
- .getInt(PodDBAdapter.KEY_FEEDFILETYPE_INDEX);
- boolean successful = logCursor
- .getInt(PodDBAdapter.KEY_SUCCESSFUL_INDEX) > 0;
- int reason = logCursor.getInt(PodDBAdapter.KEY_REASON_INDEX);
- String reasonDetailed = logCursor
- .getString(PodDBAdapter.KEY_REASON_DETAILED_INDEX);
- String title = logCursor
- .getString(PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE_INDEX);
- Date completionDate = new Date(
- logCursor
- .getLong(PodDBAdapter.KEY_COMPLETION_DATE_INDEX)
- );
- downloadLog.add(new DownloadStatus(id, title, feedfileId,
- feedfileType, successful, DownloadError.fromCode(reason), completionDate,
- reasonDetailed));
-
+ downloadLog.add(extractDownloadStatusFromCursorRow(logCursor));
} while (logCursor.moveToNext());
}
logCursor.close();
@@ -594,6 +589,60 @@ public final class DBReader {
}
/**
+ * Loads the download log for a particular feed from the database.
+ *
+ * @param context A context that is used for opening a database connection.
+ * @param feed Feed for which the download log is loaded
+ * @return A list with DownloadStatus objects that represent the feed's download log,
+ * newest events first.
+ */
+ public static List<DownloadStatus> getFeedDownloadLog(Context context, Feed feed) {
+ Log.d(TAG, "getFeedDownloadLog(CONTEXT, " + feed.toString() + ")");
+
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ Cursor cursor = adapter.getDownloadLog(Feed.FEEDFILETYPE_FEED, feed.getId());
+ List<DownloadStatus> downloadLog = new ArrayList<DownloadStatus>(
+ cursor.getCount());
+
+ if (cursor.moveToFirst()) {
+ do {
+ downloadLog.add(extractDownloadStatusFromCursorRow(cursor));
+ } while (cursor.moveToNext());
+ }
+ cursor.close();
+ Collections.sort(downloadLog, new DownloadStatusComparator());
+ return downloadLog;
+ }
+
+ /**
+ * Loads the download log for a particular feed media from the database.
+ *
+ * @param context A context that is used for opening a database connection.
+ * @param media Feed media for which the download log is loaded
+ * @return A list with DownloadStatus objects that represent the feed media's download log,
+ * newest events first.
+ */
+ public static List<DownloadStatus> getFeedMediaDownloadLog(Context context, FeedMedia media) {
+ Log.d(TAG, "getFeedDownloadLog(CONTEXT, " + media.toString() + ")");
+
+ PodDBAdapter adapter = new PodDBAdapter(context);
+ adapter.open();
+ Cursor cursor = adapter.getDownloadLog(FeedMedia.FEEDFILETYPE_FEEDMEDIA, media.getId());
+ List<DownloadStatus> downloadLog = new ArrayList<DownloadStatus>(
+ cursor.getCount());
+
+ if (cursor.moveToFirst()) {
+ do {
+ downloadLog.add(extractDownloadStatusFromCursorRow(cursor));
+ } while (cursor.moveToNext());
+ }
+ cursor.close();
+ Collections.sort(downloadLog, new DownloadStatusComparator());
+ return downloadLog;
+ }
+
+ /**
* Loads the FeedItemStatistics objects of all Feeds in the database. This method should be preferred over
* {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.core.feed.Feed)} if only metadata about
* the FeedItems is needed.
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 229f3d034..0d680fe6f 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
@@ -977,6 +977,14 @@ public class PodDBAdapter {
return c;
}
+ public final Cursor getDownloadLog(final int feedFileType, final long feedFileId) {
+ final String query = "SELECT * FROM " + TABLE_NAME_DOWNLOAD_LOG +
+ " WHERE " + KEY_FEEDFILE + "=" + feedFileId + " AND " + KEY_FEEDFILETYPE + "=" + feedFileType
+ + " ORDER BY " + KEY_ID + " DESC";
+ Cursor c = db.rawQuery(query, null);
+ return c;
+ }
+
public final Cursor getDownloadLogCursor(final int limit) {
Cursor c = db.query(TABLE_NAME_DOWNLOAD_LOG, null, null, null, null,
null, KEY_COMPLETION_DATE + " DESC LIMIT " + limit);