1<?xml version="1.0" encoding="UTF-8"?>
2<!--
3 Copyright 2014 The Android Open Source Project
4
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9     http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16-->
17<sample>
18    <name>DirectorySelection</name>
19    <group>Content</group>
20    <package>com.example.android.directoryselection</package>
21
22    <androidX>true</androidX>
23
24    <dependency>androidx.appcompat:appcompat:1.0.2</dependency>
25    <dependency>androidx.recyclerview:recyclerview:1.0.0</dependency>
26
27    <!-- change minSdk if needed-->
28    <minSdk>21</minSdk>
29    <compileSdkVersion>28</compileSdkVersion>
30
31    <strings>
32        <intro>
33            <![CDATA[
34            This sample explains how to use Directory selection API, which was introduced
35            in Android 5.0.
36            ]]>
37        </intro>
38    </strings>
39
40    <template src="base" />
41
42    <metadata>
43        <status>PUBLISHED</status>
44        <categories>Content</categories>
45        <technologies>Android</technologies>
46        <languages>Java</languages>
47        <solutions>Mobile</solutions>
48        <level>INTERMEDIATE</level>
49        <icon>screenshots/web-icon.png</icon>
50        <screenshots>
51            <img>screenshots/screenshot-1.png</img>
52            <img>screenshots/screenshot-2.png</img>
53            <img>screenshots/screenshot-3.png</img>
54        </screenshots>
55        <api_refs>
56            <android>android.content.ContentResolver</android>
57            <android>android.provider.DocumentsContract</android>
58        </api_refs>
59
60        <description>
61<![CDATA[
62A basic app showing how to use Directory Selection API to let users
63select an entire directory subtree, which extends the Storage Access Framework
64introduced in Android 4.4 (API level 19).
65]]>
66        </description>
67
68        <intro>
69<![CDATA[
70The [Directory Selection][1] API, which was introduced in Android 5.0 (API level 21)
71extends the [Storage Access Framework][2] to let users select an entire directory subtree,
72giving apps read/write access to all contained documents without requiring user
73confirmation for each item.
74
75To select a directory subtree, build and send an [OPEN_DOCUMENT_TREE intent][3] like in the
76following code:
77
78```java
79Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
80startActivityForResult(intent, REQUEST_CODE_OPEN_DIRECTORY);
81```
82
83The system displays all [DocumentsProvider][4] instances that support subtree selection,
84 letting the user browse and select a directory.
85
86The returned URI represents access to the selected subtree. You can then use
87[buildChildDocumentsUriUsingTree()][5] to access to the child documents and
88[buildDocumentUriUsingTree()][6] to access to the selected directory itself along with [query()][7]
89to explore the subtree.
90
91This example explores the child documents and the selected document by following code:
92
93```java
94@Override
95public void onActivityResult(int requestCode, int resultCode, Intent data) {
96    super.onActivityResult(requestCode, resultCode, data);
97    if (requestCode == REQUEST_CODE_OPEN_DIRECTORY && resultCode == Activity.RESULT_OK) {
98        updateDirectoryEntries(data.getData());
99    }
100}
101
102void updateDirectoryEntries(Uri uri) {
103    ContentResolver contentResolver = getActivity().getContentResolver();
104    Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri,
105            DocumentsContract.getTreeDocumentId(uri));
106    Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri,
107            DocumentsContract.getTreeDocumentId(uri));
108
109    Cursor docCursor = contentResolver.query(docUri, new String[]{
110            Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE}, null, null, null);
111    try {
112        while (docCursor.moveToNext()) {
113            Log.d(TAG, "found doc =" + docCursor.getString(0) + ", mime=" + docCursor
114                    .getString(1));
115            mCurrentDirectoryUri = uri;
116            mCurrentDirectoryTextView.setText(docCursor.getString(0));
117            mCreateDirectoryButton.setEnabled(true);
118        }
119    } finally {
120        closeQuietly(docCursor);
121    }
122
123    Cursor childCursor = contentResolver.query(childrenUri, new String[]{
124            Document.COLUMN_DISPLAY_NAME, Document.COLUMN_MIME_TYPE}, null, null, null);
125    try {
126        List<DirectoryEntry> directoryEntries = new ArrayList<>();
127        while (childCursor.moveToNext()) {
128            Log.d(TAG, "found child=" + childCursor.getString(0) + ", mime=" + childCursor
129                    .getString(1));
130            DirectoryEntry entry = new DirectoryEntry();
131            entry.fileName = childCursor.getString(0);
132            entry.mimeType = childCursor.getString(1);
133            directoryEntries.add(entry);
134        }
135        mAdapter.setDirectoryEntries(directoryEntries);
136        mAdapter.notifyDataSetChanged();
137    } finally {
138        closeQuietly(childCursor);
139    }
140}
141```
142
143Also, the new [createDocument()][8] method lets you create new documents or directories
144anywhere under the subtree.
145
146This example creates a new directory by following code:
147
148```java
149ContentResolver contentResolver = getActivity().getContentResolver();
150Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri,
151        DocumentsContract.getTreeDocumentId(uri));
152Uri directoryUri = DocumentsContract
153        .createDocument(contentResolver, docUri, Document.MIME_TYPE_DIR, directoryName);
154```
155
156[1]: https://developer.android.com/about/versions/android-5.0.html#Storage
157[2]: https://developer.android.com/guide/topics/providers/document-provider.html
158[3]: https://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT_TREE
159[4]: https://developer.android.com/reference/android/provider/DocumentsProvider.html
160[5]: https://developer.android.com/reference/android/provider/DocumentsContract.html#buildChildDocumentsUriUsingTree(android.net.Uri%2C%20java.lang.String)
161[6]: https://developer.android.com/reference/android/provider/DocumentsContract.html#buildDocumentUriUsingTree(android.net.Uri%2C%20java.lang.String)
162[7]: https://developer.android.com/reference/android/content/ContentResolver.html#query(android.net.Uri%2C%20java.lang.String%5B%5D%2C%20java.lang.String%2C%20java.lang.String%5B%5D%2C%20java.lang.String)
163[8]: https://developer.android.com/reference/android/provider/DocumentsContract.html#createDocument(android.content.ContentResolver%2C%20android.net.Uri%2C%20java.lang.String%2C%20java.lang.String)
164]]>
165        </intro>
166    </metadata>
167</sample>
168