Removed Intent.OPEN_EXTERNAL_DIRECTORY.

Such intent is now encapsulated by StorageVolume.createAccessIntent().

BUG: 26742218

Change-Id: I2e2bd71126ecd74981f77b0af7d069f51aaece74
diff --git a/api/removed.txt b/api/removed.txt
index 946f75f..0bf6594 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -15,14 +15,6 @@
 
 }
 
-package android.content {
-
-  public class Intent implements java.lang.Cloneable android.os.Parcelable {
-    field public static final java.lang.String ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
-  }
-
-}
-
 package android.content.pm {
 
   public class PackageInfo implements android.os.Parcelable {
diff --git a/api/system-removed.txt b/api/system-removed.txt
index ca3c85ab..27de913 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -6,14 +6,6 @@
 
 }
 
-package android.content {
-
-  public class Intent implements java.lang.Cloneable android.os.Parcelable {
-    field public static final java.lang.String ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
-  }
-
-}
-
 package android.content.pm {
 
   public class PackageInfo implements android.os.Parcelable {
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 946f75f..0bf6594 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -15,14 +15,6 @@
 
 }
 
-package android.content {
-
-  public class Intent implements java.lang.Cloneable android.os.Parcelable {
-    field public static final java.lang.String ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
-  }
-
-}
-
 package android.content.pm {
 
   public class PackageInfo implements android.os.Parcelable {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 4e78b8a..8f2b9c8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3187,44 +3187,6 @@
             ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
 
     /**
-     * Activity Action: Give access to a standard storage directory after obtaining the user's
-     * approval.
-     * <p>
-     * When invoked, the system will ask the user to grant access to the requested directory (and
-     * its descendants).
-     * <p>
-     * To gain access to descendant (child, grandchild, etc) documents, use
-     * {@link DocumentsContract#buildDocumentUriUsingTree(Uri, String)} and
-     * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)} with the returned URI.
-     * <p>
-     * Input: full path to a standard directory, in the form of
-     * {@code STORAGE_ROOT + STANDARD_DIRECTORY}, where {@code STORAGE_ROOT} is the physical path of
-     * a storage container, and {@code STANDARD_DIRECTORY} is one of
-     * {@link Environment#DIRECTORY_MUSIC}, {@link Environment#DIRECTORY_PODCASTS},
-     * {@link Environment#DIRECTORY_RINGTONES}, {@link Environment#DIRECTORY_ALARMS},
-     * {@link Environment#DIRECTORY_NOTIFICATIONS}, {@link Environment#DIRECTORY_PICTURES},
-     * {@link Environment#DIRECTORY_MOVIES}, {@link Environment#DIRECTORY_DOWNLOADS},
-     * {@link Environment#DIRECTORY_DCIM}, or {@link Environment#DIRECTORY_DOCUMENTS}
-     * <p>
-     * For example, to open the "Pictures" folder in the default external storage, the intent's data
-     * would be: {@code Uri.fromFile(new File(Environment.getExternalStorageDirectory(),
-     * Environment.DIRECTORY_PICTURES))}.
-     * <p>
-     * Output: The URI representing the requested directory tree.
-     *
-     * @see DocumentsContract
-     *
-     * {@removed}
-     *
-     * Will be removed / hidden before N is published; apps should use
-     * {@link android.os.storage.StorageManager#getVolumeList()} and
-     * {@link android.os.storage.StorageVolume#createAccessIntent(String)} instead.
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String
-            ACTION_OPEN_EXTERNAL_DIRECTORY = "android.intent.action.OPEN_EXTERNAL_DIRECTORY";
-
-    /**
      * Broadcast Action: List of dynamic sensor is changed due to new sensor being connected or
      * exisiting sensor being disconnected.
      *
@@ -8958,7 +8920,6 @@
                 case ACTION_MEDIA_SCANNER_SCAN_FILE:
                 case ACTION_PACKAGE_NEEDS_VERIFICATION:
                 case ACTION_PACKAGE_VERIFIED:
-                case ACTION_OPEN_EXTERNAL_DIRECTORY: // TODO: temporary until bug 26742218 is fixed
                     // Ignore legacy actions
                     break;
                 default:
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 60e1266..f838aec 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -102,6 +102,19 @@
     // Also sent on ACTION_MEDIA_UNSHARED, which is @hide
     public static final String EXTRA_STORAGE_VOLUME = "android.os.storage.extra.STORAGE_VOLUME";
 
+    /**
+     * Name of the String extra used by {@link #createAccessIntent(String) createAccessIntent}.
+     *
+     * @hide
+     */
+    public static final String EXTRA_DIRECTORY_NAME = "android.os.storage.extra.DIRECTORY_NAME";
+
+    /**
+     * Name of the intent used by {@link #createAccessIntent(String) createAccessIntent}.
+     */
+    private static final String ACTION_OPEN_EXTERNAL_DIRECTORY =
+            "android.os.storage.action.OPEN_EXTERNAL_DIRECTORY";
+
     /** {@hide} */
     public static final int STORAGE_ID_INVALID = 0x00000000;
     /** {@hide} */
@@ -318,8 +331,9 @@
      * @see DocumentsContract
      */
     public Intent createAccessIntent(@NonNull String directoryName) {
-        final Intent intent = new Intent(Intent.ACTION_OPEN_EXTERNAL_DIRECTORY);
-        intent.setData(Uri.fromFile(new File(mPath, directoryName)));
+        final Intent intent = new Intent(ACTION_OPEN_EXTERNAL_DIRECTORY);
+        intent.putExtra(EXTRA_STORAGE_VOLUME, this);
+        intent.putExtra(EXTRA_DIRECTORY_NAME, directoryName);
         return intent;
     }
 
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 9ac929b..58e7709 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -94,9 +94,8 @@
             android:name=".OpenExternalDirectoryActivity"
             android:theme="@android:style/Theme.Translucent.NoTitleBar">
             <intent-filter>
-                <action android:name="android.intent.action.OPEN_EXTERNAL_DIRECTORY" />
+                <action android:name="android.os.storage.action.OPEN_EXTERNAL_DIRECTORY" />
                 <category android:name="android.intent.category.DEFAULT" />
-                <data android:scheme="file" />
             </intent-filter>
         </activity>
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
index d601550..025faea 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
@@ -17,6 +17,8 @@
 package com.android.documentsui;
 
 import static android.os.Environment.isStandardDirectory;
+import static android.os.storage.StorageVolume.EXTRA_DIRECTORY_NAME;
+import static android.os.storage.StorageVolume.EXTRA_STORAGE_VOLUME;
 import static com.android.documentsui.Shared.DEBUG;
 
 import android.app.Activity;
@@ -35,9 +37,11 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
 import android.os.storage.VolumeInfo;
 import android.provider.DocumentsContract;
 import android.text.TextUtils;
@@ -63,16 +67,31 @@
         super.onCreate(savedInstanceState);
 
         final Intent intent = getIntent();
-        if (intent == null || intent.getData() == null) {
-            Log.d(TAG, "missing intent or intent data: " + intent);
+        if (intent == null) {
+            if (DEBUG) Log.d(TAG, "missing intent");
+            setResult(RESULT_CANCELED);
+            finish();
+            return;
+        }
+        final Parcelable storageVolume = intent.getParcelableExtra(EXTRA_STORAGE_VOLUME);
+        if (!(storageVolume instanceof StorageVolume)) {
+            if (DEBUG)
+                Log.d(TAG, "extra " + EXTRA_STORAGE_VOLUME + " is not a StorageVolume: "
+                        + storageVolume);
+            setResult(RESULT_CANCELED);
+            finish();
+            return;
+        }
+        final String directoryName = intent.getStringExtra(EXTRA_DIRECTORY_NAME);
+        if (directoryName == null) {
+            if (DEBUG) Log.d(TAG, "missing extra " + EXTRA_DIRECTORY_NAME + " on " + intent);
             setResult(RESULT_CANCELED);
             finish();
             return;
         }
 
-        final String path = intent.getData().getPath();
         final int userId = UserHandle.myUserId();
-        if (!showFragment(this, userId, path)) {
+        if (!showFragment(this, userId, (StorageVolume) storageVolume, directoryName)) {
             setResult(RESULT_CANCELED);
             finish();
             return;
@@ -80,20 +99,20 @@
     }
 
     /**
-     * Validates the given {@code path} and display the appropriate dialog asking the user to grant
-     * access to it.
+     * Validates the given path (volume + directory) and display the appropriate dialog asking the
+     * user to grant access to it.
      */
-    static boolean showFragment(Activity activity, int userId, String path) {
-        Log.d(TAG, "showFragment() for path " + path + " and user " + userId);
-        if (path == null) {
-            Log.e(TAG, "INTERNAL ERROR: showFragment() with null path");
-            return false;
-        }
+    private static boolean showFragment(Activity activity, int userId, StorageVolume storageVolume,
+            String directoryName) {
+        if (DEBUG)
+            Log.d(TAG, "showFragment() for volume " + storageVolume.dump() + ", directory "
+                    + directoryName + ", and user " + userId);
         File file;
         try {
-            file = new File(new File(path).getCanonicalPath());
+            file = new File(storageVolume.getPathFile(), directoryName).getCanonicalFile();
         } catch (IOException e) {
-            Log.e(TAG, "Could not get canonical file from " + path);
+            Log.e(TAG, "Could not get canonical file for volume " + storageVolume.dump()
+                    + " and directory " + directoryName);
             return false;
         }
         final StorageManager sm =
@@ -104,7 +123,9 @@
 
         // Verify directory is valid.
         if (TextUtils.isEmpty(directory) || !isStandardDirectory(directory)) {
-            Log.d(TAG, "Directory '" + directory + "' is not standard (full path: '" + path + "')");
+            if (DEBUG)
+                Log.d(TAG, "Directory '" + directory + "' is not standard (full path: '"
+                        + file.getAbsolutePath() + "')");
             return false;
         }
 
@@ -123,7 +144,7 @@
             }
         }
         if (volumeLabel == null) {
-            Log.e(TAG, "Could not get volume for " + path);
+            Log.e(TAG, "Could not get volume for " + file);
             return false;
         }
 
@@ -165,13 +186,13 @@
         final File userPath = volume.getPathForUser(userId);
         final String path = userPath == null ? null : volume.getPathForUser(userId).getPath();
         final boolean isVisible = volume.isVisibleForWrite(userId);
-        if (DEBUG) {
+        if (DEBUG)
             Log.d(TAG, "Volume: " + volume + " userId: " + userId + " root: " + root
                     + " volumePath: " + volume.getPath().getPath()
                     + " pathForUser: " + path
                     + " internalPathForUser: " + volume.getInternalPath()
                     + " isVisible: " + isVisible);
-        }
+
         return volume.isVisibleForWrite(userId) && root.equals(path);
     }