From ded2da137ce7c2c71ded2e6d163217ef95267ebb 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 manuallly 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 --- res/drawable-hdpi/download_pause.png | Bin 0 -> 1114 bytes res/drawable-mdpi/download_pause.png | Bin 0 -> 1107 bytes res/drawable-xhdpi/download_pause.png | Bin 0 -> 1181 bytes res/values-zh-rCN/cm_strings.xml | 6 ++- res/values/cm_strings.xml | 8 ++++ src/com/android/providers/downloads/Constants.java | 3 ++ .../providers/downloads/DownloadNotifier.java | 41 ++++++++++++++++++--- .../providers/downloads/DownloadReceiver.java | 3 +- .../downloads/DownloadStorageProvider.java | 18 +++++++-- .../providers/downloads/DownloadThread.java | 18 ++++++++- .../providers/downloads/ui/TrampolineActivity.java | 15 +++++++- 11 files changed, 100 insertions(+), 12 deletions(-) create mode 100644 res/drawable-hdpi/download_pause.png create mode 100644 res/drawable-mdpi/download_pause.png create mode 100644 res/drawable-xhdpi/download_pause.png mode change 100644 => 100755 src/com/android/providers/downloads/Constants.java mode change 100644 => 100755 src/com/android/providers/downloads/DownloadNotifier.java mode change 100644 => 100755 src/com/android/providers/downloads/DownloadReceiver.java mode change 100644 => 100755 src/com/android/providers/downloads/DownloadStorageProvider.java mode change 100644 => 100755 src/com/android/providers/downloads/DownloadThread.java mode change 100644 => 100755 ui/src/com/android/providers/downloads/ui/TrampolineActivity.java diff --git a/res/drawable-hdpi/download_pause.png b/res/drawable-hdpi/download_pause.png new file mode 100644 index 00000000..6b435bb0 Binary files /dev/null and b/res/drawable-hdpi/download_pause.png differ diff --git a/res/drawable-mdpi/download_pause.png b/res/drawable-mdpi/download_pause.png new file mode 100644 index 00000000..a5aee6f2 Binary files /dev/null and b/res/drawable-mdpi/download_pause.png differ diff --git a/res/drawable-xhdpi/download_pause.png b/res/drawable-xhdpi/download_pause.png new file mode 100644 index 00000000..333c1b24 Binary files /dev/null and b/res/drawable-xhdpi/download_pause.png differ diff --git a/res/values-zh-rCN/cm_strings.xml b/res/values-zh-rCN/cm_strings.xml index 74cc57ac..d5699eee 100644 --- a/res/values-zh-rCN/cm_strings.xml +++ b/res/values-zh-rCN/cm_strings.xml @@ -15,7 +15,11 @@ See the License for the specific language governing permissions and limitations under the License. --> - + 下载文件夹 下载 + + "已暂停" + "已暂停:%d%%" + "已加入队列:%d%%" diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index e9409a90..a1c98b98 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -17,4 +17,12 @@ Downloads folder Downloads + + + Paused + + Paused, %d%% + + Queued, %d%% diff --git a/src/com/android/providers/downloads/Constants.java b/src/com/android/providers/downloads/Constants.java old mode 100644 new mode 100755 index 89210a25..1128afc6 --- a/src/com/android/providers/downloads/Constants.java +++ b/src/com/android/providers/downloads/Constants.java @@ -60,6 +60,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 old mode 100644 new mode 100755 index ac52eba2..63e12ea8 --- a/src/com/android/providers/downloads/DownloadNotifier.java +++ b/src/com/android/providers/downloads/DownloadNotifier.java @@ -150,9 +150,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) { @@ -240,7 +256,12 @@ public class DownloadNotifier { builder.setContentTitle(getDownloadTitle(res, info)); if (type == TYPE_ACTIVE) { - if (!TextUtils.isEmpty(info.mDescription)) { + 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 (!TextUtils.isEmpty(info.mDescription)) { builder.setContentText(info.mDescription); } else { builder.setContentText(remainingText); @@ -270,8 +291,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(percentText); inboxStyle.setSummaryText(remainingText); @@ -356,7 +381,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); } @@ -366,4 +391,10 @@ 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 old mode 100644 new mode 100755 index f3d23766..a70a2936 --- a/src/com/android/providers/downloads/DownloadReceiver.java +++ b/src/com/android/providers/downloads/DownloadReceiver.java @@ -81,7 +81,8 @@ public class DownloadReceiver extends BroadcastReceiver { if (info != null && info.isConnected()) { startService(context); } - } else if (action.equals(Constants.ACTION_RETRY)) { + } else if (action.equals(Constants.ACTION_RETRY) || + action.equals(Constants.ACTION_RESUME)) { startService(context); } else if (action.equals(Constants.ACTION_OPEN) || action.equals(Constants.ACTION_LIST) diff --git a/src/com/android/providers/downloads/DownloadStorageProvider.java b/src/com/android/providers/downloads/DownloadStorageProvider.java old mode 100644 new mode 100755 index ecef54e0..ce15981c --- a/src/com/android/providers/downloads/DownloadStorageProvider.java +++ b/src/com/android/providers/downloads/DownloadStorageProvider.java @@ -305,21 +305,33 @@ public class DownloadStorageProvider extends DocumentsProvider { if (size == -1) { 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); + //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) { final long percent = progress * 100 / size; summary = getContext().getString(R.string.download_running_percent, percent); diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java old mode 100644 new mode 100755 index 93f8d650..9d5274c4 --- a/src/com/android/providers/downloads/DownloadThread.java +++ b/src/com/android/providers/downloads/DownloadThread.java @@ -92,6 +92,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"; + public DownloadThread(Context context, SystemFacade systemFacade, DownloadInfo info, StorageManager storageManager, DownloadNotifier notifier) { mContext = context; @@ -522,6 +527,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 @@ -711,6 +721,10 @@ public class DownloadThread implements Runnable { state.mHeaderETag = conn.getHeaderField("ETag"); + if (state.mHeaderETag == null) { + state.mHeaderETag = QRD_ETAG; + } + final String transferEncoding = conn.getHeaderField("Transfer-Encoding"); if (transferEncoding == null) { state.mContentLength = getHeaderFieldLong(conn, "Content-Length", -1); @@ -831,7 +845,9 @@ public class DownloadThread implements Runnable { if (state.mContinuingDownload) { if (state.mHeaderETag != null) { - conn.addRequestProperty("If-Match", state.mHeaderETag); + if (!state.mHeaderETag.equals(QRD_ETAG)) { + conn.addRequestProperty("If-Match", state.mHeaderETag); + } } conn.addRequestProperty("Range", "bytes=" + state.mCurrentBytes + "-"); } diff --git a/ui/src/com/android/providers/downloads/ui/TrampolineActivity.java b/ui/src/com/android/providers/downloads/ui/TrampolineActivity.java old mode 100644 new mode 100755 index f96c04ee..f9983fc7 --- a/ui/src/com/android/providers/downloads/ui/TrampolineActivity.java +++ b/ui/src/com/android/providers/downloads/ui/TrampolineActivity.java @@ -77,14 +77,27 @@ public class TrampolineActivity extends Activity { Log.d(Constants.TAG, "Found " + id + " with status " + status + ", reason " + reason); switch (status) { case DownloadManager.STATUS_PENDING: - case DownloadManager.STATUS_RUNNING: sendRunningDownloadClickedBroadcast(id); finish(); break; + case DownloadManager.STATUS_RUNNING: + // Add for carrier feature - pause and resume download by manual. + dm.pauseDownload(id); + finish(); + break; + case DownloadManager.STATUS_PAUSED: if (reason == DownloadManager.PAUSED_QUEUED_FOR_WIFI) { PausedDialogFragment.show(getFragmentManager(), id); + } else if (reason == DownloadManager.PAUSED_BY_MANUAL) { + // Add for carrier feature - pause and resume download by manual. + dm.resumeDownload(id); + Intent intent = new Intent(Constants.ACTION_RESUME); + intent.setClassName("com.android.providers.downloads", + "com.android.providers.downloads.DownloadReceiver"); + sendBroadcast(intent); + finish(); } else { sendRunningDownloadClickedBroadcast(id); finish(); -- cgit v1.2.3