blob: 3c40b672cdccf43d97c47f7c6393223a898c4608 [file] [log] [blame]
Steve McKay99bcc6a2015-10-26 17:03:55 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.documentsui;
18
Steve McKaybbeba522016-01-13 17:17:39 -080019import static android.provider.DocumentsContract.buildChildDocumentsUri;
20import static android.provider.DocumentsContract.buildDocumentUri;
21import static android.provider.DocumentsContract.buildRootsUri;
Steve McKay99bcc6a2015-10-26 17:03:55 -070022import static com.android.documentsui.model.DocumentInfo.getCursorString;
Steve McKaybbeba522016-01-13 17:17:39 -080023import static junit.framework.Assert.assertEquals;
24import static junit.framework.Assert.assertNotNull;
25import static junit.framework.Assert.fail;
Steve McKay99bcc6a2015-10-26 17:03:55 -070026
27import android.content.ContentProviderClient;
28import android.database.Cursor;
29import android.net.Uri;
Steve McKaybbeba522016-01-13 17:17:39 -080030import android.os.Bundle;
31import android.os.ParcelFileDescriptor;
32import android.os.ParcelFileDescriptor.AutoCloseInputStream;
33import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
Steve McKay99bcc6a2015-10-26 17:03:55 -070034import android.os.RemoteException;
35import android.provider.DocumentsContract;
36import android.provider.DocumentsContract.Document;
37import android.provider.DocumentsContract.Root;
Steve McKaybbeba522016-01-13 17:17:39 -080038import android.support.annotation.Nullable;
39import android.test.MoreAsserts;
40import android.util.Log;
Steve McKay99bcc6a2015-10-26 17:03:55 -070041
Steve McKaybbeba522016-01-13 17:17:39 -080042import com.android.documentsui.model.DocumentInfo;
Steve McKay99bcc6a2015-10-26 17:03:55 -070043import com.android.documentsui.model.RootInfo;
44
Steve McKaybbeba522016-01-13 17:17:39 -080045import com.google.android.collect.Lists;
46
Steve McKay99bcc6a2015-10-26 17:03:55 -070047import libcore.io.IoUtils;
Steve McKaybbeba522016-01-13 17:17:39 -080048import libcore.io.Streams;
49
50import java.io.IOException;
51import java.util.ArrayList;
52import java.util.List;
Steve McKay99bcc6a2015-10-26 17:03:55 -070053
54/**
55 * Provides support for creation of documents in a test settings.
56 */
57public class DocumentsProviderHelper {
58
Steve McKay99bcc6a2015-10-26 17:03:55 -070059 private final String mAuthority;
Steve McKaybbeba522016-01-13 17:17:39 -080060 private final ContentProviderClient mClient;
Steve McKay99bcc6a2015-10-26 17:03:55 -070061
62 public DocumentsProviderHelper(String authority, ContentProviderClient client) {
Steve McKay99bcc6a2015-10-26 17:03:55 -070063 mAuthority = authority;
Steve McKaybbeba522016-01-13 17:17:39 -080064 mClient = client;
Steve McKay99bcc6a2015-10-26 17:03:55 -070065 }
66
Steve McKaybbeba522016-01-13 17:17:39 -080067 public RootInfo getRoot(String documentId) throws RemoteException {
68 final Uri rootsUri = buildRootsUri(mAuthority);
Steve McKay99bcc6a2015-10-26 17:03:55 -070069
70 Cursor cursor = null;
71 try {
72 cursor = mClient.query(rootsUri, null, null, null, null);
73 while (cursor.moveToNext()) {
Steve McKaybbeba522016-01-13 17:17:39 -080074 if (documentId.equals(getCursorString(cursor, Root.COLUMN_ROOT_ID))) {
Steve McKay99bcc6a2015-10-26 17:03:55 -070075 return RootInfo.fromRootsCursor(mAuthority, cursor);
76 }
77 }
Steve McKaybbeba522016-01-13 17:17:39 -080078 throw new IllegalArgumentException("Can't find matching root for id=" + documentId);
Steve McKay99bcc6a2015-10-26 17:03:55 -070079 } catch (Exception e) {
Steve McKaybbeba522016-01-13 17:17:39 -080080 throw new RuntimeException("Can't load root for id=" + documentId , e);
Steve McKay99bcc6a2015-10-26 17:03:55 -070081 } finally {
82 IoUtils.closeQuietly(cursor);
83 }
84 }
85
86 public Uri createDocument(Uri parentUri, String mimeType, String name) {
87 if (name.contains("/")) {
88 throw new IllegalArgumentException("Name and mimetype probably interposed.");
89 }
90 try {
Steve McKaybbeba522016-01-13 17:17:39 -080091 Uri uri = DocumentsContract.createDocument(mClient, parentUri, mimeType, name);
92 return uri;
Steve McKay99bcc6a2015-10-26 17:03:55 -070093 } catch (RemoteException e) {
94 throw new RuntimeException("Couldn't create document: " + name + " with mimetype " + mimeType, e);
95 }
96 }
97
Steve McKaybbeba522016-01-13 17:17:39 -080098 public Uri createDocument(String parentId, String mimeType, String name) {
99 Uri parentUri = buildDocumentUri(mAuthority, parentId);
100 return createDocument(parentUri, mimeType, name);
101 }
102
103 public Uri createDocument(RootInfo root, String mimeType, String name) {
104 return createDocument(root.documentId, mimeType, name);
105 }
106
Steve McKay99bcc6a2015-10-26 17:03:55 -0700107 public Uri createFolder(Uri parentUri, String name) {
108 return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
109 }
110
Steve McKaybbeba522016-01-13 17:17:39 -0800111 public Uri createFolder(String parentId, String name) {
112 Uri parentUri = buildDocumentUri(mAuthority, parentId);
113 return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
Steve McKay99bcc6a2015-10-26 17:03:55 -0700114 }
115
116 public Uri createFolder(RootInfo root, String name) {
117 return createDocument(root, Document.MIME_TYPE_DIR, name);
118 }
Steve McKaybbeba522016-01-13 17:17:39 -0800119
120 public void writeDocument(Uri documentUri, byte[] contents)
121 throws RemoteException, IOException {
122 ParcelFileDescriptor file = mClient.openFile(documentUri, "w", null);
123 try (AutoCloseOutputStream out = new AutoCloseOutputStream(file)) {
124 out.write(contents, 0, contents.length);
125 }
126 }
127
128 public byte[] readDocument(Uri documentUri) throws RemoteException, IOException {
129 Log.d("DocumentsProviderHelper", "Trying to read file contents: " + documentUri);
130 ParcelFileDescriptor file = mClient.openFile(documentUri, "r", null);
131 byte[] buf = null;
132 try (AutoCloseInputStream in = new AutoCloseInputStream(file)) {
133 buf = Streams.readFully(in);
134 }
135 return buf;
136 }
137
138 public void assertChildCount(Uri parentUri, int expected) throws Exception {
139 List<DocumentInfo> children = listChildren(parentUri);
140 assertEquals("Incorrect file count after copy", expected, children.size());
141 }
142
143 public void assertChildCount(String parentId, int expected) throws Exception {
144 List<DocumentInfo> children = listChildren(parentId);
145 assertEquals("Incorrect file count after copy", expected, children.size());
146 }
147
148 public void assertChildCount(RootInfo root, int expected) throws Exception {
149 assertChildCount(root.documentId, expected);
150 }
151
152 public void assertHasFile(Uri parentUri, String name) throws Exception {
153 List<DocumentInfo> children = listChildren(parentUri);
154 for (DocumentInfo child : children) {
155 if (name.equals(child.displayName) && !child.isDirectory()) {
156 return;
157 }
158 }
159 fail("Could not find file named=" + name + " in children " + children);
160 }
161
162 public void assertHasFile(String parentId, String name) throws Exception {
163 Uri parentUri = buildDocumentUri(mAuthority, parentId);
164 assertHasFile(parentUri, name);
165 }
166
167 public void assertHasFile(RootInfo root, String name) throws Exception {
168 assertHasFile(root.documentId, name);
169 }
170
171 public void assertHasDirectory(Uri parentUri, String name) throws Exception {
172 List<DocumentInfo> children = listChildren(parentUri);
173 for (DocumentInfo child : children) {
174 if (name.equals(child.displayName) && child.isDirectory()) {
175 return;
176 }
177 }
178 fail("Could not find name=" + name + " in children " + children);
179 }
180
181 public void assertHasDirectory(String parentId, String name) throws Exception {
182 Uri parentUri = buildDocumentUri(mAuthority, parentId);
183 assertHasDirectory(parentUri, name);
184 }
185
186 public void assertHasDirectory(RootInfo root, String name) throws Exception {
187 assertHasDirectory(root.documentId, name);
188 }
189
190 public void assertDoesNotExist(Uri parentUri, String name) throws Exception {
191 List<DocumentInfo> children = listChildren(parentUri);
192 for (DocumentInfo child : children) {
193 if (name.equals(child.displayName)) {
194 fail("Found name=" + name + " in children " + children);
195 }
196 }
197 }
198
199 public void assertDoesNotExist(String parentId, String name) throws Exception {
200 Uri parentUri = buildDocumentUri(mAuthority, parentId);
201 assertDoesNotExist(parentUri, name);
202 }
203
204 public void assertDoesNotExist(RootInfo root, String name) throws Exception {
205 assertDoesNotExist(root.getUri(), name);
206 }
207
208 public @Nullable DocumentInfo findFile(String parentId, String name)
209 throws Exception {
210 List<DocumentInfo> children = listChildren(parentId);
211 for (DocumentInfo child : children) {
212 if (name.equals(child.displayName)) {
213 return child;
214 }
215 }
216 return null;
217 }
218
219 public DocumentInfo findDocument(String parentId, String name) throws Exception {
220 List<DocumentInfo> children = listChildren(parentId);
221 for (DocumentInfo child : children) {
222 if (name.equals(child.displayName)) {
223 return child;
224 }
225 }
226 return null;
227 }
228
229 public DocumentInfo findDocument(Uri parentUri, String name) throws Exception {
230 List<DocumentInfo> children = listChildren(parentUri);
231 for (DocumentInfo child : children) {
232 if (name.equals(child.displayName)) {
233 return child;
234 }
235 }
236 return null;
237 }
238
239 public List<DocumentInfo> listChildren(Uri parentUri) throws Exception {
240 String id = DocumentsContract.getDocumentId(parentUri);
241 return listChildren(id);
242 }
243
244 public List<DocumentInfo> listChildren(String documentId) throws Exception {
245 Uri uri = buildChildDocumentsUri(mAuthority, documentId);
246 List<DocumentInfo> children = new ArrayList<>();
247 try (Cursor cursor = mClient.query(uri, null, null, null, null, null)) {
248 while (cursor.moveToNext()) {
249 children.add(DocumentInfo.fromDirectoryCursor(cursor));
250 }
251 }
252 return children;
253 }
254
255 public void assertFileContents(Uri documentUri, byte[] expected) throws Exception {
256 // TODO: Fix this: java.lang.SecurityException:
257 // The authority of the uri content:/document/%2Fdata%2Fuser%2F0%2Fcom.android.documentsui.\
258 // tests%2Fcache%2FTEST_ROOT_1%2Ftest1.txt does not match the one of the contentProvider: \
259 // com.android.documentsui.stubprovider
260// MoreAsserts.assertEquals(
261// "Copied file contents differ",
262// expected, readDocument(documentUri));
263 }
264
265 public void assertFileContents(String parentId, String fileName, byte[] expected)
266 throws Exception {
267 DocumentInfo file = findFile(parentId, fileName);
268 assertNotNull(file);
269 assertFileContents(file.derivedUri, expected);
270 }
271
272 /**
273 * A helper method for StubProvider only. Won't work with other providers.
274 * @throws RemoteException
275 */
276 public Uri createVirtualFile(
277 RootInfo root, String path, String mimeType, byte[] content, String... streamTypes)
278 throws RemoteException {
279
280 Bundle args = new Bundle();
281 args.putString(StubProvider.EXTRA_ROOT, root.rootId);
282 args.putString(StubProvider.EXTRA_PATH, path);
283 args.putString(Document.COLUMN_MIME_TYPE, mimeType);
284 args.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
285 args.putByteArray(StubProvider.EXTRA_CONTENT, content);
286
287 Bundle result = mClient.call("createVirtualFile", null, args);
288 String documentId = result.getString(Document.COLUMN_DOCUMENT_ID);
289
290 return DocumentsContract.buildDocumentUri(mAuthority, documentId);
291 }
Steve McKay99bcc6a2015-10-26 17:03:55 -0700292}