mirror of
https://github.com/AntennaPod/AntennaPod.git
synced 2025-01-31 02:44:53 +01:00
Implemented download queueing
This commit is contained in:
parent
2f3ddfc35f
commit
1b6a35c8a0
@ -142,8 +142,7 @@ public class DownloadActivity extends SherlockListActivity implements
|
||||
boolean handled = false;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.cancel_download_item:
|
||||
requester.cancelDownload(this, selectedDownload.getFeedFile()
|
||||
.getDownloadId());
|
||||
requester.cancelDownload(this, selectedDownload.getFeedFile());
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
import de.danoeh.antennapod.feed.FeedItem;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.util.Converter;
|
||||
import de.danoeh.antennapod.R;
|
||||
import android.widget.ArrayAdapter;
|
||||
@ -121,7 +122,8 @@ public class FeedItemlistAdapter extends ArrayAdapter<FeedItem> {
|
||||
holder.downloaded.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (item.getMedia().isDownloading()) {
|
||||
if (DownloadRequester.getInstance().isDownloadingFile(
|
||||
item.getMedia())) {
|
||||
holder.downloading.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.downloading.setVisibility(View.GONE);
|
||||
|
@ -1,10 +1,9 @@
|
||||
package de.danoeh.antennapod.feed;
|
||||
|
||||
/** Represents a component of a Feed that has to be downloaded*/
|
||||
/** Represents a component of a Feed that has to be downloaded */
|
||||
public abstract class FeedFile extends FeedComponent {
|
||||
protected String file_url;
|
||||
protected String download_url;
|
||||
protected long downloadId; // temporary id given by the Android DownloadManager
|
||||
protected boolean downloaded;
|
||||
|
||||
public FeedFile(String file_url, String download_url, boolean downloaded) {
|
||||
@ -21,24 +20,19 @@ public abstract class FeedFile extends FeedComponent {
|
||||
public String getFile_url() {
|
||||
return file_url;
|
||||
}
|
||||
|
||||
public void setFile_url(String file_url) {
|
||||
this.file_url = file_url;
|
||||
}
|
||||
|
||||
public String getDownload_url() {
|
||||
return download_url;
|
||||
}
|
||||
|
||||
public void setDownload_url(String download_url) {
|
||||
this.download_url = download_url;
|
||||
}
|
||||
|
||||
public long getDownloadId() {
|
||||
return downloadId;
|
||||
}
|
||||
|
||||
public void setDownloadId(long downloadId) {
|
||||
this.downloadId = downloadId;
|
||||
}
|
||||
|
||||
public boolean isDownloaded() {
|
||||
return downloaded;
|
||||
}
|
||||
@ -46,10 +40,4 @@ public abstract class FeedFile extends FeedComponent {
|
||||
public void setDownloaded(boolean downloaded) {
|
||||
this.downloaded = downloaded;
|
||||
}
|
||||
|
||||
public boolean isDownloading() {
|
||||
return downloadId != 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -167,8 +167,7 @@ public class FeedManager {
|
||||
imageFile.delete();
|
||||
}
|
||||
} else if (requester.isDownloadingFile(feed.getImage())) {
|
||||
requester.cancelDownload(context, feed.getImage()
|
||||
.getDownloadId());
|
||||
requester.cancelDownload(context, feed.getImage());
|
||||
}
|
||||
// delete stored media files and mark them as read
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
@ -184,8 +183,7 @@ public class FeedManager {
|
||||
mediaFile.delete();
|
||||
} else if (item.getMedia() != null
|
||||
&& requester.isDownloadingFile(item.getMedia())) {
|
||||
requester.cancelDownload(context, item.getMedia()
|
||||
.getDownloadId());
|
||||
requester.cancelDownload(context, item.getMedia());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
import android.webkit.URLUtil;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Binder;
|
||||
import android.os.Debug;
|
||||
@ -71,6 +72,7 @@ public class DownloadService extends Service {
|
||||
* queryDownloads()
|
||||
*/
|
||||
public static final String ACTION_NOTIFY_DOWNLOADS_CHANGED = "action.de.danoeh.antennapod.service.notifyDownloadsChanged";
|
||||
public static final String ACTION_ENQUEUE_DOWNLOAD = "action.de.danoeh.antennapod.service.enqueueDownload";
|
||||
|
||||
public static final String ACTION_DOWNLOAD_HANDLED = "action.de.danoeh.antennapod.service.download_handled";
|
||||
/** True if handled feed has an image. */
|
||||
@ -78,6 +80,9 @@ public class DownloadService extends Service {
|
||||
public static final String EXTRA_DOWNLOAD_ID = "extra.de.danoeh.antennapod.service.download_id";
|
||||
public static final String EXTRA_IMAGE_DOWNLOAD_ID = "extra.de.danoeh.antennapod.service.image_download_id";
|
||||
|
||||
/** Extra for ACTION_ENQUEUE_DOWNLOAD intent. */
|
||||
public static final String EXTRA_REQUEST = "request";
|
||||
|
||||
// Download types for ACTION_DOWNLOAD_HANDLED
|
||||
public static final String EXTRA_DOWNLOAD_TYPE = "extra.de.danoeh.antennapod.service.downloadType";
|
||||
public static final int DOWNLOAD_TYPE_FEED = 1;
|
||||
@ -87,6 +92,8 @@ public class DownloadService extends Service {
|
||||
private ArrayList<DownloadStatus> completedDownloads;
|
||||
|
||||
private ExecutorService syncExecutor;
|
||||
private ExecutorService downloadExecutor;
|
||||
|
||||
private DownloadRequester requester;
|
||||
private FeedManager manager;
|
||||
private NotificationCompat.Builder notificationBuilder;
|
||||
@ -98,7 +105,7 @@ public class DownloadService extends Service {
|
||||
|
||||
private DownloadObserver downloadObserver;
|
||||
|
||||
private List<DownloadStatus> downloads;
|
||||
private List<Downloader> downloads;
|
||||
|
||||
private volatile boolean shutdownInitiated = false;
|
||||
/** True if service is running. */
|
||||
@ -117,10 +124,6 @@ public class DownloadService extends Service {
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (waiter != null) {
|
||||
waiter.interrupt();
|
||||
}
|
||||
queryDownloads();
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
|
||||
@ -131,10 +134,12 @@ public class DownloadService extends Service {
|
||||
Log.d(TAG, "Service started");
|
||||
isRunning = true;
|
||||
completedDownloads = new ArrayList<DownloadStatus>();
|
||||
downloads = new ArrayList<DownloadStatus>();
|
||||
downloads = new ArrayList<Downloader>();
|
||||
registerReceiver(downloadReceiver, createIntentFilter());
|
||||
registerReceiver(onDownloadsChanged, new IntentFilter(
|
||||
ACTION_NOTIFY_DOWNLOADS_CHANGED));
|
||||
registerReceiver(downloadQueued, new IntentFilter(
|
||||
ACTION_ENQUEUE_DOWNLOAD));
|
||||
syncExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
|
||||
|
||||
@Override
|
||||
@ -153,6 +158,15 @@ public class DownloadService extends Service {
|
||||
return t;
|
||||
}
|
||||
});
|
||||
downloadExecutor = Executors.newFixedThreadPool(2, new ThreadFactory() {
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
return t;
|
||||
}
|
||||
});
|
||||
manager = FeedManager.getInstance();
|
||||
requester = DownloadRequester.getInstance();
|
||||
mediaplayer = new MediaPlayer();
|
||||
@ -179,6 +193,7 @@ public class DownloadService extends Service {
|
||||
mediaplayer.release();
|
||||
unregisterReceiver(downloadReceiver);
|
||||
unregisterReceiver(onDownloadsChanged);
|
||||
unregisterReceiver(downloadQueued);
|
||||
downloadObserver.cancel(true);
|
||||
createReport();
|
||||
}
|
||||
@ -248,6 +263,47 @@ public class DownloadService extends Service {
|
||||
}
|
||||
};
|
||||
|
||||
private BroadcastReceiver downloadQueued = new BroadcastReceiver() {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(ACTION_ENQUEUE_DOWNLOAD)) {
|
||||
if (AppConfig.DEBUG) Log.d(TAG, "Received enqueue request");
|
||||
Request request = intent.getParcelableExtra(EXTRA_REQUEST);
|
||||
if (request == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"ACTION_ENQUEUE_DOWNLOAD intent needs request extra");
|
||||
}
|
||||
DownloadRequester requester = DownloadRequester.getInstance();
|
||||
FeedFile feedfile = requester.getDownload(request.source);
|
||||
if (feedfile != null) {
|
||||
if (waiter != null) {
|
||||
waiter.interrupt();
|
||||
}
|
||||
DownloadStatus status = new DownloadStatus(feedfile);
|
||||
Downloader downloader = getDownloader(status);
|
||||
if (downloader != null) {
|
||||
downloads.add(downloader);
|
||||
downloadExecutor.submit(downloader);
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG,
|
||||
"Could not find feedfile in download requester when trying to enqueue new download");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private Downloader getDownloader(DownloadStatus status) {
|
||||
if (URLUtil.isHttpUrl(status.getFeedFile().getDownload_url())) {
|
||||
return new HttpDownloader(this, status);
|
||||
}
|
||||
Log.e(TAG, "Could not find appropriate downloader for "
|
||||
+ status.getFeedFile().getDownload_url());
|
||||
return null;
|
||||
}
|
||||
|
||||
private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
@ -703,9 +759,15 @@ public class DownloadService extends Service {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public DownloadObserver getDownloadObserver() {
|
||||
return downloadObserver;
|
||||
|
@ -1,7 +1,10 @@
|
||||
package de.danoeh.antennapod.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
@ -23,27 +26,24 @@ import de.danoeh.antennapod.service.download.DownloadService;
|
||||
import de.danoeh.antennapod.util.NumberGenerator;
|
||||
import de.danoeh.antennapod.util.URLChecker;
|
||||
|
||||
public class DownloadRequester {// TODO handle externalstorage missing
|
||||
public class DownloadRequester {
|
||||
private static final String TAG = "DownloadRequester";
|
||||
private static final int currentApi = android.os.Build.VERSION.SDK_INT;
|
||||
|
||||
public static String EXTRA_DOWNLOAD_ID = "extra.de.danoeh.antennapod.storage.download_id";
|
||||
public static String EXTRA_ITEM_ID = "extra.de.danoeh.antennapod.storage.item_id";
|
||||
|
||||
public static String ACTION_DOWNLOAD_QUEUED = "action.de.danoeh.antennapod.storage.downloadQueued";
|
||||
|
||||
private static boolean STORE_ON_SD = true;
|
||||
public static String IMAGE_DOWNLOADPATH = "images/";
|
||||
public static String FEED_DOWNLOADPATH = "cache/";
|
||||
public static String MEDIA_DOWNLOADPATH = "media/";
|
||||
|
||||
private static DownloadRequester downloader;
|
||||
private DownloadManager manager;
|
||||
|
||||
private List<FeedFile> downloads;
|
||||
Map<String, FeedFile> downloads;
|
||||
|
||||
private DownloadRequester() {
|
||||
downloads = new CopyOnWriteArrayList<FeedFile>();
|
||||
downloads = new ConcurrentHashMap<String, FeedFile>();
|
||||
}
|
||||
|
||||
public static DownloadRequester getInstance() {
|
||||
@ -53,8 +53,7 @@ public class DownloadRequester {// TODO handle externalstorage missing
|
||||
return downloader;
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private long download(Context context, FeedFile item, File dest) {
|
||||
private void download(Context context, FeedFile item, File dest) {
|
||||
if (!isDownloadingFile(item)) {
|
||||
if (dest.exists()) {
|
||||
if (AppConfig.DEBUG)
|
||||
@ -64,74 +63,58 @@ public class DownloadRequester {// TODO handle externalstorage missing
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"Requesting download of url " + item.getDownload_url());
|
||||
downloads.add(item);
|
||||
downloads.put(item.getDownload_url(), item);
|
||||
item.setDownload_url(URLChecker.prepareURL(item.getDownload_url()));
|
||||
DownloadManager.Request request = new DownloadManager.Request(
|
||||
Uri.parse(item.getDownload_url())).setDestinationUri(Uri
|
||||
.fromFile(dest));
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Version is " + currentApi);
|
||||
if (currentApi >= 11) {
|
||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
|
||||
} else {
|
||||
request.setVisibleInDownloadsUi(false);
|
||||
request.setShowRunningNotification(false);
|
||||
}
|
||||
|
||||
// TODO Set Allowed Network Types
|
||||
DownloadManager manager = (DownloadManager) context
|
||||
.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
|
||||
long downloadId = manager.enqueue(request);
|
||||
item.setDownloadId(downloadId);
|
||||
item.setFile_url(dest.toString());
|
||||
context.startService(new Intent(context, DownloadService.class));
|
||||
|
||||
DownloadService.Request request = new DownloadService.Request(
|
||||
item.getFile_url(), item.getDownload_url());
|
||||
Intent queueIntent = new Intent(
|
||||
DownloadService.ACTION_ENQUEUE_DOWNLOAD);
|
||||
queueIntent.putExtra(DownloadService.EXTRA_REQUEST, request);
|
||||
if (!DownloadService.isRunning) {
|
||||
context.startService(new Intent(context, DownloadService.class));
|
||||
}
|
||||
context.sendBroadcast(queueIntent);
|
||||
context.sendBroadcast(new Intent(ACTION_DOWNLOAD_QUEUED));
|
||||
return downloadId;
|
||||
} else {
|
||||
Log.e(TAG, "URL " + item.getDownload_url()
|
||||
+ " is already being downloaded");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public long downloadFeed(Context context, Feed feed) {
|
||||
return download(context, feed, new File(getFeedfilePath(context),
|
||||
public void downloadFeed(Context context, Feed feed) {
|
||||
download(context, feed, new File(getFeedfilePath(context),
|
||||
getFeedfileName(feed)));
|
||||
}
|
||||
|
||||
public long downloadImage(Context context, FeedImage image) {
|
||||
return download(context, image, new File(getImagefilePath(context),
|
||||
public void downloadImage(Context context, FeedImage image) {
|
||||
download(context, image, new File(getImagefilePath(context),
|
||||
getImagefileName(image)));
|
||||
}
|
||||
|
||||
public long downloadMedia(Context context, FeedMedia feedmedia) {
|
||||
return download(context, feedmedia,
|
||||
public void downloadMedia(Context context, FeedMedia feedmedia) {
|
||||
download(context, feedmedia,
|
||||
new File(getMediafilePath(context, feedmedia),
|
||||
getMediafilename(feedmedia)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a running download.
|
||||
*
|
||||
* @param context
|
||||
* A context needed to get the DownloadManager service
|
||||
* @param id
|
||||
* ID of the download to cancel
|
||||
* */
|
||||
public void cancelDownload(final Context context, final long id) {
|
||||
public void cancelDownload(final Context context, final FeedFile f) {
|
||||
cancelDownload(context, f.getDownload_url());
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a running download.
|
||||
* */
|
||||
public void cancelDownload(final Context context, final String download_url) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Cancelling download with id " + id);
|
||||
DownloadManager dm = (DownloadManager) context
|
||||
.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
int removed = dm.remove(id);
|
||||
if (removed > 0) {
|
||||
FeedFile f = getFeedFile(id);
|
||||
if (f != null) {
|
||||
downloads.remove(f);
|
||||
f.setFile_url(null);
|
||||
f.setDownloadId(0);
|
||||
}
|
||||
Log.d(TAG, "Cancelling download with url " + download_url);
|
||||
FeedFile download = downloads.remove(download_url);
|
||||
if (download != null) {
|
||||
download.setFile_url(null);
|
||||
notifyDownloadService(context);
|
||||
}
|
||||
}
|
||||
@ -142,28 +125,17 @@ public class DownloadRequester {// TODO handle externalstorage missing
|
||||
Log.d(TAG, "Cancelling all running downloads");
|
||||
DownloadManager dm = (DownloadManager) context
|
||||
.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
for (FeedFile f : downloads) {
|
||||
for (FeedFile f : downloads.values()) {
|
||||
dm.remove(f.getDownloadId());
|
||||
f.setFile_url(null);
|
||||
f.setDownloadId(0);
|
||||
}
|
||||
downloads.clear();
|
||||
notifyDownloadService(context);
|
||||
}
|
||||
|
||||
/** Get a feedfile by its download id */
|
||||
public FeedFile getFeedFile(long id) {
|
||||
for (FeedFile f : downloads) {
|
||||
if (f.getDownloadId() == id) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns true if there is at least one Feed in the downloads queue. */
|
||||
public boolean isDownloadingFeeds() {
|
||||
for (FeedFile f : downloads) {
|
||||
for (FeedFile f : downloads.values()) {
|
||||
if (f.getClass() == Feed.class) {
|
||||
return true;
|
||||
}
|
||||
@ -173,22 +145,19 @@ public class DownloadRequester {// TODO handle externalstorage missing
|
||||
|
||||
/** Checks if feedfile is in the downloads list */
|
||||
public boolean isDownloadingFile(FeedFile item) {
|
||||
for (FeedFile f : downloads) {
|
||||
if (f.getDownload_url().equals(item.getDownload_url())) {
|
||||
return true;
|
||||
}
|
||||
if (item.getDownload_url() != null) {
|
||||
return downloads.containsKey(item.getDownload_url());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public FeedFile getDownload(String downloadUrl) {
|
||||
return downloads.get(downloadUrl);
|
||||
}
|
||||
|
||||
/** Checks if feedfile with the given download url is in the downloads list */
|
||||
public boolean isDownloadingFile(String downloadUrl) {
|
||||
for (FeedFile f : downloads) {
|
||||
if (f.getDownload_url().equals(downloadUrl)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return downloads.get(downloadUrl) != null;
|
||||
}
|
||||
|
||||
public boolean hasNoDownloads() {
|
||||
@ -204,10 +173,6 @@ public class DownloadRequester {// TODO handle externalstorage missing
|
||||
downloads.remove(f);
|
||||
}
|
||||
|
||||
public List<FeedFile> getDownloads() {
|
||||
return downloads;
|
||||
}
|
||||
|
||||
/** Get the number of uncompleted Downloads */
|
||||
public int getNumberOfDownloads() {
|
||||
return downloads.size();
|
||||
@ -243,6 +208,7 @@ public class DownloadRequester {// TODO handle externalstorage missing
|
||||
|
||||
/** Notifies the DownloadService to check if there are any Downloads left */
|
||||
public void notifyDownloadService(Context context) {
|
||||
context.sendBroadcast(new Intent(DownloadService.ACTION_NOTIFY_DOWNLOADS_CHANGED));
|
||||
context.sendBroadcast(new Intent(
|
||||
DownloadService.ACTION_NOTIFY_DOWNLOADS_CHANGED));
|
||||
}
|
||||
}
|
||||
|
@ -81,8 +81,7 @@ public class FeedItemMenuHandler {
|
||||
manager.deleteFeedMedia(context, selectedItem.getMedia());
|
||||
break;
|
||||
case R.id.cancel_download_item:
|
||||
requester.cancelDownload(context, selectedItem.getMedia()
|
||||
.getDownloadId());
|
||||
requester.cancelDownload(context, selectedItem.getMedia());
|
||||
break;
|
||||
case R.id.mark_read_item:
|
||||
manager.markItemRead(context, selectedItem, true);
|
||||
|
Loading…
x
Reference in New Issue
Block a user