blob: cac4f451307b21a1e3621a9f1b8e4ab11aa3f1e6 [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 McKayd0805062016-09-15 14:30:38 -070022import static com.android.documentsui.base.DocumentInfo.getCursorString;
Steve McKay22797f52016-01-25 16:31:35 -080023import static com.android.internal.util.Preconditions.checkArgument;
Steve McKaybbeba522016-01-13 17:17:39 -080024import static junit.framework.Assert.assertEquals;
25import static junit.framework.Assert.assertNotNull;
26import static junit.framework.Assert.fail;
Steve McKay99bcc6a2015-10-26 17:03:55 -070027
28import android.content.ContentProviderClient;
29import android.database.Cursor;
30import android.net.Uri;
Steve McKaybbeba522016-01-13 17:17:39 -080031import android.os.Bundle;
32import android.os.ParcelFileDescriptor;
33import android.os.ParcelFileDescriptor.AutoCloseInputStream;
34import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
Steve McKay99bcc6a2015-10-26 17:03:55 -070035import android.os.RemoteException;
36import android.provider.DocumentsContract;
37import android.provider.DocumentsContract.Document;
38import android.provider.DocumentsContract.Root;
Steve McKaybbeba522016-01-13 17:17:39 -080039import android.support.annotation.Nullable;
40import android.test.MoreAsserts;
Steve McKay22797f52016-01-25 16:31:35 -080041import android.text.TextUtils;
Steve McKay99bcc6a2015-10-26 17:03:55 -070042
Steve McKayd0805062016-09-15 14:30:38 -070043import com.android.documentsui.base.DocumentInfo;
44import com.android.documentsui.base.RootInfo;
Steve McKayd9caa6a2016-09-15 16:36:45 -070045import com.android.documentsui.roots.RootCursorWrapper;
Steve McKay99bcc6a2015-10-26 17:03:55 -070046
Steve McKaybbeba522016-01-13 17:17:39 -080047import com.google.android.collect.Lists;
48
Steve McKay99bcc6a2015-10-26 17:03:55 -070049import libcore.io.IoUtils;
Steve McKaybbeba522016-01-13 17:17:39 -080050import libcore.io.Streams;
51
52import java.io.IOException;
53import java.util.ArrayList;
54import java.util.List;
Steve McKay99bcc6a2015-10-26 17:03:55 -070055
56/**
57 * Provides support for creation of documents in a test settings.
58 */
59public class DocumentsProviderHelper {
60
Steve McKay99bcc6a2015-10-26 17:03:55 -070061 private final String mAuthority;
Steve McKaybbeba522016-01-13 17:17:39 -080062 private final ContentProviderClient mClient;
Steve McKay99bcc6a2015-10-26 17:03:55 -070063
64 public DocumentsProviderHelper(String authority, ContentProviderClient client) {
Steve McKay22797f52016-01-25 16:31:35 -080065 checkArgument(!TextUtils.isEmpty(authority));
Steve McKay99bcc6a2015-10-26 17:03:55 -070066 mAuthority = authority;
Steve McKaybbeba522016-01-13 17:17:39 -080067 mClient = client;
Steve McKay99bcc6a2015-10-26 17:03:55 -070068 }
69
Steve McKaybbeba522016-01-13 17:17:39 -080070 public RootInfo getRoot(String documentId) throws RemoteException {
71 final Uri rootsUri = buildRootsUri(mAuthority);
Steve McKay99bcc6a2015-10-26 17:03:55 -070072 Cursor cursor = null;
73 try {
74 cursor = mClient.query(rootsUri, null, null, null, null);
75 while (cursor.moveToNext()) {
Steve McKaybbeba522016-01-13 17:17:39 -080076 if (documentId.equals(getCursorString(cursor, Root.COLUMN_ROOT_ID))) {
Steve McKay99bcc6a2015-10-26 17:03:55 -070077 return RootInfo.fromRootsCursor(mAuthority, cursor);
78 }
79 }
Steve McKaybbeba522016-01-13 17:17:39 -080080 throw new IllegalArgumentException("Can't find matching root for id=" + documentId);
Steve McKay99bcc6a2015-10-26 17:03:55 -070081 } catch (Exception e) {
Steve McKaybbeba522016-01-13 17:17:39 -080082 throw new RuntimeException("Can't load root for id=" + documentId , e);
Steve McKay99bcc6a2015-10-26 17:03:55 -070083 } finally {
84 IoUtils.closeQuietly(cursor);
85 }
86 }
87
88 public Uri createDocument(Uri parentUri, String mimeType, String name) {
89 if (name.contains("/")) {
90 throw new IllegalArgumentException("Name and mimetype probably interposed.");
91 }
92 try {
Steve McKaybbeba522016-01-13 17:17:39 -080093 Uri uri = DocumentsContract.createDocument(mClient, parentUri, mimeType, name);
94 return uri;
Steve McKay99bcc6a2015-10-26 17:03:55 -070095 } catch (RemoteException e) {
Tomasz Mikolajewskia2ad8df2016-02-04 17:46:35 +090096 throw new RuntimeException("Couldn't create document: " + name + " with mimetype "
97 + mimeType, e);
Steve McKay99bcc6a2015-10-26 17:03:55 -070098 }
99 }
100
Steve McKaybbeba522016-01-13 17:17:39 -0800101 public Uri createDocument(String parentId, String mimeType, String name) {
102 Uri parentUri = buildDocumentUri(mAuthority, parentId);
103 return createDocument(parentUri, mimeType, name);
104 }
105
106 public Uri createDocument(RootInfo root, String mimeType, String name) {
107 return createDocument(root.documentId, mimeType, name);
108 }
109
Tomasz Mikolajewskife7f5362016-03-02 17:41:40 +0900110 public Uri createDocumentWithFlags(String documentId, String mimeType, String name, int flags,
111 String... streamTypes)
Aga Wronska18410b72016-01-26 14:06:29 -0800112 throws RemoteException {
113 Bundle in = new Bundle();
114 in.putInt(StubProvider.EXTRA_FLAGS, flags);
115 in.putString(StubProvider.EXTRA_PARENT_ID, documentId);
116 in.putString(Document.COLUMN_MIME_TYPE, mimeType);
117 in.putString(Document.COLUMN_DISPLAY_NAME, name);
Tomasz Mikolajewskife7f5362016-03-02 17:41:40 +0900118 in.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
Aga Wronska18410b72016-01-26 14:06:29 -0800119
120 Bundle out = mClient.call("createDocumentWithFlags", null, in);
121 Uri uri = out.getParcelable(DocumentsContract.EXTRA_URI);
122 return uri;
123 }
124
Steve McKay99bcc6a2015-10-26 17:03:55 -0700125 public Uri createFolder(Uri parentUri, String name) {
126 return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
127 }
128
Steve McKaybbeba522016-01-13 17:17:39 -0800129 public Uri createFolder(String parentId, String name) {
130 Uri parentUri = buildDocumentUri(mAuthority, parentId);
131 return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
Steve McKay99bcc6a2015-10-26 17:03:55 -0700132 }
133
134 public Uri createFolder(RootInfo root, String name) {
135 return createDocument(root, Document.MIME_TYPE_DIR, name);
136 }
Steve McKaybbeba522016-01-13 17:17:39 -0800137
138 public void writeDocument(Uri documentUri, byte[] contents)
139 throws RemoteException, IOException {
140 ParcelFileDescriptor file = mClient.openFile(documentUri, "w", null);
141 try (AutoCloseOutputStream out = new AutoCloseOutputStream(file)) {
142 out.write(contents, 0, contents.length);
143 }
Garfield Tan1e80be72017-02-27 18:16:00 -0800144 mClient.call("waitForWrite", null, null);
Steve McKaybbeba522016-01-13 17:17:39 -0800145 }
146
147 public byte[] readDocument(Uri documentUri) throws RemoteException, IOException {
Steve McKaybbeba522016-01-13 17:17:39 -0800148 ParcelFileDescriptor file = mClient.openFile(documentUri, "r", null);
149 byte[] buf = null;
150 try (AutoCloseInputStream in = new AutoCloseInputStream(file)) {
151 buf = Streams.readFully(in);
152 }
153 return buf;
154 }
155
156 public void assertChildCount(Uri parentUri, int expected) throws Exception {
157 List<DocumentInfo> children = listChildren(parentUri);
158 assertEquals("Incorrect file count after copy", expected, children.size());
159 }
160
161 public void assertChildCount(String parentId, int expected) throws Exception {
162 List<DocumentInfo> children = listChildren(parentId);
163 assertEquals("Incorrect file count after copy", expected, children.size());
164 }
165
166 public void assertChildCount(RootInfo root, int expected) throws Exception {
167 assertChildCount(root.documentId, expected);
168 }
169
170 public void assertHasFile(Uri parentUri, String name) throws Exception {
171 List<DocumentInfo> children = listChildren(parentUri);
172 for (DocumentInfo child : children) {
173 if (name.equals(child.displayName) && !child.isDirectory()) {
174 return;
175 }
176 }
177 fail("Could not find file named=" + name + " in children " + children);
178 }
179
180 public void assertHasFile(String parentId, String name) throws Exception {
181 Uri parentUri = buildDocumentUri(mAuthority, parentId);
182 assertHasFile(parentUri, name);
183 }
184
185 public void assertHasFile(RootInfo root, String name) throws Exception {
186 assertHasFile(root.documentId, name);
187 }
188
189 public void assertHasDirectory(Uri parentUri, String name) throws Exception {
190 List<DocumentInfo> children = listChildren(parentUri);
191 for (DocumentInfo child : children) {
192 if (name.equals(child.displayName) && child.isDirectory()) {
193 return;
194 }
195 }
196 fail("Could not find name=" + name + " in children " + children);
197 }
198
199 public void assertHasDirectory(String parentId, String name) throws Exception {
200 Uri parentUri = buildDocumentUri(mAuthority, parentId);
201 assertHasDirectory(parentUri, name);
202 }
203
204 public void assertHasDirectory(RootInfo root, String name) throws Exception {
205 assertHasDirectory(root.documentId, name);
206 }
207
208 public void assertDoesNotExist(Uri parentUri, String name) throws Exception {
209 List<DocumentInfo> children = listChildren(parentUri);
210 for (DocumentInfo child : children) {
211 if (name.equals(child.displayName)) {
212 fail("Found name=" + name + " in children " + children);
213 }
214 }
215 }
216
217 public void assertDoesNotExist(String parentId, String name) throws Exception {
218 Uri parentUri = buildDocumentUri(mAuthority, parentId);
219 assertDoesNotExist(parentUri, name);
220 }
221
222 public void assertDoesNotExist(RootInfo root, String name) throws Exception {
223 assertDoesNotExist(root.getUri(), name);
224 }
225
226 public @Nullable DocumentInfo findFile(String parentId, String name)
227 throws Exception {
228 List<DocumentInfo> children = listChildren(parentId);
229 for (DocumentInfo child : children) {
230 if (name.equals(child.displayName)) {
231 return child;
232 }
233 }
234 return null;
235 }
236
237 public DocumentInfo findDocument(String parentId, String name) throws Exception {
238 List<DocumentInfo> children = listChildren(parentId);
239 for (DocumentInfo child : children) {
240 if (name.equals(child.displayName)) {
241 return child;
242 }
243 }
244 return null;
245 }
246
247 public DocumentInfo findDocument(Uri parentUri, String name) throws Exception {
248 List<DocumentInfo> children = listChildren(parentUri);
249 for (DocumentInfo child : children) {
250 if (name.equals(child.displayName)) {
251 return child;
252 }
253 }
254 return null;
255 }
256
257 public List<DocumentInfo> listChildren(Uri parentUri) throws Exception {
258 String id = DocumentsContract.getDocumentId(parentUri);
259 return listChildren(id);
260 }
261
262 public List<DocumentInfo> listChildren(String documentId) throws Exception {
263 Uri uri = buildChildDocumentsUri(mAuthority, documentId);
264 List<DocumentInfo> children = new ArrayList<>();
265 try (Cursor cursor = mClient.query(uri, null, null, null, null, null)) {
Steve McKay22797f52016-01-25 16:31:35 -0800266 Cursor wrapper = new RootCursorWrapper(mAuthority, "totally-fake", cursor, 100);
267 while (wrapper.moveToNext()) {
268 children.add(DocumentInfo.fromDirectoryCursor(wrapper));
Steve McKaybbeba522016-01-13 17:17:39 -0800269 }
270 }
271 return children;
272 }
273
274 public void assertFileContents(Uri documentUri, byte[] expected) throws Exception {
Steve McKay22797f52016-01-25 16:31:35 -0800275 MoreAsserts.assertEquals(
276 "Copied file contents differ",
277 expected, readDocument(documentUri));
Steve McKaybbeba522016-01-13 17:17:39 -0800278 }
279
280 public void assertFileContents(String parentId, String fileName, byte[] expected)
281 throws Exception {
282 DocumentInfo file = findFile(parentId, fileName);
283 assertNotNull(file);
284 assertFileContents(file.derivedUri, expected);
285 }
286
287 /**
288 * A helper method for StubProvider only. Won't work with other providers.
289 * @throws RemoteException
290 */
291 public Uri createVirtualFile(
292 RootInfo root, String path, String mimeType, byte[] content, String... streamTypes)
293 throws RemoteException {
294
295 Bundle args = new Bundle();
296 args.putString(StubProvider.EXTRA_ROOT, root.rootId);
297 args.putString(StubProvider.EXTRA_PATH, path);
298 args.putString(Document.COLUMN_MIME_TYPE, mimeType);
299 args.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
300 args.putByteArray(StubProvider.EXTRA_CONTENT, content);
301
302 Bundle result = mClient.call("createVirtualFile", null, args);
303 String documentId = result.getString(Document.COLUMN_DOCUMENT_ID);
304
305 return DocumentsContract.buildDocumentUri(mAuthority, documentId);
306 }
Aga Wronska18410b72016-01-26 14:06:29 -0800307
Garfield Tan15666182017-01-18 16:27:55 -0800308 public void setLoadingDuration(long duration) throws RemoteException {
309 final Bundle extra = new Bundle();
310 extra.putLong(DocumentsContract.EXTRA_LOADING, duration);
311 mClient.call("setLoadingDuration", null, extra);
312 }
Steve McKay99bcc6a2015-10-26 17:03:55 -0700313}