From b31afd22737e847280213878cd94872055871654 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 12 Jun 2017 14:17:10 -0600 Subject: [PATCH] Improve developer docs for storage APIs. No code changes; only docs. Test: builds Bug: 38508833, 37987197, 37978296 Change-Id: Idfeb680480b2f818d18f787cbf20ceab896763a2 --- core/java/android/content/ContentProvider.java | 7 ++++ core/java/android/os/storage/StorageManager.java | 53 ++++++++++++++++++++---- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 9d46da16965e..64e464c318d3 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -44,6 +44,7 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.os.storage.StorageManager; import android.text.TextUtils; import android.util.Log; import android.util.MathUtils; @@ -1376,6 +1377,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { * android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)}, * {@link ParcelFileDescriptor#createReliablePipe()}, or * {@link ParcelFileDescriptor#createReliableSocketPair()}. + *

+ * If you need to return a large file that isn't backed by a real file on + * disk, such as a file on a network share or cloud storage service, + * consider using + * {@link StorageManager#openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback, android.os.Handler)} + * which will let you to stream the content on-demand. * *

For use in Intents, you will want to implement {@link #getType} * to return the appropriate MIME type for the data returned here with diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index 504673529238..f42edcd8e67e 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -29,6 +29,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.WorkerThread; +import android.app.Activity; import android.app.ActivityThread; import android.content.ContentResolver; import android.content.Context; @@ -159,6 +160,12 @@ public class StorageManager { * If the sending application has a specific storage device or allocation * size in mind, they can optionally define {@link #EXTRA_UUID} or * {@link #EXTRA_REQUESTED_BYTES}, respectively. + *

+ * This intent should be launched using + * {@link Activity#startActivityForResult(Intent, int)} so that the user + * knows which app is requesting the storage space. The returned result will + * be {@link Activity#RESULT_OK} if the requested space was made available, + * or {@link Activity#RESULT_CANCELED} otherwise. */ @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE"; @@ -1467,15 +1474,26 @@ public class StorageManager { } /** - * Opens seekable ParcelFileDescriptor that routes file operation requests to - * ProxyFileDescriptorCallback. + * Opens a seekable {@link ParcelFileDescriptor} that proxies all low-level + * I/O requests back to the given {@link ProxyFileDescriptorCallback}. + *

+ * This can be useful when you want to provide quick access to a large file + * that isn't backed by a real file on disk, such as a file on a network + * share, cloud storage service, etc. As an example, you could respond to a + * {@link ContentResolver#openFileDescriptor(android.net.Uri, String)} + * request by returning a {@link ParcelFileDescriptor} created with this + * method, and then stream the content on-demand as requested. + *

+ * Another useful example might be where you have an encrypted file that + * you're willing to decrypt on-demand, but where you want to avoid + * persisting the cleartext version. * * @param mode The desired access mode, must be one of - * {@link ParcelFileDescriptor#MODE_READ_ONLY}, - * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or - * {@link ParcelFileDescriptor#MODE_READ_WRITE} - * @param callback Callback to process file operation requests issued on returned file - * descriptor. + * {@link ParcelFileDescriptor#MODE_READ_ONLY}, + * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or + * {@link ParcelFileDescriptor#MODE_READ_WRITE} + * @param callback Callback to process file operation requests issued on + * returned file descriptor. * @param handler Handler that invokes callback methods. * @return Seekable ParcelFileDescriptor. * @throws IOException @@ -1487,7 +1505,6 @@ public class StorageManager { return openProxyFileDescriptor(mode, callback, handler, null); } - /** {@hide} */ @VisibleForTesting public int getProxyFileDescriptorMountPointId() { @@ -1660,6 +1677,10 @@ public class StorageManager { * persist, you can launch {@link #ACTION_MANAGE_STORAGE} with the * {@link #EXTRA_UUID} and {@link #EXTRA_REQUESTED_BYTES} options to help * involve the user in freeing up disk space. + *

+ * If you're progressively allocating an unbounded amount of storage space + * (such as when recording a video) you should avoid calling this method + * more than once every 30 seconds. *

* Note: if your app uses the {@code android:sharedUserId} manifest feature, * then allocatable space for all packages in your shared UID is tracked @@ -1677,6 +1698,7 @@ public class StorageManager { * @throws IOException when the storage device isn't present, or when it * doesn't support allocating space. */ + @WorkerThread public @BytesLong long getAllocatableBytes(@NonNull UUID storageUuid) throws IOException { return getAllocatableBytes(storageUuid, 0); @@ -1684,6 +1706,7 @@ public class StorageManager { /** @hide */ @SystemApi + @WorkerThread @SuppressLint("Doclava125") public long getAllocatableBytes(@NonNull UUID storageUuid, @RequiresPermission @AllocateFlags int flags) throws IOException { @@ -1699,6 +1722,7 @@ public class StorageManager { /** @removed */ @Deprecated + @WorkerThread @SuppressLint("Doclava125") public long getAllocatableBytes(@NonNull File path, @RequiresPermission @AllocateFlags int flags) throws IOException { @@ -1717,6 +1741,10 @@ public class StorageManager { * subject to race conditions. If possible, consider using * {@link #allocateBytes(FileDescriptor, long, int)} which will guarantee * that bytes are allocated to an opened file. + *

+ * If you're progressively allocating an unbounded amount of storage space + * (such as when recording a video) you should avoid calling this method + * more than once every 60 seconds. * * @param storageUuid the UUID of the storage volume where you'd like to * allocate disk space. The UUID for a specific path can be @@ -1727,6 +1755,7 @@ public class StorageManager { * trouble allocating the requested space. * @see #getAllocatableBytes(UUID, int) */ + @WorkerThread public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes) throws IOException { allocateBytes(storageUuid, bytes, 0); @@ -1734,6 +1763,7 @@ public class StorageManager { /** @hide */ @SystemApi + @WorkerThread @SuppressLint("Doclava125") public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes, @RequiresPermission @AllocateFlags int flags) throws IOException { @@ -1748,6 +1778,7 @@ public class StorageManager { /** @removed */ @Deprecated + @WorkerThread @SuppressLint("Doclava125") public void allocateBytes(@NonNull File path, @BytesLong long bytes, @RequiresPermission @AllocateFlags int flags) throws IOException { @@ -1766,6 +1797,10 @@ public class StorageManager { * otherwise it will throw if fast allocation is not possible. Fast * allocation is typically only supported in private app data directories, * and on shared/external storage devices which are emulated. + *

+ * If you're progressively allocating an unbounded amount of storage space + * (such as when recording a video) you should avoid calling this method + * more than once every 60 seconds. * * @param fd the open file that you'd like to allocate disk space for. * @param bytes the number of bytes to allocate. This is the desired final @@ -1779,12 +1814,14 @@ public class StorageManager { * @see #getAllocatableBytes(UUID, int) * @see Environment#isExternalStorageEmulated(File) */ + @WorkerThread public void allocateBytes(FileDescriptor fd, @BytesLong long bytes) throws IOException { allocateBytes(fd, bytes, 0); } /** @hide */ @SystemApi + @WorkerThread @SuppressLint("Doclava125") public void allocateBytes(FileDescriptor fd, @BytesLong long bytes, @RequiresPermission @AllocateFlags int flags) throws IOException { -- 2.11.0