diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 50c70d77d..b7859cf1e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -27,10 +27,5 @@ - - - - - diff --git a/src/de/podfetcher/feed/FeedFile.java b/src/de/podfetcher/feed/FeedFile.java index 99871c9a2..fce50d08f 100644 --- a/src/de/podfetcher/feed/FeedFile.java +++ b/src/de/podfetcher/feed/FeedFile.java @@ -1,8 +1,10 @@ package de.podfetcher.feed; +/** 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 public String getFile_url() { return file_url; @@ -16,7 +18,12 @@ public abstract class FeedFile extends FeedComponent { 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; + } } diff --git a/src/de/podfetcher/service/DownloadService.java b/src/de/podfetcher/service/DownloadService.java index 34f992b74..871ca969d 100644 --- a/src/de/podfetcher/service/DownloadService.java +++ b/src/de/podfetcher/service/DownloadService.java @@ -7,6 +7,8 @@ package de.podfetcher.service; import java.io.File; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import de.podfetcher.feed.*; import de.podfetcher.storage.DownloadRequester; import android.app.Service; @@ -21,14 +23,19 @@ import android.util.Log; public class DownloadService extends Service { public static String ACTION_ALL_FEED_DOWNLOADS_COMPLETED = "action.de.podfetcher.storage.all_feed_downloads_completed"; - + public static final String ACTION_FEED_SYNC_COMPLETED = "action.de.podfetcher.service.feed_sync_completed"; + + private volatile ScheduledThreadPoolExecutor syncExecutor; private DownloadRequester requester; private FeedManager manager; @Override public void onCreate() { Log.d(this.toString(), "Service started"); - registerReceiver(receiver, createIntentFilter()); + registerReceiver(downloadReceiver, createIntentFilter()); + syncExecutor = new ScheduledThreadPoolExecutor(Runtime.getRuntime().availableProcessors() + 2); + manager = FeedManager.getInstance(); + requester = DownloadRequester.getInstance(); } @Override @@ -38,49 +45,62 @@ public class DownloadService extends Service { @Override public void onDestroy() { - unregisterReceiver(receiver); + Log.d(this.toString(), "Service shutting down"); + sendBroadcast(new Intent(ACTION_FEED_SYNC_COMPLETED)); } private IntentFilter createIntentFilter() { IntentFilter filter = new IntentFilter(); - filter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE); - return filter; } - private BroadcastReceiver receiver = new BroadcastReceiver() { + /** Shuts down Executor service and prepares for shutdown */ + private void initiateShutdown() { + Log.d(this.toString(), "Initiating shutdown"); + // Wait until PoolExecutor is done + Thread waiter = new Thread() { + @Override + public void run() { + syncExecutor.shutdown(); + try { + syncExecutor.awaitTermination(20, TimeUnit.SECONDS); + stopSelf(); + }catch(InterruptedException e) { + e.printStackTrace(); + } + } + }; + waiter.start(); + } + + private BroadcastReceiver downloadReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0); - requester = DownloadRequester.getInstance(); - manager = FeedManager.getInstance(); - Intent item_intent = requester.getItemIntent(id); - String action = item_intent.getAction(); - if(action.equals(DownloadRequester.ACTION_FEED_DOWNLOAD_COMPLETED)) { - handleCompletedFeedDownload(context, item_intent); - if(requester.getNumberOfFeedDownloads() == 0) { - sendBroadcast(new Intent(ACTION_ALL_FEED_DOWNLOADS_COMPLETED)); + long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0); + Feed feed = requester.getFeed(downloadId); + if(feed != null) { + handleCompletedFeedDownload(context, feed); + }else { + FeedImage image = requester.getFeedImage(downloadId); + if(image != null) { + handleCompletedImageDownload(context, image); } - } else if(action.equals(DownloadRequester.ACTION_MEDIA_DOWNLOAD_COMPLETED)) { - requester.removeMediaByID(item_intent.getLongExtra(DownloadRequester.EXTRA_ITEM_ID, -1)); - } else if(action.equals(DownloadRequester.ACTION_IMAGE_DOWNLOAD_COMPLETED)) { - handleCompletedImageDownload(context, item_intent); } // Check if there's something else to download, otherwise stop if(requester.getNumberOfDownloads() == 0) { - stopSelf(); + unregisterReceiver(downloadReceiver); + initiateShutdown(); } } }; /** Is called whenever a Feed is downloaded */ - private void handleCompletedFeedDownload(Context context, Intent intent) { - requester.removeFeedByID(intent.getLongExtra(DownloadRequester.EXTRA_ITEM_ID, -1)); + private void handleCompletedFeedDownload(Context context, Feed feed) { + requester.removeFeed(feed); // Get Feed Information - Feed feed = manager.getFeed(intent.getLongExtra(DownloadRequester.EXTRA_ITEM_ID, -1)); feed.setFile_url((new File(requester.getFeedfilePath(context), requester.getFeedfileName(feed.getId()))).toString()); // Update Information in Database manager.setFeed(context, feed); @@ -88,15 +108,39 @@ public class DownloadService extends Service { if(feed.getImage() != null) { requester.downloadImage(context, feed.getImage()); } - context.startService(intent); + syncExecutor.submit(new FeedSyncThread(feed, this)); } /** Is called whenever a Feed-Image is downloaded */ - private void handleCompletedImageDownload(Context context, Intent intent) { - requester.removeImageByID(intent.getLongExtra(DownloadRequester.EXTRA_ITEM_ID, -1)); - FeedImage image = manager.getFeedImage(intent.getLongExtra(DownloadRequester.EXTRA_ITEM_ID, -1)); + private void handleCompletedImageDownload(Context context, FeedImage image) { + requester.removeFeedImage(image); image.setFile_url(requester.getImagefilePath(context) + requester.getImagefileName(image.getId())); } + + /** Takes a single Feed, parses the corresponding file and refreshes information in the manager */ + class FeedSyncThread implements Runnable { + + private Feed feed; + private DownloadService service; + + public FeedSyncThread(Feed feed, DownloadService service) { + this.feed = feed; + this.service = service; + } + + public void run() { + FeedManager manager = FeedManager.getInstance(); + FeedHandler handler = new FeedHandler(); + + feed = handler.parseFeed(feed); + Log.d(this.toString(), feed.getTitle() + " parsed"); + // Add Feeditems to the database + for(FeedItem item : feed.getItems()) { + manager.addFeedItem(service, item); + } + } + + } } diff --git a/src/de/podfetcher/service/FeedSyncService.java b/src/de/podfetcher/service/FeedSyncService.java index c03e6ef69..7cb54d855 100644 --- a/src/de/podfetcher/service/FeedSyncService.java +++ b/src/de/podfetcher/service/FeedSyncService.java @@ -65,6 +65,7 @@ public class FeedSyncService extends Service { /** Prepares itself for stopping */ private void initiateShutdown() { + Log.d(this.toString(), "Initiating shutdown"); // Wait until PoolExecutor is done Thread waiter = new Thread() { @Override diff --git a/src/de/podfetcher/storage/DownloadRequester.java b/src/de/podfetcher/storage/DownloadRequester.java index 66effe92f..ac2935a8e 100644 --- a/src/de/podfetcher/storage/DownloadRequester.java +++ b/src/de/podfetcher/storage/DownloadRequester.java @@ -3,11 +3,10 @@ package de.podfetcher.storage; import java.util.ArrayList; import java.io.File; -import de.podfetcher.feed.Feed; -import de.podfetcher.feed.FeedImage; -import de.podfetcher.feed.FeedMedia; +import de.podfetcher.feed.*; import de.podfetcher.service.DownloadService; +import android.util.Log; import android.app.DownloadManager; import android.content.Context; import android.content.Intent; @@ -30,14 +29,14 @@ public class DownloadRequester { private static DownloadRequester downloader; - public ArrayList feeds; - public ArrayList images; - public ArrayList media; + public ArrayList feeds; + public ArrayList images; + public ArrayList media; private DownloadRequester(){ - feeds = new ArrayList(); - images = new ArrayList(); - media = new ArrayList(); + feeds = new ArrayList(); + images = new ArrayList(); + media = new ArrayList(); } @@ -48,89 +47,81 @@ public class DownloadRequester { return downloader; } - private void download(Context context, ArrayList type, String str_uri, File dest, boolean visibleInUI, String action, long id) { - DownloadManager.Request request = new DownloadManager.Request(Uri.parse(str_uri)); + private void download(Context context, ArrayList type, FeedFile item, File dest, boolean visibleInUI) { + DownloadManager.Request request = new DownloadManager.Request(Uri.parse(item.getDownload_url())); //request.allowScanningByMediaScanner(); request.setDestinationUri(Uri.fromFile(dest)); request.setVisibleInDownloadsUi(visibleInUI); // TODO Set Allowed Network Types DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - Intent i = new Intent(action); context.startService(new Intent(context, DownloadService.class)); - i.putExtra(EXTRA_DOWNLOAD_ID, manager.enqueue(request)); - i.putExtra(EXTRA_ITEM_ID, id); - type.add(i); + item.setDownloadId(manager.enqueue(request)); + type.add(item); } public void downloadFeed(Context context, Feed feed) { - download(context, feeds, feed.getDownload_url(), + download(context, feeds, feed, new File(getFeedfilePath(context), getFeedfileName(feed.getId())), - true, ACTION_FEED_DOWNLOAD_COMPLETED, feed.getId()); + true); } public void downloadImage(Context context, FeedImage image) { - download(context, images, image.getDownload_url(), + download(context, images, image, new File(getImagefilePath(context), getImagefileName(image.getId())), - true, ACTION_IMAGE_DOWNLOAD_COMPLETED, image.getId()); + true); } public void downloadMedia(Context context, FeedMedia feedmedia) { - download(context, media, feedmedia.getDownload_url(), + download(context, media, feedmedia, new File(context.getExternalFilesDir(MEDIA_DOWNLOADPATH), "media-" + feedmedia.getId()), - true, ACTION_MEDIA_DOWNLOAD_COMPLETED, feedmedia.getId()); + true); } - - public void removeFeedByID(long id) { - int len = feeds.size(); - for(int x = 0; x < len; x++) { - if(feeds.get(x).getLongExtra(EXTRA_ITEM_ID, -1) == id) { - feeds.remove(x); - break; - } - } - } - - public void removeMediaByID(long id) { - int len = media.size(); - for(int x = 0; x < len; x++) { - if(media.get(x).getLongExtra(EXTRA_ITEM_ID, -1) == id) { - media.remove(x); - break; - } - } - } - - public void removeImageByID(long id) { - int len = images.size(); - for(int x = 0; x < len; x++) { - if(images.get(x).getLongExtra(EXTRA_ITEM_ID, -1) == id) { - images.remove(x); - break; - } - } - } - - /* Returns the stored intent by looking for the right download id */ - public Intent getItemIntent(long id) { - for(Intent i : feeds) { - if(i.getLongExtra(EXTRA_DOWNLOAD_ID, -1) == id) { - return i; - } - } - for(Intent i : media) { - if(i.getLongExtra(EXTRA_DOWNLOAD_ID, -1) == id) { - return i; - } - } - for(Intent i : images) { - if(i.getLongExtra(EXTRA_DOWNLOAD_ID, -1) == id) { - return i; + + /** Get a Feed by its download id */ + public Feed getFeed(long id) { + for(FeedFile f: feeds) { + if(f.getDownloadId() == id) { + return (Feed) f; } } return null; } + /** Get a FeedImage by its download id */ + public FeedImage getFeedImage(long id) { + for(FeedFile f: images) { + if(f.getDownloadId() == id) { + return (FeedImage) f; + } + } + return null; + } + + + /** Get media by its download id */ + public FeedMedia getFeedMedia(long id) { + for(FeedFile f: media) { + if(f.getDownloadId() == id) { + return (FeedMedia) f; + } + } + return null; + } + + public void removeFeed(Feed f) { + feeds.remove(f); + } + + public void removeFeedMedia(FeedMedia m) { + media.remove(m); + } + + public void removeFeedImage(FeedImage fi) { + images.remove(fi); + } + + /** Get the number of uncompleted Downloads */ public int getNumberOfDownloads() { return feeds.size() + images.size() + media.size();