From ecd609e7017b8a69688bbae25c17d878ea305f19 Mon Sep 17 00:00:00 2001 From: qqzhou Date: Tue, 17 Dec 2013 14:18:55 +0800 Subject: DownloadProvider: add to support pause/resume download by manual This feature contains below points: 1. add to pause running download by manual. 2. add to resume manually paused download by manual. 3. add to show proper contents in notification and download-list for manually paused status. 4. add to support download breakpoint continuing when HTTP server doesn't contain etag in response header. Android baseline only supports this when etag is not null. 5. add to show proper contents in notification and download-list for status of waiting-for-network. Change-Id: I433cdee2de8b3add0248bbb0a9d02f8da4e5bb38 --- src/com/android/providers/downloads/Constants.java | 3 ++ .../providers/downloads/DownloadNotifier.java | 41 +++++++++++++++++++--- .../providers/downloads/DownloadReceiver.java | 3 +- .../downloads/DownloadStorageProvider.java | 17 +++++++-- .../providers/downloads/DownloadThread.java | 18 +++++++++- 5 files changed, 72 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/com/android/providers/downloads/Constants.java b/src/com/android/providers/downloads/Constants.java index 7b8fcd24..a10cb514 100644 --- a/src/com/android/providers/downloads/Constants.java +++ b/src/com/android/providers/downloads/Constants.java @@ -57,6 +57,9 @@ public class Constants { /** the intent that gets sent when deleting the notification of a completed download */ public static final String ACTION_HIDE = "android.intent.action.DOWNLOAD_HIDE"; + /** the intent that gets sent when choosing to resume the paused download */ + public static final String ACTION_RESUME = "android.intent.action.DOWNLOAD_RESUME"; + /** The default base name for downloaded files if we can't get one at the HTTP level */ public static final String DEFAULT_DL_FILENAME = "downloadfile"; diff --git a/src/com/android/providers/downloads/DownloadNotifier.java b/src/com/android/providers/downloads/DownloadNotifier.java index 3af97463..5e1b9de2 100644 --- a/src/com/android/providers/downloads/DownloadNotifier.java +++ b/src/com/android/providers/downloads/DownloadNotifier.java @@ -154,9 +154,25 @@ public class DownloadNotifier { } builder.setWhen(firstShown); + // Check paused status about these downloads. If exists, will + // update icon and content title/content text in notification. + boolean hasPausedStatus = false; + int pausedStatus = -1; + for (DownloadInfo info : cluster) { + if (isPausedStatus(info.mStatus)) { + hasPausedStatus = true; + pausedStatus = info.mStatus; + break; + } + } + // Show relevant icon if (type == TYPE_ACTIVE) { - builder.setSmallIcon(android.R.drawable.stat_sys_download); + if (hasPausedStatus) { + builder.setSmallIcon(R.drawable.download_pause); + } else { + builder.setSmallIcon(android.R.drawable.stat_sys_download); + } } else if (type == TYPE_WAITING) { builder.setSmallIcon(android.R.drawable.stat_sys_warning); } else if (type == TYPE_COMPLETE) { @@ -264,7 +280,13 @@ public class DownloadNotifier { builder.setContentTitle(getDownloadTitle(res, info)); if (type == TYPE_ACTIVE) { - if (speedAsSizeText != null) { + if (hasPausedStatus) { + if (pausedStatus == Downloads.Impl.STATUS_PAUSED_BY_MANUAL) { + builder.setContentText(res.getText(R.string.download_paused)); + } else { + builder.setContentText(res.getText(R.string.download_queued)); + } + } else if (speedAsSizeText != null) { builder.setContentText(res.getString(R.string.download_speed_text, remainingText, speedAsSizeText)); } @@ -293,8 +315,12 @@ public class DownloadNotifier { } if (type == TYPE_ACTIVE) { - builder.setContentTitle(res.getQuantityString( - R.plurals.notif_summary_active, cluster.size(), cluster.size())); + if (hasPausedStatus) { + builder.setContentTitle(res.getString(R.string.download_queued)); + } else { + builder.setContentTitle(res.getQuantityString( + R.plurals.notif_summary_active, cluster.size(), cluster.size())); + } builder.setContentText(remainingText); builder.setContentInfo(res.getString(R.string.download_speed_text, percentText, speedAsSizeText)); @@ -380,7 +406,7 @@ public class DownloadNotifier { } private static boolean isActiveAndVisible(DownloadInfo download) { - return download.mStatus == STATUS_RUNNING && + return Downloads.Impl.isStatusInformational(download.mStatus) && (download.mVisibility == VISIBILITY_VISIBLE || download.mVisibility == VISIBILITY_VISIBLE_NOTIFY_COMPLETED); } @@ -390,4 +416,9 @@ public class DownloadNotifier { (download.mVisibility == VISIBILITY_VISIBLE_NOTIFY_COMPLETED || download.mVisibility == VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION); } + + private static boolean isPausedStatus(int status) { + return status == Downloads.Impl.STATUS_WAITING_FOR_NETWORK || + status == Downloads.Impl.STATUS_PAUSED_BY_MANUAL; + } } diff --git a/src/com/android/providers/downloads/DownloadReceiver.java b/src/com/android/providers/downloads/DownloadReceiver.java index 28e2a673..d2872356 100644 --- a/src/com/android/providers/downloads/DownloadReceiver.java +++ b/src/com/android/providers/downloads/DownloadReceiver.java @@ -87,7 +87,8 @@ public class DownloadReceiver extends BroadcastReceiver { } }); - } else if (Constants.ACTION_RETRY.equals(action)) { + } else if (Constants.ACTION_RETRY.equals(action) || + Constants.ACTION_RESUME.equals(action)) { startService(context); } else if (Constants.ACTION_OPEN.equals(action) diff --git a/src/com/android/providers/downloads/DownloadStorageProvider.java b/src/com/android/providers/downloads/DownloadStorageProvider.java index 1b5dc844..69efab31 100644 --- a/src/com/android/providers/downloads/DownloadStorageProvider.java +++ b/src/com/android/providers/downloads/DownloadStorageProvider.java @@ -303,20 +303,31 @@ public class DownloadStorageProvider extends DocumentsProvider { size = null; } + final long progress = cursor.getLong(cursor.getColumnIndexOrThrow( + DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); final int status = cursor.getInt( cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)); + final int reason = cursor.getInt( + cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON)); switch (status) { case DownloadManager.STATUS_SUCCESSFUL: break; case DownloadManager.STATUS_PAUSED: - summary = getContext().getString(R.string.download_queued); + if (size != null) { + final long percent = progress * 100 / size; + summary = (reason == DownloadManager.PAUSED_BY_MANUAL) ? + getContext().getString(R.string.download_paused_percent, percent) : + getContext().getString(R.string.download_queued_percent, percent); + } else { + summary = (reason == DownloadManager.PAUSED_BY_MANUAL) ? + getContext().getString(R.string.download_paused) : + getContext().getString(R.string.download_queued); + } break; case DownloadManager.STATUS_PENDING: summary = getContext().getString(R.string.download_queued); break; case DownloadManager.STATUS_RUNNING: - final long progress = cursor.getLong(cursor.getColumnIndexOrThrow( - DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); if (size != null) { String percent = NumberFormat.getPercentInstance().format((double) progress / size); diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java index 325b4eee..c905e25a 100644 --- a/src/com/android/providers/downloads/DownloadThread.java +++ b/src/com/android/providers/downloads/DownloadThread.java @@ -116,6 +116,11 @@ public class DownloadThread implements Runnable { private volatile boolean mPolicyDirty; + // Add for carrier feature - download breakpoint continuing. + // Support continuing download after the download is broken + // although HTTP Server doesn't contain etag in its response. + private final static String QRD_ETAG = "qrd_magic_etag"; + /** * Local changes to {@link DownloadInfo}. These are kept local to avoid * racing with the thread that updates based on change notifications. @@ -686,6 +691,11 @@ public class DownloadThread implements Runnable { if (mInfo.mStatus == Downloads.Impl.STATUS_CANCELED || mInfo.mDeleted) { throw new StopRequestException(Downloads.Impl.STATUS_CANCELED, "download canceled"); } + if (mInfo.mStatus == Downloads.Impl.STATUS_PAUSED_BY_MANUAL) { + // user pauses the download by manual, here send exception and stop data transfer. + throw new StopRequestException(Downloads.Impl.STATUS_PAUSED_BY_MANUAL, + "download paused by manual"); + } } // if policy has been changed, trigger connectivity check @@ -767,6 +777,10 @@ public class DownloadThread implements Runnable { mInfoDelta.mETag = conn.getHeaderField("ETag"); + if (mInfoDelta.mETag == null) { + mInfoDelta.mETag = QRD_ETAG; + } + mInfoDelta.writeToDatabaseOrThrow(); // Check connectivity again now that we know the total size @@ -812,7 +826,9 @@ public class DownloadThread implements Runnable { if (resuming) { if (mInfoDelta.mETag != null) { - conn.addRequestProperty("If-Match", mInfoDelta.mETag); + if (!mInfoDelta.mETag.equals(QRD_ETAG)) { + conn.addRequestProperty("If-Match", mInfoDelta.mETag); + } } conn.addRequestProperty("Range", "bytes=" + mInfoDelta.mCurrentBytes + "-"); } -- cgit v1.2.3