diff options
Diffstat (limited to 'src/de/danoeh/antennapod/service/download')
6 files changed, 423 insertions, 274 deletions
diff --git a/src/de/danoeh/antennapod/service/download/APRedirectHandler.java b/src/de/danoeh/antennapod/service/download/APRedirectHandler.java index 8a31c9390..ddf8d605d 100644 --- a/src/de/danoeh/antennapod/service/download/APRedirectHandler.java +++ b/src/de/danoeh/antennapod/service/download/APRedirectHandler.java @@ -1,14 +1,13 @@ package de.danoeh.antennapod.service.download; -import java.net.URI; - +import android.util.Log; +import de.danoeh.antennapod.BuildConfig; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.impl.client.DefaultRedirectHandler; import org.apache.http.protocol.HttpContext; -import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import java.net.URI; public class APRedirectHandler extends DefaultRedirectHandler { // Identifier for logger @@ -39,12 +38,12 @@ public class APRedirectHandler extends DefaultRedirectHandler { // If anything had to be fixed, then replace the header if (!s.equals(h[0].getValue())) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Original URL: " + h[0].getValue()); response.setHeader(LOC, s); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Fixed URL: " + s); } } diff --git a/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java b/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java index 7e1c9178a..7b3f014e8 100644 --- a/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java +++ b/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java @@ -2,6 +2,7 @@ package de.danoeh.antennapod.service.download; import android.util.Log; import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import org.apache.http.client.HttpClient; import org.apache.http.client.params.HttpClientParams; import org.apache.http.conn.ClientConnectionManager; @@ -42,7 +43,7 @@ public class AntennapodHttpClient { */ public static synchronized HttpClient getHttpClient() { if (httpClient == null) { - if (AppConfig.DEBUG) Log.d(TAG, "Creating new instance of HTTP client"); + if (BuildConfig.DEBUG) Log.d(TAG, "Creating new instance of HTTP client"); HttpParams params = new BasicHttpParams(); params.setParameter(CoreProtocolPNames.USER_AGENT, AppConfig.USER_AGENT); diff --git a/src/de/danoeh/antennapod/service/download/DownloadRequest.java b/src/de/danoeh/antennapod/service/download/DownloadRequest.java index 1f4e32e1b..be22bbebb 100644 --- a/src/de/danoeh/antennapod/service/download/DownloadRequest.java +++ b/src/de/danoeh/antennapod/service/download/DownloadRequest.java @@ -5,173 +5,214 @@ 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; - } + private final String destination; + private final String source; + private final String title; + private String username; + private String password; + 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, String username, String password) { + 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; + this.username = username; + this.password = password; + } + + public DownloadRequest(String destination, String source, String title, + long feedfileId, int feedfileType) { + this(destination, source, title, feedfileId, feedfileType, null, null); + } + + private DownloadRequest(Parcel in) { + destination = in.readString(); + source = in.readString(); + title = in.readString(); + feedfileId = in.readLong(); + feedfileType = in.readInt(); + if (in.dataAvail() > 0) { + username = in.readString(); + } else { + username = null; + } + if (in.dataAvail() > 0) { + password = in.readString(); + } else { + password = null; + } + } + + @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); + if (username != null) { + dest.writeString(username); + } + if (password != null) { + dest.writeString(password); + } + } + + 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; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public void setUsername(String username) { + this.username = username; + } + + public void setPassword(String password) { + this.password = password; + } } 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(); diff --git a/src/de/danoeh/antennapod/service/download/DownloadStatus.java b/src/de/danoeh/antennapod/service/download/DownloadStatus.java index 487c3b3de..b240cddbc 100644 --- a/src/de/danoeh/antennapod/service/download/DownloadStatus.java +++ b/src/de/danoeh/antennapod/service/download/DownloadStatus.java @@ -1,10 +1,10 @@ package de.danoeh.antennapod.service.download; -import java.util.Date; - import de.danoeh.antennapod.feed.FeedFile; import de.danoeh.antennapod.util.DownloadError; +import java.util.Date; + /** Contains status attributes for one download */ public class DownloadStatus { /** diff --git a/src/de/danoeh/antennapod/service/download/HttpDownloader.java b/src/de/danoeh/antennapod/service/download/HttpDownloader.java index fc2b3178b..84bafb027 100644 --- a/src/de/danoeh/antennapod/service/download/HttpDownloader.java +++ b/src/de/danoeh/antennapod/service/download/HttpDownloader.java @@ -2,20 +2,27 @@ package de.danoeh.antennapod.service.download; import android.net.http.AndroidHttpClient; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.feed.FeedImage; import de.danoeh.antennapod.util.DownloadError; import de.danoeh.antennapod.util.StorageUtils; +import de.danoeh.antennapod.util.URIUtil; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; +import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.auth.BasicScheme; import java.io.*; -import java.net.*; +import java.net.HttpURLConnection; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; public class HttpDownloader extends Downloader { private static final String TAG = "HttpDownloader"; @@ -26,24 +33,37 @@ public class HttpDownloader extends Downloader { super(request); } - private URI getURIFromRequestUrl(String source) { - try { - URL url = new URL(source); - return new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(e); - } catch (URISyntaxException e) { - throw new IllegalArgumentException(e); - } - } - @Override protected void download() { + File destination = new File(request.getDestination()); + if (destination.exists()) { + Log.w(TAG, "File already exists"); + if (request.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE) { + onFail(DownloadError.ERROR_FILE_EXISTS, null); + return; + } else { + onSuccess(); + return; + } + } + HttpClient httpClient = AntennapodHttpClient.getHttpClient(); BufferedOutputStream out = null; InputStream connection = null; try { - HttpGet httpGet = new HttpGet(getURIFromRequestUrl(request.getSource())); + HttpGet httpGet = new HttpGet(URIUtil.getURIFromRequestUrl(request.getSource())); + String userInfo = httpGet.getURI().getUserInfo(); + if (userInfo != null) { + String[] parts = userInfo.split(":"); + if (parts.length == 2) { + httpGet.addHeader(BasicScheme.authenticate( + new UsernamePasswordCredentials(parts[0], parts[1]), + "UTF-8", false)); + } + } else if (!StringUtils.isEmpty(request.getUsername()) && request.getPassword() != null) { + httpGet.addHeader(BasicScheme.authenticate(new UsernamePasswordCredentials(request.getUsername(), + request.getPassword()), "UTF-8", false)); + } HttpResponse response = httpClient.execute(httpGet); HttpEntity httpEntity = response.getEntity(); int responseCode = response.getStatusLine().getStatusCode(); @@ -52,12 +72,20 @@ public class HttpDownloader extends Downloader { final boolean isGzip = contentEncodingHeader != null && contentEncodingHeader.getValue().equalsIgnoreCase("gzip"); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Response code is " + responseCode); if (responseCode != HttpURLConnection.HTTP_OK || httpEntity == null) { - onFail(DownloadError.ERROR_HTTP_DATA_ERROR, - String.valueOf(responseCode)); + final DownloadError error; + final String details; + if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { + error = DownloadError.ERROR_UNAUTHORIZED; + details = String.valueOf(responseCode); + } else { + error = DownloadError.ERROR_HTTP_DATA_ERROR; + details = String.valueOf(responseCode); + } + onFail(error, details); return; } @@ -66,13 +94,6 @@ public class HttpDownloader extends Downloader { return; } - File destination = new File(request.getDestination()); - if (destination.exists()) { - Log.w(TAG, "File already exists"); - onFail(DownloadError.ERROR_FILE_EXISTS, null); - return; - } - connection = new BufferedInputStream(AndroidHttpClient .getUngzippedContent(httpEntity)); out = new BufferedOutputStream(new FileOutputStream( @@ -80,17 +101,17 @@ public class HttpDownloader extends Downloader { byte[] buffer = new byte[BUFFER_SIZE]; int count = 0; request.setStatusMsg(R.string.download_running); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Getting size of download"); request.setSize(httpEntity.getContentLength()); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Size is " + request.getSize()); if (request.getSize() < 0) { request.setSize(DownloadStatus.SIZE_UNKNOWN); } long freeSpace = StorageUtils.getFreeSpaceAvailable(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Free space is " + freeSpace); if (request.getSize() != DownloadStatus.SIZE_UNKNOWN @@ -99,7 +120,7 @@ public class HttpDownloader extends Downloader { return; } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Starting download"); while (!cancelled && (count = connection.read(buffer)) != -1) { @@ -121,7 +142,8 @@ public class HttpDownloader extends Downloader { "Download completed but size: " + request.getSoFar() + " does not equal expected size " + - request.getSize()); + request.getSize() + ); return; } onSuccess(); @@ -150,13 +172,13 @@ public class HttpDownloader extends Downloader { } private void onSuccess() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Download was successful"); result.setSuccessful(); } private void onFail(DownloadError reason, String reasonDetailed) { - if (AppConfig.DEBUG) { + if (BuildConfig.DEBUG) { Log.d(TAG, "Download failed"); } result.setFailed(reason, reasonDetailed); @@ -164,7 +186,7 @@ public class HttpDownloader extends Downloader { } private void onCancelled() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Download was cancelled"); result.setCancelled(); cleanup(); @@ -178,11 +200,11 @@ public class HttpDownloader extends Downloader { File dest = new File(request.getDestination()); if (dest.exists()) { boolean rc = dest.delete(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Deleted file " + dest.getName() + "; Result: " + rc); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "cleanup() didn't delete file: does not exist."); } } |