diff --git a/F-Droid/res/values/strings.xml b/F-Droid/res/values/strings.xml index 5617be28b..25e9ded61 100644 --- a/F-Droid/res/values/strings.xml +++ b/F-Droid/res/values/strings.xml @@ -344,6 +344,7 @@ Do you want to replace this app with the factory version? Do you want to uninstall this app? Download completed, tap to install + Download unsuccessful New: Provided by %1$s. diff --git a/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloaderFromAndroid.java b/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloaderFromAndroid.java index 8350fb226..5e06f8fc7 100644 --- a/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloaderFromAndroid.java +++ b/F-Droid/src/org/fdroid/fdroid/net/AsyncDownloaderFromAndroid.java @@ -12,7 +12,9 @@ import android.os.Build; import android.os.ParcelFileDescriptor; import android.support.v4.content.LocalBroadcastManager; import android.text.TextUtils; +import android.util.Log; +import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; import java.io.File; @@ -68,9 +70,22 @@ public class AsyncDownloaderFromAndroid implements AsyncDownloader { 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 if ((downloadManagerId = isDownloadComplete(context, uniqueDownloadId)) > 0) { - // clear the notification + // clear the download dm.remove(downloadManagerId); try { @@ -313,6 +328,35 @@ public class AsyncDownloaderFromAndroid implements AsyncDownloader { 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 + } else { + 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 */ diff --git a/F-Droid/src/org/fdroid/fdroid/receiver/DownloadManagerReceiver.java b/F-Droid/src/org/fdroid/fdroid/receiver/DownloadManagerReceiver.java index 3c50edf00..52aa51b1a 100644 --- a/F-Droid/src/org/fdroid/fdroid/receiver/DownloadManagerReceiver.java +++ b/F-Droid/src/org/fdroid/fdroid/receiver/DownloadManagerReceiver.java @@ -1,5 +1,6 @@ package org.fdroid.fdroid.receiver; +import android.annotation.TargetApi; import android.app.DownloadManager; import android.app.Notification; import android.app.NotificationManager; @@ -7,16 +8,20 @@ import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.database.Cursor; +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.AsyncDownloader; 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) { @@ -30,28 +35,18 @@ public class DownloadManagerReceiver extends BroadcastReceiver { } if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) { - // 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.putExtras(intent.getExtras()); - appDetails.putExtra(AppDetails.EXTRA_APPID, appId); + int status = AsyncDownloaderFromAndroid.validDownload(context, downloadId); + if (status == 0) { + // successful download + showNotification(context, appId, intent, downloadId, R.string.tap_to_install); + } else { + // download failed! + showNotification(context, appId, intent, downloadId, R.string.download_error); - PendingIntent pi = PendingIntent.getActivity( - context, 1, appDetails, PendingIntent.FLAG_ONE_SHOT); - - // launch LocalRepoActivity if the user selects this notification - String downloadTitle = AsyncDownloaderFromAndroid.getDownloadTitle(context, downloadId); - Notification notif = new NotificationCompat.Builder(context) - .setContentTitle(downloadTitle) - .setContentText(context.getString(R.string.tap_to_install)) - .setSmallIcon(R.drawable.ic_stat_notify) - .setContentIntent(pi) - .setAutoCancel(true) - .build(); - - NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - nm.notify((int)downloadId, notif); + // 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); @@ -62,4 +57,30 @@ public class DownloadManagerReceiver extends BroadcastReceiver { context.startActivity(appDetails); } } + + private void showNotification(Context context, String appId, 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.putExtras(intent.getExtras()); + appDetails.putExtra(AppDetails.EXTRA_APPID, appId); + + PendingIntent pi = PendingIntent.getActivity( + context, 1, appDetails, PendingIntent.FLAG_ONE_SHOT); + + // launch LocalRepoActivity if the user selects this 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); + } }