Make DocumentsContract methods more general.
Accepting only ContentResolver arguments was quite limiting, so use
the newly created super-interface ContentInterface, which lets
callers use a ContentResolver, and ContentProviderClient, or even a
specific ContentProvider.
This is a safe API change, since we're accepting a more-general
argument, and existing API users can continue passing ContentResolver
to these methods.
Bug: 117635768
Test: atest DocumentsUITests
Test: atest android.appsecurity.cts.DocumentsTest
Change-Id: I8f0cd1335c9b763dd81eeb237fb0517e9073b625
diff --git a/api/current.txt b/api/current.txt
index bf7dedf..8919257 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -37397,26 +37397,26 @@
method public static android.net.Uri buildRootsUri(java.lang.String);
method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
- method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
- method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
- method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
- method public static void ejectRoot(android.content.ContentResolver, android.net.Uri);
- method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.net.Uri copyDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.net.Uri createDocument(android.content.ContentInterface, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+ method public static android.content.IntentSender createWebLinkIntent(android.content.ContentInterface, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException;
+ method public static boolean deleteDocument(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static void ejectRoot(android.content.ContentInterface, android.net.Uri);
+ method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
method public static java.lang.String getDocumentId(android.net.Uri);
- method public static android.os.Bundle getDocumentMetadata(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
+ method public static android.os.Bundle getDocumentMetadata(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentInterface, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException;
method public static java.lang.String getRootId(android.net.Uri);
method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
method public static java.lang.String getTreeDocumentId(android.net.Uri);
- method public static boolean isChildDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static boolean isChildDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
method public static boolean isRootUri(android.content.Context, android.net.Uri);
method public static boolean isRootsUri(android.content.Context, android.net.Uri);
method public static boolean isTreeUri(android.net.Uri);
- method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
- method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
+ method public static android.net.Uri moveDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static boolean removeDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException;
+ method public static android.net.Uri renameDocument(android.content.ContentInterface, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException;
field public static final java.lang.String ACTION_DOCUMENT_SETTINGS = "android.provider.action.DOCUMENT_SETTINGS";
field public static final java.lang.String EXTRA_ERROR = "error";
field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF";
@@ -53285,7 +53285,7 @@
method public abstract boolean getDomStorageEnabled();
method public abstract java.lang.String getFantasyFontFamily();
method public abstract java.lang.String getFixedFontFamily();
- method public abstract int getForceDarkMode();
+ method public int getForceDarkMode();
method public abstract boolean getJavaScriptCanOpenWindowsAutomatically();
method public abstract boolean getJavaScriptEnabled();
method public abstract android.webkit.WebSettings.LayoutAlgorithm getLayoutAlgorithm();
@@ -53332,7 +53332,7 @@
method public abstract deprecated void setEnableSmoothTransition(boolean);
method public abstract void setFantasyFontFamily(java.lang.String);
method public abstract void setFixedFontFamily(java.lang.String);
- method public abstract void setForceDarkMode(int);
+ method public void setForceDarkMode(int);
method public abstract deprecated void setGeolocationDatabasePath(java.lang.String);
method public abstract void setGeolocationEnabled(boolean);
method public abstract void setJavaScriptCanOpenWindowsAutomatically(boolean);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 866050a..da65941 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -3283,10 +3283,10 @@
}
/** {@hide} */
- public static Bitmap loadThumbnail(@NonNull ContentProviderClient client, @NonNull Uri uri,
+ public static Bitmap loadThumbnail(@NonNull ContentInterface content, @NonNull Uri uri,
@NonNull Size size, @Nullable CancellationSignal signal, int allocator)
throws IOException {
- Objects.requireNonNull(client);
+ Objects.requireNonNull(content);
Objects.requireNonNull(uri);
Objects.requireNonNull(size);
@@ -3295,7 +3295,7 @@
opts.putParcelable(EXTRA_SIZE, Point.convert(size));
return ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> {
- return client.openTypedAssetFileDescriptor(uri, "image/*", opts, signal);
+ return content.openTypedAssetFile(uri, "image/*", opts, signal);
}), (ImageDecoder decoder, ImageInfo info, Source source) -> {
decoder.setAllocator(allocator);
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 4737577..ff77228 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -24,7 +24,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
-import android.content.ContentProviderClient;
+import android.content.ContentInterface;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -48,10 +48,10 @@
import android.os.Parcelable;
import android.os.ParcelableException;
import android.os.RemoteException;
-import android.os.storage.StorageVolume;
-import android.util.DataUnit;
import android.util.Log;
+import dalvik.system.VMRuntime;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -68,8 +68,7 @@
* All client apps must hold a valid URI permission grant to access documents,
* typically issued when a user makes a selection through
* {@link Intent#ACTION_OPEN_DOCUMENT}, {@link Intent#ACTION_CREATE_DOCUMENT},
- * {@link Intent#ACTION_OPEN_DOCUMENT_TREE}, or
- * {@link StorageVolume#createAccessIntent(String) StorageVolume.createAccessIntent}.
+ * or {@link Intent#ACTION_OPEN_DOCUMENT_TREE}.
*
* @see DocumentsProvider
*/
@@ -234,11 +233,6 @@
public static final String
ACTION_DOCUMENT_ROOT_SETTINGS = "android.provider.action.DOCUMENT_ROOT_SETTINGS";
- /**
- * Buffer is large enough to rewind past any EXIF headers.
- */
- private static final int THUMBNAIL_BUFFER_SIZE = (int) DataUnit.KIBIBYTES.toBytes(128);
-
/** {@hide} */
public static final String EXTERNAL_STORAGE_PROVIDER_AUTHORITY =
"com.android.externalstorage.documents";
@@ -381,7 +375,7 @@
* Flag indicating that a document can be represented as a thumbnail.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#getDocumentThumbnail(ContentResolver, Uri,
+ * @see DocumentsContract#getDocumentThumbnail(ContentInterface, Uri,
* Point, CancellationSignal)
* @see DocumentsProvider#openDocumentThumbnail(String, Point,
* android.os.CancellationSignal)
@@ -407,7 +401,7 @@
* Flag indicating that a document is deletable.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#deleteDocument(ContentResolver, Uri)
+ * @see DocumentsContract#deleteDocument(ContentInterface, Uri)
* @see DocumentsProvider#deleteDocument(String)
*/
public static final int FLAG_SUPPORTS_DELETE = 1 << 2;
@@ -445,8 +439,7 @@
* Flag indicating that a document can be renamed.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#renameDocument(ContentResolver, Uri,
- * String)
+ * @see DocumentsContract#renameDocument(ContentInterface, Uri, String)
* @see DocumentsProvider#renameDocument(String, String)
*/
public static final int FLAG_SUPPORTS_RENAME = 1 << 6;
@@ -456,7 +449,7 @@
* within the same document provider.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#copyDocument(ContentResolver, Uri, Uri)
+ * @see DocumentsContract#copyDocument(ContentInterface, Uri, Uri)
* @see DocumentsProvider#copyDocument(String, String)
*/
public static final int FLAG_SUPPORTS_COPY = 1 << 7;
@@ -466,7 +459,7 @@
* within the same document provider.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#moveDocument(ContentResolver, Uri, Uri, Uri)
+ * @see DocumentsContract#moveDocument(ContentInterface, Uri, Uri, Uri)
* @see DocumentsProvider#moveDocument(String, String, String)
*/
public static final int FLAG_SUPPORTS_MOVE = 1 << 8;
@@ -490,7 +483,7 @@
* Flag indicating that a document can be removed from a parent.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#removeDocument(ContentResolver, Uri, Uri)
+ * @see DocumentsContract#removeDocument(ContentInterface, Uri, Uri)
* @see DocumentsProvider#removeDocument(String, String)
*/
public static final int FLAG_SUPPORTS_REMOVE = 1 << 10;
@@ -684,7 +677,7 @@
* Flag indicating that this root can be ejected.
*
* @see #COLUMN_FLAGS
- * @see DocumentsContract#ejectRoot(ContentResolver, Uri)
+ * @see DocumentsContract#ejectRoot(ContentInterface, Uri)
* @see DocumentsProvider#ejectRoot(String)
*/
public static final int FLAG_SUPPORTS_EJECT = 1 << 5;
@@ -807,10 +800,7 @@
/** {@hide} */
public static final String EXTRA_URI_PERMISSIONS = "uriPermissions";
- /**
- * @see #createWebLinkIntent(ContentResolver, Uri, Bundle)
- * {@hide}
- */
+ /** {@hide} */
public static final String EXTRA_OPTIONS = "options";
private static final String PATH_ROOT = "root";
@@ -1255,32 +1245,20 @@
* @see DocumentsProvider#openDocumentThumbnail(String, Point,
* android.os.CancellationSignal)
*/
- public static Bitmap getDocumentThumbnail(
- ContentResolver resolver, Uri documentUri, Point size, CancellationSignal signal)
- throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- documentUri.getAuthority());
+ public static Bitmap getDocumentThumbnail(ContentInterface content, Uri documentUri, Point size,
+ CancellationSignal signal) throws FileNotFoundException {
try {
- return getDocumentThumbnail(client, documentUri, size, signal);
+ return ContentResolver.loadThumbnail(content, documentUri, Point.convert(size), signal,
+ ImageDecoder.ALLOCATOR_SOFTWARE);
} catch (Exception e) {
if (!(e instanceof OperationCanceledException)) {
Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e);
}
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- @UnsupportedAppUsage
- public static Bitmap getDocumentThumbnail(ContentProviderClient client, Uri documentUri,
- Point size, CancellationSignal signal) throws IOException {
- return ContentResolver.loadThumbnail(client, documentUri, Point.convert(size), signal,
- ImageDecoder.ALLOCATOR_SOFTWARE);
- }
-
/**
* Create a new document with given MIME type and display name.
*
@@ -1289,33 +1267,24 @@
* @param displayName name of new document
* @return newly created document, or {@code null} if failed
*/
- public static Uri createDocument(ContentResolver resolver, Uri parentDocumentUri,
+ public static Uri createDocument(ContentInterface content, Uri parentDocumentUri,
String mimeType, String displayName) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- parentDocumentUri.getAuthority());
try {
- return createDocument(client, parentDocumentUri, mimeType, displayName);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
+ in.putString(Document.COLUMN_MIME_TYPE, mimeType);
+ in.putString(Document.COLUMN_DISPLAY_NAME, displayName);
+
+ final Bundle out = content.call(parentDocumentUri.getAuthority(),
+ METHOD_CREATE_DOCUMENT, null, in);
+ return out.getParcelable(DocumentsContract.EXTRA_URI);
} catch (Exception e) {
Log.w(TAG, "Failed to create document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static Uri createDocument(ContentProviderClient client, Uri parentDocumentUri,
- String mimeType, String displayName) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
- in.putString(Document.COLUMN_MIME_TYPE, mimeType);
- in.putString(Document.COLUMN_DISPLAY_NAME, displayName);
-
- final Bundle out = client.call(METHOD_CREATE_DOCUMENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_URI);
- }
-
/**
* Test if a document is descendant (child, grandchild, etc) from the given
@@ -1326,39 +1295,29 @@
* @return if given document is a descendant of the given parent.
* @see Root#FLAG_SUPPORTS_IS_CHILD
*/
- public static boolean isChildDocument(ContentResolver resolver, Uri parentDocumentUri,
+ public static boolean isChildDocument(ContentInterface content, Uri parentDocumentUri,
Uri childDocumentUri) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- parentDocumentUri.getAuthority());
try {
- return isChildDocument(client, parentDocumentUri, childDocumentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
+ in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, childDocumentUri);
+
+ final Bundle out = content.call(parentDocumentUri.getAuthority(),
+ METHOD_IS_CHILD_DOCUMENT, null, in);
+ if (out == null) {
+ throw new RemoteException("Failed to get a reponse from isChildDocument query.");
+ }
+ if (!out.containsKey(DocumentsContract.EXTRA_RESULT)) {
+ throw new RemoteException("Response did not include result field..");
+ }
+ return out.getBoolean(DocumentsContract.EXTRA_RESULT);
} catch (Exception e) {
- Log.w(TAG, "Failed to query isChildDocument", e);
- rethrowIfNecessary(resolver, e);
+ Log.w(TAG, "Failed to create document", e);
+ rethrowIfNecessary(e);
return false;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static boolean isChildDocument(ContentProviderClient client, Uri parentDocumentUri,
- Uri childDocumentUri) throws RemoteException {
-
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, parentDocumentUri);
- in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, childDocumentUri);
-
- final Bundle out = client.call(METHOD_IS_CHILD_DOCUMENT, null, in);
- if (out == null) {
- throw new RemoteException("Failed to get a response from isChildDocument query.");
- }
- if (!out.containsKey(DocumentsContract.EXTRA_RESULT)) {
- throw new RemoteException("Response did not include result field..");
- }
- return out.getBoolean(DocumentsContract.EXTRA_RESULT);
- }
-
/**
* Change the display name of an existing document.
* <p>
@@ -1372,64 +1331,46 @@
* @return the existing or new document after the rename, or {@code null} if
* failed.
*/
- public static Uri renameDocument(ContentResolver resolver, Uri documentUri,
+ public static Uri renameDocument(ContentInterface content, Uri documentUri,
String displayName) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- documentUri.getAuthority());
try {
- return renameDocument(client, documentUri, displayName);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
+ in.putString(Document.COLUMN_DISPLAY_NAME, displayName);
+
+ final Bundle out = content.call(documentUri.getAuthority(),
+ METHOD_RENAME_DOCUMENT, null, in);
+ final Uri outUri = out.getParcelable(DocumentsContract.EXTRA_URI);
+ return (outUri != null) ? outUri : documentUri;
} catch (Exception e) {
Log.w(TAG, "Failed to rename document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static Uri renameDocument(ContentProviderClient client, Uri documentUri,
- String displayName) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
- in.putString(Document.COLUMN_DISPLAY_NAME, displayName);
-
- final Bundle out = client.call(METHOD_RENAME_DOCUMENT, null, in);
- final Uri outUri = out.getParcelable(DocumentsContract.EXTRA_URI);
- return (outUri != null) ? outUri : documentUri;
- }
-
/**
* Delete the given document.
*
* @param documentUri document with {@link Document#FLAG_SUPPORTS_DELETE}
* @return if the document was deleted successfully.
*/
- public static boolean deleteDocument(ContentResolver resolver, Uri documentUri)
+ public static boolean deleteDocument(ContentInterface content, Uri documentUri)
throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- documentUri.getAuthority());
try {
- deleteDocument(client, documentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
+
+ content.call(documentUri.getAuthority(),
+ METHOD_DELETE_DOCUMENT, null, in);
return true;
} catch (Exception e) {
Log.w(TAG, "Failed to delete document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return false;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static void deleteDocument(ContentProviderClient client, Uri documentUri)
- throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
-
- client.call(METHOD_DELETE_DOCUMENT, null, in);
- }
-
/**
* Copies the given document.
*
@@ -1438,32 +1379,23 @@
* document's copy.
* @return the copied document, or {@code null} if failed.
*/
- public static Uri copyDocument(ContentResolver resolver, Uri sourceDocumentUri,
+ public static Uri copyDocument(ContentInterface content, Uri sourceDocumentUri,
Uri targetParentDocumentUri) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- sourceDocumentUri.getAuthority());
try {
- return copyDocument(client, sourceDocumentUri, targetParentDocumentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
+ in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, targetParentDocumentUri);
+
+ final Bundle out = content.call(sourceDocumentUri.getAuthority(),
+ METHOD_COPY_DOCUMENT, null, in);
+ return out.getParcelable(DocumentsContract.EXTRA_URI);
} catch (Exception e) {
Log.w(TAG, "Failed to copy document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static Uri copyDocument(ContentProviderClient client, Uri sourceDocumentUri,
- Uri targetParentDocumentUri) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
- in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, targetParentDocumentUri);
-
- final Bundle out = client.call(METHOD_COPY_DOCUMENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_URI);
- }
-
/**
* Moves the given document under a new parent.
*
@@ -1473,35 +1405,24 @@
* document.
* @return the moved document, or {@code null} if failed.
*/
- public static Uri moveDocument(ContentResolver resolver, Uri sourceDocumentUri,
+ public static Uri moveDocument(ContentInterface content, Uri sourceDocumentUri,
Uri sourceParentDocumentUri, Uri targetParentDocumentUri) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- sourceDocumentUri.getAuthority());
try {
- return moveDocument(client, sourceDocumentUri, sourceParentDocumentUri,
- targetParentDocumentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
+ in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, sourceParentDocumentUri);
+ in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, targetParentDocumentUri);
+
+ final Bundle out = content.call(sourceDocumentUri.getAuthority(),
+ METHOD_MOVE_DOCUMENT, null, in);
+ return out.getParcelable(DocumentsContract.EXTRA_URI);
} catch (Exception e) {
Log.w(TAG, "Failed to move document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- @UnsupportedAppUsage
- public static Uri moveDocument(ContentProviderClient client, Uri sourceDocumentUri,
- Uri sourceParentDocumentUri, Uri targetParentDocumentUri) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, sourceDocumentUri);
- in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, sourceParentDocumentUri);
- in.putParcelable(DocumentsContract.EXTRA_TARGET_URI, targetParentDocumentUri);
-
- final Bundle out = client.call(METHOD_MOVE_DOCUMENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_URI);
- }
-
/**
* Removes the given document from a parent directory.
*
@@ -1512,58 +1433,40 @@
* @param parentDocumentUri parent document of the document to remove.
* @return true if the document was removed successfully.
*/
- public static boolean removeDocument(ContentResolver resolver, Uri documentUri,
+ public static boolean removeDocument(ContentInterface content, Uri documentUri,
Uri parentDocumentUri) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- documentUri.getAuthority());
try {
- removeDocument(client, documentUri, parentDocumentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
+ in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, parentDocumentUri);
+
+ content.call(documentUri.getAuthority(),
+ METHOD_REMOVE_DOCUMENT, null, in);
return true;
} catch (Exception e) {
Log.w(TAG, "Failed to remove document", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return false;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static void removeDocument(ContentProviderClient client, Uri documentUri,
- Uri parentDocumentUri) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
- in.putParcelable(DocumentsContract.EXTRA_PARENT_URI, parentDocumentUri);
-
- client.call(METHOD_REMOVE_DOCUMENT, null, in);
- }
-
/**
* Ejects the given root. It throws {@link IllegalStateException} when ejection failed.
*
* @param rootUri root with {@link Root#FLAG_SUPPORTS_EJECT} to be ejected
*/
- public static void ejectRoot(ContentResolver resolver, Uri rootUri) {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- rootUri.getAuthority());
+ public static void ejectRoot(ContentInterface content, Uri rootUri) {
try {
- ejectRoot(client, rootUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, rootUri);
+
+ content.call(rootUri.getAuthority(),
+ METHOD_EJECT_ROOT, null, in);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
- /** {@hide} */
- public static void ejectRoot(ContentProviderClient client, Uri rootUri)
- throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, rootUri);
-
- client.call(METHOD_EJECT_ROOT, null, in);
- }
-
/**
* Returns metadata associated with the document. The type of metadata returned
* is specific to the document type. For example the data returned for an image
@@ -1594,67 +1497,22 @@
* @param documentUri a Document URI
* @return a Bundle of Bundles.
*/
- public static Bundle getDocumentMetadata(ContentResolver resolver, Uri documentUri)
+ public static Bundle getDocumentMetadata(ContentInterface content, Uri documentUri)
throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- documentUri.getAuthority());
-
try {
- return getDocumentMetadata(client, documentUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(EXTRA_URI, documentUri);
+
+ return content.call(documentUri.getAuthority(),
+ METHOD_GET_DOCUMENT_METADATA, null, in);
} catch (Exception e) {
Log.w(TAG, "Failed to get document metadata");
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
/**
- * Returns metadata associated with the document. The type of metadata returned
- * is specific to the document type. For example the data returned for an image
- * file will likely consist primarily or soley of EXIF metadata.
- *
- * <p>The returned {@link Bundle} will contain zero or more entries depending
- * on the type of data supported by the document provider.
- *
- * <ol>
- * <li>A {@link DocumentsContract.METADATA_TYPES} containing a {@code String[]} value.
- * The string array identifies the type or types of metadata returned. Each
- * value in the can be used to access a {@link Bundle} of data
- * containing that type of data.
- * <li>An entry each for each type of returned metadata. Each set of metadata is
- * itself represented as a bundle and accessible via a string key naming
- * the type of data.
- * </ol>
- *
- * <p>Example:
- * <p><pre><code>
- * Bundle metadata = DocumentsContract.getDocumentMetadata(client, imageDocUri, tags);
- * if (metadata.containsKey(DocumentsContract.METADATA_EXIF)) {
- * Bundle exif = metadata.getBundle(DocumentsContract.METADATA_EXIF);
- * int imageLength = exif.getInt(ExifInterface.TAG_IMAGE_LENGTH);
- * }
- * </code></pre>
- *
- * @param documentUri a Document URI
- * @return a Bundle of Bundles.
- * {@hide}
- */
- public static Bundle getDocumentMetadata(
- ContentProviderClient client, Uri documentUri) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(EXTRA_URI, documentUri);
-
- final Bundle out = client.call(METHOD_GET_DOCUMENT_METADATA, null, in);
-
- if (out == null) {
- throw new RemoteException("Failed to get a response from getDocumentMetadata");
- }
- return out;
- }
-
- /**
* Finds the canonical path from the top of the document tree.
*
* The {@link Path#getPath()} of the return value contains the document ID
@@ -1667,52 +1525,25 @@
* @return the path of the document, or {@code null} if failed.
* @see DocumentsProvider#findDocumentPath(String, String)
*/
- public static Path findDocumentPath(ContentResolver resolver, Uri treeUri)
+ public static Path findDocumentPath(ContentInterface content, Uri treeUri)
throws FileNotFoundException {
checkArgument(isTreeUri(treeUri), treeUri + " is not a tree uri.");
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- treeUri.getAuthority());
try {
- return findDocumentPath(client, treeUri);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, treeUri);
+
+ final Bundle out = content.call(treeUri.getAuthority(),
+ METHOD_FIND_DOCUMENT_PATH, null, in);
+ return out.getParcelable(DocumentsContract.EXTRA_RESULT);
} catch (Exception e) {
Log.w(TAG, "Failed to find path", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
/**
- * Finds the canonical path. If uri is a document uri returns path from a root and
- * its associated root id. If uri is a tree uri returns the path from the top of
- * the tree. The {@link Path#getPath()} of the return value contains document ID
- * starts from the top of the tree or the root document to the requested document,
- * both inclusive.
- *
- * Callers can expect the root ID returned from multiple calls to this method is
- * consistent.
- *
- * @param uri uri of the document which path is requested. It can be either a
- * plain document uri or a tree uri.
- * @return the path of the document.
- * @see DocumentsProvider#findDocumentPath(String, String)
- *
- * {@hide}
- */
- public static Path findDocumentPath(ContentProviderClient client, Uri uri)
- throws RemoteException {
-
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, uri);
-
- final Bundle out = client.call(METHOD_FIND_DOCUMENT_PATH, null, in);
-
- return out.getParcelable(DocumentsContract.EXTRA_RESULT);
- }
-
- /**
* Creates an intent for obtaining a web link for the specified document.
*
* <p>Note, that due to internal limitations, if there is already a web link
@@ -1763,40 +1594,29 @@
* @see DocumentsProvider#createWebLinkIntent(String, Bundle)
* @see Intent#EXTRA_EMAIL
*/
- public static IntentSender createWebLinkIntent(ContentResolver resolver, Uri uri,
+ public static IntentSender createWebLinkIntent(ContentInterface content, Uri uri,
Bundle options) throws FileNotFoundException {
- final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
- uri.getAuthority());
try {
- return createWebLinkIntent(client, uri, options);
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, uri);
+
+ // Options may be provider specific, so put them in a separate bundle to
+ // avoid overriding the Uri.
+ if (options != null) {
+ in.putBundle(EXTRA_OPTIONS, options);
+ }
+
+ final Bundle out = content.call(uri.getAuthority(),
+ METHOD_CREATE_WEB_LINK_INTENT, null, in);
+ return out.getParcelable(DocumentsContract.EXTRA_RESULT);
} catch (Exception e) {
Log.w(TAG, "Failed to create a web link intent", e);
- rethrowIfNecessary(resolver, e);
+ rethrowIfNecessary(e);
return null;
- } finally {
- ContentProviderClient.releaseQuietly(client);
}
}
/**
- * {@hide}
- */
- public static IntentSender createWebLinkIntent(ContentProviderClient client, Uri uri,
- Bundle options) throws RemoteException {
- final Bundle in = new Bundle();
- in.putParcelable(DocumentsContract.EXTRA_URI, uri);
-
- // Options may be provider specific, so put them in a separate bundle to
- // avoid overriding the Uri.
- if (options != null) {
- in.putBundle(EXTRA_OPTIONS, options);
- }
-
- final Bundle out = client.call(METHOD_CREATE_WEB_LINK_INTENT, null, in);
- return out.getParcelable(DocumentsContract.EXTRA_RESULT);
- }
-
- /**
* Open the given image for thumbnail purposes, using any embedded EXIF
* thumbnail if available, and providing orientation hints from the parent
* image.
@@ -1836,10 +1656,9 @@
return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH, extras);
}
- private static void rethrowIfNecessary(ContentResolver resolver, Exception e)
- throws FileNotFoundException {
+ private static void rethrowIfNecessary(Exception e) throws FileNotFoundException {
// We only want to throw applications targetting O and above
- if (resolver.getTargetSdkVersion() >= Build.VERSION_CODES.O) {
+ if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.O) {
if (e instanceof ParcelableException) {
((ParcelableException) e).maybeRethrow(FileNotFoundException.class);
} else if (e instanceof RemoteException) {