purge disabled Android DownloadManager code
Unfortunately, this approach did not really work out. It would have been really nice to rely on the provided DownloadManager stuff, but it has too many issues, like not working with Tor or other proxies, and being difficult to tightly integrate.
This commit is contained in:
parent
acc2a3154f
commit
9d1743af33
@ -437,14 +437,6 @@
|
|||||||
<action android:name="android.net.wifi.STATE_CHANGE" />
|
<action android:name="android.net.wifi.STATE_CHANGE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver android:name=".receiver.DownloadManagerReceiver" >
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
|
||||||
</intent-filter>
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED" />
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
|
||||||
|
|
||||||
<service android:name=".UpdateService" />
|
<service android:name=".UpdateService" />
|
||||||
<service android:name=".net.WifiStateChangeService" />
|
<service android:name=".net.WifiStateChangeService" />
|
||||||
|
@ -92,7 +92,6 @@ 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.AsyncDownloaderFromAndroid;
|
|
||||||
import org.fdroid.fdroid.net.Downloader;
|
import org.fdroid.fdroid.net.Downloader;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -434,18 +433,6 @@ 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
|
|
||||||
if (AsyncDownloaderFromAndroid.isDownloading(this, app.packageName) >= 0) {
|
|
||||||
// call install() to re-setup the listeners and downloaders
|
|
||||||
// the AsyncDownloader will not restart the download since the download is running,
|
|
||||||
// and thus the version we pass to install() is not important
|
|
||||||
refreshHeader();
|
|
||||||
refreshApkList();
|
|
||||||
final Apk apkToInstall = ApkProvider.Helper.find(this, app.packageName, app.suggestedVercode);
|
|
||||||
install(apkToInstall);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,396 +0,0 @@
|
|||||||
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 android.support.v4.content.LocalBroadcastManager;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
|
|
||||||
import org.fdroid.fdroid.R;
|
|
||||||
import org.fdroid.fdroid.Utils;
|
|
||||||
|
|
||||||
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 implements AsyncDownloader {
|
|
||||||
private final Context context;
|
|
||||||
private final DownloadManager dm;
|
|
||||||
private final LocalBroadcastManager localBroadcastManager;
|
|
||||||
private final File localFile;
|
|
||||||
private final String remoteAddress;
|
|
||||||
private final String downloadTitle;
|
|
||||||
private final String uniqueDownloadId;
|
|
||||||
private final Listener listener;
|
|
||||||
private boolean isCancelled;
|
|
||||||
|
|
||||||
private long downloadManagerId = -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.
|
|
||||||
*/
|
|
||||||
public AsyncDownloaderFromAndroid(Context context, Listener listener, String downloadTitle, String downloadId, String remoteAddress, File localFile) {
|
|
||||||
this.context = context;
|
|
||||||
this.uniqueDownloadId = downloadId;
|
|
||||||
this.remoteAddress = remoteAddress;
|
|
||||||
this.listener = listener;
|
|
||||||
this.localFile = localFile;
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(downloadTitle)) {
|
|
||||||
this.downloadTitle = remoteAddress;
|
|
||||||
} else {
|
|
||||||
this.downloadTitle = downloadTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
localBroadcastManager = LocalBroadcastManager.getInstance(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void download() {
|
|
||||||
isCancelled = false;
|
|
||||||
|
|
||||||
// check if download failed
|
|
||||||
if (downloadManagerId >= 0) {
|
|
||||||
int status = validDownload(context, downloadManagerId);
|
|
||||||
if (status > 0) {
|
|
||||||
// error downloading
|
|
||||||
dm.remove(downloadManagerId);
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onErrorDownloading(context.getString(R.string.download_error));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the download is complete
|
|
||||||
downloadManagerId = isDownloadComplete(context, uniqueDownloadId);
|
|
||||||
if (downloadManagerId > 0) {
|
|
||||||
// clear the download
|
|
||||||
dm.remove(downloadManagerId);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// write the downloaded file to the expected location
|
|
||||||
ParcelFileDescriptor fd = dm.openDownloadedFile(downloadManagerId);
|
|
||||||
copyFile(fd.getFileDescriptor(), localFile);
|
|
||||||
listener.onDownloadComplete();
|
|
||||||
} catch (IOException e) {
|
|
||||||
listener.onErrorDownloading(e.getLocalizedMessage());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the download is still in progress
|
|
||||||
if (downloadManagerId < 0) {
|
|
||||||
downloadManagerId = isDownloading(context, uniqueDownloadId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start a new download
|
|
||||||
if (downloadManagerId < 0) {
|
|
||||||
// set up download request
|
|
||||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(remoteAddress));
|
|
||||||
request.setTitle(downloadTitle);
|
|
||||||
request.setDescription(uniqueDownloadId); // we will retrieve this later from the description field
|
|
||||||
this.downloadManagerId = dm.enqueue(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.registerReceiver(receiver,
|
|
||||||
new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
|
||||||
|
|
||||||
Thread progressThread = new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while (!isCancelled && isDownloading(context, uniqueDownloadId) >= 0) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
sendProgress(getBytesRead(), getTotalBytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
progressThread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy input file to output file
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private void copyFile(FileDescriptor inputFile, File outputFile) throws IOException {
|
|
||||||
InputStream input = null;
|
|
||||||
OutputStream output = null;
|
|
||||||
try {
|
|
||||||
input = new FileInputStream(inputFile);
|
|
||||||
output = new FileOutputStream(outputFile);
|
|
||||||
Utils.copy(input, output);
|
|
||||||
} finally {
|
|
||||||
Utils.closeQuietly(output);
|
|
||||||
Utils.closeQuietly(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBytesRead() {
|
|
||||||
if (downloadManagerId < 0) return 0;
|
|
||||||
|
|
||||||
DownloadManager.Query query = new DownloadManager.Query();
|
|
||||||
query.setFilterById(downloadManagerId);
|
|
||||||
Cursor c = dm.query(query);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (c.moveToFirst()) {
|
|
||||||
// we use the description column to store the unique id of this download
|
|
||||||
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
|
|
||||||
return c.getInt(columnIndex);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getTotalBytes() {
|
|
||||||
if (downloadManagerId < 0) return 0;
|
|
||||||
|
|
||||||
DownloadManager.Query query = new DownloadManager.Query();
|
|
||||||
query.setFilterById(downloadManagerId);
|
|
||||||
Cursor c = dm.query(query);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (c.moveToFirst()) {
|
|
||||||
// we use the description column to store the unique id for this download
|
|
||||||
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
|
|
||||||
return c.getInt(columnIndex);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendProgress(int bytesRead, int totalBytes) {
|
|
||||||
Intent intent = new Intent(Downloader.LOCAL_ACTION_PROGRESS);
|
|
||||||
intent.putExtra(Downloader.EXTRA_ADDRESS, remoteAddress);
|
|
||||||
intent.putExtra(Downloader.EXTRA_BYTES_READ, bytesRead);
|
|
||||||
intent.putExtra(Downloader.EXTRA_TOTAL_BYTES, totalBytes);
|
|
||||||
localBroadcastManager.sendBroadcast(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void attemptCancel(boolean userRequested) {
|
|
||||||
isCancelled = true;
|
|
||||||
try {
|
|
||||||
context.unregisterReceiver(receiver);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// ignore if receiver already unregistered
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userRequested && downloadManagerId >= 0) {
|
|
||||||
dm.remove(downloadManagerId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract the uniqueDownloadId from a given download id.
|
|
||||||
* @return - uniqueDownloadId or null if not found
|
|
||||||
*/
|
|
||||||
public static String getDownloadId(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 unique id for this download
|
|
||||||
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.
|
|
||||||
* @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()) {
|
|
||||||
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_TITLE);
|
|
||||||
return c.getString(columnIndex);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the downloadManagerId from an Intent sent by the DownloadManagerReceiver
|
|
||||||
*/
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
|
||||||
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 unique id for that download
|
|
||||||
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 specified id
|
|
||||||
* @return -1 if not downloading, else the id from the Android download manager
|
|
||||||
*/
|
|
||||||
public static long isDownloading(Context context, String uniqueDownloadId) {
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
|
|
||||||
// TODO: remove. This is necessary because AppDetails calls this
|
|
||||||
// static method directly, without using the whole pipe through
|
|
||||||
// DownloaderFactory. This shouldn't be called at all on android-8
|
|
||||||
// devices, since AppDetails is really using the old downloader,
|
|
||||||
// not this one.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
DownloadManager.Query query = new DownloadManager.Query();
|
|
||||||
Cursor c = dm.query(query);
|
|
||||||
if (c == null) {
|
|
||||||
// TODO: same as above.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int columnUniqueDownloadId = c.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION);
|
|
||||||
int columnId = c.getColumnIndex(DownloadManager.COLUMN_ID);
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (c.moveToNext()) {
|
|
||||||
if (uniqueDownloadId.equals(c.getString(columnUniqueDownloadId))) {
|
|
||||||
return c.getLong(columnId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a specific download is complete.
|
|
||||||
* @return -1 if download is not complete, otherwise the download id
|
|
||||||
*/
|
|
||||||
private static long isDownloadComplete(Context context, String uniqueDownloadId) {
|
|
||||||
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 columnUniqueDownloadId = c.getColumnIndex(DownloadManager.COLUMN_DESCRIPTION);
|
|
||||||
int columnId = c.getColumnIndex(DownloadManager.COLUMN_ID);
|
|
||||||
|
|
||||||
try {
|
|
||||||
while (c.moveToNext()) {
|
|
||||||
if (uniqueDownloadId.equals(c.getString(columnUniqueDownloadId))) {
|
|
||||||
return c.getLong(columnId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if download was valid, see issue
|
|
||||||
* http://code.google.com/p/android/issues/detail?id=18462
|
|
||||||
* From http://stackoverflow.com/questions/8937817/downloadmanager-action-download-complete-broadcast-receiver-receiving-same-downl
|
|
||||||
* @return 0 if successful, -1 if download doesn't exist, else the DownloadManager.ERROR_... code
|
|
||||||
*/
|
|
||||||
public static int validDownload(Context context, long downloadId) {
|
|
||||||
//Verify if download is a success
|
|
||||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
Cursor c = dm.query(new DownloadManager.Query().setFilterById(downloadId));
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (c.moveToFirst()) {
|
|
||||||
int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
|
|
||||||
|
|
||||||
if (status == DownloadManager.STATUS_SUCCESSFUL) {
|
|
||||||
return 0; // Download is valid, celebrate
|
|
||||||
}
|
|
||||||
return c.getInt(c.getColumnIndex(DownloadManager.COLUMN_REASON));
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
c.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1; // download doesn't exist
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcast receiver to listen for ACTION_DOWNLOAD_COMPLETE broadcasts
|
|
||||||
*/
|
|
||||||
private final 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 downloadId = getDownloadId(context, dId);
|
|
||||||
if (listener != null && dId == AsyncDownloaderFromAndroid.this.downloadManagerId && downloadId != 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,14 +1,9 @@
|
|||||||
package org.fdroid.fdroid.net;
|
package org.fdroid.fdroid.net;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.DownloadManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
|
|
||||||
import org.fdroid.fdroid.Utils;
|
|
||||||
import org.fdroid.fdroid.data.Credentials;
|
import org.fdroid.fdroid.data.Credentials;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -90,62 +85,11 @@ public class DownloaderFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static AsyncDownloader createAsync(Context context, String urlString, File destFile, String title, String id, Credentials credentials, AsyncDownloader.Listener listener) throws IOException {
|
public static AsyncDownloader createAsync(Context context, String urlString, File destFile, String title, String id, Credentials credentials, AsyncDownloader.Listener listener) throws IOException {
|
||||||
return createAsync(context, new URL(urlString), destFile, title, id, credentials, listener);
|
URL url = new URL(urlString);
|
||||||
}
|
|
||||||
|
|
||||||
public static AsyncDownloader createAsync(Context context, URL url, File destFile, String title, String id, Credentials credentials, AsyncDownloader.Listener listener)
|
|
||||||
throws IOException {
|
|
||||||
// To re-enable, fix the following:
|
|
||||||
// * https://gitlab.com/fdroid/fdroidclient/issues/445
|
|
||||||
// * https://gitlab.com/fdroid/fdroidclient/issues/459
|
|
||||||
if (false && canUseDownloadManager(context, url)) {
|
|
||||||
Utils.debugLog(TAG, "Using AsyncDownloaderFromAndroid");
|
|
||||||
return new AsyncDownloaderFromAndroid(context, listener, title, id, url.toString(), destFile);
|
|
||||||
}
|
|
||||||
Utils.debugLog(TAG, "Using AsyncDownloadWrapper");
|
|
||||||
return new AsyncDownloadWrapper(create(context, url, destFile, credentials), listener);
|
return new AsyncDownloadWrapper(create(context, url, destFile, credentials), listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isOnionAddress(URL url) {
|
private static boolean isOnionAddress(URL url) {
|
||||||
return url.getHost().endsWith(".onion");
|
return url.getHost().endsWith(".onion");
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
|
|
||||||
private static boolean hasDownloadManager(Context context) {
|
|
||||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
if (dm == null) {
|
|
||||||
// Service was not found
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DownloadManager.Query query = new DownloadManager.Query();
|
|
||||||
Cursor c = dm.query(query);
|
|
||||||
if (c == null) {
|
|
||||||
// Download Manager was disabled
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
c.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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(Context context, URL url) {
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
|
||||||
// No HTTPS support on 2.3, no DownloadManager on 2.2. Don't have
|
|
||||||
// 3.0 devices to test on, so require 4.0.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isOnionAddress(url)) {
|
|
||||||
// We support onion addresses through our own downloader.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isBluetoothAddress(url)) {
|
|
||||||
// Completely differnet protocol not understood by the download manager.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return hasDownloadManager(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,85 +0,0 @@
|
|||||||
package org.fdroid.fdroid.receiver;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.DownloadManager;
|
|
||||||
import android.app.Notification;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.support.annotation.StringRes;
|
|
||||||
import android.support.v4.app.NotificationCompat;
|
|
||||||
|
|
||||||
import org.fdroid.fdroid.AppDetails;
|
|
||||||
import org.fdroid.fdroid.R;
|
|
||||||
import org.fdroid.fdroid.net.AsyncDownloaderFromAndroid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receive notifications from the Android DownloadManager and pass them onto the
|
|
||||||
* AppDetails activity
|
|
||||||
*/
|
|
||||||
@TargetApi(9)
|
|
||||||
public class DownloadManagerReceiver extends BroadcastReceiver {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
// work out the package name to send to the AppDetails Screen
|
|
||||||
long downloadId = AsyncDownloaderFromAndroid.getDownloadId(intent);
|
|
||||||
String packageName = AsyncDownloaderFromAndroid.getDownloadId(context, downloadId);
|
|
||||||
|
|
||||||
if (packageName == null) {
|
|
||||||
// bogus broadcast (e.g. download cancelled, but system sent a DOWNLOAD_COMPLETE)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
|
|
||||||
int status = AsyncDownloaderFromAndroid.validDownload(context, downloadId);
|
|
||||||
if (status == 0) {
|
|
||||||
// successful download
|
|
||||||
showNotification(context, packageName, intent, downloadId, R.string.tap_to_install);
|
|
||||||
} else {
|
|
||||||
// download failed!
|
|
||||||
showNotification(context, packageName, intent, downloadId, R.string.download_error);
|
|
||||||
|
|
||||||
// clear the download to allow user to download again
|
|
||||||
DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
dm.remove(downloadId);
|
|
||||||
}
|
|
||||||
} else if (DownloadManager.ACTION_NOTIFICATION_CLICKED.equals(intent.getAction())) {
|
|
||||||
// pass the notification click onto the AppDetails screen and let it handle it
|
|
||||||
Intent appDetails = new Intent(context, AppDetails.class);
|
|
||||||
appDetails.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
appDetails.setAction(intent.getAction());
|
|
||||||
appDetails.putExtras(intent.getExtras());
|
|
||||||
appDetails.putExtra(AppDetails.EXTRA_APPID, packageName);
|
|
||||||
context.startActivity(appDetails);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showNotification(Context context, String packageName, Intent intent, long downloadId,
|
|
||||||
@StringRes int messageResId) {
|
|
||||||
// show a notification the user can click to install the app
|
|
||||||
Intent appDetails = new Intent(context, AppDetails.class);
|
|
||||||
appDetails.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
||||||
appDetails.setAction(intent.getAction());
|
|
||||||
appDetails.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId);
|
|
||||||
appDetails.putExtra(AppDetails.EXTRA_APPID, packageName);
|
|
||||||
|
|
||||||
// set separate pending intents per download id
|
|
||||||
PendingIntent pi = PendingIntent.getActivity(
|
|
||||||
context, (int) downloadId, appDetails, PendingIntent.FLAG_ONE_SHOT);
|
|
||||||
|
|
||||||
// build & show notification
|
|
||||||
String downloadTitle = AsyncDownloaderFromAndroid.getDownloadTitle(context, downloadId);
|
|
||||||
Notification notif = new NotificationCompat.Builder(context)
|
|
||||||
.setContentTitle(downloadTitle)
|
|
||||||
.setContentText(context.getString(messageResId))
|
|
||||||
.setSmallIcon(R.drawable.ic_stat_notify)
|
|
||||||
.setContentIntent(pi)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
|
||||||
nm.notify((int) downloadId, notif);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user