DocumentsProviderHelper.java revision ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139d
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
17package com.android.documentsui;
18
19import static android.provider.DocumentsContract.buildChildDocumentsUri;
20import static android.provider.DocumentsContract.buildDocumentUri;
21import static android.provider.DocumentsContract.buildRootsUri;
22import static com.android.documentsui.model.DocumentInfo.getCursorString;
23import static junit.framework.Assert.assertEquals;
24import static junit.framework.Assert.assertNotNull;
25import static junit.framework.Assert.fail;
26
27import android.content.ContentProviderClient;
28import android.database.Cursor;
29import android.net.Uri;
30import android.os.Bundle;
31import android.os.ParcelFileDescriptor;
32import android.os.ParcelFileDescriptor.AutoCloseInputStream;
33import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
34import android.os.RemoteException;
35import android.provider.DocumentsContract;
36import android.provider.DocumentsContract.Document;
37import android.provider.DocumentsContract.Root;
38import android.support.annotation.Nullable;
39import android.test.MoreAsserts;
40import android.util.Log;
41
42import com.android.documentsui.model.DocumentInfo;
43import com.android.documentsui.model.RootInfo;
44
45import com.google.android.collect.Lists;
46
47import libcore.io.IoUtils;
48import libcore.io.Streams;
49
50import java.io.IOException;
51import java.util.ArrayList;
52import java.util.List;
53
54/**
55 * Provides support for creation of documents in a test settings.
56 */
57public class DocumentsProviderHelper {
58
59    private final String mAuthority;
60    private final ContentProviderClient mClient;
61
62    public DocumentsProviderHelper(String authority, ContentProviderClient client) {
63        mAuthority = authority;
64        mClient = client;
65    }
66
67    public RootInfo getRoot(String documentId) throws RemoteException {
68        final Uri rootsUri = buildRootsUri(mAuthority);
69
70        Cursor cursor = null;
71        try {
72            cursor = mClient.query(rootsUri, null, null, null, null);
73            while (cursor.moveToNext()) {
74                if (documentId.equals(getCursorString(cursor, Root.COLUMN_ROOT_ID))) {
75                    return RootInfo.fromRootsCursor(mAuthority, cursor);
76                }
77            }
78            throw new IllegalArgumentException("Can't find matching root for id=" + documentId);
79        } catch (Exception e) {
80            throw new RuntimeException("Can't load root for id=" + documentId , e);
81        } 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 {
91            Uri uri = DocumentsContract.createDocument(mClient, parentUri, mimeType, name);
92            return uri;
93        } catch (RemoteException e) {
94            throw new RuntimeException("Couldn't create document: " + name + " with mimetype " + mimeType, e);
95        }
96    }
97
98    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
107    public Uri createFolder(Uri parentUri, String name) {
108        return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
109    }
110
111    public Uri createFolder(String parentId, String name) {
112        Uri parentUri = buildDocumentUri(mAuthority, parentId);
113        return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
114    }
115
116    public Uri createFolder(RootInfo root, String name) {
117        return createDocument(root, Document.MIME_TYPE_DIR, name);
118    }
119
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    }
292}
293