diff --git a/src/org/fdroid/fdroid/AppDetails.java b/src/org/fdroid/fdroid/AppDetails.java index 5362dc2fa..cfc4b15c3 100644 --- a/src/org/fdroid/fdroid/AppDetails.java +++ b/src/org/fdroid/fdroid/AppDetails.java @@ -1073,11 +1073,16 @@ public class AppDetails extends ListActivity implements ProgressListener { pd.setMessage(getString(R.string.download_server) + ":\n " + file); pd.setCancelable(true); pd.setCanceledOnTouchOutside(false); - pd.setIndeterminate(true); // This will get overridden on the first progress event we receive. + + // The indeterminate-ness will get overridden on the first progress event we receive. + pd.setIndeterminate(true); + pd.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { downloadHandler.cancel(); + progressDialog = null; + Toast.makeText(AppDetails.this, getString(R.string.download_cancelled), Toast.LENGTH_LONG).show(); } }); pd.setButton(DialogInterface.BUTTON_NEUTRAL, @@ -1118,9 +1123,6 @@ public class AppDetails extends ListActivity implements ProgressListener { } else if (event.type.equals(ApkDownloader.EVENT_APK_DOWNLOAD_COMPLETE)) { installApk(downloadHandler.localFile(), downloadHandler.getApk().id); finished = true; - } else if (event.type.equals(ApkDownloader.EVENT_APK_DOWNLOAD_CANCELLED)) { - Toast.makeText(this, getString(R.string.download_cancelled), Toast.LENGTH_LONG).show(); - finished = true; } if (finished) { diff --git a/src/org/fdroid/fdroid/ProgressListener.java b/src/org/fdroid/fdroid/ProgressListener.java index 1b408d81d..6af2daf4b 100644 --- a/src/org/fdroid/fdroid/ProgressListener.java +++ b/src/org/fdroid/fdroid/ProgressListener.java @@ -16,7 +16,6 @@ public interface ProgressListener { public static class Event implements Parcelable { public static final int NO_VALUE = Integer.MIN_VALUE; - public static final String PROGRESS_DATA_REPO = "repo"; public final String type; public final Bundle data; diff --git a/src/org/fdroid/fdroid/net/Downloader.java b/src/org/fdroid/fdroid/net/Downloader.java index 8f28a252a..9be48bd20 100644 --- a/src/org/fdroid/fdroid/net/Downloader.java +++ b/src/org/fdroid/fdroid/net/Downloader.java @@ -128,11 +128,41 @@ public abstract class Downloader { InputStream input = null; try { input = inputStream(); + + // Getting the input stream is slow(ish) for HTTP downloads, so we'll check if + // we were interrupted before proceeding to the download. + throwExceptionIfInterrupted(); + copyInputToOutputStream(inputStream()); } finally { Utils.closeQuietly(outputStream); Utils.closeQuietly(input); } + + // Even if we have completely downloaded the file, we should probably respect + // the wishes of the user who wanted to cancel us. + throwExceptionIfInterrupted(); + } + + /** + * In a synchronous download (the usual usage of the Downloader interface), + * you will not be able to interrupt this because the thread will block + * after you have called download(). However if you use the AsyncDownloadWrapper, + * then it will use this mechanism to cancel the download. + * + * After every network operation that could take a while, we will check if an + * interrupt occured during that blocking operation. The goal is to ensure we + * don't move onto another slow, network operation if we have cancelled the + * download. + * @throws InterruptedException + */ + private void throwExceptionIfInterrupted() throws InterruptedException { + if (Thread.interrupted()) { + // TODO: Do we need to provide more information to whoever needs it, + // so they can, for example, remove any partially created files? + Log.d(TAG, "Received interrupt, cancelling download"); + throw new InterruptedException(); + } } protected void copyInputToOutputStream(InputStream input) throws IOException, InterruptedException { @@ -140,21 +170,17 @@ public abstract class Downloader { byte[] buffer = new byte[Utils.BUFFER_SIZE]; int bytesRead = 0; int totalBytes = totalDownloadSize(); + + // Getting the total download size could potentially take time, depending on how + // it is implemented, so we may as well check this before we proceed. + throwExceptionIfInterrupted(); + sendProgress(bytesRead, totalBytes); while (true) { - // In a synchronous download (the usual usage of the Downloader interface), - // you will not be able to interrupt this because the thread will block - // after you have called download(). However if you use the AsyncDownloadWrapper, - // then it will use this mechanism to cancel the download. - if (Thread.interrupted()) { - // TODO: Do we need to provide more information to whoever needs it, - // so they can, for example, remove any partially created files? - Log.d(TAG, "Received interrupt, cancelling download"); - throw new InterruptedException(); - } - int count = input.read(buffer); + throwExceptionIfInterrupted(); + bytesRead += count; sendProgress(bytesRead, totalBytes); if (count == -1) { diff --git a/src/org/fdroid/fdroid/updater/RepoUpdater.java b/src/org/fdroid/fdroid/updater/RepoUpdater.java index 40864f881..eab4291d7 100644 --- a/src/org/fdroid/fdroid/updater/RepoUpdater.java +++ b/src/org/fdroid/fdroid/updater/RepoUpdater.java @@ -94,7 +94,7 @@ abstract public class RepoUpdater { if (progressListener != null) { // interactive session, show progress Bundle data = new Bundle(1); - data.putString(PROGRESS_DATA_REPO_ADDRESS, getIndexAddress()); + data.putString(PROGRESS_DATA_REPO_ADDRESS, repo.address); downloader.setProgressListener(progressListener, data); }