added asyndownloader to use DownloadManager when possible
This commit is contained in:
parent
13c90e6c4a
commit
dbd4c467f8
@ -21,8 +21,8 @@
|
|||||||
package org.fdroid.fdroid.net;
|
package org.fdroid.fdroid.net;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
@ -38,6 +38,7 @@ import org.fdroid.fdroid.data.SanitizedFile;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -193,11 +194,17 @@ public class ApkDownloader implements AsyncDownloadWrapper.Listener {
|
|||||||
Utils.DebugLog(TAG, "Downloading apk from " + remoteAddress + " to " + localFile);
|
Utils.DebugLog(TAG, "Downloading apk from " + remoteAddress + " to " + localFile);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Downloader downloader = DownloaderFactory.create(context, remoteAddress, localFile);
|
if (canUseDownloadManager(new URL(remoteAddress))) {
|
||||||
dlWrapper = new AsyncDownloadWrapper(downloader, this);
|
// If we can use Android's DownloadManager, let's use it, because
|
||||||
|
// of better OS integration, reliability, and async ability
|
||||||
|
dlWrapper = new AsyncDownloader(context, this, curApk.apkName, remoteAddress, localFile);
|
||||||
|
} else {
|
||||||
|
Downloader downloader = DownloaderFactory.create(context, remoteAddress, localFile);
|
||||||
|
dlWrapper = new AsyncDownloadWrapper(downloader, this);
|
||||||
|
}
|
||||||
|
|
||||||
dlWrapper.download();
|
dlWrapper.download();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
onErrorDownloading(e.getLocalizedMessage());
|
onErrorDownloading(e.getLocalizedMessage());
|
||||||
}
|
}
|
||||||
@ -205,6 +212,17 @@ public class ApkDownloader implements AsyncDownloadWrapper.Listener {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests to see if we can use Android's DownloadManager to download the APK, instead of
|
||||||
|
* a downloader returned from DownloadFactory.
|
||||||
|
* @param url
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean canUseDownloadManager(URL url) {
|
||||||
|
return Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO
|
||||||
|
&& !DownloaderFactory.isOnionAddress(url);
|
||||||
|
}
|
||||||
|
|
||||||
private void sendMessage(String type) {
|
private void sendMessage(String type) {
|
||||||
sendProgressEvent(new ProgressListener.Event(type));
|
sendProgressEvent(new ProgressListener.Event(type));
|
||||||
}
|
}
|
||||||
|
134
F-Droid/src/org/fdroid/fdroid/net/AsyncDownloader.java
Normal file
134
F-Droid/src/org/fdroid/fdroid/net/AsyncDownloader.java
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package org.fdroid.fdroid.net;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.DownloadManager;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
|
||||||
|
import org.fdroid.fdroid.data.SanitizedFile;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A downloader that uses Android's DownloadManager to perform a download.
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
|
||||||
|
public class AsyncDownloader extends AsyncDownloadWrapper {
|
||||||
|
private final Context context;
|
||||||
|
private final DownloadManager dm;
|
||||||
|
private SanitizedFile localFile;
|
||||||
|
private String remoteAddress;
|
||||||
|
private String appName;
|
||||||
|
private Listener listener;
|
||||||
|
|
||||||
|
private long downloadId = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
public AsyncDownloader(Context context, Listener listener, String appName, String remoteAddress, SanitizedFile localFile) {
|
||||||
|
super(null, listener);
|
||||||
|
this.context = context;
|
||||||
|
this.appName = appName;
|
||||||
|
this.remoteAddress = remoteAddress;
|
||||||
|
this.listener = listener;
|
||||||
|
this.localFile = localFile;
|
||||||
|
|
||||||
|
if (appName == null || appName.trim().length() == 0) {
|
||||||
|
this.appName = remoteAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void download() {
|
||||||
|
// set up download request
|
||||||
|
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(remoteAddress));
|
||||||
|
request.setTitle(appName);
|
||||||
|
|
||||||
|
if (listener != null) {
|
||||||
|
IntentFilter intentFilter = new IntentFilter();
|
||||||
|
intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
|
||||||
|
intentFilter.addAction(DownloadManager.ACTION_NOTIFICATION_CLICKED);
|
||||||
|
context.registerReceiver(downloadReceiver, intentFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadId = dm.enqueue(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBytesRead() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTotalBytes() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attemptCancel() {
|
||||||
|
if (downloadId >= 0) dm.remove(downloadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Broadcast receiver to receive broadcasts from the download manager
|
||||||
|
private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (listener == null) return; // no point if no-one is listening
|
||||||
|
|
||||||
|
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
|
||||||
|
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
|
||||||
|
if (id == downloadId) {
|
||||||
|
context.unregisterReceiver(this);
|
||||||
|
|
||||||
|
// clear the notification
|
||||||
|
dm.remove(id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// write the downloaded file to the expected location
|
||||||
|
ParcelFileDescriptor fd = dm.openDownloadedFile(id);
|
||||||
|
InputStream is = new FileInputStream(fd.getFileDescriptor());
|
||||||
|
OutputStream os = new FileOutputStream(localFile);
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int count = 0;
|
||||||
|
while ((count = is.read(buffer, 0, buffer.length)) > 0) {
|
||||||
|
os.write(buffer, 0, count);
|
||||||
|
}
|
||||||
|
os.close();
|
||||||
|
|
||||||
|
listener.onDownloadComplete();
|
||||||
|
} catch (IOException e) {
|
||||||
|
listener.onErrorDownloading(e.getLocalizedMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DownloadManager.ACTION_NOTIFICATION_CLICKED.equals(intent.getAction())) {
|
||||||
|
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
|
||||||
|
if (id == downloadId) {
|
||||||
|
// TODO - display app details screen for this app
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -51,7 +51,7 @@ public class DownloaderFactory {
|
|||||||
return "bluetooth".equalsIgnoreCase(url.getProtocol());
|
return "bluetooth".equalsIgnoreCase(url.getProtocol());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isOnionAddress(URL url) {
|
static boolean isOnionAddress(URL url) {
|
||||||
return url.getHost().endsWith(".onion");
|
return url.getHost().endsWith(".onion");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user