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

Commit d734c698 authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android Git Automerger
Browse files

am 99f4fe07: Merge "Refactor directory API to "opening document tree."" into lmp-preview-dev

* commit '99f4fe0797adb8350f92c7d1ba11776d1947e768':
  Refactor directory API to "opening document tree."
parents b71f764c f8f69b89
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -7414,6 +7414,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";
@@ -7428,7 +7429,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";
@@ -23971,21 +23971,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";
@@ -24024,7 +24024,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
@@ -2735,6 +2735,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
     */
@@ -2769,28 +2770,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";

    // ---------------------------------------------------------------------
    // ---------------------------------------------------------------------
@@ -3369,8 +3372,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