Provider-level changes for implementing direct eject of a root in Files app.

Several changes at different levels:
1. Introduction of ejectRoot(String) for DocumentsProvider
2. Introduction of ejectRoot(ContentResolver, Uri, String) for
DocumentsContract
4. Additional permission for MOUNT_UNMOUNT for ExternalStorageProvider
5. Implementation of ejectRoot(String) for External StorageProvider

Bug: 29584653
Change-Id: I28557af63259548784cf24d5b051eb06ad5193ca
(cherry picked from commit 2ccc18357d6741dde56edc4d5a2608f15f4b9078)
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 1158776..b0ea99c 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -593,6 +593,9 @@
          * @hide
          */
         public static final int FLAG_REMOVABLE_USB = 1 << 20;
+
+        /** {@hide} */
+        public static final int FLAG_SUPPORTS_EJECT = 1 << 21;
     }
 
     /**
@@ -643,6 +646,8 @@
     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 METHOD_EJECT_ROOT = "android:ejectRoot";
 
     /** {@hide} */
     public static final String EXTRA_PARENT_URI = "parentUri";
@@ -1274,6 +1279,37 @@
         client.call(METHOD_REMOVE_DOCUMENT, null, in);
     }
 
+    /** {@hide} */
+    public static boolean 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;
+        } finally {
+            ContentProviderClient.releaseQuietly(client);
+        }
+    }
+
+    /** {@hide} */
+    public static boolean 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);
+    }
+
     /**
      * Open the given image for thumbnail purposes, using any embedded EXIF
      * thumbnail if available, and providing orientation hints from the parent