Split DownloadStatus into two separate classes

DownloadStatus is now used only for finished downloads, whereas
DownloadRequest is used for running/unfinished downloads
This commit is contained in:
daniel oeh 2013-05-19 17:32:15 +02:00
parent 11fb858909
commit a704a33e2b
16 changed files with 445 additions and 380 deletions

View File

@ -24,8 +24,8 @@ import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.DownloadlistAdapter;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.download.DownloadRequest;
import de.danoeh.antennapod.service.download.DownloadService;
import de.danoeh.antennapod.storage.DownloadRequester;
@ -43,7 +43,7 @@ public class DownloadActivity extends SherlockListActivity implements
private DownloadRequester requester;
private ActionMode mActionMode;
private DownloadStatus selectedDownload;
private DownloadRequest selectedDownload;
private DownloadService downloadService = null;
boolean mIsBound;
@ -159,7 +159,8 @@ public class DownloadActivity extends SherlockListActivity implements
@Override
public boolean onItemLongClick(AdapterView<?> arg0, View view,
int position, long id) {
DownloadStatus selection = dla.getItem(position).getStatus();
DownloadRequest selection = dla.getItem(position)
.getDownloadRequest();
if (selection != null && mActionMode != null) {
mActionMode.finish();
}
@ -204,7 +205,7 @@ public class DownloadActivity extends SherlockListActivity implements
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
if (!selectedDownload.isDone()) {
if (selectedDownload != null) {
TypedArray drawables = obtainStyledAttributes(new int[] { R.attr.navigation_cancel });
menu.add(Menu.NONE, R.id.cancel_download_item, Menu.NONE,
R.string.cancel_download_label).setIcon(
@ -223,7 +224,7 @@ public class DownloadActivity extends SherlockListActivity implements
boolean handled = false;
switch (item.getItemId()) {
case R.id.cancel_download_item:
requester.cancelDownload(this, selectedDownload.getFeedFile());
requester.cancelDownload(this, selectedDownload.getSource());
handled = true;
break;
}

View File

@ -21,9 +21,10 @@ import com.actionbarsherlock.app.SherlockFragmentActivity;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.download.DownloadRequest;
import de.danoeh.antennapod.service.download.DownloadStatus;
import de.danoeh.antennapod.service.download.Downloader;
import de.danoeh.antennapod.service.download.DownloaderCallback;
import de.danoeh.antennapod.service.download.HttpDownloader;
@ -45,7 +46,7 @@ import de.danoeh.antennapod.util.URLChecker;
public abstract class OnlineFeedViewActivity extends SherlockFragmentActivity {
private static final String TAG = "OnlineFeedViewActivity";
private static final String ARG_FEEDURL = "arg.feedurl";
public static final int RESULT_ERROR = 2;
private Feed feed;
@ -70,7 +71,7 @@ public abstract class OnlineFeedViewActivity extends SherlockFragmentActivity {
@Override
protected void onStop() {
super.onStop();
if (downloader != null && downloader.getStatus().isDone() == false) {
if (downloader != null && !downloader.isFinished()) {
downloader.cancel();
}
}
@ -82,7 +83,7 @@ public abstract class OnlineFeedViewActivity extends SherlockFragmentActivity {
@Override
public void run() {
DownloadStatus status = downloader.getStatus();
DownloadStatus status = downloader.getResult();
if (status != null) {
if (!status.isCancelled()) {
if (status.isSuccessful()) {
@ -119,9 +120,10 @@ public abstract class OnlineFeedViewActivity extends SherlockFragmentActivity {
FileNameGenerator.generateFileName(feed.getDownload_url()))
.toString();
feed.setFile_url(fileUrl);
DownloadStatus status = new DownloadStatus(feed, "OnlineFeed");
DownloadRequest request = new DownloadRequest(feed.getFile_url(),
feed.getDownload_url(), "OnlineFeed", 0, Feed.FEEDFILETYPE_FEED);
HttpDownloader httpDownloader = new HttpDownloader(downloaderCallback,
status);
request);
httpDownloader.start();
}
@ -217,13 +219,14 @@ public abstract class OnlineFeedViewActivity extends SherlockFragmentActivity {
} else {
builder.setMessage(R.string.error_msg_prefix);
}
builder.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setNeutralButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {

View File

@ -8,11 +8,11 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedImage;
import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.service.download.DownloadStatus;
import de.danoeh.antennapod.util.DownloadError;
/** Displays a list of DownloadStatus entries. */

View File

@ -10,11 +10,12 @@ import android.widget.ArrayAdapter;
import android.widget.ProgressBar;
import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedFile;
import de.danoeh.antennapod.feed.FeedImage;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.service.download.DownloadRequest;
import de.danoeh.antennapod.service.download.DownloadStatus;
import de.danoeh.antennapod.service.download.Downloader;
import de.danoeh.antennapod.util.Converter;
import de.danoeh.antennapod.util.ThemeUtils;
@ -33,8 +34,7 @@ public class DownloadlistAdapter extends ArrayAdapter<Downloader> {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder;
DownloadStatus status = getItem(position).getStatus();
FeedFile feedFile = status.getFeedFile();
DownloadRequest request = getItem(position).getDownloadRequest();
// Inflate layout
if (convertView == null) {
holder = new Holder();
@ -62,31 +62,16 @@ public class DownloadlistAdapter extends ArrayAdapter<Downloader> {
} else {
convertView.setBackgroundResource(0);
}
String titleText = null;
if (feedFile.getClass() == FeedMedia.class) {
titleText = ((FeedMedia) feedFile).getItem().getTitle();
} else if (feedFile.getClass() == Feed.class) {
titleText = ((Feed) feedFile).getTitle();
} else if (feedFile.getClass() == FeedImage.class) {
FeedImage image = (FeedImage) feedFile;
if (image.getFeed() != null) {
titleText = convertView.getResources().getString(
R.string.image_of_prefix)
+ image.getFeed().getTitle();
} else {
titleText = ((FeedImage) feedFile).getTitle();
}
holder.title.setText(request.getTitle());
if (request.getStatusMsg() != 0) {
holder.message.setText(request.getStatusMsg());
}
holder.title.setText(titleText);
if (status.getStatusMsg() != 0) {
holder.message.setText(status.getStatusMsg());
}
String strDownloaded = Converter.byteToString(status.getSoFar());
if (status.getSize() != DownloadStatus.SIZE_UNKNOWN) {
strDownloaded += " / " + Converter.byteToString(status.getSize());
holder.percent.setText(status.getProgressPercent() + "%");
holder.progbar.setProgress(status.getProgressPercent());
String strDownloaded = Converter.byteToString(request.getSoFar());
if (request.getSize() != DownloadStatus.SIZE_UNKNOWN) {
strDownloaded += " / " + Converter.byteToString(request.getSize());
holder.percent.setText(request.getProgressPercent() + "%");
holder.progbar.setProgress(request.getProgressPercent());
holder.percent.setVisibility(View.VISIBLE);
} else {
holder.progbar.setProgress(0);

View File

@ -25,10 +25,10 @@ import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.preferences.PlaybackPreferences;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.PlaybackService;
import de.danoeh.antennapod.service.download.DownloadStatus;
import de.danoeh.antennapod.storage.DBReader;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.storage.DownloadRequester;
@ -1400,11 +1400,6 @@ public class FeedManager {
/** Get a download status object from the download log by its FeedFile. */
public DownloadStatus getDownloadStatus(FeedFile feedFile) {
for (DownloadStatus status : downloadLog) {
if (status.getFeedFile() == feedFile) {
return status;
}
}
return null;
}

View File

@ -0,0 +1,177 @@
package de.danoeh.antennapod.service.download;
import android.os.Parcel;
import android.os.Parcelable;
public class DownloadRequest implements Parcelable {
private final String destination;
private final String source;
private final String title;
private final long feedfileId;
private final int feedfileType;
protected int progressPercent;
protected long soFar;
protected long size;
protected int statusMsg;
public DownloadRequest(String destination, String source, String title,
long feedfileId, int feedfileType) {
if (destination == null) {
throw new IllegalArgumentException("Destination must not be null");
}
if (source == null) {
throw new IllegalArgumentException("Source must not be null");
}
if (title == null) {
throw new IllegalArgumentException("Title must not be null");
}
this.destination = destination;
this.source = source;
this.title = title;
this.feedfileId = feedfileId;
this.feedfileType = feedfileType;
}
private DownloadRequest(Parcel in) {
destination = in.readString();
source = in.readString();
title = in.readString();
feedfileId = in.readLong();
feedfileType = in.readInt();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(destination);
dest.writeString(source);
dest.writeString(title);
dest.writeLong(feedfileId);
dest.writeInt(feedfileType);
}
public static final Parcelable.Creator<DownloadRequest> CREATOR = new Parcelable.Creator<DownloadRequest>() {
public DownloadRequest createFromParcel(Parcel in) {
return new DownloadRequest(in);
}
public DownloadRequest[] newArray(int size) {
return new DownloadRequest[size];
}
};
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((destination == null) ? 0 : destination.hashCode());
result = prime * result + (int) (feedfileId ^ (feedfileId >>> 32));
result = prime * result + feedfileType;
result = prime * result + progressPercent;
result = prime * result + (int) (size ^ (size >>> 32));
result = prime * result + (int) (soFar ^ (soFar >>> 32));
result = prime * result + ((source == null) ? 0 : source.hashCode());
result = prime * result + statusMsg;
result = prime * result + ((title == null) ? 0 : title.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DownloadRequest other = (DownloadRequest) obj;
if (destination == null) {
if (other.destination != null)
return false;
} else if (!destination.equals(other.destination))
return false;
if (feedfileId != other.feedfileId)
return false;
if (feedfileType != other.feedfileType)
return false;
if (progressPercent != other.progressPercent)
return false;
if (size != other.size)
return false;
if (soFar != other.soFar)
return false;
if (source == null) {
if (other.source != null)
return false;
} else if (!source.equals(other.source))
return false;
if (statusMsg != other.statusMsg)
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
return true;
}
public String getDestination() {
return destination;
}
public String getSource() {
return source;
}
public String getTitle() {
return title;
}
public long getFeedfileId() {
return feedfileId;
}
public int getFeedfileType() {
return feedfileType;
}
public int getProgressPercent() {
return progressPercent;
}
public void setProgressPercent(int progressPercent) {
this.progressPercent = progressPercent;
}
public long getSoFar() {
return soFar;
}
public void setSoFar(long soFar) {
this.soFar = soFar;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public int getStatusMsg() {
return statusMsg;
}
public void setStatusMsg(int statusMsg) {
this.statusMsg = statusMsg;
}
}

View File

@ -41,8 +41,6 @@ import android.os.AsyncTask;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.webkit.URLUtil;
@ -50,10 +48,8 @@ import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.DownloadActivity;
import de.danoeh.antennapod.activity.DownloadLogActivity;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedFile;
import de.danoeh.antennapod.feed.FeedImage;
import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedManager;
@ -257,30 +253,26 @@ public class DownloadService extends Service {
StringBuilder bigText = new StringBuilder("");
for (int i = 0; i < downloads.size(); i++) {
Downloader downloader = downloads.get(i);
if (downloader.getStatus() != null) {
FeedFile f = downloader.getStatus().getFeedFile();
if (f.getClass() == Feed.class) {
Feed feed = (Feed) f;
if (feed.getTitle() != null) {
if (i > 0) {
bigText.append("\n");
}
bigText.append("\u2022 " + feed.getTitle());
final DownloadRequest request = downloader
.getDownloadRequest();
if (request.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
if (request.getTitle() != null) {
if (i > 0) {
bigText.append("\n");
}
} else if (f.getClass() == FeedMedia.class) {
FeedMedia media = (FeedMedia) f;
if (media.getItem().getTitle() != null) {
if (i > 0) {
bigText.append("\n");
}
bigText.append("\u2022 "
+ media.getItem().getTitle()
+ " ("
+ downloader.getStatus()
.getProgressPercent() + "%)");
bigText.append("\u2022 " + request.getTitle());
}
} else if (request.getFeedfileType() == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
if (request.getTitle() != null) {
if (i > 0) {
bigText.append("\n");
}
bigText.append("\u2022 " + request.getTitle()
+ " (" + request.getProgressPercent()
+ "%)");
}
}
}
notificationBuilder.setSummaryText(downloadsLeft);
notificationBuilder.setBigContentTitle(contentTitle);
@ -301,8 +293,7 @@ public class DownloadService extends Service {
private Downloader getDownloader(String downloadUrl) {
for (Downloader downloader : downloads) {
if (downloader.getStatus().getFeedFile().getDownload_url()
.equals(downloadUrl)) {
if (downloader.getDownloadRequest().getSource().equals(downloadUrl)) {
return downloader;
}
}
@ -333,8 +324,7 @@ public class DownloadService extends Service {
for (Downloader d : downloads) {
d.cancel();
DownloadRequester.getInstance().removeDownload(
d.getStatus().getFeedFile());
d.getStatus().getFeedFile().setFile_url(null);
d.getDownloadRequest());
if (AppConfig.DEBUG)
Log.d(TAG, "Cancelled all downloads");
}
@ -350,7 +340,7 @@ public class DownloadService extends Service {
private void onDownloadQueued(Intent intent) {
if (AppConfig.DEBUG)
Log.d(TAG, "Received enqueue request");
Request request = intent.getParcelableExtra(EXTRA_REQUEST);
DownloadRequest request = intent.getParcelableExtra(EXTRA_REQUEST);
if (request == null) {
throw new IllegalArgumentException(
"ACTION_ENQUEUE_DOWNLOAD intent needs request extra");
@ -361,22 +351,13 @@ public class DownloadService extends Service {
shutdownInitiated = false;
}
DownloadRequester requester = DownloadRequester.getInstance();
FeedFile feedfile = requester.getDownload(request.source);
if (feedfile != null) {
DownloadStatus status = new DownloadStatus(feedfile,
feedfile.getHumanReadableIdentifier());
Downloader downloader = getDownloader(status);
if (downloader != null) {
downloads.add(downloader);
downloadExecutor.submit(downloader);
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
}
} else {
Log.e(TAG,
"Could not find feedfile in download requester when trying to enqueue new download");
Downloader downloader = getDownloader(request);
if (downloader != null) {
downloads.add(downloader);
downloadExecutor.submit(downloader);
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
}
queryDownloads();
}
@ -389,8 +370,8 @@ public class DownloadService extends Service {
};
private Downloader getDownloader(DownloadStatus status) {
if (URLUtil.isHttpUrl(status.getFeedFile().getDownload_url())) {
private Downloader getDownloader(DownloadRequest request) {
if (URLUtil.isHttpUrl(request.getSource())) {
return new HttpDownloader(new DownloaderCallback() {
@Override
@ -404,10 +385,11 @@ public class DownloadService extends Service {
}
});
}
}, status);
}, request);
}
Log.e(TAG, "Could not find appropriate downloader for "
+ status.getFeedFile().getDownload_url());
Log.e(TAG,
"Could not find appropriate downloader for "
+ request.getSource());
return null;
}
@ -435,31 +417,28 @@ public class DownloadService extends Service {
if (AppConfig.DEBUG)
Log.d(TAG, "Received 'Download Complete' - message.");
downloadsBeingHandled += 1;
DownloadStatus status = downloader.getStatus();
status.setCompletionDate(new Date());
DownloadStatus status = downloader.getResult();
successful = status.isSuccessful();
FeedFile download = status.getFeedFile();
if (download != null) {
if (successful) {
if (download.getClass() == Feed.class) {
handleCompletedFeedDownload(status);
} else if (download.getClass() == FeedImage.class) {
handleCompletedImageDownload(status);
} else if (download.getClass() == FeedMedia.class) {
handleCompletedFeedMediaDownload(status);
}
} else {
download.setFile_url(null);
download.setDownloaded(false);
if (!successful && !status.isCancelled()) {
Log.e(TAG, "Download failed");
saveDownloadStatus(status);
}
sendDownloadHandledIntent();
downloadsBeingHandled -= 1;
final int type = status.getFeedfileType();
if (successful) {
if (type == Feed.FEEDFILETYPE_FEED) {
handleCompletedFeedDownload(downloader
.getDownloadRequest());
} else if (type == FeedImage.FEEDFILETYPE_FEEDIMAGE) {
handleCompletedImageDownload(status, downloader.getDownloadRequest());
} else if (type == FeedMedia.FEEDFILETYPE_FEEDMEDIA) {
handleCompletedFeedMediaDownload(status, downloader.getDownloadRequest());
}
} else {
if (!successful && !status.isCancelled()) {
Log.e(TAG, "Download failed");
saveDownloadStatus(status);
}
sendDownloadHandledIntent();
downloadsBeingHandled -= 1;
}
return null;
}
};
@ -477,12 +456,11 @@ public class DownloadService extends Service {
private void removeDownload(final Downloader d) {
if (AppConfig.DEBUG)
Log.d(TAG, "Removing downloader: "
+ d.getStatus().getFeedFile().getDownload_url());
+ d.getDownloadRequest().getSource());
boolean rc = downloads.remove(d);
if (AppConfig.DEBUG)
Log.d(TAG, "Result of downloads.remove: " + rc);
DownloadRequester.getInstance().removeDownload(
d.getStatus().getFeedFile());
DownloadRequester.getInstance().removeDownload(d.getDownloadRequest());
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
}
@ -521,7 +499,7 @@ public class DownloadService extends Service {
if (status.isSuccessful()) {
successfulDownloads++;
} else if (!status.isCancelled()) {
if (status.getFeedFile().getClass() != FeedImage.class) {
if (status.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE) {
createReport = true;
}
failedDownloads++;
@ -581,25 +559,25 @@ public class DownloadService extends Service {
}
/** Is called whenever a Feed is downloaded */
private void handleCompletedFeedDownload(DownloadStatus status) {
private void handleCompletedFeedDownload(DownloadRequest request) {
if (AppConfig.DEBUG)
Log.d(TAG, "Handling completed Feed Download");
syncExecutor.execute(new FeedSyncThread(status));
syncExecutor.execute(new FeedSyncThread(request));
}
/** Is called whenever a Feed-Image is downloaded */
private void handleCompletedImageDownload(DownloadStatus status) {
private void handleCompletedImageDownload(DownloadStatus status, DownloadRequest request) {
if (AppConfig.DEBUG)
Log.d(TAG, "Handling completed Image Download");
syncExecutor.execute(new ImageHandlerThread(status));
syncExecutor.execute(new ImageHandlerThread(status, request));
}
/** Is called whenever a FeedMedia is downloaded. */
private void handleCompletedFeedMediaDownload(DownloadStatus status) {
private void handleCompletedFeedMediaDownload(DownloadStatus status, DownloadRequest request) {
if (AppConfig.DEBUG)
Log.d(TAG, "Handling completed FeedMedia Download");
syncExecutor.execute(new MediaHandlerThread(status));
syncExecutor.execute(new MediaHandlerThread(status, request));
}
/**
@ -609,25 +587,31 @@ public class DownloadService extends Service {
class FeedSyncThread implements Runnable {
private static final String TAG = "FeedSyncThread";
private Feed feed;
private DownloadStatus status;
private DownloadRequest request;
private int reason;
private boolean successful;
public FeedSyncThread(DownloadStatus status) {
this.feed = (Feed) status.getFeedFile();
this.status = status;
public FeedSyncThread(DownloadRequest request) {
if (request == null) {
throw new IllegalArgumentException("Request must not be null");
}
this.request = request;
}
public void run() {
Feed savedFeed = null;
Feed feed = new Feed(request.getSource(), new Date());
feed.setFile_url(request.getDestination());
feed.setDownloaded(true);
reason = 0;
String reasonDetailed = null;
successful = true;
final FeedManager manager = FeedManager.getInstance();
FeedHandler feedHandler = new FeedHandler();
feed.setDownloaded(true);
try {
feed = feedHandler.parseFeed(feed);
@ -751,7 +735,7 @@ public class DownloadService extends Service {
}
/** Delete files that aren't needed anymore */
private void cleanup() {
private void cleanup(Feed feed) {
if (feed.getFile_url() != null) {
if (new File(feed.getFile_url()).delete())
if (AppConfig.DEBUG)
@ -768,16 +752,29 @@ public class DownloadService extends Service {
/** Handles a completed image download. */
class ImageHandlerThread implements Runnable {
private FeedImage image;
private DownloadRequest request;
private DownloadStatus status;
public ImageHandlerThread(DownloadStatus status) {
this.image = (FeedImage) status.getFeedFile();
public ImageHandlerThread(DownloadStatus status, DownloadRequest request) {
if (status == null) {
throw new IllegalArgumentException("Status must not be null");
}
if (request == null) {
throw new IllegalArgumentException("Request must not be null");
}
this.status = status;
this.request = request;
}
@Override
public void run() {
FeedImage image = FeedManager.getInstance().getFeedImage(request.getFeedfileId());
if (image == null) {
throw new IllegalStateException("Could not find downloaded image in database");
}
image.setFile_url(request.getDestination());
image.setDownloaded(true);
saveDownloadStatus(status);
@ -803,20 +800,34 @@ public class DownloadService extends Service {
/** Handles a completed media download. */
class MediaHandlerThread implements Runnable {
private FeedMedia media;
private DownloadStatus status;
public MediaHandlerThread(DownloadStatus status) {
super();
this.media = (FeedMedia) status.getFeedFile();
private DownloadRequest request;
private DownloadStatus status;
public MediaHandlerThread(DownloadStatus status, DownloadRequest request) {
if (status == null) {
throw new IllegalArgumentException("Status must not be null");
}
if (request == null) {
throw new IllegalArgumentException("Request must not be null");
}
this.status = status;
this.request = request;
}
@Override
public void run() {
FeedMedia media = FeedManager.getInstance().getFeedMedia(
request.getFeedfileId());
if (media == null) {
throw new IllegalStateException(
"Could not find downloaded media object in database");
}
boolean chaptersRead = false;
media.setDownloaded(true);
media.setFile_url(request.getDestination());
// Get duration
MediaPlayer mediaplayer = new MediaPlayer();
try {
@ -863,53 +874,6 @@ public class DownloadService extends Service {
}
}
/** Is used to request a new download. */
public static class Request implements Parcelable {
private String destination;
private String source;
public Request(String destination, String source) {
super();
this.destination = destination;
this.source = source;
}
private Request(Parcel in) {
destination = in.readString();
source = in.readString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(destination);
dest.writeString(source);
}
public static final Parcelable.Creator<Request> CREATOR = new Parcelable.Creator<Request>() {
public Request createFromParcel(Parcel in) {
return new Request(in);
}
public Request[] newArray(int size) {
return new Request[size];
}
};
public String getDestination() {
return destination;
}
public String getSource() {
return source;
}
}
/** Schedules the notification updater task if it hasn't been scheduled yet. */
private void setupNotificationUpdater() {
if (AppConfig.DEBUG)

View File

@ -1,4 +1,4 @@
package de.danoeh.antennapod.asynctask;
package de.danoeh.antennapod.service.download;
import java.util.Date;
@ -12,10 +12,6 @@ public class DownloadStatus {
*/
public static final int SIZE_UNKNOWN = -1;
public Date getCompletionDate() {
return completionDate;
}
// ----------------------------------- ATTRIBUTES STORED IN DB
/** Unique id for storing the object in database. */
protected long id;
@ -33,7 +29,6 @@ public class DownloadStatus {
protected String reasonDetailed;
protected boolean successful;
protected Date completionDate;
protected FeedFile feedfile;
protected long feedfileId;
/**
* Is used to determine the type of the feedfile even if the feedfile does
@ -43,29 +38,13 @@ public class DownloadStatus {
protected int feedfileType;
// ------------------------------------ NOT STORED IN DB
protected int progressPercent;
protected long soFar;
protected long size;
protected int statusMsg;
protected boolean done;
protected boolean cancelled;
public DownloadStatus(FeedFile feedfile, String title) {
this.feedfile = feedfile;
if (feedfile != null) {
feedfileType = feedfile.getTypeAsInt();
}
this.title = title;
}
/** Constructor for restoring Download status entries from DB. */
public DownloadStatus(long id, String title, long feedfileId,
int feedfileType, boolean successful, int reason,
Date completionDate, String reasonDetailed) {
progressPercent = 100;
soFar = 0;
size = 0;
this.id = id;
this.title = title;
this.done = true;
@ -77,21 +56,49 @@ public class DownloadStatus {
this.feedfileType = feedfileType;
}
public DownloadStatus(DownloadRequest request, int reason,
boolean successful, boolean cancelled, String reasonDetailed) {
if (request == null) {
throw new IllegalArgumentException("request must not be null");
}
this.title = request.getTitle();
this.feedfileId = request.getFeedfileId();
this.feedfileType = request.getFeedfileType();
this.reason = reason;
this.successful = successful;
this.cancelled = cancelled;
this.reasonDetailed = reasonDetailed;
this.completionDate = new Date();
}
/** Constructor for creating new completed downloads. */
public DownloadStatus(FeedFile feedfile, String title, int reason,
boolean successful, String reasonDetailed) {
progressPercent = 100;
soFar = 0;
size = 0;
if (feedfile == null) {
throw new IllegalArgumentException("feedfile must not be null");
}
this.title = title;
this.done = true;
this.feedfile = feedfile;
this.feedfileId = feedfile.getId();
this.feedfileType = feedfile.getTypeAsInt();
this.reason = reason;
this.successful = successful;
this.completionDate = new Date();
this.reasonDetailed = reasonDetailed;
}
/** Constructor for creating new completed downloads. */
public DownloadStatus(long feedfileId, int feedfileType, String title,
int reason, boolean successful, String reasonDetailed) {
this.title = title;
this.done = true;
this.feedfileId = feedfileId;
this.feedfileType = feedfileType;
this.reason = reason;
this.successful = successful;
this.completionDate = new Date();
this.reasonDetailed = reasonDetailed;
this.feedfileType = feedfile.getTypeAsInt();
}
@Override
@ -99,115 +106,53 @@ public class DownloadStatus {
return "DownloadStatus [id=" + id + ", title=" + title + ", reason="
+ reason + ", reasonDetailed=" + reasonDetailed
+ ", successful=" + successful + ", completionDate="
+ completionDate + ", feedfile=" + feedfile + ", feedfileType="
+ feedfileType + ", progressPercent=" + progressPercent
+ ", soFar=" + soFar + ", size=" + size + ", statusMsg="
+ statusMsg + ", done=" + done + ", cancelled=" + cancelled
+ "]";
}
public FeedFile getFeedFile() {
return feedfile;
}
public int getProgressPercent() {
return progressPercent;
}
public long getSoFar() {
return soFar;
}
public long getSize() {
return size;
}
public int getStatusMsg() {
return statusMsg;
}
public int getReason() {
return reason;
}
public boolean isSuccessful() {
return successful;
+ completionDate + ", feedfileId=" + feedfileId
+ ", feedfileType=" + feedfileType + ", done=" + done
+ ", cancelled=" + cancelled + "]";
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
public String getTitle() {
return title;
}
public boolean isDone() {
return done;
}
public void setProgressPercent(int progressPercent) {
this.progressPercent = progressPercent;
}
public void setSoFar(long soFar) {
this.soFar = soFar;
}
public void setSize(long size) {
this.size = size;
}
public void setStatusMsg(int statusMsg) {
this.statusMsg = statusMsg;
}
public void setReason(int reason) {
this.reason = reason;
}
public void setSuccessful(boolean successful) {
this.successful = successful;
}
public void setDone(boolean done) {
this.done = done;
}
public void setCompletionDate(Date completionDate) {
this.completionDate = completionDate;
public int getReason() {
return reason;
}
public String getReasonDetailed() {
return reasonDetailed;
}
public void setReasonDetailed(String reasonDetailed) {
this.reasonDetailed = reasonDetailed;
public boolean isSuccessful() {
return successful;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getFeedfileType() {
return feedfileType;
public Date getCompletionDate() {
return completionDate;
}
public long getFeedfileId() {
return feedfileId;
}
public int getFeedfileType() {
return feedfileType;
}
public boolean isDone() {
return done;
}
public boolean isCancelled() {
return cancelled;
}
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
public void setId(long id) {
this.id = id;
}
}

View File

@ -1,7 +1,6 @@
package de.danoeh.antennapod.service.download;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.DownloadStatus;
/** Downloads files */
public abstract class Downloader extends Thread {
@ -12,14 +11,15 @@ public abstract class Downloader extends Thread {
protected volatile boolean cancelled;
protected volatile DownloadStatus status;
protected volatile DownloadRequest request;
protected volatile DownloadStatus result;
public Downloader(DownloaderCallback downloaderCallback,
DownloadStatus status) {
DownloadRequest request) {
super();
this.downloaderCallback = downloaderCallback;
this.status = status;
this.status.setStatusMsg(R.string.download_pending);
this.request = request;
this.request.setStatusMsg(R.string.download_pending);
this.cancelled = false;
}
@ -39,11 +39,23 @@ public abstract class Downloader extends Thread {
@Override
public final void run() {
download();
if (result == null) {
throw new IllegalStateException(
"Downloader hasn't created DownloadStatus object");
}
finish();
}
public DownloadStatus getStatus() {
return status;
public DownloadRequest getDownloadRequest() {
return request;
}
public DownloadStatus getResult() {
return result;
}
public boolean isFinished() {
return finished;
}
public void cancel() {

View File

@ -26,7 +26,6 @@ import android.util.Log;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.util.DownloadError;
import de.danoeh.antennapod.util.StorageUtils;
@ -40,8 +39,8 @@ public class HttpDownloader extends Downloader {
private static final int SOCKET_TIMEOUT = 30000;
public HttpDownloader(DownloaderCallback downloaderCallback,
DownloadStatus status) {
super(downloaderCallback, status);
DownloadRequest request) {
super(downloaderCallback, request);
}
private DefaultHttpClient createHttpClient() {
@ -66,8 +65,7 @@ public class HttpDownloader extends Downloader {
OutputStream out = null;
InputStream connection = null;
try {
HttpGet httpGet = new HttpGet(status.getFeedFile()
.getDownload_url());
HttpGet httpGet = new HttpGet(request.getSource());
httpClient = createHttpClient();
HttpResponse response = httpClient.execute(httpGet);
HttpEntity httpEntity = response.getEntity();
@ -76,8 +74,7 @@ public class HttpDownloader extends Downloader {
Log.d(TAG, "Response code is " + responseCode);
if (responseCode == HttpURLConnection.HTTP_OK && httpEntity != null) {
if (StorageUtils.storageAvailable(PodcastApp.getInstance())) {
File destination = new File(status.getFeedFile()
.getFile_url());
File destination = new File(request.getDestination());
if (!destination.exists()) {
connection = AndroidHttpClient
.getUngzippedContent(httpEntity);
@ -86,29 +83,30 @@ public class HttpDownloader extends Downloader {
destination));
byte[] buffer = new byte[BUFFER_SIZE];
int count = 0;
status.setStatusMsg(R.string.download_running);
request.setStatusMsg(R.string.download_running);
if (AppConfig.DEBUG)
Log.d(TAG, "Getting size of download");
status.setSize(httpEntity.getContentLength());
request.setSize(httpEntity.getContentLength());
if (AppConfig.DEBUG)
Log.d(TAG, "Size is " + status.getSize());
if (status.getSize() < 0) {
status.setSize(DownloadStatus.SIZE_UNKNOWN);
Log.d(TAG, "Size is " + request.getSize());
if (request.getSize() < 0) {
request.setSize(DownloadStatus.SIZE_UNKNOWN);
}
long freeSpace = StorageUtils.getFreeSpaceAvailable();
if (AppConfig.DEBUG)
Log.d(TAG, "Free space is " + freeSpace);
if (status.getSize() == DownloadStatus.SIZE_UNKNOWN
|| status.getSize() <= freeSpace) {
if (request.getSize() == DownloadStatus.SIZE_UNKNOWN
|| request.getSize() <= freeSpace) {
if (AppConfig.DEBUG)
Log.d(TAG, "Starting download");
while (!cancelled
&& (count = in.read(buffer)) != -1) {
out.write(buffer, 0, count);
status.setSoFar(status.getSoFar() + count);
status.setProgressPercent((int) (((double) status
.getSoFar() / (double) status.getSize()) * 100));
request.setSoFar(request.getSoFar() + count);
request.setProgressPercent((int) (((double) request
.getSoFar() / (double) request
.getSize()) * 100));
}
if (cancelled) {
onCancelled();
@ -144,8 +142,7 @@ public class HttpDownloader extends Downloader {
} catch (NullPointerException e) {
// might be thrown by connection.getInputStream()
e.printStackTrace();
onFail(DownloadError.ERROR_CONNECTION_ERROR, status.getFeedFile()
.getDownload_url());
onFail(DownloadError.ERROR_CONNECTION_ERROR, request.getSource());
} finally {
IOUtils.closeQuietly(connection);
IOUtils.closeQuietly(out);
@ -158,36 +155,30 @@ public class HttpDownloader extends Downloader {
private void onSuccess() {
if (AppConfig.DEBUG)
Log.d(TAG, "Download was successful");
status.setSuccessful(true);
status.setDone(true);
result = new DownloadStatus(request, 0, true, false, null);
}
private void onFail(int reason, String reasonDetailed) {
if (AppConfig.DEBUG) {
Log.d(TAG, "Download failed");
}
status.setReason(reason);
status.setReasonDetailed(reasonDetailed);
status.setDone(true);
status.setSuccessful(false);
result = new DownloadStatus(request, reason, false, false,
reasonDetailed);
cleanup();
}
private void onCancelled() {
if (AppConfig.DEBUG)
Log.d(TAG, "Download was cancelled");
status.setReason(DownloadError.ERROR_DOWNLOAD_CANCELLED);
status.setDone(true);
status.setSuccessful(false);
status.setCancelled(true);
result = new DownloadStatus(request,
DownloadError.ERROR_DOWNLOAD_CANCELLED, false, true, null);
cleanup();
}
/** Deletes unfinished downloads. */
private void cleanup() {
if (status != null && status.getFeedFile() != null
&& status.getFeedFile().getFile_url() != null) {
File dest = new File(status.getFeedFile().getFile_url());
if (request.getDestination() != null) {
File dest = new File(request.getDestination());
if (dest.exists()) {
boolean rc = dest.delete();
if (AppConfig.DEBUG)

View File

@ -10,7 +10,6 @@ import android.database.Cursor;
import android.database.SQLException;
import android.util.Log;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.feed.Chapter;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedImage;
@ -19,6 +18,7 @@ import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.feed.ID3Chapter;
import de.danoeh.antennapod.feed.SimpleChapter;
import de.danoeh.antennapod.feed.VorbisCommentChapter;
import de.danoeh.antennapod.service.download.DownloadStatus;
import de.danoeh.antennapod.util.comparator.DownloadStatusComparator;
import de.danoeh.antennapod.util.comparator.FeedItemPubdateComparator;

View File

@ -14,13 +14,13 @@ import android.database.Cursor;
import android.preference.PreferenceManager;
import android.util.Log;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.preferences.PlaybackPreferences;
import de.danoeh.antennapod.service.PlaybackService;
import de.danoeh.antennapod.service.download.DownloadStatus;
public class DBWriter {
private static final String TAG = "DBWriter";

View File

@ -5,6 +5,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import android.content.Context;
import android.content.Intent;
@ -17,6 +18,7 @@ import de.danoeh.antennapod.feed.FeedFile;
import de.danoeh.antennapod.feed.FeedImage;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.download.DownloadRequest;
import de.danoeh.antennapod.service.download.DownloadService;
import de.danoeh.antennapod.util.FileNameGenerator;
import de.danoeh.antennapod.util.URLChecker;
@ -30,10 +32,10 @@ public class DownloadRequester {
private static DownloadRequester downloader;
Map<String, FeedFile> downloads;
Map<String, DownloadRequest> downloads;
private DownloadRequester() {
downloads = new ConcurrentHashMap<String, FeedFile>();
downloads = new ConcurrentHashMap<String, DownloadRequest>();
}
public static DownloadRequester getInstance() {
@ -83,11 +85,13 @@ public class DownloadRequester {
Log.d(TAG,
"Requesting download of url " + item.getDownload_url());
item.setDownload_url(URLChecker.prepareURL(item.getDownload_url()));
item.setFile_url(dest.toString());
downloads.put(item.getDownload_url(), item);
DownloadService.Request request = new DownloadService.Request(
item.getFile_url(), item.getDownload_url());
DownloadRequest request = new DownloadRequest(item.getFile_url(),
item.getDownload_url(), item.getHumanReadableIdentifier(),
item.getId(), item.getTypeAsInt());
downloads.put(request.getSource(), request);
if (!DownloadService.isRunning) {
Intent launchIntent = new Intent(context, DownloadService.class);
@ -112,8 +116,8 @@ public class DownloadRequester {
*/
private boolean isFilenameAvailable(String path) {
for (String key : downloads.keySet()) {
FeedFile f = downloads.get(key);
if (f.getFile_url() != null && f.getFile_url().equals(path)) {
DownloadRequest r = downloads.get(key);
if (StringUtils.equals(r.getDestination(), path)) {
if (AppConfig.DEBUG)
Log.d(TAG, path
+ " is already used by another requested download");
@ -194,8 +198,8 @@ public class DownloadRequester {
/** Returns true if there is at least one Feed in the downloads queue. */
public boolean isDownloadingFeeds() {
for (FeedFile f : downloads.values()) {
if (f.getClass() == Feed.class) {
for (DownloadRequest r : downloads.values()) {
if (r.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
return true;
}
}
@ -210,7 +214,7 @@ public class DownloadRequester {
return false;
}
public FeedFile getDownload(String downloadUrl) {
public DownloadRequest getDownload(String downloadUrl) {
return downloads.get(downloadUrl);
}
@ -223,15 +227,11 @@ public class DownloadRequester {
return downloads.isEmpty();
}
public FeedFile getDownloadAt(int index) {
return downloads.get(index);
}
/** Remove an object from the downloads-list of the requester. */
public void removeDownload(FeedFile f) {
if (downloads.remove(f.getDownload_url()) == null) {
public void removeDownload(DownloadRequest r) {
if (downloads.remove(r.getSource()) == null) {
Log.e(TAG,
"Could not remove object with url " + f.getDownload_url());
"Could not remove object with url " + r.getSource());
}
}

View File

@ -14,12 +14,12 @@ import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.feed.Chapter;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedImage;
import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.service.download.DownloadStatus;
/**
* Implements methods for accessing the database
@ -456,16 +456,8 @@ public class PodDBAdapter {
* */
public long setDownloadStatus(DownloadStatus status) {
ContentValues values = new ContentValues();
if (status.getFeedFile() != null) {
values.put(KEY_FEEDFILE, status.getFeedFile().getId());
if (status.getFeedFile().getClass() == Feed.class) {
values.put(KEY_FEEDFILETYPE, Feed.FEEDFILETYPE_FEED);
} else if (status.getFeedFile().getClass() == FeedImage.class) {
values.put(KEY_FEEDFILETYPE, FeedImage.FEEDFILETYPE_FEEDIMAGE);
} else if (status.getFeedFile().getClass() == FeedMedia.class) {
values.put(KEY_FEEDFILETYPE, FeedMedia.FEEDFILETYPE_FEEDMEDIA);
}
}
values.put(KEY_FEEDFILE, status.getFeedfileId());
values.put(KEY_FEEDFILETYPE, status.getFeedfileType());
values.put(KEY_REASON, status.getReason());
values.put(KEY_SUCCESSFUL, status.isSuccessful());
values.put(KEY_COMPLETION_DATE, status.getCompletionDate().getTime());
@ -679,11 +671,11 @@ public class PodDBAdapter {
+ "=0", null, null, null, KEY_PUBDATE + " DESC");
return c;
}
public final Cursor getUnreadItemIdsCursor() {
open();
Cursor c = db.query(TABLE_NAME_FEED_ITEMS, new String[]{KEY_ID}, KEY_READ
+ "=0", null, null, null, KEY_PUBDATE + " DESC");
Cursor c = db.query(TABLE_NAME_FEED_ITEMS, new String[] { KEY_ID },
KEY_READ + "=0", null, null, null, KEY_PUBDATE + " DESC");
return c;
}

View File

@ -2,7 +2,7 @@ package de.danoeh.antennapod.util.comparator;
import java.util.Comparator;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.service.download.DownloadStatus;
/** Compares the completion date of two Downloadstatus objects. */
public class DownloadStatusComparator implements Comparator<DownloadStatus> {

View File

@ -6,8 +6,8 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.service.download.DownloadStatus;
import de.danoeh.antennapod.service.download.Downloader;
import de.danoeh.antennapod.service.download.DownloaderCallback;
import de.danoeh.antennapod.service.download.HttpDownloader;