• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.documentsui;
18 
19 import static android.provider.DocumentsContract.buildChildDocumentsUri;
20 import static android.provider.DocumentsContract.buildDocumentUri;
21 import static android.provider.DocumentsContract.buildRootsUri;
22 import static com.android.documentsui.base.DocumentInfo.getCursorString;
23 import static com.android.internal.util.Preconditions.checkArgument;
24 import static junit.framework.Assert.assertEquals;
25 import static junit.framework.Assert.assertNotNull;
26 import static junit.framework.Assert.fail;
27 
28 import android.content.ContentProviderClient;
29 import android.database.Cursor;
30 import android.net.Uri;
31 import android.os.Bundle;
32 import android.os.ParcelFileDescriptor;
33 import android.os.ParcelFileDescriptor.AutoCloseInputStream;
34 import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
35 import android.os.RemoteException;
36 import android.provider.DocumentsContract;
37 import android.provider.DocumentsContract.Document;
38 import android.provider.DocumentsContract.Root;
39 import android.support.annotation.Nullable;
40 import android.test.MoreAsserts;
41 import android.text.TextUtils;
42 
43 import com.android.documentsui.base.DocumentInfo;
44 import com.android.documentsui.base.RootInfo;
45 import com.android.documentsui.roots.RootCursorWrapper;
46 
47 import com.google.android.collect.Lists;
48 
49 import libcore.io.IoUtils;
50 import libcore.io.Streams;
51 
52 import java.io.IOException;
53 import java.util.ArrayList;
54 import java.util.List;
55 
56 /**
57  * Provides support for creation of documents in a test settings.
58  */
59 public class DocumentsProviderHelper {
60 
61     private final String mAuthority;
62     private final ContentProviderClient mClient;
63 
DocumentsProviderHelper(String authority, ContentProviderClient client)64     public DocumentsProviderHelper(String authority, ContentProviderClient client) {
65         checkArgument(!TextUtils.isEmpty(authority));
66         mAuthority = authority;
67         mClient = client;
68     }
69 
getRoot(String documentId)70     public RootInfo getRoot(String documentId) throws RemoteException {
71         final Uri rootsUri = buildRootsUri(mAuthority);
72         Cursor cursor = null;
73         try {
74             cursor = mClient.query(rootsUri, null, null, null, null);
75             while (cursor.moveToNext()) {
76                 if (documentId.equals(getCursorString(cursor, Root.COLUMN_ROOT_ID))) {
77                     return RootInfo.fromRootsCursor(mAuthority, cursor);
78                 }
79             }
80             throw new IllegalArgumentException("Can't find matching root for id=" + documentId);
81         } catch (Exception e) {
82             throw new RuntimeException("Can't load root for id=" + documentId , e);
83         } finally {
84             IoUtils.closeQuietly(cursor);
85         }
86     }
87 
createDocument(Uri parentUri, String mimeType, String name)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 {
93             Uri uri = DocumentsContract.createDocument(mClient, parentUri, mimeType, name);
94             return uri;
95         } catch (RemoteException e) {
96             throw new RuntimeException("Couldn't create document: " + name + " with mimetype "
97                     + mimeType, e);
98         }
99     }
100 
createDocument(String parentId, String mimeType, String name)101     public Uri createDocument(String parentId, String mimeType, String name) {
102         Uri parentUri = buildDocumentUri(mAuthority, parentId);
103         return createDocument(parentUri, mimeType, name);
104     }
105 
createDocument(RootInfo root, String mimeType, String name)106     public Uri createDocument(RootInfo root, String mimeType, String name) {
107         return createDocument(root.documentId, mimeType, name);
108     }
109 
createDocumentWithFlags(String documentId, String mimeType, String name, int flags, String... streamTypes)110     public Uri createDocumentWithFlags(String documentId, String mimeType, String name, int flags,
111             String... streamTypes)
112             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);
118         in.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
119 
120         Bundle out = mClient.call("createDocumentWithFlags", null, in);
121         Uri uri = out.getParcelable(DocumentsContract.EXTRA_URI);
122         return uri;
123     }
124 
createFolder(Uri parentUri, String name)125     public Uri createFolder(Uri parentUri, String name) {
126         return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
127     }
128 
createFolder(String parentId, String name)129     public Uri createFolder(String parentId, String name) {
130         Uri parentUri = buildDocumentUri(mAuthority, parentId);
131         return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
132     }
133 
createFolder(RootInfo root, String name)134     public Uri createFolder(RootInfo root, String name) {
135         return createDocument(root, Document.MIME_TYPE_DIR, name);
136     }
137 
writeDocument(Uri documentUri, byte[] contents)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         }
144         waitForWrite();
145     }
146 
writeAppendDocument(Uri documentUri, byte[] contents)147     public void writeAppendDocument(Uri documentUri, byte[] contents)
148             throws RemoteException, IOException {
149         ParcelFileDescriptor file = mClient.openFile(documentUri, "wa", null);
150         try (AutoCloseOutputStream out = new AutoCloseOutputStream(file)) {
151             out.write(contents);
152         }
153         waitForWrite();
154     }
155 
waitForWrite()156     public void waitForWrite() throws RemoteException {
157         mClient.call("waitForWrite", null, null);
158     }
159 
readDocument(Uri documentUri)160     public byte[] readDocument(Uri documentUri) throws RemoteException, IOException {
161         ParcelFileDescriptor file = mClient.openFile(documentUri, "r", null);
162         byte[] buf = null;
163         try (AutoCloseInputStream in = new AutoCloseInputStream(file)) {
164             buf = Streams.readFully(in);
165         }
166         return buf;
167     }
168 
assertChildCount(Uri parentUri, int expected)169     public void assertChildCount(Uri parentUri, int expected) throws Exception {
170         List<DocumentInfo> children = listChildren(parentUri);
171         assertEquals("Incorrect file count after copy", expected, children.size());
172     }
173 
assertChildCount(String parentId, int expected)174     public void assertChildCount(String parentId, int expected) throws Exception {
175         List<DocumentInfo> children = listChildren(parentId, -1);
176         assertEquals("Incorrect file count after copy", expected, children.size());
177     }
178 
assertChildCount(RootInfo root, int expected)179     public void assertChildCount(RootInfo root, int expected) throws Exception {
180         assertChildCount(root.documentId, expected);
181     }
182 
assertHasFile(Uri parentUri, String name)183     public void assertHasFile(Uri parentUri, String name) throws Exception {
184         List<DocumentInfo> children = listChildren(parentUri);
185         for (DocumentInfo child : children) {
186             if (name.equals(child.displayName) && !child.isDirectory()) {
187                 return;
188             }
189         }
190         fail("Could not find file named=" + name + " in children " + children);
191     }
192 
assertHasFile(String parentId, String name)193     public void assertHasFile(String parentId, String name) throws Exception {
194         Uri parentUri = buildDocumentUri(mAuthority, parentId);
195         assertHasFile(parentUri, name);
196     }
197 
assertHasFile(RootInfo root, String name)198     public void assertHasFile(RootInfo root, String name) throws Exception {
199         assertHasFile(root.documentId, name);
200     }
201 
assertHasDirectory(Uri parentUri, String name)202     public void assertHasDirectory(Uri parentUri, String name) throws Exception {
203         List<DocumentInfo> children = listChildren(parentUri);
204         for (DocumentInfo child : children) {
205             if (name.equals(child.displayName) && child.isDirectory()) {
206                 return;
207             }
208         }
209         fail("Could not find name=" + name + " in children " + children);
210     }
211 
assertHasDirectory(String parentId, String name)212     public void assertHasDirectory(String parentId, String name) throws Exception {
213         Uri parentUri = buildDocumentUri(mAuthority, parentId);
214         assertHasDirectory(parentUri, name);
215     }
216 
assertHasDirectory(RootInfo root, String name)217     public void assertHasDirectory(RootInfo root, String name) throws Exception {
218         assertHasDirectory(root.documentId, name);
219     }
220 
assertDoesNotExist(Uri parentUri, String name)221     public void assertDoesNotExist(Uri parentUri, String name) throws Exception {
222         List<DocumentInfo> children = listChildren(parentUri);
223         for (DocumentInfo child : children) {
224             if (name.equals(child.displayName)) {
225                 fail("Found name=" + name + " in children " + children);
226             }
227         }
228     }
229 
assertDoesNotExist(String parentId, String name)230     public void assertDoesNotExist(String parentId, String name) throws Exception {
231         Uri parentUri = buildDocumentUri(mAuthority, parentId);
232         assertDoesNotExist(parentUri, name);
233     }
234 
assertDoesNotExist(RootInfo root, String name)235     public void assertDoesNotExist(RootInfo root, String name) throws Exception {
236         assertDoesNotExist(root.getUri(), name);
237     }
238 
findFile(String parentId, String name)239     public @Nullable DocumentInfo findFile(String parentId, String name)
240             throws Exception {
241         List<DocumentInfo> children = listChildren(parentId);
242         for (DocumentInfo child : children) {
243             if (name.equals(child.displayName)) {
244                 return child;
245             }
246         }
247         return null;
248     }
249 
findDocument(String parentId, String name)250     public DocumentInfo findDocument(String parentId, String name) throws Exception {
251         List<DocumentInfo> children = listChildren(parentId);
252         for (DocumentInfo child : children) {
253             if (name.equals(child.displayName)) {
254                 return child;
255             }
256         }
257         return null;
258     }
259 
findDocument(Uri parentUri, String name)260     public DocumentInfo findDocument(Uri parentUri, String name) throws Exception {
261         List<DocumentInfo> children = listChildren(parentUri);
262         for (DocumentInfo child : children) {
263             if (name.equals(child.displayName)) {
264                 return child;
265             }
266         }
267         return null;
268     }
269 
listChildren(Uri parentUri)270     public List<DocumentInfo> listChildren(Uri parentUri) throws Exception {
271         String id = DocumentsContract.getDocumentId(parentUri);
272         return listChildren(id);
273     }
274 
listChildren(String documentId)275     public List<DocumentInfo> listChildren(String documentId) throws Exception {
276         return listChildren(documentId, 100);
277     }
278 
listChildren(Uri parentUri, int maxCount)279     public List<DocumentInfo> listChildren(Uri parentUri, int maxCount) throws Exception {
280         String id = DocumentsContract.getDocumentId(parentUri);
281         return listChildren(id, maxCount);
282     }
283 
listChildren(String documentId, int maxCount)284     public List<DocumentInfo> listChildren(String documentId, int maxCount) throws Exception {
285         Uri uri = buildChildDocumentsUri(mAuthority, documentId);
286         List<DocumentInfo> children = new ArrayList<>();
287         try (Cursor cursor = mClient.query(uri, null, null, null, null, null)) {
288             Cursor wrapper = new RootCursorWrapper(mAuthority, "totally-fake", cursor, maxCount);
289             while (wrapper.moveToNext()) {
290                 children.add(DocumentInfo.fromDirectoryCursor(wrapper));
291             }
292         }
293         return children;
294     }
295 
assertFileContents(Uri documentUri, byte[] expected)296     public void assertFileContents(Uri documentUri, byte[] expected) throws Exception {
297         MoreAsserts.assertEquals(
298                 "Copied file contents differ",
299                 expected, readDocument(documentUri));
300     }
301 
assertFileContents(String parentId, String fileName, byte[] expected)302     public void assertFileContents(String parentId, String fileName, byte[] expected)
303             throws Exception {
304         DocumentInfo file = findFile(parentId, fileName);
305         assertNotNull(file);
306         assertFileContents(file.derivedUri, expected);
307     }
308 
309     /**
310      * A helper method for StubProvider only. Won't work with other providers.
311      * @throws RemoteException
312      */
createVirtualFile( RootInfo root, String path, String mimeType, byte[] content, String... streamTypes)313     public Uri createVirtualFile(
314             RootInfo root, String path, String mimeType, byte[] content, String... streamTypes)
315                     throws RemoteException {
316 
317         Bundle args = new Bundle();
318         args.putString(StubProvider.EXTRA_ROOT, root.rootId);
319         args.putString(StubProvider.EXTRA_PATH, path);
320         args.putString(Document.COLUMN_MIME_TYPE, mimeType);
321         args.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
322         args.putByteArray(StubProvider.EXTRA_CONTENT, content);
323 
324         Bundle result = mClient.call("createVirtualFile", null, args);
325         String documentId = result.getString(Document.COLUMN_DOCUMENT_ID);
326 
327         return DocumentsContract.buildDocumentUri(mAuthority, documentId);
328     }
329 
setLoadingDuration(long duration)330     public void setLoadingDuration(long duration) throws RemoteException {
331         final Bundle extra = new Bundle();
332         extra.putLong(DocumentsContract.EXTRA_LOADING, duration);
333         mClient.call("setLoadingDuration", null, extra);
334     }
335 
configure(String args, Bundle configuration)336     public void configure(String args, Bundle configuration) throws RemoteException {
337         mClient.call("configure", args, configuration);
338     }
339 }
340