diff options
| -rw-r--r-- | core/java/android/app/DownloadManager.java | 93 | ||||
| -rw-r--r-- | core/java/android/os/Environment.java | 20 | ||||
| -rw-r--r-- | core/java/android/provider/Downloads.java | 6 |
3 files changed, 95 insertions, 24 deletions
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index 7ae88fd0dbb3..4a95099d271a 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -23,6 +23,7 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; +import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; @@ -33,9 +34,11 @@ import android.net.ConnectivityManager; import android.net.NetworkPolicyManager; import android.net.Uri; import android.os.Build; +import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.provider.Downloads; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; @@ -471,6 +474,15 @@ public class DownloadManager { * By default, downloads are saved to a generated filename in the shared download cache and * may be deleted by the system at any time to reclaim space. * + * <p> For applications targeting {@link android.os.Build.VERSION_CODES#Q} or above, + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE WRITE EXTERNAL_STORAGE} + * permission is not needed and the {@code uri} must refer to a path within the + * directories owned by the application (e.g. {@link Context#getExternalFilesDir(String)}) + * or a path within the top-level Downloads directory (as returned by + * {@link Environment#getExternalStoragePublicDirectory(String)} with + * {@link Environment#DIRECTORY_DOWNLOADS}). + * + * @param uri a file {@link Uri} indicating the destination for the downloaded file. * @return this object */ public Request setDestinationUri(Uri uri) { @@ -524,6 +536,11 @@ public class DownloadManager { * The downloaded file is not scanned by MediaScanner. But it can be * made scannable by calling {@link #allowScanningByMediaScanner()}. * + * <p> For applications targeting {@link android.os.Build.VERSION_CODES#Q} or above, + * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE} + * permission is not needed and the {@code dirType} must + * be {@link Environment#DIRECTORY_DOWNLOADS}. + * * @param dirType the directory type to pass to {@link Environment#getExternalStoragePublicDirectory(String)} * @param subPath the path within the external directory, including the * destination filename @@ -535,15 +552,29 @@ public class DownloadManager { File file = Environment.getExternalStoragePublicDirectory(dirType); if (file == null) { throw new IllegalStateException("Failed to get external storage public directory"); - } else if (file.exists()) { - if (!file.isDirectory()) { - throw new IllegalStateException(file.getAbsolutePath() + - " already exists and is not a directory"); + } + + final Context context = AppGlobals.getInitialApplication(); + if (context.getApplicationInfo().targetSdkVersion + >= Build.VERSION_CODES.Q || Environment.isExternalStorageSandboxed()) { + try (ContentProviderClient client = context.getContentResolver() + .acquireContentProviderClient(Downloads.Impl.AUTHORITY)) { + final Bundle extras = new Bundle(); + extras.putString(Downloads.DIR_TYPE, dirType); + client.call(Downloads.CALL_CREATE_EXTERNAL_PUBLIC_DIR, null, extras); + } catch (RemoteException e) { + throw new IllegalStateException("Unable to create directory: " + + file.getAbsolutePath()); } } else { - if (!file.mkdirs()) { - throw new IllegalStateException("Unable to create directory: "+ - file.getAbsolutePath()); + if (file.exists()) { + if (!file.isDirectory()) { + throw new IllegalStateException(file.getAbsolutePath() + + " already exists and is not a directory"); + } + } else if (!file.mkdirs()) { + throw new IllegalStateException("Unable to create directory: " + + file.getAbsolutePath()); } } setDestinationFromBase(file, subPath); @@ -1316,6 +1347,16 @@ public class DownloadManager { * isMediaScannerScannable to true. It makes the file visible in media managing * applications such as Gallery App, which could be a useful purpose of using this API. * + * <p> For applications targeting {@link android.os.Build.VERSION_CODES#Q} or above, + * {@code path} must be within directories owned by the application + * {e.g. {@link Context#getExternalFilesDir(String)}} or if the application is running under + * the legacy storage model (see + * {@link android.R.styleable#AndroidManifestApplication_requestLegacyExternalStorage + * android:requestLegacyExternalStorage}), {@code path} can also be within the top-level + * Downloads directory (as returned by + * {@link Environment#getExternalStoragePublicDirectory(String)} with + * {@link Environment#DIRECTORY_DOWNLOADS}). + * * @param title the title that would appear for this file in Downloads App. * @param description the description that would appear for this file in Downloads App. * @param isMediaScannerScannable true if the file is to be scanned by MediaScanner. Files @@ -1345,6 +1386,16 @@ public class DownloadManager { * isMediaScannerScannable to true. It makes the file visible in media managing * applications such as Gallery App, which could be a useful purpose of using this API. * + * <p> For applications targeting {@link android.os.Build.VERSION_CODES#Q} or above, + * {@code path} must be within directories owned by the application + * {e.g. {@link Context#getExternalFilesDir(String)}} or if the application is running under + * the legacy storage model (see + * {@link android.R.styleable#AndroidManifestApplication_requestLegacyExternalStorage + * android:requestLegacyExternalStorage}), {@code path} can also be within the top-level + * Downloads directory (as returned by + * {@link Environment#getExternalStoragePublicDirectory(String)} with + * {@link Environment#DIRECTORY_DOWNLOADS}). + * * @param title the title that would appear for this file in Downloads App. * @param description the description that would appear for this file in Downloads App. * @param isMediaScannerScannable true if the file is to be scanned by MediaScanner. Files @@ -1368,7 +1419,19 @@ public class DownloadManager { length, showNotification, false, uri, referer); } - /** {@hide} */ + /** + * <p> For applications targeting {@link android.os.Build.VERSION_CODES#Q} or above, + * {@code path} must be within directories owned by the application + * {e.g. {@link Context#getExternalFilesDir(String)}} or if the application is running under + * the legacy storage model (see + * {@link android.R.styleable#AndroidManifestApplication_requestLegacyExternalStorage + * android:requestLegacyExternalStorage}), {@code path} can also be within the top-level + * Downloads directory (as returned by + * {@link Environment#getExternalStoragePublicDirectory(String)} with + * {@link Environment#DIRECTORY_DOWNLOADS}). + * + * {@hide} + */ public long addCompletedDownload(String title, String description, boolean isMediaScannerScannable, String mimeType, String path, long length, boolean showNotification, boolean allowWrite) { @@ -1376,7 +1439,19 @@ public class DownloadManager { length, showNotification, allowWrite, null, null); } - /** {@hide} */ + /** + * <p> For applications targeting {@link android.os.Build.VERSION_CODES#Q} or above, + * {@code path} must be within directories owned by the application + * {e.g. {@link Context#getExternalFilesDir(String)}} or if the application is running under + * the legacy storage model (see + * {@link android.R.styleable#AndroidManifestApplication_requestLegacyExternalStorage + * android:requestLegacyExternalStorage}), {@code path} can also be within the top-level + * Downloads directory (as returned by + * {@link Environment#getExternalStoragePublicDirectory(String)} with + * {@link Environment#DIRECTORY_DOWNLOADS}). + * + * {@hide} + */ public long addCompletedDownload(String title, String description, boolean isMediaScannerScannable, String mimeType, String path, long length, boolean showNotification, boolean allowWrite, Uri uri, Uri referer) { diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index dde1e6a7f5f7..c32c264367ae 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -54,7 +54,6 @@ public class Environment { /** {@hide} */ public static final String DIR_ANDROID = "Android"; - private static final String DIR_SANDBOX = "sandbox"; private static final String DIR_DATA = "data"; private static final String DIR_MEDIA = "media"; private static final String DIR_OBB = "obb"; @@ -128,10 +127,6 @@ public class Environment { return buildPaths(getExternalDirs(), type); } - public File[] buildExternalStorageAndroidSandboxDirs() { - return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_SANDBOX); - } - public File[] buildExternalStorageAndroidDataDirs() { return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA); } @@ -842,15 +837,6 @@ public class Environment { * Returns the path for android-specific data on the SD card. * @hide */ - public static File[] buildExternalStorageAndroidSandboxDirs() { - throwIfUserRequired(); - return sCurrentUser.buildExternalStorageAndroidSandboxDirs(); - } - - /** - * Returns the path for android-specific data on the SD card. - * @hide - */ @UnsupportedAppUsage public static File[] buildExternalStorageAndroidDataDirs() { throwIfUserRequired(); @@ -907,6 +893,12 @@ public class Environment { return sCurrentUser.buildExternalStorageAppCacheDirs(packageName); } + /** @hide */ + public static File[] buildExternalStoragePublicDirs(@NonNull String dirType) { + throwIfUserRequired(); + return sCurrentUser.buildExternalStoragePublicDirs(dirType); + } + /** * Return the download/cache content directory. */ diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java index 89d1c447a709..d507447c45fa 100644 --- a/core/java/android/provider/Downloads.java +++ b/core/java/android/provider/Downloads.java @@ -846,12 +846,16 @@ public final class Downloads { } /** @hide */ - public static final String MEDIASTORE_DOWNLOADS_DELETED_CALL = "mediastore_downloads_deleted"; + public static final String CALL_MEDIASTORE_DOWNLOADS_DELETED = "mediastore_downloads_deleted"; + /** @hide */ + public static final String CALL_CREATE_EXTERNAL_PUBLIC_DIR = "create_external_public_dir"; /** @hide */ public static final String EXTRA_IDS = "ids"; /** @hide */ public static final String EXTRA_MIME_TYPES = "mime_types"; + /** @hide */ + public static final String DIR_TYPE = "dir_type"; /** * Query where clause for general querying. |