replace Downloader's ProgressListener with local broadcasts

This removes lots of boiler plate, makes it much easier to get the info
where it is needed, and puts the code in line with rest of FDroid. The
ProgressListener pattern was forcing a lot of passing the listener
instances around through classes that never used the listener even.
This commit is contained in:
Hans-Christoph Steiner 2015-06-19 18:03:37 -04:00
parent e984ed82ef
commit 7d48ad736c
6 changed files with 73 additions and 71 deletions

View File

@ -24,10 +24,12 @@ import android.app.Activity;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
@ -40,6 +42,7 @@ import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
import android.support.v4.app.NavUtils;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AlertDialog;
@ -316,6 +319,7 @@ public class AppDetails extends ActionBarActivity implements ProgressListener, A
private App app;
private PackageManager mPm;
private ApkDownloader downloadHandler;
private LocalBroadcastManager localBroadcastManager;
private boolean startingIgnoreAll;
private int startingIgnoreThis;
@ -425,6 +429,7 @@ public class AppDetails extends ActionBarActivity implements ProgressListener, A
// progress indicator after returning from that prompt).
setSupportProgressBarIndeterminateVisibility(false);
localBroadcastManager = LocalBroadcastManager.getInstance(this);
}
// The signature of the installed version.
@ -449,6 +454,8 @@ public class AppDetails extends ActionBarActivity implements ProgressListener, A
if (downloadHandler.isComplete()) {
downloadCompleteInstallApk();
} else {
localBroadcastManager.registerReceiver(downloaderProgressReceiver,
new IntentFilter(Downloader.LOCAL_ACTION_PROGRESS));
downloadHandler.setProgressListener(this);
// Show the progress dialog, if for no other reason than to prevent them attempting
@ -504,6 +511,7 @@ public class AppDetails extends ActionBarActivity implements ProgressListener, A
setIgnoreUpdates(app.id, app.ignoreAllUpdates, app.ignoreThisUpdate);
}
localBroadcastManager.unregisterReceiver(downloaderProgressReceiver);
if (downloadHandler != null) {
downloadHandler.removeProgressListener();
}
@ -511,6 +519,14 @@ public class AppDetails extends ActionBarActivity implements ProgressListener, A
removeProgressDialog();
}
private final BroadcastReceiver downloaderProgressReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateProgressDialog(intent.getIntExtra(Downloader.EXTRA_BYTES_READ, -1),
intent.getIntExtra(Downloader.EXTRA_TOTAL_BYTES, -1));
}
};
private void onAppChanged() {
if (!reset(app.id)) {
AppDetails.this.finish();
@ -854,6 +870,8 @@ public class AppDetails extends ActionBarActivity implements ProgressListener, A
private void startDownload(Apk apk, String repoAddress) {
downloadHandler = new ApkDownloader(getBaseContext(), apk, repoAddress);
localBroadcastManager.registerReceiver(downloaderProgressReceiver,
new IntentFilter(Downloader.LOCAL_ACTION_PROGRESS));
downloadHandler.setProgressListener(this);
if (downloadHandler.download()) {
updateProgressDialog();
@ -1034,9 +1052,6 @@ public class AppDetails extends ActionBarActivity implements ProgressListener, A
boolean finished = false;
switch (event.type) {
case Downloader.EVENT_PROGRESS:
updateProgressDialog(event.progress, event.total);
break;
case ApkDownloader.EVENT_ERROR:
final String text;
if (event.getData().getInt(ApkDownloader.EVENT_DATA_ERROR_TYPE) == ApkDownloader.ERROR_HASH_MISMATCH)

View File

@ -3,7 +3,6 @@ package org.fdroid.fdroid;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
@ -90,13 +89,6 @@ public class RepoUpdater {
downloader = DownloaderFactory.create(context,
getIndexAddress(), File.createTempFile("index-", "-downloaded", context.getCacheDir()));
downloader.setCacheTag(repo.lastetag);
if (progressListener != null) { // interactive session, show progress
Bundle data = new Bundle(1);
data.putString(PROGRESS_DATA_REPO_ADDRESS, repo.address);
downloader.setProgressListener(progressListener, data);
}
downloader.downloadUninterrupted();
if (downloader.isCached()) {

View File

@ -36,7 +36,6 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.preference.PreferenceManager;
@ -79,6 +78,8 @@ public class UpdateService extends IntentService implements ProgressListener {
public static final int STATUS_ERROR_LOCAL_SMALL = 4;
public static final int STATUS_INFO = 5;
private LocalBroadcastManager localBroadcastManager;
private static final int NOTIFY_ID_UPDATING = 0;
private static final int NOTIFY_ID_UPDATES_AVAILABLE = 1;
@ -147,8 +148,11 @@ public class UpdateService extends IntentService implements ProgressListener {
public void onCreate() {
super.onCreate();
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
lbm.registerReceiver(localBroadcastReceiver, new IntentFilter(LOCAL_ACTION_STATUS));
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.registerReceiver(downloadProgressReceiver,
new IntentFilter(Downloader.LOCAL_ACTION_PROGRESS));
localBroadcastManager.registerReceiver(updateStatusReceiver,
new IntentFilter(LOCAL_ACTION_STATUS));
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
@ -164,6 +168,8 @@ public class UpdateService extends IntentService implements ProgressListener {
public void onDestroy() {
super.onDestroy();
notificationManager.cancel(NOTIFY_ID_UPDATING);
localBroadcastManager.unregisterReceiver(downloadProgressReceiver);
localBroadcastManager.unregisterReceiver(updateStatusReceiver);
}
protected void sendStatus(int statusCode) {
@ -185,14 +191,35 @@ public class UpdateService extends IntentService implements ProgressListener {
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private final BroadcastReceiver downloadProgressReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (TextUtils.isEmpty(action))
return;
if (!action.equals(Downloader.LOCAL_ACTION_PROGRESS))
return;
String repoAddress = intent.getStringExtra(Downloader.EXTRA_ADDRESS);
int downloadedSize = intent.getIntExtra(Downloader.EXTRA_BYTES_READ, -1);
int totalSize = intent.getIntExtra(Downloader.EXTRA_TOTAL_BYTES, -1);
int percent = (int) ((double) downloadedSize / totalSize * 100);
sendStatus(STATUS_INFO,
getString(R.string.status_download, repoAddress,
Utils.getFriendlySize(downloadedSize),
Utils.getFriendlySize(totalSize), percent));
}
};
// For receiving results from the UpdateService when we've told it to
// update in response to a user request.
private BroadcastReceiver localBroadcastReceiver = new BroadcastReceiver() {
private final BroadcastReceiver updateStatusReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null)
if (TextUtils.isEmpty(action))
return;
if (!action.equals(LOCAL_ACTION_STATUS))
@ -733,9 +760,6 @@ public class UpdateService extends IntentService implements ProgressListener {
String totalSize = Utils.getFriendlySize(event.total);
int percent = (int) ((double) event.progress / event.total * 100);
switch (event.type) {
case Downloader.EVENT_PROGRESS:
message = getString(R.string.status_download, repoAddress, downloadedSize, totalSize, percent);
break;
case RepoUpdater.PROGRESS_TYPE_PROCESS_XML:
message = getString(R.string.status_processing_xml_percent, repoAddress, downloadedSize, totalSize, percent);
break;

View File

@ -216,14 +216,6 @@ public class ApkDownloader implements AsyncDownloadWrapper.Listener {
}
private void sendProgressEvent(Event event) {
switch (event.type) {
case Downloader.EVENT_PROGRESS:
// Keep a copy of these ourselves, so people can interrogate us for the
// info (in addition to receiving events with the info).
totalSize = event.total;
progress = event.progress;
break;
}
event.getData().putLong(EVENT_SOURCE_ID, id);

View File

@ -21,7 +21,6 @@ public class AsyncDownloadWrapper extends Handler {
private static final String TAG = "AsyncDownloadWrapper";
private static final int MSG_PROGRESS = 1;
private static final int MSG_DOWNLOAD_COMPLETE = 2;
private static final int MSG_DOWNLOAD_CANCELLED = 3;
private static final int MSG_ERROR = 4;
@ -61,11 +60,6 @@ public class AsyncDownloadWrapper extends Handler {
*/
public void handleMessage(Message message) {
switch (message.arg1) {
case MSG_PROGRESS:
Bundle data = message.getData();
ProgressListener.Event event = data.getParcelable(MSG_DATA);
listener.onProgress(event);
break;
case MSG_DOWNLOAD_COMPLETE:
listener.onDownloadComplete();
break;
@ -84,11 +78,10 @@ public class AsyncDownloadWrapper extends Handler {
void onDownloadCancelled();
}
private class DownloadThread extends Thread implements ProgressListener {
private class DownloadThread extends Thread {
public void run() {
try {
downloader.setProgressListener(this);
downloader.download();
sendMessage(MSG_DOWNLOAD_COMPLETE);
} catch (InterruptedException e) {
@ -109,16 +102,5 @@ public class AsyncDownloadWrapper extends Handler {
message.arg1 = messageType;
AsyncDownloadWrapper.this.sendMessage(message);
}
@Override
public void onProgress(Event event) {
Message message = new Message();
Bundle data = new Bundle();
data.putParcelable(MSG_DATA, event);
message.setData(data);
message.arg1 = MSG_PROGRESS;
AsyncDownloadWrapper.this.sendMessage(message);
}
}
}

View File

@ -1,10 +1,10 @@
package org.fdroid.fdroid.net;
import android.content.Context;
import android.os.Bundle;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import org.fdroid.fdroid.ProgressListener;
import org.fdroid.fdroid.Utils;
import java.io.File;
@ -19,35 +19,29 @@ import java.net.URL;
public abstract class Downloader {
private static final String TAG = "Downloader";
public static final String LOCAL_ACTION_PROGRESS = "Downloader.PROGRESS";
public static final String EXTRA_ADDRESS = "extraAddress";
public static final String EXTRA_BYTES_READ = "extraBytesRead";
public static final String EXTRA_TOTAL_BYTES = "extraTotalBytes";
private OutputStream outputStream;
private ProgressListener progressListener = null;
private Bundle eventData = null;
private final Context context;
private LocalBroadcastManager localBroadcastManager;
private final File outputFile;
protected URL sourceUrl;
protected String cacheTag = null;
public static final String EVENT_PROGRESS = "downloadProgress";
public abstract InputStream getInputStream() throws IOException;
Downloader(Context context, URL url, File destFile)
throws FileNotFoundException, MalformedURLException {
this.context = context;
this.sourceUrl = url;
outputFile = destFile;
outputStream = new FileOutputStream(outputFile);
}
public void setProgressListener(ProgressListener listener) {
setProgressListener(listener, null);
}
public void setProgressListener(ProgressListener listener, Bundle eventData) {
this.progressListener = listener;
this.eventData = eventData;
localBroadcastManager = LocalBroadcastManager.getInstance(context);
}
/**
@ -142,6 +136,11 @@ public abstract class Downloader {
}
}
/**
* This copies the downloaded data from the InputStream to the OutputStream,
* keeping track of the number of bytes that have flowed through for the
* progress counter.
*/
protected void copyInputToOutputStream(InputStream input) throws IOException, InterruptedException {
byte[] buffer = new byte[Utils.BUFFER_SIZE];
@ -170,13 +169,11 @@ public abstract class Downloader {
}
protected void sendProgress(int bytesRead, int totalBytes) {
sendProgress(new ProgressListener.Event(EVENT_PROGRESS, bytesRead, totalBytes, eventData));
}
protected void sendProgress(ProgressListener.Event event) {
if (progressListener != null) {
progressListener.onProgress(event);
}
Intent intent = new Intent(LOCAL_ACTION_PROGRESS);
intent.putExtra(EXTRA_ADDRESS, sourceUrl.toString());
intent.putExtra(EXTRA_BYTES_READ, bytesRead);
intent.putExtra(EXTRA_TOTAL_BYTES, totalBytes);
localBroadcastManager.sendBroadcast(intent);
}
}