diff options
author | Ricardo Cerqueira <ricardo@cyngn.com> | 2015-03-10 12:28:19 +0000 |
---|---|---|
committer | Ricardo Cerqueira <ricardo@cyngn.com> | 2015-03-10 12:28:19 +0000 |
commit | 1958bec7cd1cd58a0ee83fcd837ff19c226d6470 (patch) | |
tree | e6bfd4d91dcfeb5d9dd1ce9adccafa3ac4574145 /src/com/android/providers | |
parent | 05775ecc734a8fa1de16692962b5ee2808332b7e (diff) | |
parent | 1de359e31359f9aa6c500b378082e9d6e37d94b3 (diff) | |
download | android_packages_providers_DownloadProvider-1958bec7cd1cd58a0ee83fcd837ff19c226d6470.tar.gz android_packages_providers_DownloadProvider-1958bec7cd1cd58a0ee83fcd837ff19c226d6470.tar.bz2 android_packages_providers_DownloadProvider-1958bec7cd1cd58a0ee83fcd837ff19c226d6470.zip |
Merge tag 'android-5.1.0_r1' into HEADstaging/cm-12.1
Android 5.1.0 release 1
Diffstat (limited to 'src/com/android/providers')
4 files changed, 47 insertions, 66 deletions
diff --git a/src/com/android/providers/downloads/DownloadNotifier.java b/src/com/android/providers/downloads/DownloadNotifier.java index 0fb5a583..3af97463 100644 --- a/src/com/android/providers/downloads/DownloadNotifier.java +++ b/src/com/android/providers/downloads/DownloadNotifier.java @@ -43,6 +43,7 @@ import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import java.text.NumberFormat; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -221,8 +222,8 @@ public class DownloadNotifier { } if (total > 0) { - final int percent = (int) ((current * 100) / total); - percentText = res.getString(R.string.download_percent, percent); + percentText = + NumberFormat.getPercentInstance().format((double) current / total); if (speed > 0) { final long remainingMillis = ((total - current) * 1000) / speed; @@ -248,6 +249,7 @@ public class DownloadNotifier { speedAsSizeText = Formatter.formatFileSize(mContext, speed); } + final int percent = (int) ((current * 100) / total); builder.setProgress(100, percent, false); } else { builder.setProgress(100, 0, true); diff --git a/src/com/android/providers/downloads/DownloadStorageProvider.java b/src/com/android/providers/downloads/DownloadStorageProvider.java index 78b3c430..80d78551 100644 --- a/src/com/android/providers/downloads/DownloadStorageProvider.java +++ b/src/com/android/providers/downloads/DownloadStorageProvider.java @@ -42,6 +42,7 @@ import libcore.io.IoUtils; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.text.NumberFormat; /** * Presents a {@link DocumentsContract} view of {@link DownloadManager} @@ -321,7 +322,8 @@ public class DownloadStorageProvider extends DocumentsProvider { final long progress = cursor.getLong(cursor.getColumnIndexOrThrow( DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); if (size != null) { - final long percent = progress * 100 / size; + String percent = + NumberFormat.getPercentInstance().format((double) progress / size); summary = getContext().getString(R.string.download_running_percent, percent); } else { summary = getContext().getString(R.string.download_running); diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java index aa0190bf..c75e4193 100644 --- a/src/com/android/providers/downloads/DownloadThread.java +++ b/src/com/android/providers/downloads/DownloadThread.java @@ -17,6 +17,7 @@ package com.android.providers.downloads; import static android.provider.Downloads.Impl.STATUS_BAD_REQUEST; +import static android.provider.Downloads.Impl.STATUS_CANCELED; import static android.provider.Downloads.Impl.STATUS_CANNOT_RESUME; import static android.provider.Downloads.Impl.STATUS_FILE_ERROR; import static android.provider.Downloads.Impl.STATUS_HTTP_DATA_ERROR; @@ -143,10 +144,7 @@ public class DownloadThread implements Runnable { mETag = info.mETag; } - /** - * Push update of current delta values to provider. - */ - public void writeToDatabase() { + private ContentValues buildContentValues() { final ContentValues values = new ContentValues(); values.put(Downloads.Impl.COLUMN_URI, mUri); @@ -162,7 +160,26 @@ public class DownloadThread implements Runnable { values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, mSystemFacade.currentTimeMillis()); values.put(Downloads.Impl.COLUMN_ERROR_MSG, mErrorMsg); - mContext.getContentResolver().update(mInfo.getAllDownloadsUri(), values, null, null); + return values; + } + + /** + * Blindly push update of current delta values to provider. + */ + public void writeToDatabase() { + mContext.getContentResolver().update(mInfo.getAllDownloadsUri(), buildContentValues(), + null, null); + } + + /** + * Push update of current delta values to provider, asserting strongly + * that we haven't been paused or deleted. + */ + public void writeToDatabaseOrThrow() throws StopRequestException { + if (mContext.getContentResolver().update(mInfo.getAllDownloadsUri(), + buildContentValues(), Downloads.Impl.COLUMN_DELETED + " == '0'", null) == 0) { + throw new StopRequestException(STATUS_CANCELED, "Download deleted or missing!"); + } } } @@ -422,12 +439,16 @@ public class DownloadThread implements Runnable { */ private void transferData(HttpURLConnection conn) throws StopRequestException { - // To detect when we're really finished, we either need a length or - // chunked encoding. + // To detect when we're really finished, we either need a length, closed + // connection, or chunked encoding. final boolean hasLength = mInfoDelta.mTotalBytes != -1; - final String transferEncoding = conn.getHeaderField("Transfer-Encoding"); - final boolean isChunked = "chunked".equalsIgnoreCase(transferEncoding); - if (!hasLength && !isChunked) { + final boolean isConnectionClose = "close".equalsIgnoreCase( + conn.getHeaderField("Connection")); + final boolean isEncodingChunked = "chunked".equalsIgnoreCase( + conn.getHeaderField("Transfer-Encoding")); + + final boolean finishKnown = hasLength || isConnectionClose || isEncodingChunked; + if (!finishKnown) { throw new StopRequestException( STATUS_CANNOT_RESUME, "can't know size of download, giving up"); } @@ -666,7 +687,7 @@ public class DownloadThread implements Runnable { /** * Report download progress through the database if necessary. */ - private void updateProgress(FileDescriptor outFd) throws IOException { + private void updateProgress(FileDescriptor outFd) throws IOException, StopRequestException { final long now = SystemClock.elapsedRealtime(); final long currentBytes = mInfoDelta.mCurrentBytes; @@ -697,7 +718,7 @@ public class DownloadThread implements Runnable { // so we can always resume based on latest database information. outFd.sync(); - mInfoDelta.writeToDatabase(); + mInfoDelta.writeToDatabaseOrThrow(); mLastUpdateBytes = currentBytes; mLastUpdateTime = now; @@ -736,7 +757,7 @@ public class DownloadThread implements Runnable { mInfoDelta.mETag = conn.getHeaderField("ETag"); - mInfoDelta.writeToDatabase(); + mInfoDelta.writeToDatabaseOrThrow(); // Check connectivity again now that we know the total size checkConnectivity(); @@ -775,6 +796,10 @@ public class DownloadThread implements Runnable { // easily resume partial downloads. conn.setRequestProperty("Accept-Encoding", "identity"); + // Defeat connection reuse, since otherwise servers may continue + // streaming large downloads after cancelled. + conn.setRequestProperty("Connection", "close"); + if (resuming) { if (mInfoDelta.mETag != null) { conn.addRequestProperty("If-Match", mInfoDelta.mETag); @@ -834,6 +859,7 @@ public class DownloadThread implements Runnable { case STATUS_HTTP_DATA_ERROR: case HTTP_UNAVAILABLE: case HTTP_INTERNAL_ERROR: + case STATUS_FILE_ERROR: return true; default: return false; diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java index eb071395..0aa49c0a 100644 --- a/src/com/android/providers/downloads/Helpers.java +++ b/src/com/android/providers/downloads/Helpers.java @@ -214,7 +214,7 @@ public class Helpers { // The VFAT file system is assumed as target for downloads. // Replace invalid characters according to the specifications of VFAT. - filename = replaceInvalidVfatCharacters(filename); + filename = FileUtils.buildValidFatFilename(filename); return filename; } @@ -665,53 +665,4 @@ public class Helpers { (c >= '0' && c <= '9'); } } - - /** - * Replace invalid filename characters according to - * specifications of the VFAT. - * @note Package-private due to testing. - */ - private static String replaceInvalidVfatCharacters(String filename) { - final char START_CTRLCODE = 0x00; - final char END_CTRLCODE = 0x1f; - final char QUOTEDBL = 0x22; - final char ASTERISK = 0x2A; - final char SLASH = 0x2F; - final char COLON = 0x3A; - final char LESS = 0x3C; - final char GREATER = 0x3E; - final char QUESTION = 0x3F; - final char BACKSLASH = 0x5C; - final char BAR = 0x7C; - final char DEL = 0x7F; - final char UNDERSCORE = 0x5F; - - StringBuffer sb = new StringBuffer(); - char ch; - boolean isRepetition = false; - for (int i = 0; i < filename.length(); i++) { - ch = filename.charAt(i); - if ((START_CTRLCODE <= ch && - ch <= END_CTRLCODE) || - ch == QUOTEDBL || - ch == ASTERISK || - ch == SLASH || - ch == COLON || - ch == LESS || - ch == GREATER || - ch == QUESTION || - ch == BACKSLASH || - ch == BAR || - ch == DEL){ - if (!isRepetition) { - sb.append(UNDERSCORE); - isRepetition = true; - } - } else { - sb.append(ch); - isRepetition = false; - } - } - return sb.toString(); - } } |