summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/providers/downloads/Constants.java3
-rw-r--r--src/com/android/providers/downloads/DownloadInfo.java3
-rw-r--r--src/com/android/providers/downloads/DownloadNotifier.java104
-rw-r--r--src/com/android/providers/downloads/DownloadReceiver.java3
-rw-r--r--src/com/android/providers/downloads/DownloadService.java3
-rw-r--r--src/com/android/providers/downloads/DownloadStorageProvider.java17
-rw-r--r--src/com/android/providers/downloads/DownloadThread.java18
-rw-r--r--src/com/android/providers/downloads/OpenHelper.java18
8 files changed, 151 insertions, 18 deletions
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/DownloadInfo.java b/src/com/android/providers/downloads/DownloadInfo.java
index bee5c4a9..a0a77b43 100644
--- a/src/com/android/providers/downloads/DownloadInfo.java
+++ b/src/com/android/providers/downloads/DownloadInfo.java
@@ -372,7 +372,8 @@ public class DownloadInfo {
if (!Downloads.Impl.isStatusCompleted(mStatus)) {
return false;
}
- if (mVisibility == Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
+ if (mVisibility == Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED ||
+ mVisibility == DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION) {
return true;
}
return false;
diff --git a/src/com/android/providers/downloads/DownloadNotifier.java b/src/com/android/providers/downloads/DownloadNotifier.java
index 60c249f9..7fbb35b8 100644
--- a/src/com/android/providers/downloads/DownloadNotifier.java
+++ b/src/com/android/providers/downloads/DownloadNotifier.java
@@ -35,6 +35,7 @@ import android.os.SystemClock;
import android.provider.Downloads;
import android.text.TextUtils;
import android.text.format.DateUtils;
+import android.text.format.Formatter;
import android.util.Log;
import android.util.LongSparseLongArray;
@@ -153,9 +154,37 @@ 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;
+ }
+ }
+
+ // Check error status about downloads. If error exists, will
+ // update icon and content title/content text in notification.
+ boolean hasErrorStatus = false;
+ for (DownloadInfo info : cluster) {
+ if (isErrorStatus(info.mStatus)) {
+ hasErrorStatus = true;
+ 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 if (hasErrorStatus) {
+ builder.setSmallIcon(R.drawable.download_error);
+ } 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) {
@@ -205,9 +234,10 @@ public class DownloadNotifier {
// Calculate and show progress
String remainingText = null;
String percentText = null;
+ String speedAsSizeText = null;
+ long total = 0;
if (type == TYPE_ACTIVE) {
long current = 0;
- long total = 0;
long speed = 0;
synchronized (mDownloadSpeed) {
for (DownloadInfo info : cluster) {
@@ -225,8 +255,26 @@ public class DownloadNotifier {
if (speed > 0) {
final long remainingMillis = ((total - current) * 1000) / speed;
+ final int duration, durationResId;
+
+ // This duplicates DateUtils.formatDuration(), but uses our
+ // abbreviated plurals.
+ if (remainingMillis >= DateUtils.HOUR_IN_MILLIS) {
+ duration = (int) ((remainingMillis + 1800000)
+ / DateUtils.HOUR_IN_MILLIS);
+ durationResId = R.plurals.duration_hours;
+ } else if (remainingMillis >= DateUtils.MINUTE_IN_MILLIS) {
+ duration = (int) ((remainingMillis + 30000)
+ / DateUtils.MINUTE_IN_MILLIS);
+ durationResId = R.plurals.duration_minutes;
+ } else {
+ duration = (int) ((remainingMillis + 500)
+ / DateUtils.SECOND_IN_MILLIS);
+ durationResId = R.plurals.duration_seconds;
+ }
remainingText = res.getString(R.string.download_remaining,
- DateUtils.formatDuration(remainingMillis));
+ res.getQuantityString(durationResId, duration, duration));
+ speedAsSizeText = Formatter.formatFileSize(mContext, speed);
}
final int percent = (int) ((current * 100) / total);
@@ -244,10 +292,20 @@ public class DownloadNotifier {
builder.setContentTitle(getDownloadTitle(res, info));
if (type == TYPE_ACTIVE) {
- if (!TextUtils.isEmpty(info.mDescription)) {
- builder.setContentText(info.mDescription);
- } else {
- builder.setContentText(remainingText);
+ 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));
+ } else if (hasErrorStatus) {
+ builder.setContentText(res.getText(
+ R.string.notification_download_failed));
+ if (total == 0)
+ builder.setProgress(100, 0, false);
}
builder.setContentInfo(percentText);
@@ -274,10 +332,20 @@ 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 if (hasErrorStatus) {
+ builder.setContentText(res.getText(
+ R.string.notification_download_failed));
+ if (total == 0)
+ builder.setProgress(100, 0, false);
+ } else {
+ builder.setContentTitle(res.getQuantityString(
+ R.plurals.notif_summary_active, cluster.size(), cluster.size()));
+ }
builder.setContentText(remainingText);
- builder.setContentInfo(percentText);
+ builder.setContentInfo(res.getString(R.string.download_speed_text,
+ percentText, speedAsSizeText));
inboxStyle.setSummaryText(remainingText);
} else if (type == TYPE_WAITING) {
@@ -360,7 +428,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);
}
@@ -370,4 +438,18 @@ 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;
+ }
+
+ private static boolean isErrorStatus(int status) {
+ boolean isErrorStatus = Downloads.Impl.isStatusError(status)
+ || Downloads.Impl.isStatusClientError(status)
+ || Downloads.Impl.isStatusServerError(status)
+ || status == Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR
+ || status == Downloads.Impl.STATUS_DEVICE_NOT_FOUND_ERROR;
+ return isErrorStatus;
+ }
}
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/DownloadService.java b/src/com/android/providers/downloads/DownloadService.java
index b0b73297..d1190cc1 100644
--- a/src/com/android/providers/downloads/DownloadService.java
+++ b/src/com/android/providers/downloads/DownloadService.java
@@ -366,7 +366,6 @@ public class DownloadService extends Service {
final int idColumn = cursor.getColumnIndexOrThrow(Downloads.Impl._ID);
while (cursor.moveToNext()) {
final long id = cursor.getLong(idColumn);
- staleIds.remove(id);
DownloadInfo info = mDownloads.get(id);
if (info != null) {
@@ -383,6 +382,7 @@ public class DownloadService extends Service {
deleteFileIfExists(info.mFileName);
resolver.delete(info.getAllDownloadsUri(), null, null);
+ staleIds.add(info.mId);
} else {
// Kick off download task if ready
@@ -398,6 +398,7 @@ public class DownloadService extends Service {
isActive |= activeDownload;
isActive |= activeScan;
+ staleIds.remove(id);
}
// Keep track of nearest next 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 + "-");
}
diff --git a/src/com/android/providers/downloads/OpenHelper.java b/src/com/android/providers/downloads/OpenHelper.java
index 4eb319c4..8cca9bed 100644
--- a/src/com/android/providers/downloads/OpenHelper.java
+++ b/src/com/android/providers/downloads/OpenHelper.java
@@ -18,6 +18,7 @@ package com.android.providers.downloads;
import static android.app.DownloadManager.COLUMN_LOCAL_FILENAME;
import static android.app.DownloadManager.COLUMN_LOCAL_URI;
+import static android.app.DownloadManager.COLUMN_MEDIAPROVIDER_URI;
import static android.app.DownloadManager.COLUMN_MEDIA_TYPE;
import static android.app.DownloadManager.COLUMN_URI;
import static android.provider.Downloads.Impl.ALL_DOWNLOADS_CONTENT_URI;
@@ -32,6 +33,7 @@ import android.database.Cursor;
import android.net.Uri;
import android.provider.Downloads.Impl.RequestHeaders;
import android.util.Log;
+import android.webkit.MimeTypeMap;
import java.io.File;
@@ -75,6 +77,14 @@ public class OpenHelper {
final Uri localUri = getCursorUri(cursor, COLUMN_LOCAL_URI);
final File file = getCursorFile(cursor, COLUMN_LOCAL_FILENAME);
String mimeType = getCursorString(cursor, COLUMN_MEDIA_TYPE);
+ if ("application/octet-stream".equals(mimeType)) {
+ MimeTypeMap m = MimeTypeMap.getSingleton();
+ String guess = m.getMimeTypeFromExtension(
+ m.getFileExtensionFromUrl(localUri.toString()));
+ if (guess != null) {
+ mimeType = guess;
+ }
+ }
mimeType = DownloadDrmHelper.getOriginalMimeType(context, file, mimeType);
final Intent intent = new Intent(Intent.ACTION_VIEW);
@@ -88,6 +98,10 @@ public class OpenHelper {
intent.putExtra(Intent.EXTRA_ORIGINATING_URI, remoteUri);
intent.putExtra(Intent.EXTRA_REFERRER, getRefererUri(context, id));
intent.putExtra(Intent.EXTRA_ORIGINATING_UID, getOriginatingUid(context, id));
+ } else if (mimeType.startsWith("image/") && !isNull(cursor, COLUMN_MEDIAPROVIDER_URI)) {
+ final Uri mediaUri = getCursorUri(cursor, COLUMN_MEDIAPROVIDER_URI);
+ intent.setDataAndType(mediaUri, mimeType);
+ intent.putExtra("SingleItemOnly", true);
} else if ("file".equals(localUri.getScheme())) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
@@ -139,6 +153,10 @@ public class OpenHelper {
return -1;
}
+ private static Boolean isNull(Cursor cursor, String column) {
+ return cursor.isNull(cursor.getColumnIndexOrThrow(column));
+ }
+
private static String getCursorString(Cursor cursor, String column) {
return cursor.getString(cursor.getColumnIndexOrThrow(column));
}