Refactored AsyncDownloader to only ever be constructed by DownloadFactory.
This commit is contained in:
parent
9b7c4c7b4a
commit
69ecaf023f
@ -22,7 +22,6 @@
|
|||||||
package org.fdroid.fdroid;
|
package org.fdroid.fdroid;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.DownloadManager;
|
|
||||||
import android.bluetooth.BluetoothAdapter;
|
import android.bluetooth.BluetoothAdapter;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
@ -35,7 +34,6 @@ import android.content.pm.PackageInfo;
|
|||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.Signature;
|
import android.content.pm.Signature;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -94,7 +92,7 @@ import org.fdroid.fdroid.installer.Installer;
|
|||||||
import org.fdroid.fdroid.installer.Installer.AndroidNotCompatibleException;
|
import org.fdroid.fdroid.installer.Installer.AndroidNotCompatibleException;
|
||||||
import org.fdroid.fdroid.installer.Installer.InstallerCallback;
|
import org.fdroid.fdroid.installer.Installer.InstallerCallback;
|
||||||
import org.fdroid.fdroid.net.ApkDownloader;
|
import org.fdroid.fdroid.net.ApkDownloader;
|
||||||
import org.fdroid.fdroid.net.AsyncDownloader;
|
import org.fdroid.fdroid.net.AsyncDownloaderFromAndroid;
|
||||||
import org.fdroid.fdroid.net.Downloader;
|
import org.fdroid.fdroid.net.Downloader;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -435,7 +433,7 @@ public class AppDetails extends AppCompatActivity implements ProgressListener, A
|
|||||||
localBroadcastManager = LocalBroadcastManager.getInstance(this);
|
localBroadcastManager = LocalBroadcastManager.getInstance(this);
|
||||||
|
|
||||||
// Check if a download is running for this app
|
// Check if a download is running for this app
|
||||||
if (AsyncDownloader.isDownloading(this, app.id) >= 0) {
|
if (AsyncDownloaderFromAndroid.isDownloading(this, app.id) >= 0) {
|
||||||
// call install() to re-setup the listeners and downloaders
|
// call install() to re-setup the listeners and downloaders
|
||||||
// the AsyncDownloader will not restart the download since the download is running,
|
// the AsyncDownloader will not restart the download since the download is running,
|
||||||
// and thus the version we pass to install() is not important
|
// and thus the version we pass to install() is not important
|
||||||
|
@ -47,7 +47,7 @@ import java.security.NoSuchAlgorithmException;
|
|||||||
* If the file has previously been downloaded, it will make use of that
|
* If the file has previously been downloaded, it will make use of that
|
||||||
* instead, without going to the network to download a new one.
|
* instead, without going to the network to download a new one.
|
||||||
*/
|
*/
|
||||||
public class ApkDownloader implements AsyncDownloadWrapper.Listener {
|
public class ApkDownloader implements AsyncDownloader.Listener {
|
||||||
|
|
||||||
private static final String TAG = "ApkDownloader";
|
private static final String TAG = "ApkDownloader";
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ public class ApkDownloader implements AsyncDownloadWrapper.Listener {
|
|||||||
@NonNull private final SanitizedFile potentiallyCachedFile;
|
@NonNull private final SanitizedFile potentiallyCachedFile;
|
||||||
|
|
||||||
private ProgressListener listener;
|
private ProgressListener listener;
|
||||||
private AsyncDownloadWrapper dlWrapper = null;
|
private AsyncDownloader dlWrapper = null;
|
||||||
private boolean isComplete = false;
|
private boolean isComplete = false;
|
||||||
|
|
||||||
private final long id = ++downloadIdCounter;
|
private final long id = ++downloadIdCounter;
|
||||||
@ -197,17 +197,7 @@ 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 {
|
||||||
if (canUseDownloadManager(new URL(remoteAddress))) {
|
dlWrapper = DownloaderFactory.createAsync(context, remoteAddress, localFile, app.name + " " + curApk.version, curApk.id, 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,
|
|
||||||
app.name + " " + curApk.version, curApk.id,
|
|
||||||
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) {
|
||||||
@ -217,17 +207,6 @@ 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));
|
||||||
}
|
}
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
package org.fdroid.fdroid.net;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
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 AsyncDownloadWrapper#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 AsyncDownloadWrapper extends Handler {
|
|
||||||
|
|
||||||
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 AsyncDownloadWrapper(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 org.fdroid.fdroid.net.AsyncDownloadWrapper.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 {
|
|
||||||
void onErrorDownloading(String localisedExceptionDetails);
|
|
||||||
void onDownloadComplete();
|
|
||||||
void onDownloadCancelled();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +1,34 @@
|
|||||||
package org.fdroid.fdroid.net;
|
package org.fdroid.fdroid.net;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.os.Bundle;
|
||||||
import android.app.DownloadManager;
|
import android.os.Handler;
|
||||||
import android.content.BroadcastReceiver;
|
import android.os.Message;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.ParcelFileDescriptor;
|
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.fdroid.fdroid.AppDetails;
|
|
||||||
import org.fdroid.fdroid.ProgressListener;
|
import org.fdroid.fdroid.ProgressListener;
|
||||||
import org.fdroid.fdroid.data.Apk;
|
|
||||||
import org.fdroid.fdroid.data.App;
|
|
||||||
import org.fdroid.fdroid.data.SanitizedFile;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileDescriptor;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A downloader that uses Android's DownloadManager to perform a download.
|
* 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.
|
||||||
*/
|
*/
|
||||||
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
|
@SuppressWarnings("serial")
|
||||||
public class AsyncDownloader extends AsyncDownloadWrapper {
|
public class AsyncDownloader extends Handler {
|
||||||
private final Context context;
|
|
||||||
private final DownloadManager dm;
|
|
||||||
private SanitizedFile localFile;
|
|
||||||
private String remoteAddress;
|
|
||||||
private String appName;
|
|
||||||
private String appId;
|
|
||||||
private Listener listener;
|
|
||||||
|
|
||||||
private long downloadId = -1;
|
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.
|
* Normally the listener would be provided using a setListener method.
|
||||||
@ -49,287 +36,79 @@ public class AsyncDownloader extends AsyncDownloadWrapper {
|
|||||||
* sense to have an async task without any way to notify the outside
|
* sense to have an async task without any way to notify the outside
|
||||||
* world about completion. Therefore, we require the listener as a
|
* world about completion. Therefore, we require the listener as a
|
||||||
* parameter to the constructor.
|
* parameter to the constructor.
|
||||||
*
|
|
||||||
* @param listener
|
|
||||||
*/
|
*/
|
||||||
public AsyncDownloader(Context context, Listener listener, String appName, String appId, String remoteAddress, SanitizedFile localFile) {
|
public AsyncDownloader(Downloader downloader, Listener listener) {
|
||||||
super(null, listener);
|
this.downloader = downloader;
|
||||||
this.context = context;
|
|
||||||
this.appName = appName;
|
|
||||||
this.appId = appId;
|
|
||||||
this.remoteAddress = remoteAddress;
|
|
||||||
this.listener = listener;
|
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() {
|
public void download() {
|
||||||
// Check if the download is complete
|
downloadThread = new DownloadThread();
|
||||||
if ((downloadId = isDownloadComplete(context, appId)) > 0) {
|
downloadThread.start();
|
||||||
// clear the notification
|
|
||||||
dm.remove(downloadId);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// write the downloaded file to the expected location
|
|
||||||
ParcelFileDescriptor fd = dm.openDownloadedFile(downloadId);
|
|
||||||
copyFile(fd.getFileDescriptor(), localFile);
|
|
||||||
listener.onDownloadComplete();
|
|
||||||
} catch (IOException e) {
|
|
||||||
listener.onErrorDownloading(e.getLocalizedMessage());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the download is still in progress
|
|
||||||
if (downloadId < 0) {
|
|
||||||
downloadId = isDownloading(context, appId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start a new download
|
|
||||||
if (downloadId < 0) {
|
|
||||||
// set up download request
|
|
||||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(remoteAddress));
|
|
||||||
request.setTitle(appName);
|
|
||||||
request.setDescription(appId); // we will retrieve this later from the description field
|
|
||||||
this.downloadId = dm.enqueue(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.registerReceiver(receiver,
|
|
||||||
new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy input file to output file
|
|
||||||
* @param inputFile
|
|
||||||
* @param outputFile
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private void copyFile(FileDescriptor inputFile, SanitizedFile outputFile) throws IOException {
|
|
||||||
InputStream is = new FileInputStream(inputFile);
|
|
||||||
OutputStream os = new FileOutputStream(outputFile);
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
try {
|
|
||||||
while ((count = is.read(buffer, 0, buffer.length)) > 0) {
|
|
||||||
os.write(buffer, 0, count);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
os.close();
|
|
||||||
is.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBytesRead() {
|
|
||||||
if (downloadId < 0) return 0;
|
|
||||||
|
|
||||||
DownloadManager.Query query = new DownloadManager.Query();
|
|
||||||
query.setFilterById(downloadId);
|
|
||||||
Cursor c = dm.query(query);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (c.moveToFirst()) {
|
|
||||||
// we use the description column to store the app id
|
|
||||||
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
|
|
||||||
return c.getInt(columnIndex);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getTotalBytes() {
|
|
||||||
if (downloadId < 0) return 0;
|
|
||||||
|
|
||||||
DownloadManager.Query query = new DownloadManager.Query();
|
|
||||||
query.setFilterById(downloadId);
|
|
||||||
Cursor c = dm.query(query);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (c.moveToFirst()) {
|
|
||||||
// we use the description column to store the app id
|
|
||||||
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
|
|
||||||
return c.getInt(columnIndex);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void attemptCancel(boolean userRequested) {
|
public void attemptCancel(boolean userRequested) {
|
||||||
try {
|
if (downloadThread != null) {
|
||||||
context.unregisterReceiver(receiver);
|
downloadThread.interrupt();
|
||||||
} catch (Exception e) {
|
|
||||||
// ignore if receiver already unregistered
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userRequested && downloadId >= 0) {
|
|
||||||
dm.remove(downloadId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the appId from a given download id.
|
* Receives "messages" from the download thread, and passes them onto the
|
||||||
* @param context
|
* relevant {@link AsyncDownloader.Listener}
|
||||||
* @param downloadId
|
* @param message
|
||||||
* @return - appId or null if not found
|
|
||||||
*/
|
*/
|
||||||
public static String getAppId(Context context, long downloadId) {
|
public void handleMessage(Message message) {
|
||||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
switch (message.arg1) {
|
||||||
DownloadManager.Query query = new DownloadManager.Query();
|
case MSG_DOWNLOAD_COMPLETE:
|
||||||
query.setFilterById(downloadId);
|
listener.onDownloadComplete();
|
||||||
Cursor c = dm.query(query);
|
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 {
|
||||||
|
void onErrorDownloading(String localisedExceptionDetails);
|
||||||
|
void onDownloadComplete();
|
||||||
|
void onDownloadCancelled();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DownloadThread extends Thread {
|
||||||
|
|
||||||
|
public void run() {
|
||||||
try {
|
try {
|
||||||
if (c.moveToFirst()) {
|
downloader.download();
|
||||||
// we use the description column to store the app id
|
sendMessage(MSG_DOWNLOAD_COMPLETE);
|
||||||
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION);
|
} catch (InterruptedException e) {
|
||||||
return c.getString(columnIndex);
|
sendMessage(MSG_DOWNLOAD_CANCELLED);
|
||||||
}
|
} catch (IOException e) {
|
||||||
} finally {
|
Log.e(TAG, "I/O exception in download thread", e);
|
||||||
c.close();
|
Bundle data = new Bundle(1);
|
||||||
}
|
data.putString(MSG_DATA, e.getLocalizedMessage());
|
||||||
|
Message message = new Message();
|
||||||
return null;
|
message.arg1 = MSG_ERROR;
|
||||||
}
|
message.setData(data);
|
||||||
|
AsyncDownloader.this.sendMessage(message);
|
||||||
/**
|
|
||||||
* Extract the download title from a given download id.
|
|
||||||
* @param context
|
|
||||||
* @param downloadId
|
|
||||||
* @return - title or null if not found
|
|
||||||
*/
|
|
||||||
public static String getDownloadTitle(Context context, long downloadId) {
|
|
||||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
DownloadManager.Query query = new DownloadManager.Query();
|
|
||||||
query.setFilterById(downloadId);
|
|
||||||
Cursor c = dm.query(query);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (c.moveToFirst()) {
|
|
||||||
// we use the description column to store the app id
|
|
||||||
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_TITLE);
|
|
||||||
return c.getString(columnIndex);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the downloadId from an Intent sent by the DownloadManagerReceiver
|
|
||||||
* @param intent
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static long getDownloadId(Intent intent) {
|
|
||||||
if (intent != null) {
|
|
||||||
if (intent.hasExtra(DownloadManager.EXTRA_DOWNLOAD_ID)) {
|
|
||||||
// we have been passed a DownloadManager download id, so get the app id for it
|
|
||||||
return intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intent.hasExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS)) {
|
|
||||||
// we have been passed multiple download id's - just return the first one
|
|
||||||
long[] downloadIds = intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);
|
|
||||||
if (downloadIds != null && downloadIds.length > 0) {
|
|
||||||
return downloadIds[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
private void sendMessage(int messageType) {
|
||||||
}
|
Message message = new Message();
|
||||||
|
message.arg1 = messageType;
|
||||||
/**
|
AsyncDownloader.this.sendMessage(message);
|
||||||
* Check if a download is running for the app
|
|
||||||
* @param context
|
|
||||||
* @param appId
|
|
||||||
* @return -1 if not downloading, else the downloadId
|
|
||||||
*/
|
|
||||||
public static long isDownloading(Context context, String appId) {
|
|
||||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
DownloadManager.Query query = new DownloadManager.Query();
|
|
||||||
Cursor c = dm.query(query);
|
|
||||||
int columnAppId = c.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION);
|
|
||||||
int columnId = c.getColumnIndex(DownloadManager.COLUMN_ID);
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (c.moveToNext()) {
|
|
||||||
if (appId.equals(c.getString(columnAppId))) {
|
|
||||||
return c.getLong(columnId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a download for an app is complete.
|
|
||||||
* @param context
|
|
||||||
* @param appId
|
|
||||||
* @return -1 if download is not complete, otherwise the download id
|
|
||||||
*/
|
|
||||||
public static long isDownloadComplete(Context context, String appId) {
|
|
||||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
DownloadManager.Query query = new DownloadManager.Query();
|
|
||||||
query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
|
|
||||||
Cursor c = dm.query(query);
|
|
||||||
int columnAppId = c.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION);
|
|
||||||
int columnId = c.getColumnIndex(DownloadManager.COLUMN_ID);
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (c.moveToNext()) {
|
|
||||||
if (appId.equals(c.getString(columnAppId))) {
|
|
||||||
return c.getLong(columnId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcast receiver to listen for ACTION_DOWNLOAD_COMPLETE broadcasts
|
|
||||||
*/
|
|
||||||
BroadcastReceiver receiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
|
|
||||||
long dId = getDownloadId(intent);
|
|
||||||
String appId = getAppId(context, dId);
|
|
||||||
if (listener != null && dId == downloadId && appId != null) {
|
|
||||||
// our current download has just completed, so let's throw up install dialog
|
|
||||||
// immediately
|
|
||||||
try {
|
|
||||||
context.unregisterReceiver(receiver);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// ignore if receiver already unregistered
|
|
||||||
}
|
|
||||||
|
|
||||||
// call download() to copy the file and start the installer
|
|
||||||
download();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,326 @@
|
|||||||
|
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.database.Cursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
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 AsyncDownloaderFromAndroid extends AsyncDownloader {
|
||||||
|
private final Context context;
|
||||||
|
private final DownloadManager dm;
|
||||||
|
private File localFile;
|
||||||
|
private String remoteAddress;
|
||||||
|
private String appName;
|
||||||
|
private String appId;
|
||||||
|
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 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;
|
||||||
|
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() {
|
||||||
|
// Check if the download is complete
|
||||||
|
if ((downloadId = isDownloadComplete(context, appId)) > 0) {
|
||||||
|
// clear the notification
|
||||||
|
dm.remove(downloadId);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// write the downloaded file to the expected location
|
||||||
|
ParcelFileDescriptor fd = dm.openDownloadedFile(downloadId);
|
||||||
|
copyFile(fd.getFileDescriptor(), localFile);
|
||||||
|
listener.onDownloadComplete();
|
||||||
|
} catch (IOException e) {
|
||||||
|
listener.onErrorDownloading(e.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the download is still in progress
|
||||||
|
if (downloadId < 0) {
|
||||||
|
downloadId = isDownloading(context, appId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a new download
|
||||||
|
if (downloadId < 0) {
|
||||||
|
// set up download request
|
||||||
|
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(remoteAddress));
|
||||||
|
request.setTitle(appName);
|
||||||
|
request.setDescription(appId); // we will retrieve this later from the description field
|
||||||
|
this.downloadId = dm.enqueue(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.registerReceiver(receiver,
|
||||||
|
new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy input file to output file
|
||||||
|
* @param inputFile
|
||||||
|
* @param outputFile
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void copyFile(FileDescriptor inputFile, File outputFile) throws IOException {
|
||||||
|
InputStream is = new FileInputStream(inputFile);
|
||||||
|
OutputStream os = new FileOutputStream(outputFile);
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
while ((count = is.read(buffer, 0, buffer.length)) > 0) {
|
||||||
|
os.write(buffer, 0, count);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
os.close();
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBytesRead() {
|
||||||
|
if (downloadId < 0) return 0;
|
||||||
|
|
||||||
|
DownloadManager.Query query = new DownloadManager.Query();
|
||||||
|
query.setFilterById(downloadId);
|
||||||
|
Cursor c = dm.query(query);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (c.moveToFirst()) {
|
||||||
|
// we use the description column to store the app id
|
||||||
|
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
|
||||||
|
return c.getInt(columnIndex);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTotalBytes() {
|
||||||
|
if (downloadId < 0) return 0;
|
||||||
|
|
||||||
|
DownloadManager.Query query = new DownloadManager.Query();
|
||||||
|
query.setFilterById(downloadId);
|
||||||
|
Cursor c = dm.query(query);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (c.moveToFirst()) {
|
||||||
|
// we use the description column to store the app id
|
||||||
|
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
|
||||||
|
return c.getInt(columnIndex);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attemptCancel(boolean userRequested) {
|
||||||
|
try {
|
||||||
|
context.unregisterReceiver(receiver);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignore if receiver already unregistered
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userRequested && downloadId >= 0) {
|
||||||
|
dm.remove(downloadId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the appId from a given download id.
|
||||||
|
* @param context
|
||||||
|
* @param downloadId
|
||||||
|
* @return - appId or null if not found
|
||||||
|
*/
|
||||||
|
public static String getAppId(Context context, long downloadId) {
|
||||||
|
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||||
|
DownloadManager.Query query = new DownloadManager.Query();
|
||||||
|
query.setFilterById(downloadId);
|
||||||
|
Cursor c = dm.query(query);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (c.moveToFirst()) {
|
||||||
|
// we use the description column to store the app id
|
||||||
|
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION);
|
||||||
|
return c.getString(columnIndex);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the download title from a given download id.
|
||||||
|
* @param context
|
||||||
|
* @param downloadId
|
||||||
|
* @return - title or null if not found
|
||||||
|
*/
|
||||||
|
public static String getDownloadTitle(Context context, long downloadId) {
|
||||||
|
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||||
|
DownloadManager.Query query = new DownloadManager.Query();
|
||||||
|
query.setFilterById(downloadId);
|
||||||
|
Cursor c = dm.query(query);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (c.moveToFirst()) {
|
||||||
|
// we use the description column to store the app id
|
||||||
|
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_TITLE);
|
||||||
|
return c.getString(columnIndex);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the downloadId from an Intent sent by the DownloadManagerReceiver
|
||||||
|
* @param intent
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static long getDownloadId(Intent intent) {
|
||||||
|
if (intent != null) {
|
||||||
|
if (intent.hasExtra(DownloadManager.EXTRA_DOWNLOAD_ID)) {
|
||||||
|
// we have been passed a DownloadManager download id, so get the app id for it
|
||||||
|
return intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intent.hasExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS)) {
|
||||||
|
// we have been passed multiple download id's - just return the first one
|
||||||
|
long[] downloadIds = intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);
|
||||||
|
if (downloadIds != null && downloadIds.length > 0) {
|
||||||
|
return downloadIds[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a download is running for the app
|
||||||
|
* @param context
|
||||||
|
* @param appId
|
||||||
|
* @return -1 if not downloading, else the downloadId
|
||||||
|
*/
|
||||||
|
public static long isDownloading(Context context, String appId) {
|
||||||
|
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||||
|
DownloadManager.Query query = new DownloadManager.Query();
|
||||||
|
Cursor c = dm.query(query);
|
||||||
|
int columnAppId = c.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION);
|
||||||
|
int columnId = c.getColumnIndex(DownloadManager.COLUMN_ID);
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (c.moveToNext()) {
|
||||||
|
if (appId.equals(c.getString(columnAppId))) {
|
||||||
|
return c.getLong(columnId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a download for an app is complete.
|
||||||
|
* @param context
|
||||||
|
* @param appId
|
||||||
|
* @return -1 if download is not complete, otherwise the download id
|
||||||
|
*/
|
||||||
|
public static long isDownloadComplete(Context context, String appId) {
|
||||||
|
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||||
|
DownloadManager.Query query = new DownloadManager.Query();
|
||||||
|
query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
|
||||||
|
Cursor c = dm.query(query);
|
||||||
|
int columnAppId = c.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION);
|
||||||
|
int columnId = c.getColumnIndex(DownloadManager.COLUMN_ID);
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (c.moveToNext()) {
|
||||||
|
if (appId.equals(c.getString(columnAppId))) {
|
||||||
|
return c.getLong(columnId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast receiver to listen for ACTION_DOWNLOAD_COMPLETE broadcasts
|
||||||
|
*/
|
||||||
|
BroadcastReceiver receiver = new BroadcastReceiver() {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
|
||||||
|
long dId = getDownloadId(intent);
|
||||||
|
String appId = getAppId(context, dId);
|
||||||
|
if (listener != null && dId == downloadId && appId != null) {
|
||||||
|
// our current download has just completed, so let's throw up install dialog
|
||||||
|
// immediately
|
||||||
|
try {
|
||||||
|
context.unregisterReceiver(receiver);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignore if receiver already unregistered
|
||||||
|
}
|
||||||
|
|
||||||
|
// call download() to copy the file and start the installer
|
||||||
|
download();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
package org.fdroid.fdroid.net;
|
package org.fdroid.fdroid.net;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
public class DownloaderFactory {
|
public class DownloaderFactory {
|
||||||
@ -51,7 +53,29 @@ public class DownloaderFactory {
|
|||||||
return "bluetooth".equalsIgnoreCase(url.getProtocol());
|
return "bluetooth".equalsIgnoreCase(url.getProtocol());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static AsyncDownloader createAsync(Context context, String urlString, File destFile, String title, String id, AsyncDownloader.Listener listener) throws IOException {
|
||||||
|
return createAsync(context, new URL(urlString), destFile, title, id, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AsyncDownloader createAsync(Context context, URL url, File destFile, String title, String id, AsyncDownloader.Listener listener)
|
||||||
|
throws IOException {
|
||||||
|
if (canUseDownloadManager(url)) {
|
||||||
|
return new AsyncDownloaderFromAndroid(context, listener, title, id, url.toString(), destFile);
|
||||||
|
} else {
|
||||||
|
return new AsyncDownloader(create(context, url, destFile), listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static boolean isOnionAddress(URL url) {
|
static boolean isOnionAddress(URL url) {
|
||||||
return url.getHost().endsWith(".onion");
|
return url.getHost().endsWith(".onion");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests to see if we can use Android's DownloadManager to download the APK, instead of
|
||||||
|
* a downloader returned from DownloadFactory.
|
||||||
|
*/
|
||||||
|
private static boolean canUseDownloadManager(URL url) {
|
||||||
|
return Build.VERSION.SDK_INT > Build.VERSION_CODES.FROYO && !isOnionAddress(url);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import android.support.v4.app.NotificationCompat;
|
|||||||
|
|
||||||
import org.fdroid.fdroid.AppDetails;
|
import org.fdroid.fdroid.AppDetails;
|
||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
import org.fdroid.fdroid.net.AsyncDownloader;
|
import org.fdroid.fdroid.net.AsyncDownloaderFromAndroid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive notifications from the Android DownloadManager and pass them onto the
|
* Receive notifications from the Android DownloadManager and pass them onto the
|
||||||
@ -21,8 +21,8 @@ public class DownloadManagerReceiver extends BroadcastReceiver {
|
|||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
// work out the app Id to send to the AppDetails Screen
|
// work out the app Id to send to the AppDetails Screen
|
||||||
long downloadId = AsyncDownloader.getDownloadId(intent);
|
long downloadId = AsyncDownloaderFromAndroid.getDownloadId(intent);
|
||||||
String appId = AsyncDownloader.getAppId(context, downloadId);
|
String appId = AsyncDownloaderFromAndroid.getAppId(context, downloadId);
|
||||||
|
|
||||||
if (appId == null) {
|
if (appId == null) {
|
||||||
// bogus broadcast (e.g. download cancelled, but system sent a DOWNLOAD_COMPLETE)
|
// bogus broadcast (e.g. download cancelled, but system sent a DOWNLOAD_COMPLETE)
|
||||||
@ -41,7 +41,7 @@ public class DownloadManagerReceiver extends BroadcastReceiver {
|
|||||||
context, 1, appDetails, PendingIntent.FLAG_ONE_SHOT);
|
context, 1, appDetails, PendingIntent.FLAG_ONE_SHOT);
|
||||||
|
|
||||||
// launch LocalRepoActivity if the user selects this notification
|
// launch LocalRepoActivity if the user selects this notification
|
||||||
String downloadTitle = AsyncDownloader.getDownloadTitle(context, downloadId);
|
String downloadTitle = AsyncDownloaderFromAndroid.getDownloadTitle(context, downloadId);
|
||||||
Notification notif = new NotificationCompat.Builder(context)
|
Notification notif = new NotificationCompat.Builder(context)
|
||||||
.setContentTitle(downloadTitle)
|
.setContentTitle(downloadTitle)
|
||||||
.setContentText(context.getString(R.string.tap_to_install))
|
.setContentText(context.getString(R.string.tap_to_install))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user