summaryrefslogtreecommitdiff
path: root/src/de/danoeh/antennapod/service/download/DownloadService.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/de/danoeh/antennapod/service/download/DownloadService.java')
-rw-r--r--src/de/danoeh/antennapod/service/download/DownloadService.java210
1 files changed, 148 insertions, 62 deletions
diff --git a/src/de/danoeh/antennapod/service/download/DownloadService.java b/src/de/danoeh/antennapod/service/download/DownloadService.java
index c27b4d4fe..72e0852bb 100644
--- a/src/de/danoeh/antennapod/service/download/DownloadService.java
+++ b/src/de/danoeh/antennapod/service/download/DownloadService.java
@@ -1,20 +1,5 @@
package de.danoeh.antennapod.service.download;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.*;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-import android.media.MediaMetadataRetriever;
-import de.danoeh.antennapod.storage.*;
-import org.xml.sax.SAXException;
-
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
@@ -26,27 +11,37 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.os.AsyncTask;
+import android.media.MediaMetadataRetriever;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.webkit.URLUtil;
-import de.danoeh.antennapod.AppConfig;
+import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.DownloadActivity;
+import de.danoeh.antennapod.activity.DownloadAuthenticationActivity;
import de.danoeh.antennapod.activity.DownloadLogActivity;
-import de.danoeh.antennapod.feed.EventDistributor;
-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.feed.*;
+import de.danoeh.antennapod.storage.*;
import de.danoeh.antennapod.syndication.handler.FeedHandler;
import de.danoeh.antennapod.syndication.handler.UnsupportedFeedtypeException;
import de.danoeh.antennapod.util.ChapterUtils;
import de.danoeh.antennapod.util.DownloadError;
import de.danoeh.antennapod.util.InvalidFeedException;
+import org.apache.commons.lang3.StringUtils;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Manages the download of feedfiles in the app. Downloads can be enqueued viathe startService intent.
@@ -140,11 +135,11 @@ public class DownloadService extends Service {
@Override
public void run() {
- if (AppConfig.DEBUG) Log.d(TAG, "downloadCompletionThread was started");
+ if (BuildConfig.DEBUG) Log.d(TAG, "downloadCompletionThread was started");
while (!isInterrupted()) {
try {
Downloader downloader = downloadExecutor.take().get();
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Received 'Download Complete' - message.");
removeDownload(downloader);
DownloadStatus status = downloader.getResult();
@@ -162,21 +157,25 @@ public class DownloadService extends Service {
}
} else {
numberOfDownloads.decrementAndGet();
- if (!successful && !status.isCancelled()) {
- Log.e(TAG, "Download failed");
- saveDownloadStatus(status);
+ if (!status.isCancelled()) {
+ if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) {
+ postAuthenticationNotification(downloader.getDownloadRequest());
+ } else {
+ Log.e(TAG, "Download failed");
+ saveDownloadStatus(status);
+ }
}
sendDownloadHandledIntent();
queryDownloadsAsync();
}
} catch (InterruptedException e) {
- if (AppConfig.DEBUG) Log.d(TAG, "DownloadCompletionThread was interrupted");
+ if (BuildConfig.DEBUG) Log.d(TAG, "DownloadCompletionThread was interrupted");
} catch (ExecutionException e) {
e.printStackTrace();
numberOfDownloads.decrementAndGet();
}
}
- if (AppConfig.DEBUG) Log.d(TAG, "End of downloadCompletionThread");
+ if (BuildConfig.DEBUG) Log.d(TAG, "End of downloadCompletionThread");
}
};
@@ -193,7 +192,7 @@ public class DownloadService extends Service {
@SuppressLint("NewApi")
@Override
public void onCreate() {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Service started");
isRunning = true;
handler = new Handler();
@@ -224,7 +223,9 @@ public class DownloadService extends Service {
t.setPriority(Thread.MIN_PRIORITY);
return t;
}
- }));
+ }
+ )
+ );
schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOL_SIZE,
new ThreadFactory() {
@@ -255,7 +256,7 @@ public class DownloadService extends Service {
@Override
public void onDestroy() {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Service shutting down");
isRunning = false;
updateReport();
@@ -274,8 +275,9 @@ public class DownloadService extends Service {
@SuppressLint("NewApi")
private void setupNotificationBuilders() {
PendingIntent pIntent = PendingIntent.getActivity(this, 0, new Intent(
- this, DownloadActivity.class),
- PendingIntent.FLAG_UPDATE_CURRENT);
+ this, DownloadActivity.class),
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
Bitmap icon = BitmapFactory.decodeResource(getResources(),
R.drawable.stat_notify_sync);
@@ -284,14 +286,15 @@ public class DownloadService extends Service {
notificationBuilder = new Notification.BigTextStyle(
new Notification.Builder(this).setOngoing(true)
.setContentIntent(pIntent).setLargeIcon(icon)
- .setSmallIcon(R.drawable.stat_notify_sync));
+ .setSmallIcon(R.drawable.stat_notify_sync)
+ );
} else {
notificationCompatBuilder = new NotificationCompat.Builder(this)
.setOngoing(true).setContentIntent(pIntent)
.setLargeIcon(icon)
.setSmallIcon(R.drawable.stat_notify_sync);
}
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Notification set up");
}
@@ -368,7 +371,7 @@ public class DownloadService extends Service {
throw new IllegalArgumentException(
"ACTION_CANCEL_DOWNLOAD intent needs download url extra");
}
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Cancelling download with url " + url);
Downloader d = getDownloader(url);
if (d != null) {
@@ -380,7 +383,7 @@ public class DownloadService extends Service {
} else if (intent.getAction().equals(ACTION_CANCEL_ALL_DOWNLOADS)) {
for (Downloader d : downloads) {
d.cancel();
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Cancelled all downloads");
}
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
@@ -392,7 +395,7 @@ public class DownloadService extends Service {
};
private void onDownloadQueued(Intent intent) {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Received enqueue request");
DownloadRequest request = intent.getParcelableExtra(EXTRA_REQUEST);
if (request == null) {
@@ -413,12 +416,13 @@ public class DownloadService extends Service {
private Downloader getDownloader(DownloadRequest request) {
if (URLUtil.isHttpUrl(request.getSource())
- || URLUtil.isHttpsUrl(request.getSource())) {
+ || URLUtil.isHttpsUrl(request.getSource())) {
return new HttpDownloader(request);
}
Log.e(TAG,
"Could not find appropriate downloader for "
- + request.getSource());
+ + request.getSource()
+ );
return null;
}
@@ -430,11 +434,11 @@ public class DownloadService extends Service {
handler.post(new Runnable() {
@Override
public void run() {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Removing downloader: "
+ d.getDownloadRequest().getSource());
boolean rc = downloads.remove(d);
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Result of downloads.remove: " + rc);
DownloadRequester.getInstance().removeDownload(d.getDownloadRequest());
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
@@ -484,7 +488,7 @@ public class DownloadService extends Service {
}
if (createReport) {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Creating report");
// create notification object
Notification notification = new NotificationCompat.Builder(this)
@@ -495,19 +499,22 @@ public class DownloadService extends Service {
.setContentText(
String.format(
getString(R.string.download_report_content),
- successfulDownloads, failedDownloads))
+ successfulDownloads, failedDownloads)
+ )
.setSmallIcon(R.drawable.stat_notify_sync)
.setLargeIcon(
BitmapFactory.decodeResource(getResources(),
- R.drawable.stat_notify_sync))
+ R.drawable.stat_notify_sync)
+ )
.setContentIntent(
PendingIntent.getActivity(this, 0, new Intent(this,
- DownloadLogActivity.class), 0))
+ DownloadLogActivity.class), 0)
+ )
.setAutoCancel(true).getNotification();
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(REPORT_ID, notification);
} else {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "No report is created");
}
completedDownloads.clear();
@@ -530,12 +537,12 @@ public class DownloadService extends Service {
* Check if there's something else to download, otherwise stop
*/
void queryDownloads() {
- if (AppConfig.DEBUG) {
+ if (BuildConfig.DEBUG) {
Log.d(TAG, numberOfDownloads.get() + " downloads left");
}
if (numberOfDownloads.get() <= 0 && DownloadRequester.getInstance().hasNoDownloads()) {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Number of downloads is " + numberOfDownloads.get() + ", attempting shutdown");
stopSelf();
} else {
@@ -544,11 +551,40 @@ public class DownloadService extends Service {
}
}
+ private void postAuthenticationNotification(final DownloadRequest downloadRequest) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ final String resourceTitle = (downloadRequest.getTitle() != null)
+ ? downloadRequest.getTitle() : downloadRequest.getSource();
+
+ final Intent activityIntent = new Intent(getApplicationContext(), DownloadAuthenticationActivity.class);
+ activityIntent.putExtra(DownloadAuthenticationActivity.ARG_DOWNLOAD_REQUEST, downloadRequest);
+ activityIntent.putExtra(DownloadAuthenticationActivity.ARG_SEND_TO_DOWNLOAD_REQUESTER_BOOL, true);
+ final PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, activityIntent, PendingIntent.FLAG_ONE_SHOT);
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(DownloadService.this);
+ builder.setTicker(getText(R.string.authentication_notification_title))
+ .setContentTitle(getText(R.string.authentication_notification_title))
+ .setContentText(getText(R.string.authentication_notification_msg))
+ .setStyle(new NotificationCompat.BigTextStyle().bigText(getText(R.string.authentication_notification_msg)
+ + ": " + resourceTitle))
+ .setSmallIcon(R.drawable.ic_stat_authentication)
+ .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_stat_authentication))
+ .setAutoCancel(true)
+ .setContentIntent(contentIntent);
+ Notification n = builder.build();
+ NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ nm.notify(downloadRequest.getSource().hashCode(), n);
+ }
+ });
+ }
+
/**
* Is called whenever a Feed is downloaded
*/
private void handleCompletedFeedDownload(DownloadRequest request) {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Handling completed Feed Download");
syncExecutor.execute(new FeedSyncThread(request));
@@ -558,7 +594,7 @@ public class DownloadService extends Service {
* Is called whenever a Feed-Image is downloaded
*/
private void handleCompletedImageDownload(DownloadStatus status, DownloadRequest request) {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Handling completed Image Download");
syncExecutor.execute(new ImageHandlerThread(status, request));
}
@@ -567,7 +603,7 @@ public class DownloadService extends Service {
* Is called whenever a FeedMedia is downloaded.
*/
private void handleCompletedFeedMediaDownload(DownloadStatus status, DownloadRequest request) {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Handling completed FeedMedia Download");
syncExecutor.execute(new MediaHandlerThread(status, request));
}
@@ -598,6 +634,7 @@ public class DownloadService extends Service {
Feed feed = new Feed(request.getSource(), new Date());
feed.setFile_url(request.getDestination());
feed.setDownloaded(true);
+ feed.setPreferences(new FeedPreferences(0, true, request.getUsername(), request.getPassword()));
reason = null;
String reasonDetailed = null;
@@ -606,19 +643,22 @@ public class DownloadService extends Service {
try {
feed = feedHandler.parseFeed(feed);
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, feed.getTitle() + " parsed");
if (checkFeedData(feed) == false) {
throw new InvalidFeedException();
}
+
+ removeDuplicateImages(feed); // duplicate images have to removed because the DownloadRequester does not accept two downloads with the same download URL yet.
+
// Save information of feed in DB
savedFeed = DBTasks.updateFeed(DownloadService.this, feed);
// Download Feed Image if provided and not downloaded
if (savedFeed.getImage() != null
&& savedFeed.getImage().isDownloaded() == false) {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Feed has image; Downloading....");
- savedFeed.getImage().setFeed(savedFeed);
+ savedFeed.getImage().setOwner(savedFeed);
final Feed savedFeedRef = savedFeed;
try {
requester.downloadImage(DownloadService.this,
@@ -633,9 +673,36 @@ public class DownloadService extends Service {
.getImage()
.getHumanReadableIdentifier(),
DownloadError.ERROR_REQUEST_ERROR,
- false, e.getMessage()));
+ false, e.getMessage()
+ )
+ );
}
}
+ // download FeedItem images if provided and not downloaded
+ for (FeedItem item : savedFeed.getItems()) {
+ if (item.hasItemImage() && (!item.getImage().isDownloaded())) {
+ if (BuildConfig.DEBUG)
+ Log.d(TAG, "Item has image; Downloading....");
+ try {
+ requester.downloadImage(DownloadService.this,
+ item.getImage());
+ } catch (DownloadRequestException e) {
+ e.printStackTrace();
+ DBWriter.addDownloadStatus(
+ DownloadService.this,
+ new DownloadStatus(
+ item.getImage(),
+ item
+ .getImage()
+ .getHumanReadableIdentifier(),
+ DownloadError.ERROR_REQUEST_ERROR,
+ false, e.getMessage()
+ )
+ );
+ }
+ }
+ }
+
} catch (SAXException e) {
successful = false;
@@ -689,10 +756,29 @@ public class DownloadService extends Service {
Log.e(TAG, "Feed has invalid items");
return false;
}
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Feed appears to be valid.");
return true;
+ }
+ /**
+ * Checks if the FeedItems of this feed have images that point
+ * to the same URL. If two FeedItems have an image that points to
+ * the same URL, the reference of the second item is removed, so that every image
+ * reference is unique.
+ */
+ private void removeDuplicateImages(Feed feed) {
+ for (int x = 0; x < feed.getItems().size(); x++) {
+ for (int y = x + 1; y < feed.getItems().size(); y++) {
+ FeedItem item1 = feed.getItems().get(x);
+ FeedItem item2 = feed.getItems().get(y);
+ if (item1.hasItemImage() && item2.hasItemImage()) {
+ if (StringUtils.equals(item1.getImage().getDownload_url(), item2.getImage().getDownload_url())) {
+ item2.setImage(null);
+ }
+ }
+ }
+ }
}
private boolean hasValidFeedItems(Feed feed) {
@@ -719,12 +805,12 @@ public class DownloadService extends Service {
private void cleanup(Feed feed) {
if (feed.getFile_url() != null) {
if (new File(feed.getFile_url()).delete())
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Successfully deleted cache file.");
else
Log.e(TAG, "Failed to delete cache file.");
feed.setFile_url(null);
- } else if (AppConfig.DEBUG) {
+ } else if (BuildConfig.DEBUG) {
Log.d(TAG, "Didn't delete cache file: File url is not set.");
}
}
@@ -807,7 +893,7 @@ public class DownloadService extends Service {
mmr.setDataSource(media.getFile_url());
String durationStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
media.setDuration(Integer.parseInt(durationStr));
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Duration of file is " + media.getDuration());
} catch (NumberFormatException e) {
e.printStackTrace();
@@ -854,7 +940,7 @@ public class DownloadService extends Service {
* Schedules the notification updater task if it hasn't been scheduled yet.
*/
private void setupNotificationUpdater() {
- if (AppConfig.DEBUG)
+ if (BuildConfig.DEBUG)
Log.d(TAG, "Setting up notification updater");
if (notificationUpdater == null) {
notificationUpdater = new NotificationUpdater();