summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Tomasz Mikolajewski <mtomasz@google.com> 2016-01-28 12:39:25 +0900
committer Tomasz Mikolajewski <mtomasz@google.com> 2016-01-28 14:06:22 +0900
commitcbcd39488b4bddfaa84dfe378ede2f707aedd6ca (patch)
tree718a66ece29dd75e5376e48c92dc1b299c84dda4
parentd5ee47033fab5aa229ad194cfedd492d372cbcd8 (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.txt3
-rw-r--r--api/system-current.txt3
-rw-r--r--api/test-current.txt3
-rw-r--r--core/java/android/provider/DocumentsContract.java49
-rw-r--r--core/java/android/provider/DocumentsProvider.java31
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);
}