Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f8f69b89 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Refactor directory API to "opening document tree."" into lmp-preview-dev

parents 2641ab27 b9fbb729
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -7400,6 +7400,7 @@ package android.content {
    field public static final java.lang.String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
    field public static final java.lang.String ACTION_NEW_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
    field public static final java.lang.String ACTION_OPEN_DOCUMENT = "android.intent.action.OPEN_DOCUMENT";
    field public static final java.lang.String ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
    field public static final java.lang.String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";
    field public static final java.lang.String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
    field public static final java.lang.String ACTION_PACKAGE_DATA_CLEARED = "android.intent.action.PACKAGE_DATA_CLEARED";
@@ -7414,7 +7415,6 @@ package android.content {
    field public static final java.lang.String ACTION_PASTE = "android.intent.action.PASTE";
    field public static final java.lang.String ACTION_PICK = "android.intent.action.PICK";
    field public static final java.lang.String ACTION_PICK_ACTIVITY = "android.intent.action.PICK_ACTIVITY";
    field public static final java.lang.String ACTION_PICK_DIRECTORY = "android.intent.action.PICK_DIRECTORY";
    field public static final java.lang.String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
    field public static final java.lang.String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
    field public static final java.lang.String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
@@ -23824,21 +23824,21 @@ package android.provider {
  public final class DocumentsContract {
    method public static android.net.Uri buildChildDocumentsUri(java.lang.String, java.lang.String);
    method public static android.net.Uri buildChildDocumentsViaUri(android.net.Uri, java.lang.String);
    method public static android.net.Uri buildChildDocumentsUriUsingTree(android.net.Uri, java.lang.String);
    method public static android.net.Uri buildDocumentUri(java.lang.String, java.lang.String);
    method public static android.net.Uri buildDocumentViaUri(android.net.Uri, java.lang.String);
    method public static android.net.Uri buildDocumentUriUsingTree(android.net.Uri, java.lang.String);
    method public static android.net.Uri buildRecentDocumentsUri(java.lang.String, java.lang.String);
    method public static android.net.Uri buildRootUri(java.lang.String, java.lang.String);
    method public static android.net.Uri buildRootsUri(java.lang.String);
    method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String);
    method public static android.net.Uri buildViaUri(java.lang.String, java.lang.String);
    method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
    method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
    method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
    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);
    method public static java.lang.String getRootId(android.net.Uri);
    method public static java.lang.String getSearchDocumentsQuery(android.net.Uri);
    method public static java.lang.String getViaDocumentId(android.net.Uri);
    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 renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String);
    field public static final java.lang.String EXTRA_ERROR = "error";
@@ -23877,7 +23877,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_DIR_SELECTION = 16; // 0x10
    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
  }
