diff options
7 files changed, 128 insertions, 114 deletions
diff --git a/src/de/danoeh/antennapod/activity/DownloadActivity.java b/src/de/danoeh/antennapod/activity/DownloadActivity.java index 4ec7a9859..566d1099d 100644 --- a/src/de/danoeh/antennapod/activity/DownloadActivity.java +++ b/src/de/danoeh/antennapod/activity/DownloadActivity.java @@ -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; } diff --git a/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java index 568768058..9dbc225d0 100644 --- a/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java @@ -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); diff --git a/src/de/danoeh/antennapod/feed/FeedFile.java b/src/de/danoeh/antennapod/feed/FeedFile.java index c7a9b7bc1..5ec52d7d2 100644 --- a/src/de/danoeh/antennapod/feed/FeedFile.java +++ b/src/de/danoeh/antennapod/feed/FeedFile.java @@ -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; - } - - } diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java index 2aab5c5de..d49e73e0c 100644 --- a/src/de/danoeh/antennapod/feed/FeedManager.java +++ b/src/de/danoeh/antennapod/feed/FeedManager.java @@ -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()); } } diff --git a/src/de/danoeh/antennapod/service/download/DownloadService.java b/src/de/danoeh/antennapod/service/download/DownloadService.java index fba955e59..db9b293d5 100644 --- a/src/de/danoeh/antennapod/service/download/DownloadService.java +++ b/src/de/danoeh/antennapod/service/download/DownloadService.java @@ -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; diff --git a/src/de/danoeh/antennapod/storage/DownloadRequester.java b/src/de/danoeh/antennapod/storage/DownloadRequester.java index ca81ed4a0..9399de465 100644 --- a/src/de/danoeh/antennapod/storage/DownloadRequester.java +++ b/src/de/danoeh/antennapod/storage/DownloadRequester.java @@ -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)); } } diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java index 24100d8c4..d88902c6f 100644 --- a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java +++ b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java @@ -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); |