diff options
author | Garfield Tan <xutan@google.com> | 2017-03-22 12:01:14 -0700 |
---|---|---|
committer | Garfield Tan <xutan@google.com> | 2017-03-23 16:41:24 -0700 |
commit | 8787703ae057b6df3691036d667fab0859be92d9 (patch) | |
tree | aa4fb7c583782f25f71a58cb9cc9f687658b5ab7 | |
parent | db1b3cfb2fd5bde20e943d01c521747cb43a8bdd (diff) |
Unhide FLAG_SUPPORT_EJECT and related methods.
Test: Builds and CTS tests pass. Some manual tests as well.
Bug: 36483910
Change-Id: Idd9b1c9d9573222ee12127044ff11b9ab2487f0a
-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 | 39 | ||||
-rw-r--r-- | core/java/android/provider/DocumentsProvider.java | 19 | ||||
-rw-r--r-- | packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java | 7 |
6 files changed, 42 insertions, 32 deletions
diff --git a/api/current.txt b/api/current.txt index 360c4f2f5596..627eedc54b08 100644 --- a/api/current.txt +++ b/api/current.txt @@ -34230,6 +34230,7 @@ package android.provider { 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 java.lang.String getDocumentId(android.net.Uri); method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException; @@ -34298,6 +34299,7 @@ package android.provider { field public static final java.lang.String COLUMN_TITLE = "title"; field public static final int FLAG_LOCAL_ONLY = 2; // 0x2 field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1 + field public static final int FLAG_SUPPORTS_EJECT = 32; // 0x20 field public static final int FLAG_SUPPORTS_IS_CHILD = 16; // 0x10 field public static final int FLAG_SUPPORTS_RECENTS = 4; // 0x4 field public static final int FLAG_SUPPORTS_SEARCH = 8; // 0x8 @@ -34311,6 +34313,7 @@ package android.provider { method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException; method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]); method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException; + method public void ejectRoot(java.lang.String); method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException; method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String); method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException; diff --git a/api/system-current.txt b/api/system-current.txt index 1a0a8bb8faf2..afcfa043742a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -37136,6 +37136,7 @@ package android.provider { 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 java.lang.String getDocumentId(android.net.Uri); method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException; @@ -37204,6 +37205,7 @@ package android.provider { field public static final java.lang.String COLUMN_TITLE = "title"; field public static final int FLAG_LOCAL_ONLY = 2; // 0x2 field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1 + field public static final int FLAG_SUPPORTS_EJECT = 32; // 0x20 field public static final int FLAG_SUPPORTS_IS_CHILD = 16; // 0x10 field public static final int FLAG_SUPPORTS_RECENTS = 4; // 0x4 field public static final int FLAG_SUPPORTS_SEARCH = 8; // 0x8 @@ -37217,6 +37219,7 @@ package android.provider { method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException; method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]); method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException; + method public void ejectRoot(java.lang.String); method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException; method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String); method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException; diff --git a/api/test-current.txt b/api/test-current.txt index 674ffa610f52..6db9a046a4d6 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -34358,6 +34358,7 @@ package android.provider { 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 java.lang.String getDocumentId(android.net.Uri); method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException; @@ -34426,6 +34427,7 @@ package android.provider { field public static final java.lang.String COLUMN_TITLE = "title"; field public static final int FLAG_LOCAL_ONLY = 2; // 0x2 field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1 + field public static final int FLAG_SUPPORTS_EJECT = 32; // 0x20 field public static final int FLAG_SUPPORTS_IS_CHILD = 16; // 0x10 field public static final int FLAG_SUPPORTS_RECENTS = 4; // 0x4 field public static final int FLAG_SUPPORTS_SEARCH = 8; // 0x8 @@ -34439,6 +34441,7 @@ package android.provider { method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException; method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]); method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException; + method public void ejectRoot(java.lang.String); method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException; method public java.lang.String[] getDocumentStreamTypes(java.lang.String, java.lang.String); method public java.lang.String getDocumentType(java.lang.String) throws java.io.FileNotFoundException; diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 56d4ff79eb04..16eb35868027 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -594,6 +594,15 @@ public final class DocumentsContract { public static final int FLAG_SUPPORTS_IS_CHILD = 1 << 4; /** + * Flag indicating that this root can be ejected. + * + * @see #COLUMN_FLAGS + * @see DocumentsContract#ejectRoot(ContentResolver, Uri) + * @see DocumentsProvider#ejectRoot(String) + */ + public static final int FLAG_SUPPORTS_EJECT = 1 << 5; + + /** * Flag indicating that this root is currently empty. This may be used * to hide the root when opening documents, but the root will still be * shown when creating documents and {@link #FLAG_SUPPORTS_CREATE} is @@ -641,9 +650,6 @@ public final class DocumentsContract { * @hide */ public static final int FLAG_REMOVABLE_USB = 1 << 20; - - /** {@hide} */ - public static final int FLAG_SUPPORTS_EJECT = 1 << 21; } /** @@ -1345,35 +1351,30 @@ public final class DocumentsContract { client.call(METHOD_REMOVE_DOCUMENT, null, in); } - /** {@hide} */ - public static boolean ejectRoot(ContentResolver resolver, Uri rootUri) { + /** + * 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()); try { - return ejectRoot(client, rootUri); - } catch (Exception e) { - Log.w(TAG, "Failed to eject root", e); - return false; + ejectRoot(client, rootUri); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); } finally { ContentProviderClient.releaseQuietly(client); } } /** {@hide} */ - public static boolean ejectRoot(ContentProviderClient client, Uri rootUri) + public static void ejectRoot(ContentProviderClient client, Uri rootUri) throws RemoteException { final Bundle in = new Bundle(); in.putParcelable(DocumentsContract.EXTRA_URI, rootUri); - final Bundle out = client.call(METHOD_EJECT_ROOT, null, in); - - if (out == null) { - throw new RemoteException("Failed to get a reponse from ejectRoot."); - } - if (!out.containsKey(DocumentsContract.EXTRA_RESULT)) { - throw new RemoteException("Response did not include result field.."); - } - return out.getBoolean(DocumentsContract.EXTRA_RESULT); + client.call(METHOD_EJECT_ROOT, null, in); } /** diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 620d33a5e915..24c9a6a560f0 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -629,9 +629,14 @@ public abstract class DocumentsProvider extends ContentProvider { throw new UnsupportedOperationException("Search not supported"); } - /** {@hide} */ + /** + * Ejects the root. Throws {@link IllegalStateException} if ejection failed. + * + * @param rootId the root to be ejected. + * @see Root#FLAG_SUPPORTS_EJECT + */ @SuppressWarnings("unused") - public boolean ejectRoot(String rootId) { + public void ejectRoot(String rootId) { throw new UnsupportedOperationException("Eject not supported"); } @@ -963,14 +968,12 @@ public abstract class DocumentsProvider extends ContentProvider { if (METHOD_EJECT_ROOT.equals(method)) { // Given that certain system apps can hold MOUNT_UNMOUNT permission, but only apps // signed with platform signature can hold MANAGE_DOCUMENTS, we are going to check for - // MANAGE_DOCUMENTS here instead - getContext().enforceCallingPermission( - android.Manifest.permission.MANAGE_DOCUMENTS, null); + // MANAGE_DOCUMENTS or associated URI permission here instead final Uri rootUri = extras.getParcelable(DocumentsContract.EXTRA_URI); - final String rootId = DocumentsContract.getRootId(rootUri); - final boolean ejected = ejectRoot(rootId); + enforceWritePermissionInner(rootUri, getCallingPackage(), null); - out.putBoolean(DocumentsContract.EXTRA_RESULT, ejected); + final String rootId = DocumentsContract.getRootId(rootUri); + ejectRoot(rootId); return out; } diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 8802010c06d0..b60e2fefd6e7 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -480,21 +480,18 @@ public class ExternalStorageProvider extends FileSystemProvider { } @Override - public boolean ejectRoot(String rootId) { + public void ejectRoot(String rootId) { final long token = Binder.clearCallingIdentity(); - boolean ejected = false; RootInfo root = mRoots.get(rootId); if (root != null) { try { mStorageManager.unmount(root.volumeId); - ejected = true; } catch (RuntimeException e) { - Log.w(TAG, "Root '" + root.title + "' could not be ejected"); + throw new IllegalStateException(e); } finally { Binder.restoreCallingIdentity(token); } } - return ejected; } @Override |