diff options
| author | 2016-01-28 12:39:25 +0900 | |
|---|---|---|
| committer | 2016-01-28 14:06:22 +0900 | |
| commit | cbcd39488b4bddfaa84dfe378ede2f707aedd6ca (patch) | |
| tree | 718a66ece29dd75e5376e48c92dc1b299c84dda4 | |
| parent | d5ee47033fab5aa229ad194cfedd492d372cbcd8 (diff) | |
Add DocumentsProvider::removeDocument().
Multi-parents are supported already in moveDocument(). For parity, this CL
adds removeDocument, so it's possible to delete a file from a specific
parent.
Bug: 26481380
Change-Id: Icd4213abc0c3413931902f4f8984746c84c65e52
| -rw-r--r-- | api/current.txt | 3 | ||||
| -rw-r--r-- | api/system-current.txt | 3 | ||||
| -rw-r--r-- | api/test-current.txt | 3 | ||||
| -rw-r--r-- | core/java/android/provider/DocumentsContract.java | 49 | ||||
| -rw-r--r-- | core/java/android/provider/DocumentsProvider.java | 31 |
5 files changed, 89 insertions, 0 deletions
diff --git a/api/current.txt b/api/current.txt index 350c50acfd50..902f5c9bf2ec 100644 --- a/api/current.txt +++ b/api/current.txt @@ -31545,6 +31545,7 @@ package android.provider { method public static java.lang.String getTreeDocumentId(android.net.Uri); method public static boolean isDocumentUri(android.content.Context, android.net.Uri); method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri); + method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri); method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String); 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"; @@ -31570,6 +31571,7 @@ package android.provider { field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80 field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4 field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100 + field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800 field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40 field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1 field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2 @@ -31617,6 +31619,7 @@ package android.provider { method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException; method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException; method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException; + method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException; method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException; method public final void revokeDocumentPermission(java.lang.String); method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]); diff --git a/api/system-current.txt b/api/system-current.txt index 50a789d2e5d8..53ac61fe7428 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -33444,6 +33444,7 @@ package android.provider { method public static java.lang.String getTreeDocumentId(android.net.Uri); method public static boolean isDocumentUri(android.content.Context, android.net.Uri); method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri); + method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri); method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String); 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"; @@ -33469,6 +33470,7 @@ package android.provider { field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80 field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4 field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100 + field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800 field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40 field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1 field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2 @@ -33516,6 +33518,7 @@ package android.provider { method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException; method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException; method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException; + method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException; method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException; method public final void revokeDocumentPermission(java.lang.String); method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]); diff --git a/api/test-current.txt b/api/test-current.txt index 787c3ccc7566..07492d57d3e0 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -31558,6 +31558,7 @@ package android.provider { method public static java.lang.String getTreeDocumentId(android.net.Uri); method public static boolean isDocumentUri(android.content.Context, android.net.Uri); method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri); + method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri); method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String); 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"; @@ -31583,6 +31584,7 @@ package android.provider { field public static final int FLAG_SUPPORTS_COPY = 128; // 0x80 field public static final int FLAG_SUPPORTS_DELETE = 4; // 0x4 field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100 + field public static final int FLAG_SUPPORTS_REMOVE = 2048; // 0x800 field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40 field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1 field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2 @@ -31630,6 +31632,7 @@ package android.provider { method public android.database.Cursor queryRecentDocuments(java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException; method public abstract android.database.Cursor queryRoots(java.lang.String[]) throws java.io.FileNotFoundException; method public android.database.Cursor querySearchDocuments(java.lang.String, java.lang.String, java.lang.String[]) throws java.io.FileNotFoundException; + method public boolean removeDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException; method public java.lang.String renameDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException; method public final void revokeDocumentPermission(java.lang.String); method public final int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]); diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index cdd88f60244f..5c58a2a5c19e 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -234,6 +234,9 @@ public final class DocumentsContract { * @see #FLAG_DIR_PREFERS_LAST_MODIFIED * @see #FLAG_VIRTUAL_DOCUMENT * @see #FLAG_ARCHIVE + * @see #FLAG_SUPPORTS_COPY + * @see #FLAG_SUPPORTS_MOVE + * @see #FLAG_SUPPORTS_REMOVE */ public static final String COLUMN_FLAGS = "flags"; @@ -371,6 +374,15 @@ public final class DocumentsContract { public static final int FLAG_ARCHIVE = 1 << 10; /** + * Flag indicating that a document can be removed from a parent. + * + * @see #COLUMN_FLAGS + * @see DocumentsContract#removeDocument(ContentProviderClient, Uri, Uri) + * @see DocumentsProvider#removeDocument(String, String) + */ + public static final int FLAG_SUPPORTS_REMOVE = 1 << 11; + + /** * Flag indicating that document titles should be hidden when viewing * this directory in a larger format grid. For example, a directory * containing only images may want the image thumbnails to speak for @@ -612,6 +624,8 @@ public final class DocumentsContract { public static final String METHOD_MOVE_DOCUMENT = "android:moveDocument"; /** {@hide} */ public static final String METHOD_IS_CHILD_DOCUMENT = "android:isChildDocument"; + /** {@hide} */ + public static final String METHOD_REMOVE_DOCUMENT = "android:removeDocument"; /** {@hide} */ public static final String EXTRA_PARENT_URI = "parentUri"; @@ -1204,6 +1218,41 @@ public final class DocumentsContract { } /** + * Removes the given document from a parent directory. + * + * <p>In contrast to {@link #deleteDocument} it requires specifying the parent. + * This method is especially useful if the document can be in multiple parents. + * + * @param documentUri document with {@link Document#FLAG_SUPPORTS_REMOVE} + * @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, + Uri parentDocumentUri) { + final ContentProviderClient client = resolver.acquireUnstableContentProviderClient( + documentUri.getAuthority()); + try { + removeDocument(client, documentUri, parentDocumentUri); + return true; + } catch (Exception e) { + Log.w(TAG, "Failed to remove document", 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); + } + + /** * Open the given image for thumbnail purposes, using any embedded EXIF * thumbnail if available, and providing orientation hints from the parent * image. diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index bae928d1755d..7a82cd1ec36f 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -21,6 +21,7 @@ import static android.provider.DocumentsContract.METHOD_CREATE_DOCUMENT; import static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT; import static android.provider.DocumentsContract.METHOD_IS_CHILD_DOCUMENT; import static android.provider.DocumentsContract.METHOD_MOVE_DOCUMENT; +import static android.provider.DocumentsContract.METHOD_REMOVE_DOCUMENT; import static android.provider.DocumentsContract.METHOD_RENAME_DOCUMENT; import static android.provider.DocumentsContract.buildDocumentUri; import static android.provider.DocumentsContract.buildDocumentUriMaybeUsingTree; @@ -300,6 +301,25 @@ public abstract class DocumentsProvider extends ContentProvider { throws FileNotFoundException { throw new UnsupportedOperationException("Move not supported"); } + + /** + * Removes the requested document or a document tree. + * + * <p>In contrast to {@link #deleteDocument} it requires specifying the parent. + * This method is especially useful if the document can be in multiple parents. + * + * <p>It's the responsibility of the provider to revoke grants if the document is + * removed from the last parent, and effectively the document is deleted. + * + * @param documentId the document to remove. + * @param parentDocumentId the parent of the document to move. + */ + @SuppressWarnings("unused") + public boolean removeDocument(String documentId, String parentDocumentId) + throws FileNotFoundException { + throw new UnsupportedOperationException("Remove not supported"); + } + /** * Return all roots currently provided. To display to users, you must define * at least one root. You should avoid making network requests to keep this @@ -822,6 +842,17 @@ public abstract class DocumentsProvider extends ContentProvider { // Original document no longer exists, clean up any grants. revokeDocumentPermission(documentId); + } else if (METHOD_REMOVE_DOCUMENT.equals(method)) { + final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI); + final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri); + + enforceReadPermissionInner(parentSourceUri, getCallingPackage(), null); + enforceWritePermissionInner(documentUri, getCallingPackage(), null); + removeDocument(documentId, parentSourceId); + + // It's responsibility of the provider to revoke any grants, as the document may be + // still attached to another parents. + } else { throw new UnsupportedOperationException("Method not supported " + method); } |