+13 −10
Original line number Diff line number Diff line
@@ -2731,6 +2731,7 @@ public class Intent implements Parcelable, Cloneable {
     * returned in {@link #getClipData()}.
     *
     * @see DocumentsContract
     * @see #ACTION_OPEN_DOCUMENT_TREE
     * @see #ACTION_CREATE_DOCUMENT
     * @see #FLAG_GRANT_PERSISTABLE_URI_PERMISSION
     */
@@ -2765,28 +2766,30 @@ public class Intent implements Parcelable, Cloneable {
     *
     * @see DocumentsContract
     * @see #ACTION_OPEN_DOCUMENT
     * @see #ACTION_OPEN_DOCUMENT_TREE
     * @see #FLAG_GRANT_PERSISTABLE_URI_PERMISSION
     */
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public static final String ACTION_CREATE_DOCUMENT = "android.intent.action.CREATE_DOCUMENT";

    /**
     * Activity Action: Allow the user to pick a directory. When invoked, the
     * system will display the various {@link DocumentsProvider} instances
     * installed on the device, letting the user navigate through them. Apps can
     * fully manage documents within the returned directory.
     * Activity Action: Allow the user to pick a directory subtree. When
     * invoked, the system will display the various {@link DocumentsProvider}
     * instances installed on the device, letting the user navigate through
     * them. Apps can fully manage documents within the returned directory.
     * <p>
     * To gain access to descendant (child, grandchild, etc) documents, use
     * {@link DocumentsContract#buildDocumentViaUri(Uri, String)} and
     * {@link DocumentsContract#buildChildDocumentsViaUri(Uri, String)} using
     * the returned directory URI.
     * {@link DocumentsContract#buildDocumentUriUsingTree(Uri, String)} and
     * {@link DocumentsContract#buildChildDocumentsUriUsingTree(Uri, String)}
     * with the returned URI.
     * <p>
     * Output: The URI representing the selected directory.
     * Output: The URI representing the selected directory tree.
     *
     * @see DocumentsContract
     */
    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    public static final String ACTION_PICK_DIRECTORY = "android.intent.action.PICK_DIRECTORY";
    public static final String
            ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";

    // ---------------------------------------------------------------------
    // ---------------------------------------------------------------------
@@ -3365,8 +3368,8 @@ public class Intent implements Parcelable, Cloneable {
     *
     * @see #ACTION_GET_CONTENT
     * @see #ACTION_OPEN_DOCUMENT
     * @see #ACTION_OPEN_DOCUMENT_TREE
     * @see #ACTION_CREATE_DOCUMENT
     * @see #ACTION_PICK_DIRECTORY
     */
    public static final String EXTRA_LOCAL_ONLY =
            "android.intent.extra.LOCAL_ONLY";
+66 −54
Original line number Diff line number Diff line
@@ -60,7 +60,8 @@ import java.util.List;
 * <p>
 * All client apps must hold a valid URI permission grant to access documents,
 * typically issued when a user makes a selection through
 * {@link Intent#ACTION_OPEN_DOCUMENT} or {@link Intent#ACTION_CREATE_DOCUMENT}.
 * {@link Intent#ACTION_OPEN_DOCUMENT}, {@link Intent#ACTION_CREATE_DOCUMENT},
 * or {@link Intent#ACTION_OPEN_DOCUMENT_TREE}.
 *
 * @see DocumentsProvider
 */
@@ -73,8 +74,8 @@ public final class DocumentsContract {
    // content://com.example/root/sdcard/search/?query=pony
    // content://com.example/document/12/
    // content://com.example/document/12/children/
    // content://com.example/via/12/document/24/
    // content://com.example/via/12/document/24/children/
    // content://com.example/tree/12/document/24/
    // content://com.example/tree/12/document/24/children/

    private DocumentsContract() {
    }
@@ -441,12 +442,13 @@ public final class DocumentsContract {
        public static final int FLAG_SUPPORTS_SEARCH = 1 << 3;

        /**
         * Flag indicating that this root supports directory selection.
         * Flag indicating that this root supports testing parent child
         * relationships.
         *
         * @see #COLUMN_FLAGS
         * @see DocumentsProvider#isChildDocument(String, String)
         */
        public static final int FLAG_SUPPORTS_DIR_SELECTION = 1 << 4;
        public static final int FLAG_SUPPORTS_IS_CHILD = 1 << 4;

        /**
         * Flag indicating that this root is currently empty. This may be used
@@ -518,7 +520,7 @@ public final class DocumentsContract {
    private static final String PATH_DOCUMENT = "document";
    private static final String PATH_CHILDREN = "children";
    private static final String PATH_SEARCH = "search";
    private static final String PATH_VIA = "via";
    private static final String PATH_TREE = "tree";

    private static final String PARAM_QUERY = "query";
    private static final String PARAM_MANAGE = "manage";
@@ -564,17 +566,17 @@ public final class DocumentsContract {
     * Build URI representing access to descendant documents of the given
     * {@link Document#COLUMN_DOCUMENT_ID}.
     *
     * @see #getViaDocumentId(Uri)
     * @see #getTreeDocumentId(Uri)
     */
    public static Uri buildViaUri(String authority, String documentId) {
    public static Uri buildTreeDocumentUri(String authority, String documentId) {
        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(authority)
                .appendPath(PATH_VIA).appendPath(documentId).build();
                .appendPath(PATH_TREE).appendPath(documentId).build();
    }

    /**
     * Build URI representing the given {@link Document#COLUMN_DOCUMENT_ID} in a
     * document provider. When queried, a provider will return a single row with
     * columns defined by {@link Document}.
     * Build URI representing the target {@link Document#COLUMN_DOCUMENT_ID} in
     * a document provider. When queried, a provider will return a single row
     * with columns defined by {@link Document}.
     *
     * @see DocumentsProvider#queryDocument(String, String[])
     * @see #getDocumentId(Uri)
@@ -585,42 +587,46 @@ public final class DocumentsContract {
    }

    /**
     * Build URI representing the given {@link Document#COLUMN_DOCUMENT_ID} in a
     * document provider. Instead of directly accessing the target document,
     * gain access via another document. The target document must be a
     * descendant (child, grandchild, etc) of the via document.
     * Build URI representing the target {@link Document#COLUMN_DOCUMENT_ID} in
     * a document provider. When queried, a provider will return a single row
     * with columns defined by {@link Document}.
     * <p>
     * However, instead of directly accessing the target document, the returned
     * URI will leverage access granted through a subtree URI, typically
     * returned by {@link Intent#ACTION_OPEN_DOCUMENT_TREE}. The target document
     * must be a descendant (child, grandchild, etc) of the subtree.
     * <p>
     * This is typically used to access documents under a user-selected
     * directory, since it doesn't require the user to separately confirm each
     * new document access.
     * directory tree, since it doesn't require the user to separately confirm
     * each new document access.
     *
     * @param viaUri a related document (directory) that the caller is
     *            leveraging to gain access to the target document. The target
     *            document must be a descendant of this directory.
     * @param treeUri the subtree to leverage to gain access to the target
     *            document. The target directory must be a descendant of this
     *            subtree.
     * @param documentId the target document, which the caller may not have
     *            direct access to.
     * @see Intent#ACTION_PICK_DIRECTORY
     * @see Intent#ACTION_OPEN_DOCUMENT_TREE
     * @see DocumentsProvider#isChildDocument(String, String)
     * @see #buildDocumentUri(String, String)
     */
    public static Uri buildDocumentViaUri(Uri viaUri, String documentId) {
    public static Uri buildDocumentUriUsingTree(Uri treeUri, String documentId) {
        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
                .authority(viaUri.getAuthority()).appendPath(PATH_VIA)
                .appendPath(getViaDocumentId(viaUri)).appendPath(PATH_DOCUMENT)
                .authority(treeUri.getAuthority()).appendPath(PATH_TREE)
                .appendPath(getTreeDocumentId(treeUri)).appendPath(PATH_DOCUMENT)
                .appendPath(documentId).build();
    }

    /** {@hide} */
    public static Uri buildDocumentMaybeViaUri(Uri baseUri, String documentId) {
        if (isViaUri(baseUri)) {
            return buildDocumentViaUri(baseUri, documentId);
    public static Uri buildDocumentUriMaybeUsingTree(Uri baseUri, String documentId) {
        if (isTreeUri(baseUri)) {
            return buildDocumentUriUsingTree(baseUri, documentId);
        } else {
            return buildDocumentUri(baseUri.getAuthority(), documentId);
        }
    }

    /**
     * Build URI representing the children of the given directory in a document
     * Build URI representing the children of the target directory in a document
     * provider. When queried, a provider will return zero or more rows with
     * columns defined by {@link Document}.
     *
@@ -637,28 +643,33 @@ public final class DocumentsContract {
    }

    /**
     * Build URI representing the children of the given directory in a document
     * provider. Instead of directly accessing the target document, gain access
     * via another document. The target document must be a descendant (child,
     * grandchild, etc) of the via document.
     * Build URI representing the children of the target directory in a document
     * provider. When queried, a provider will return zero or more rows with
     * columns defined by {@link Document}.
     * <p>
     * However, instead of directly accessing the target directory, the returned
     * URI will leverage access granted through a subtree URI, typically
     * returned by {@link Intent#ACTION_OPEN_DOCUMENT_TREE}. The target
     * directory must be a descendant (child, grandchild, etc) of the subtree.
     * <p>
     * This is typically used to access documents under a user-selected
     * directory, since it doesn't require the user to separately confirm each
     * new document access.
     *
     * @param viaUri a related document (directory) that the caller is
     *            leveraging to gain access to the target document. The target
     *            document must be a descendant of this directory.
     * @param parentDocumentId the target document, which the caller may not
     *            have direct access to.
     * @see Intent#ACTION_PICK_DIRECTORY
     * directory tree, since it doesn't require the user to separately confirm
     * each new document access.
     *
     * @param treeUri the subtree to leverage to gain access to the target
     *            document. The target directory must be a descendant of this
     *            subtree.
     * @param parentDocumentId the document to return children for, which the
     *            caller may not have direct access to, and which must be a
     *            directory with MIME type of {@link Document#MIME_TYPE_DIR}.
     * @see Intent#ACTION_OPEN_DOCUMENT_TREE
     * @see DocumentsProvider#isChildDocument(String, String)
     * @see #buildChildDocumentsUri(String, String)
     */
    public static Uri buildChildDocumentsViaUri(Uri viaUri, String parentDocumentId) {
    public static Uri buildChildDocumentsUriUsingTree(Uri treeUri, String parentDocumentId) {
        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
                .authority(viaUri.getAuthority()).appendPath(PATH_VIA)
                .appendPath(getViaDocumentId(viaUri)).appendPath(PATH_DOCUMENT)
                .authority(treeUri.getAuthority()).appendPath(PATH_TREE)
                .appendPath(getTreeDocumentId(treeUri)).appendPath(PATH_DOCUMENT)
                .appendPath(parentDocumentId).appendPath(PATH_CHILDREN).build();
    }

@@ -683,21 +694,24 @@ public final class DocumentsContract {
     * {@link DocumentsProvider}.
     *
     * @see #buildDocumentUri(String, String)
     * @see #buildDocumentViaUri(Uri, String)
     * @see #buildDocumentUriUsingTree(Uri, String)
     */
    public static boolean isDocumentUri(Context context, Uri uri) {
        final List<String> paths = uri.getPathSegments();
        if (paths.size() >= 2
                && (PATH_DOCUMENT.equals(paths.get(0)) || PATH_VIA.equals(paths.get(0)))) {
        if (paths.size() == 2 && PATH_DOCUMENT.equals(paths.get(0))) {
            return isDocumentsProvider(context, uri.getAuthority());
        }
        if (paths.size() == 4 && PATH_TREE.equals(paths.get(0))
                && PATH_DOCUMENT.equals(paths.get(2))) {
            return isDocumentsProvider(context, uri.getAuthority());
        }
        return false;
    }

    /** {@hide} */
    public static boolean isViaUri(Uri uri) {
    public static boolean isTreeUri(Uri uri) {
        final List<String> paths = uri.getPathSegments();
        return (paths.size() >= 2 && PATH_VIA.equals(paths.get(0)));
        return (paths.size() >= 2 && PATH_TREE.equals(paths.get(0)));
    }

    private static boolean isDocumentsProvider(Context context, String authority) {
@@ -733,7 +747,7 @@ public final class DocumentsContract {
        if (paths.size() >= 2 && PATH_DOCUMENT.equals(paths.get(0))) {
            return paths.get(1);
        }
        if (paths.size() >= 4 && PATH_VIA.equals(paths.get(0))
        if (paths.size() >= 4 && PATH_TREE.equals(paths.get(0))
                && PATH_DOCUMENT.equals(paths.get(2))) {
            return paths.get(3);
        }
@@ -742,12 +756,10 @@ public final class DocumentsContract {

    /**
     * Extract the via {@link Document#COLUMN_DOCUMENT_ID} from the given URI.
     *
     * @see #isViaUri(Uri)
     */
    public static String getViaDocumentId(Uri documentUri) {
    public static String getTreeDocumentId(Uri documentUri) {
        final List<String> paths = documentUri.getPathSegments();
        if (paths.size() >= 2 && PATH_VIA.equals(paths.get(0))) {
        if (paths.size() >= 2 && PATH_TREE.equals(paths.get(0))) {
            return paths.get(1);
        }
        throw new IllegalArgumentException("Invalid URI: " + documentUri);
+43 −38

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@
                <data android:mimeType="*/*" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.PICK_DIRECTORY" />
                <action android:name="android.intent.action.OPEN_DOCUMENT_TREE" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <intent-filter>
Loading