Improve developer docs for storage APIs.
No code changes; only docs.
Test: builds
Bug: 38508833, 37987197, 37978296
Change-Id: Idfeb680480b2f818d18f787cbf20ceab896763a2
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 9d46da1..64e464c 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -44,6 +44,7 @@
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 @@
* android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener)},
* {@link ParcelFileDescriptor#createReliablePipe()}, or
* {@link ParcelFileDescriptor#createReliableSocketPair()}.
+ * <p>
+ * 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.
*
* <p class="note">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 5046735..f42edcd 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -29,6 +29,7 @@
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 @@
* 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.
+ * <p>
+ * 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 @@
}
/**
- * 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}.
+ * <p>
+ * 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.
+ * <p>
+ * 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 @@
return openProxyFileDescriptor(mode, callback, handler, null);
}
-
/** {@hide} */
@VisibleForTesting
public int getProxyFileDescriptorMountPointId() {
@@ -1660,6 +1677,10 @@
* 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.
+ * <p>
+ * 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.
* <p class="note">
* 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 @@
* @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 @@
/** @hide */
@SystemApi
+ @WorkerThread
@SuppressLint("Doclava125")
public long getAllocatableBytes(@NonNull UUID storageUuid,
@RequiresPermission @AllocateFlags int flags) throws IOException {
@@ -1699,6 +1722,7 @@
/** @removed */
@Deprecated
+ @WorkerThread
@SuppressLint("Doclava125")
public long getAllocatableBytes(@NonNull File path,
@RequiresPermission @AllocateFlags int flags) throws IOException {
@@ -1717,6 +1741,10 @@
* subject to race conditions. If possible, consider using
* {@link #allocateBytes(FileDescriptor, long, int)} which will guarantee
* that bytes are allocated to an opened file.
+ * <p>
+ * 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 @@
* 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 @@
/** @hide */
@SystemApi
+ @WorkerThread
@SuppressLint("Doclava125")
public void allocateBytes(@NonNull UUID storageUuid, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
@@ -1748,6 +1778,7 @@
/** @removed */
@Deprecated
+ @WorkerThread
@SuppressLint("Doclava125")
public void allocateBytes(@NonNull File path, @BytesLong long bytes,
@RequiresPermission @AllocateFlags int flags) throws IOException {
@@ -1766,6 +1797,10 @@
* 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.
+ * <p>
+ * 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 @@
* @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 {