diff --git a/src/org/lineageos/updater/UpdatesActivity.java b/src/org/lineageos/updater/UpdatesActivity.java index 9bfe042..4bc9c31 100644 --- a/src/org/lineageos/updater/UpdatesActivity.java +++ b/src/org/lineageos/updater/UpdatesActivity.java @@ -40,6 +40,7 @@ import org.json.JSONException; import org.lineageos.updater.controller.UpdaterController; import org.lineageos.updater.controller.UpdaterControllerInt; import org.lineageos.updater.controller.UpdaterService; +import org.lineageos.updater.download.DownloadClient; import org.lineageos.updater.misc.Constants; import org.lineageos.updater.misc.LegacySupport; import org.lineageos.updater.misc.Utils; @@ -264,8 +265,12 @@ public class UpdatesActivity extends AppCompatActivity { } }; - final DownloadClient downloadClient = - DownloadClient.downloadFile(url, jsonFileTmp, callback); + final DownloadClient downloadClient = new DownloadClient.Builder() + .setUrl(url) + .setDestination(jsonFileTmp) + .setDownloadCallback(callback) + .build(); + progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { @@ -274,6 +279,7 @@ public class UpdatesActivity extends AppCompatActivity { } }); progressDialog.show(); + downloadClient.start(); } private void showSnackBar(int stringId, int duration) { diff --git a/src/org/lineageos/updater/UpdatesCheckReceiver.java b/src/org/lineageos/updater/UpdatesCheckReceiver.java index 5406606..632fcf5 100644 --- a/src/org/lineageos/updater/UpdatesCheckReceiver.java +++ b/src/org/lineageos/updater/UpdatesCheckReceiver.java @@ -28,6 +28,7 @@ import android.support.v7.app.NotificationCompat; import android.util.Log; import org.json.JSONException; +import org.lineageos.updater.download.DownloadClient; import org.lineageos.updater.misc.Constants; import org.lineageos.updater.misc.Utils; @@ -64,7 +65,7 @@ public class UpdatesCheckReceiver extends BroadcastReceiver { final File json = Utils.getCachedUpdateList(context); final File jsonNew = new File(json.getAbsolutePath() + ".tmp"); String url = Utils.getServerURL(context); - DownloadClient.downloadFile(url, jsonNew, new DownloadClient.DownloadCallback() { + DownloadClient.DownloadCallback callback = new DownloadClient.DownloadCallback() { @Override public void onFailure(boolean cancelled) { Log.e(TAG, "Could not download updates list, scheduling new check"); @@ -91,7 +92,14 @@ public class UpdatesCheckReceiver extends BroadcastReceiver { scheduleUpdatesCheck(context); } } - }); + }; + + DownloadClient downloadClient = new DownloadClient.Builder() + .setUrl(url) + .setDestination(jsonNew) + .setDownloadCallback(callback) + .build(); + downloadClient.start(); } } diff --git a/src/org/lineageos/updater/controller/UpdaterController.java b/src/org/lineageos/updater/controller/UpdaterController.java index 987483e..c0c5d4b 100644 --- a/src/org/lineageos/updater/controller/UpdaterController.java +++ b/src/org/lineageos/updater/controller/UpdaterController.java @@ -23,10 +23,10 @@ import android.os.SystemClock; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; -import org.lineageos.updater.DownloadClient; import org.lineageos.updater.UpdateDownload; import org.lineageos.updater.UpdateStatus; import org.lineageos.updater.UpdatesDbHelper; +import org.lineageos.updater.download.DownloadClient; import org.lineageos.updater.misc.Utils; import java.io.File; @@ -345,11 +345,13 @@ public class UpdaterController implements UpdaterControllerInt { UpdateDownload update = mDownloads.get(downloadId).mUpdate; File destination = new File(mDownloadRoot, update.getName()); update.setFile(destination); - DownloadClient downloadClient = - DownloadClient.downloadFile(update.getDownloadUrl(), - update.getFile(), - getDownloadCallback(downloadId), - getProgressListener(downloadId)); + DownloadClient downloadClient = new DownloadClient.Builder() + .setUrl(update.getDownloadUrl()) + .setDestination(update.getFile()) + .setDownloadCallback(getDownloadCallback(downloadId)) + .setProgressListener(getProgressListener(downloadId)) + .build(); + downloadClient.start(); addDownloadClient(mDownloads.get(downloadId), downloadClient); update.setStatus(UpdateStatus.STARTING); notifyUpdateChange(downloadId); @@ -371,11 +373,13 @@ public class UpdaterController implements UpdaterControllerInt { verifyUpdateAsync(downloadId); notifyUpdateChange(downloadId); } else { - DownloadClient downloadClient = - DownloadClient.downloadFileResume(update.getDownloadUrl(), - update.getFile(), - getDownloadCallback(downloadId), - getProgressListener(downloadId)); + DownloadClient downloadClient = new DownloadClient.Builder() + .setUrl(update.getDownloadUrl()) + .setDestination(update.getFile()) + .setDownloadCallback(getDownloadCallback(downloadId)) + .setProgressListener(getProgressListener(downloadId)) + .build(); + downloadClient.resume(); addDownloadClient(mDownloads.get(downloadId), downloadClient); update.setStatus(UpdateStatus.STARTING); notifyUpdateChange(downloadId); diff --git a/src/org/lineageos/updater/download/DownloadClient.java b/src/org/lineageos/updater/download/DownloadClient.java new file mode 100644 index 0000000..fa437fd --- /dev/null +++ b/src/org/lineageos/updater/download/DownloadClient.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2017 The LineageOS Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lineageos.updater.download; + +import java.io.File; +import java.util.List; +import java.util.Map; + +public interface DownloadClient { + + interface DownloadCallback { + void onResponse(int statusCode, String url, Headers headers); + + void onSuccess(String body); + + void onFailure(boolean cancelled); + } + + interface ProgressListener { + void update(long bytesRead, long contentLength, long speed, long eta, boolean done); + } + + interface Headers { + String get(String name); + + Map> getAll(); + } + + void start(); + + void resume(); + + void cancel(); + + final class Builder { + private String mUrl; + private File mDestination; + private DownloadClient.DownloadCallback mCallback; + private DownloadClient.ProgressListener mProgressListener; + + public DownloadClient build() { + if (mUrl == null) { + throw new IllegalStateException("No download URL defined"); + } else if (mDestination == null) { + throw new IllegalStateException("No download destination defined"); + } else if (mCallback == null) { + throw new IllegalStateException("No download callback defined"); + } + return new OkHttpDownloadClient(mUrl, mDestination, mProgressListener, mCallback); + } + + public Builder setUrl(String url) { + mUrl = url; + return this; + } + + public Builder setDestination(File destination) { + mDestination = destination; + return this; + } + + public Builder setDownloadCallback(DownloadClient.DownloadCallback downloadCallback) { + mCallback = downloadCallback; + return this; + } + + public Builder setProgressListener(DownloadClient.ProgressListener progressListener) { + mProgressListener = progressListener; + return this; + } + } +} diff --git a/src/org/lineageos/updater/DownloadClient.java b/src/org/lineageos/updater/download/OkHttpDownloadClient.java similarity index 69% rename from src/org/lineageos/updater/DownloadClient.java rename to src/org/lineageos/updater/download/OkHttpDownloadClient.java index 00f61e5..0e57da2 100644 --- a/src/org/lineageos/updater/DownloadClient.java +++ b/src/org/lineageos/updater/download/OkHttpDownloadClient.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.lineageos.updater; +package org.lineageos.updater.download; import android.os.SystemClock; import android.util.Log; @@ -22,12 +22,12 @@ import com.android.okhttp.Callback; import com.android.okhttp.Interceptor; import com.android.okhttp.MediaType; import com.android.okhttp.OkHttpClient; +import com.android.okhttp.Request; import com.android.okhttp.Response; import com.android.okhttp.ResponseBody; -import com.android.okhttp.Request; +import com.android.okhttp.okio.Buffer; import com.android.okhttp.okio.BufferedSink; import com.android.okhttp.okio.BufferedSource; -import com.android.okhttp.okio.Buffer; import com.android.okhttp.okio.ForwardingSource; import com.android.okhttp.okio.Okio; import com.android.okhttp.okio.Source; @@ -37,71 +37,78 @@ import java.io.IOException; import java.util.List; import java.util.Map; -public class DownloadClient { +class OkHttpDownloadClient implements DownloadClient { private static final String TAG = "DownloadClient"; private final Object DOWNLOAD_TAG = new Object(); + private final OkHttpClient mClient = new OkHttpClient(); + + private final String mUrl; + private final File mDestination; + private final DownloadClient.ProgressListener mProgressListener; + private final DownloadClient.DownloadCallback mCallback; + private long mResumeOffset = 0; + + private boolean mDownloading = false; private boolean mCancelled = false; - public interface DownloadCallback { - void onResponse(int statusCode, String url, Headers headers); - void onSuccess(String body); - void onFailure(boolean cancelled); - } - - public interface ProgressListener { - void update(long bytesRead, long contentLength, long speed, long eta, boolean done); - } - - public class Headers { + public class Headers implements DownloadClient.Headers { private com.android.okhttp.Headers mHeaders; private Headers(com.android.okhttp.Headers headers) { mHeaders = headers; } + @Override public String get(String name) { return mHeaders.get(name); } + @Override public Map> getAll() { return mHeaders.toMultimap(); } } - private final OkHttpClient mClient = new OkHttpClient(); - - private long mResumeOffset = 0; - - private DownloadClient() { } - - public static void download(String url, DownloadCallback callback) { - DownloadClient downloadClient = new DownloadClient(); - downloadClient.downloadInternal(url, callback); + OkHttpDownloadClient(String url, File destination, + DownloadClient.ProgressListener progressListener, + DownloadClient.DownloadCallback callback) { + mUrl = url; + mDestination = destination; + mProgressListener = progressListener; + mCallback = callback; } - public static DownloadClient downloadFile(String url, File destination, - DownloadCallback callback, ProgressListener progressListener) { - DownloadClient downloadClient = new DownloadClient(); - downloadClient.downloadFileInternal(url, destination, callback, progressListener); - return downloadClient; + @Override + public void start() { + if (mDownloading) { + Log.e(TAG, "Already downloading"); + return; + } + mCancelled = false; + mDownloading = true; + downloadFileInternal(mCallback, mProgressListener); } - public static DownloadClient downloadFile(String url, File destination, - DownloadCallback callback) { - return downloadFile(url, destination, callback, null); - } - - public static DownloadClient downloadFileResume(String url, File destination, - DownloadCallback callback, ProgressListener progressListener) { - DownloadClient downloadClient = new DownloadClient(); - downloadClient.downloadFileResumeInternal(url, destination, callback, progressListener); - return downloadClient; + @Override + public void resume() { + if (mDownloading) { + Log.e(TAG, "Already downloading"); + return; + } + mCancelled = false; + mDownloading = true; + downloadFileResumeInternal(mCallback, mProgressListener); } public void cancel() { + if (!mDownloading) { + Log.e(TAG, "Not downloading"); + return; + } + mDownloading = false; new Thread(new Runnable() { @Override public void run() { @@ -111,57 +118,33 @@ public class DownloadClient { }).start(); } - private void downloadInternal(String url, final DownloadCallback callback) { + private void downloadFileInternal(final DownloadClient.DownloadCallback callback, + final DownloadClient.ProgressListener progressListener) { final Request request = new Request.Builder() - .url(url) - .build(); - - mClient.newCall(request).enqueue(new Callback() { - @Override - public void onFailure(Request request, IOException e) { - Log.d(TAG, "Download failed, cancelled=" + mCancelled, e); - callback.onFailure(mCancelled); - } - - @Override - public void onResponse(Response response) { - try { - callback.onResponse(response.code(), response.request().urlString(), - new Headers(response.headers())); - callback.onSuccess(response.body().string()); - } catch (IOException e) { - onFailure(request, e); - } - } - }); - } - - private void downloadFileInternal(String url, final File destination, - final DownloadCallback callback, final ProgressListener progressListener) { - final Request request = new Request.Builder() - .url(url) + .url(mUrl) .tag(DOWNLOAD_TAG) .build(); - downloadFileInternalCommon(request, destination, callback, progressListener); + downloadFileInternalCommon(request, callback, progressListener); } - private void downloadFileResumeInternal(String url, final File destination, - final DownloadCallback callback, final ProgressListener progressListener) { + private void downloadFileResumeInternal(final DownloadClient.DownloadCallback callback, + final DownloadClient.ProgressListener progressListener) { final Request.Builder requestBuilder = new Request.Builder() - .url(url) + .url(mUrl) .tag(DOWNLOAD_TAG); - long offset = destination.length(); + long offset = mDestination.length(); requestBuilder.addHeader("Range", "bytes=" + offset + "-"); final Request request = requestBuilder.build(); - downloadFileInternalCommon(request, destination, callback, progressListener); + downloadFileInternalCommon(request, callback, progressListener); } private boolean isSuccessful(int statusCode) { return (statusCode / 100) == 2; } - private void downloadFileInternalCommon(final Request request, final File destination, - final DownloadCallback callback, final ProgressListener progressListener) { + private void downloadFileInternalCommon(final Request request, + final DownloadClient.DownloadCallback callback, + final DownloadClient.ProgressListener progressListener) { mClient.networkInterceptors().add(new Interceptor() { @Override @@ -190,7 +173,7 @@ public class DownloadClient { final ResponseBody body = response.body(); final boolean resume = response.code() == 206; if (resume) { - mResumeOffset = destination.length(); + mResumeOffset = mDestination.length(); Log.d(TAG, "The server fulfilled the partial content request"); } else if (!isSuccessful(response.code())) { Log.e(TAG, "The server replied with code " + response.code()); @@ -206,7 +189,7 @@ public class DownloadClient { callback.onResponse(response.code(), response.request().urlString(), new Headers(response.headers())); try (BufferedSink sink = Okio.buffer(resume ? - Okio.appendingSink(destination) : Okio.sink(destination))) { + Okio.appendingSink(mDestination) : Okio.sink(mDestination))) { sink.writeAll(body.source()); Log.d(TAG, "Download complete"); sink.flush(); @@ -227,10 +210,11 @@ public class DownloadClient { private class ProgressResponseBody extends ResponseBody { private final ResponseBody mResponseBody; - private final ProgressListener mProgressListener; + private final DownloadClient.ProgressListener mProgressListener; private BufferedSource mBufferedSource; - ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) { + ProgressResponseBody(ResponseBody responseBody, + DownloadClient.ProgressListener progressListener) { mResponseBody = responseBody; mProgressListener = progressListener; }