diff options
author | Steve Howard <showard@google.com> | 2010-07-12 17:24:17 -0700 |
---|---|---|
committer | Steve Howard <showard@google.com> | 2010-07-14 11:33:17 -0700 |
commit | 6d9b98282c817b86a00f9c19a705da4cb19bc3a6 (patch) | |
tree | d262513c211424ffcefa26440f3ee0d63e3b0849 /src/com/android/providers/downloads/Helpers.java | |
parent | f413bd5422d918872e576c1c0c3e0b9227f15304 (diff) | |
download | android_packages_providers_DownloadProvider-6d9b98282c817b86a00f9c19a705da4cb19bc3a6.tar.gz android_packages_providers_DownloadProvider-6d9b98282c817b86a00f9c19a705da4cb19bc3a6.tar.bz2 android_packages_providers_DownloadProvider-6d9b98282c817b86a00f9c19a705da4cb19bc3a6.zip |
Support for file URI destinations + last modified timestamp
File URI destinations:
* permission checking in DownloadProvider
* implementation in Helpers.generateSaveFile(). it's a fairly small
amount of logic added here, but I did some significant method
extraction to simplify this change and clean up the code in general.
* added test case
Last modified timestamp:
* made DownloadProvider use a SystemFacade for getting system time, so I could properly test timestamps
* updated test cases to cover last modified time + handle new ordering
Diffstat (limited to 'src/com/android/providers/downloads/Helpers.java')
-rw-r--r-- | src/com/android/providers/downloads/Helpers.java | 146 |
1 files changed, 94 insertions, 52 deletions
diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java index 6bb5093a..2705a7cb 100644 --- a/src/com/android/providers/downloads/Helpers.java +++ b/src/com/android/providers/downloads/Helpers.java @@ -35,7 +35,7 @@ import android.util.Config; import android.util.Log; import android.webkit.MimeTypeMap; -import java.io.File; +import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.util.Random; @@ -76,6 +76,17 @@ public class Helpers { } /** + * Exception thrown from methods called by generateSaveFile() for any fatal error. + */ + private static class GenerateSaveFileError extends Exception { + int mStatus; + + public GenerateSaveFileError(int status) { + mStatus = status; + } + } + + /** * Creates a filename (where the file should be saved) from a uri. */ public static DownloadFileInfo generateSaveFile( @@ -88,16 +99,80 @@ public class Helpers { int destination, int contentLength) throws FileNotFoundException { - /* - * Don't download files that we won't be able to handle - */ + if (!canHandleDownload(context, mimeType, destination)) { + return new DownloadFileInfo(null, null, Downloads.Impl.STATUS_NOT_ACCEPTABLE); + } + + String fullFilename; + try { + if (destination == Downloads.Impl.DESTINATION_FILE_URI) { + fullFilename = getPathForFileUri(hint); + } else { + fullFilename = chooseFullPath(context, url, hint, contentDisposition, + contentLocation, mimeType, destination, + contentLength); + } + } catch (GenerateSaveFileError exc) { + return new DownloadFileInfo(null, null, exc.mStatus); + } + + return new DownloadFileInfo(fullFilename, new FileOutputStream(fullFilename), 0); + } + + private static String getPathForFileUri(String hint) throws GenerateSaveFileError { + Uri uri = Uri.parse(hint); + if (!uri.getScheme().equals("file")) { + Log.d(Constants.TAG, "Not a file URI: " + hint); + throw new GenerateSaveFileError(Downloads.Impl.STATUS_FILE_ERROR); + } + + String path = uri.getSchemeSpecificPart(); + if (new File(path).exists()) { + Log.d(Constants.TAG, "File already exists: " + path); + throw new GenerateSaveFileError(Downloads.Impl.STATUS_FILE_ERROR); + } + + return path; + } + + private static String chooseFullPath(Context context, String url, String hint, + String contentDisposition, String contentLocation, + String mimeType, int destination, int contentLength) + throws GenerateSaveFileError { + File base = locateDestinationDirectory(context, mimeType, destination, contentLength); + String filename = chooseFilename(url, hint, contentDisposition, contentLocation, + destination); + + // Split filename between base and extension + // Add an extension if filename does not have one + String extension = null; + int dotIndex = filename.indexOf('.'); + if (dotIndex < 0) { + extension = chooseExtensionFromMimeType(mimeType, true); + } else { + extension = chooseExtensionFromFilename(mimeType, destination, filename, dotIndex); + filename = filename.substring(0, dotIndex); + } + + boolean recoveryDir = Constants.RECOVERY_DIRECTORY.equalsIgnoreCase(filename + extension); + + filename = base.getPath() + File.separator + filename; + + if (Constants.LOGVV) { + Log.v(Constants.TAG, "target file: " + filename + extension); + } + + return chooseUniqueFilename(destination, filename, extension, recoveryDir); + } + + private static boolean canHandleDownload(Context context, String mimeType, int destination) { if (destination == Downloads.Impl.DESTINATION_EXTERNAL || destination == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE) { if (mimeType == null) { if (Config.LOGD) { Log.d(Constants.TAG, "external download with no mime type not allowed"); } - return new DownloadFileInfo(null, null, Downloads.Impl.STATUS_NOT_ACCEPTABLE); + return false; } if (!DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equalsIgnoreCase(mimeType)) { // Check to see if we are allowed to download this file. Only files @@ -121,32 +196,19 @@ public class Helpers { if (Config.LOGD) { Log.d(Constants.TAG, "no handler found for type " + mimeType); } - return new DownloadFileInfo(null, null, Downloads.Impl.STATUS_NOT_ACCEPTABLE); + return false; } } } - String filename = chooseFilename( - url, hint, contentDisposition, contentLocation, destination); - - // Split filename between base and extension - // Add an extension if filename does not have one - String extension = null; - int dotIndex = filename.indexOf('.'); - if (dotIndex < 0) { - extension = chooseExtensionFromMimeType(mimeType, true); - } else { - extension = chooseExtensionFromFilename( - mimeType, destination, filename, dotIndex); - filename = filename.substring(0, dotIndex); - } - - /* - * Locate the directory where the file will be saved - */ + return true; + } + private static File locateDestinationDirectory(Context context, String mimeType, + int destination, int contentLength) + throws GenerateSaveFileError { File base = null; StatFs stat = null; - // DRM messages should be temporarily stored internally and then passed to + // DRM messages should be temporarily stored internally and then passed to // the DRM content provider if (destination == Downloads.Impl.DESTINATION_CACHE_PARTITION || destination == Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE @@ -170,8 +232,7 @@ public class Helpers { Log.d(Constants.TAG, "download aborted - not enough free space in internal storage"); } - return new DownloadFileInfo(null, null, - Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR); + throw new GenerateSaveFileError(Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR); } else { // Recalculate available space and try again. stat.restat(base.getPath()); @@ -192,8 +253,7 @@ public class Helpers { if (Config.LOGD) { Log.d(Constants.TAG, "download aborted - not enough free space"); } - return new DownloadFileInfo(null, null, - Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR); + throw new GenerateSaveFileError(Downloads.Impl.STATUS_INSUFFICIENT_SPACE_ERROR); } base = new File(root + Constants.DEFAULT_DL_SUBDIR); @@ -204,35 +264,17 @@ public class Helpers { Log.d(Constants.TAG, "download aborted - can't create base directory " + base.getPath()); } - return new DownloadFileInfo(null, null, Downloads.Impl.STATUS_FILE_ERROR); + throw new GenerateSaveFileError(Downloads.Impl.STATUS_FILE_ERROR); } } else { // No SD card found. if (Config.LOGD) { Log.d(Constants.TAG, "download aborted - no external storage"); } - return new DownloadFileInfo(null, null, - Downloads.Impl.STATUS_DEVICE_NOT_FOUND_ERROR); + throw new GenerateSaveFileError(Downloads.Impl.STATUS_DEVICE_NOT_FOUND_ERROR); } - boolean recoveryDir = Constants.RECOVERY_DIRECTORY.equalsIgnoreCase(filename + extension); - - filename = base.getPath() + File.separator + filename; - - /* - * Generate a unique filename, create the file, return it. - */ - if (Constants.LOGVV) { - Log.v(Constants.TAG, "target file: " + filename + extension); - } - - String fullFilename = chooseUniqueFilename( - destination, filename, extension, recoveryDir); - if (fullFilename != null) { - return new DownloadFileInfo(fullFilename, new FileOutputStream(fullFilename), 0); - } else { - return new DownloadFileInfo(null, null, Downloads.Impl.STATUS_FILE_ERROR); - } + return base; } private static String chooseFilename(String url, String hint, String contentDisposition, @@ -383,7 +425,7 @@ public class Helpers { } private static String chooseUniqueFilename(int destination, String filename, - String extension, boolean recoveryDir) { + String extension, boolean recoveryDir) throws GenerateSaveFileError { String fullFilename = filename + extension; if (!new File(fullFilename).exists() && (!recoveryDir || @@ -420,7 +462,7 @@ public class Helpers { sequence += sRandom.nextInt(magnitude) + 1; } } - return null; + throw new GenerateSaveFileError(Downloads.Impl.STATUS_FILE_ERROR); } /** |