From 0a9941d93d5757867851cac636d0f3b24f988414 Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Wed, 9 Sep 2015 17:13:30 +1000 Subject: [PATCH] Refactor AsyncDownloader to be an interface. The interface is used by both AsyncDownloadWrapper and AsyncDownloaderFromAndroid. --- .../fdroid/net/AsyncDownloadWrapper.java | 98 +++++++++++++++++ .../fdroid/fdroid/net/AsyncDownloader.java | 101 ++---------------- .../net/AsyncDownloaderFromAndroid.java | 3 +- .../fdroid/fdroid/net/DownloaderFactory.java | 3 +- 4 files changed, 106 insertions(+), 99 deletions(-) create mode 100644 F-Droid/src/org/fdroid/fdroid/net/AsyncDownloadWrapper.java diff --git a/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloadWrapper.java b/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloadWrapper.java new file mode 100644 index 000000000..36021300b --- /dev/null +++ b/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloadWrapper.java @@ -0,0 +1,98 @@ +package org.fdroid.fdroid.net; + +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import java.io.IOException; + +class AsyncDownloadWrapper extends Handler implements AsyncDownloader { + + private static final String TAG = "AsyncDownloadWrapper"; + + private static final int MSG_DOWNLOAD_COMPLETE = 2; + private static final int MSG_DOWNLOAD_CANCELLED = 3; + private static final int MSG_ERROR = 4; + private static final String MSG_DATA = "data"; + + private final Downloader downloader; + private DownloadThread downloadThread = null; + + private final Listener listener; + + /** + * Normally the listener would be provided using a setListener method. + * However for the purposes of this async downloader, it doesn't make + * sense to have an async task without any way to notify the outside + * world about completion. Therefore, we require the listener as a + * parameter to the constructor. + */ + public AsyncDownloadWrapper(Downloader downloader, Listener listener) { + this.downloader = downloader; + this.listener = listener; + } + + public int getBytesRead() { + return downloader.getBytesRead(); + } + + public int getTotalBytes() { + return downloader.getTotalBytes(); + } + + public void download() { + downloadThread = new DownloadThread(); + downloadThread.start(); + } + + public void attemptCancel(boolean userRequested) { + if (downloadThread != null) { + downloadThread.interrupt(); + } + } + + /** + * Receives "messages" from the download thread, and passes them onto the + * relevant {@link AsyncDownloader.Listener} + */ + public void handleMessage(Message message) { + switch (message.arg1) { + case MSG_DOWNLOAD_COMPLETE: + listener.onDownloadComplete(); + break; + case MSG_DOWNLOAD_CANCELLED: + listener.onDownloadCancelled(); + break; + case MSG_ERROR: + listener.onErrorDownloading(message.getData().getString(MSG_DATA)); + break; + } + } + + private class DownloadThread extends Thread { + + public void run() { + try { + downloader.download(); + sendMessage(MSG_DOWNLOAD_COMPLETE); + } catch (InterruptedException e) { + sendMessage(MSG_DOWNLOAD_CANCELLED); + } catch (IOException e) { + Log.e(TAG, "I/O exception in download thread", e); + Bundle data = new Bundle(1); + data.putString(MSG_DATA, e.getLocalizedMessage()); + Message message = new Message(); + message.arg1 = MSG_ERROR; + message.setData(data); + AsyncDownloadWrapper.this.sendMessage(message); + } + } + + private void sendMessage(int messageType) { + Message message = new Message(); + message.arg1 = messageType; + AsyncDownloadWrapper.this.sendMessage(message); + } + } +} diff --git a/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloader.java b/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloader.java index 2589ad709..9612ce975 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloader.java +++ b/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloader.java @@ -9,106 +9,17 @@ import org.fdroid.fdroid.ProgressListener; import java.io.IOException; -/** - * Given a {@link org.fdroid.fdroid.net.Downloader}, this wrapper will conduct the download operation on a - * separate thread. All progress/status/error/etc events will be forwarded from that thread to the thread - * that {@link AsyncDownloader#download()} was invoked on. If you want to respond with UI feedback - * to these events, it is important that you execute the download method of this class from the UI thread. - * That way, all forwarded events will be handled on that thread. - */ -@SuppressWarnings("serial") -public class AsyncDownloader extends Handler { +public interface AsyncDownloader { - private static final String TAG = "AsyncDownloadWrapper"; - - private static final int MSG_DOWNLOAD_COMPLETE = 2; - private static final int MSG_DOWNLOAD_CANCELLED = 3; - private static final int MSG_ERROR = 4; - private static final String MSG_DATA = "data"; - - private final Downloader downloader; - private final Listener listener; - private DownloadThread downloadThread = null; - - /** - * Normally the listener would be provided using a setListener method. - * However for the purposes of this async downloader, it doesn't make - * sense to have an async task without any way to notify the outside - * world about completion. Therefore, we require the listener as a - * parameter to the constructor. - */ - public AsyncDownloader(Downloader downloader, Listener listener) { - this.downloader = downloader; - this.listener = listener; - } - - public void download() { - downloadThread = new DownloadThread(); - downloadThread.start(); - } - - public void attemptCancel(boolean userRequested) { - if (downloadThread != null) { - downloadThread.interrupt(); - } - } - - /** - * Receives "messages" from the download thread, and passes them onto the - * relevant {@link AsyncDownloader.Listener} - * @param message - */ - public void handleMessage(Message message) { - switch (message.arg1) { - case MSG_DOWNLOAD_COMPLETE: - listener.onDownloadComplete(); - break; - case MSG_DOWNLOAD_CANCELLED: - listener.onDownloadCancelled(); - break; - case MSG_ERROR: - listener.onErrorDownloading(message.getData().getString(MSG_DATA)); - break; - } - } - - public int getBytesRead() { - return downloader.getBytesRead(); - } - - public int getTotalBytes() { - return downloader.getTotalBytes(); - } - - public interface Listener extends ProgressListener { + interface Listener extends ProgressListener { void onErrorDownloading(String localisedExceptionDetails); void onDownloadComplete(); void onDownloadCancelled(); } - private class DownloadThread extends Thread { + int getBytesRead(); + int getTotalBytes(); + void download(); + void attemptCancel(boolean userRequested); - public void run() { - try { - downloader.download(); - sendMessage(MSG_DOWNLOAD_COMPLETE); - } catch (InterruptedException e) { - sendMessage(MSG_DOWNLOAD_CANCELLED); - } catch (IOException e) { - Log.e(TAG, "I/O exception in download thread", e); - Bundle data = new Bundle(1); - data.putString(MSG_DATA, e.getLocalizedMessage()); - Message message = new Message(); - message.arg1 = MSG_ERROR; - message.setData(data); - AsyncDownloader.this.sendMessage(message); - } - } - - private void sendMessage(int messageType) { - Message message = new Message(); - message.arg1 = messageType; - AsyncDownloader.this.sendMessage(message); - } - } } diff --git a/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloaderFromAndroid.java b/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloaderFromAndroid.java index d75574a8a..dc839ea53 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloaderFromAndroid.java +++ b/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloaderFromAndroid.java @@ -23,7 +23,7 @@ import java.io.OutputStream; * A downloader that uses Android's DownloadManager to perform a download. */ @TargetApi(Build.VERSION_CODES.GINGERBREAD) -public class AsyncDownloaderFromAndroid extends AsyncDownloader { +public class AsyncDownloaderFromAndroid implements AsyncDownloader { private final Context context; private final DownloadManager dm; private File localFile; @@ -42,7 +42,6 @@ public class AsyncDownloaderFromAndroid extends AsyncDownloader { * parameter to the constructor. */ public AsyncDownloaderFromAndroid(Context context, Listener listener, String appName, String appId, String remoteAddress, File localFile) { - super(null, listener); this.context = context; this.appName = appName; this.appId = appId; diff --git a/F-Droid/src/org/fdroid/fdroid/net/DownloaderFactory.java b/F-Droid/src/org/fdroid/fdroid/net/DownloaderFactory.java index 575e141af..672071a82 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/DownloaderFactory.java +++ b/F-Droid/src/org/fdroid/fdroid/net/DownloaderFactory.java @@ -5,7 +5,6 @@ import android.os.Build; import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; import java.net.URL; public class DownloaderFactory { @@ -62,7 +61,7 @@ public class DownloaderFactory { if (canUseDownloadManager(url)) { return new AsyncDownloaderFromAndroid(context, listener, title, id, url.toString(), destFile); } else { - return new AsyncDownloader(create(context, url, destFile), listener); + return new AsyncDownloadWrapper(create(context, url, destFile), listener); } }