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
This commit is contained in:
Tomasz Mikolajewski
2016-01-28 12:39:25 +09:00
parent d5ee47033f
commit cbcd39488b
5 changed files with 89 additions and 0 deletions

View File

@@ -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[]);

View File

@@ -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[]);

View File

@@ -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[]);

View File

@@ -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";
@@ -370,6 +373,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
@@ -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";
@@ -1203,6 +1217,41 @@ public final class DocumentsContract {
return out.getParcelable(DocumentsContract.EXTRA_URI);
}
/**
* 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

View File

@@ -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);
}