DocumentsProviderHelper.java revision 2ed9f813b0870cfa11032aa9c9c10be0bee4b64b
10c3c695469715288568a514842b157c05df430a0Steve McKay/*
20c3c695469715288568a514842b157c05df430a0Steve McKay * Copyright (C) 2015 The Android Open Source Project
30c3c695469715288568a514842b157c05df430a0Steve McKay *
40c3c695469715288568a514842b157c05df430a0Steve McKay * Licensed under the Apache License, Version 2.0 (the "License");
50c3c695469715288568a514842b157c05df430a0Steve McKay * you may not use this file except in compliance with the License.
60c3c695469715288568a514842b157c05df430a0Steve McKay * You may obtain a copy of the License at
70c3c695469715288568a514842b157c05df430a0Steve McKay *
80c3c695469715288568a514842b157c05df430a0Steve McKay *      http://www.apache.org/licenses/LICENSE-2.0
90c3c695469715288568a514842b157c05df430a0Steve McKay *
100c3c695469715288568a514842b157c05df430a0Steve McKay * Unless required by applicable law or agreed to in writing, software
110c3c695469715288568a514842b157c05df430a0Steve McKay * distributed under the License is distributed on an "AS IS" BASIS,
120c3c695469715288568a514842b157c05df430a0Steve McKay * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130c3c695469715288568a514842b157c05df430a0Steve McKay * See the License for the specific language governing permissions and
140c3c695469715288568a514842b157c05df430a0Steve McKay * limitations under the License.
150c3c695469715288568a514842b157c05df430a0Steve McKay */
160c3c695469715288568a514842b157c05df430a0Steve McKay
170c3c695469715288568a514842b157c05df430a0Steve McKaypackage com.android.documentsui;
180c3c695469715288568a514842b157c05df430a0Steve McKay
19ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport static android.provider.DocumentsContract.buildChildDocumentsUri;
20ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport static android.provider.DocumentsContract.buildDocumentUri;
21ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport static android.provider.DocumentsContract.buildRootsUri;
220c3c695469715288568a514842b157c05df430a0Steve McKayimport static com.android.documentsui.model.DocumentInfo.getCursorString;
232ed9f813b0870cfa11032aa9c9c10be0bee4b64bSteve McKayimport static com.android.internal.util.Preconditions.checkArgument;
24ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport static junit.framework.Assert.assertEquals;
25ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport static junit.framework.Assert.assertNotNull;
26ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport static junit.framework.Assert.fail;
270c3c695469715288568a514842b157c05df430a0Steve McKay
280c3c695469715288568a514842b157c05df430a0Steve McKayimport android.content.ContentProviderClient;
290c3c695469715288568a514842b157c05df430a0Steve McKayimport android.database.Cursor;
300c3c695469715288568a514842b157c05df430a0Steve McKayimport android.net.Uri;
31ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport android.os.Bundle;
32ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport android.os.ParcelFileDescriptor;
33ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport android.os.ParcelFileDescriptor.AutoCloseInputStream;
34ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport android.os.ParcelFileDescriptor.AutoCloseOutputStream;
350c3c695469715288568a514842b157c05df430a0Steve McKayimport android.os.RemoteException;
360c3c695469715288568a514842b157c05df430a0Steve McKayimport android.provider.DocumentsContract;
370c3c695469715288568a514842b157c05df430a0Steve McKayimport android.provider.DocumentsContract.Document;
380c3c695469715288568a514842b157c05df430a0Steve McKayimport android.provider.DocumentsContract.Root;
39ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport android.support.annotation.Nullable;
40ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport android.test.MoreAsserts;
412ed9f813b0870cfa11032aa9c9c10be0bee4b64bSteve McKayimport android.text.TextUtils;
420c3c695469715288568a514842b157c05df430a0Steve McKay
43ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport com.android.documentsui.model.DocumentInfo;
440c3c695469715288568a514842b157c05df430a0Steve McKayimport com.android.documentsui.model.RootInfo;
450c3c695469715288568a514842b157c05df430a0Steve McKay
46ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport com.google.android.collect.Lists;
47ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
480c3c695469715288568a514842b157c05df430a0Steve McKayimport libcore.io.IoUtils;
49ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport libcore.io.Streams;
50ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
51ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport java.io.IOException;
52ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport java.util.ArrayList;
53ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKayimport java.util.List;
540c3c695469715288568a514842b157c05df430a0Steve McKay
550c3c695469715288568a514842b157c05df430a0Steve McKay/**
560c3c695469715288568a514842b157c05df430a0Steve McKay * Provides support for creation of documents in a test settings.
570c3c695469715288568a514842b157c05df430a0Steve McKay */
580c3c695469715288568a514842b157c05df430a0Steve McKaypublic class DocumentsProviderHelper {
590c3c695469715288568a514842b157c05df430a0Steve McKay
600c3c695469715288568a514842b157c05df430a0Steve McKay    private final String mAuthority;
61ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    private final ContentProviderClient mClient;
620c3c695469715288568a514842b157c05df430a0Steve McKay
630c3c695469715288568a514842b157c05df430a0Steve McKay    public DocumentsProviderHelper(String authority, ContentProviderClient client) {
642ed9f813b0870cfa11032aa9c9c10be0bee4b64bSteve McKay        checkArgument(!TextUtils.isEmpty(authority));
650c3c695469715288568a514842b157c05df430a0Steve McKay        mAuthority = authority;
66ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        mClient = client;
670c3c695469715288568a514842b157c05df430a0Steve McKay    }
680c3c695469715288568a514842b157c05df430a0Steve McKay
69ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public RootInfo getRoot(String documentId) throws RemoteException {
70ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        final Uri rootsUri = buildRootsUri(mAuthority);
710c3c695469715288568a514842b157c05df430a0Steve McKay        Cursor cursor = null;
720c3c695469715288568a514842b157c05df430a0Steve McKay        try {
730c3c695469715288568a514842b157c05df430a0Steve McKay            cursor = mClient.query(rootsUri, null, null, null, null);
740c3c695469715288568a514842b157c05df430a0Steve McKay            while (cursor.moveToNext()) {
75ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay                if (documentId.equals(getCursorString(cursor, Root.COLUMN_ROOT_ID))) {
760c3c695469715288568a514842b157c05df430a0Steve McKay                    return RootInfo.fromRootsCursor(mAuthority, cursor);
770c3c695469715288568a514842b157c05df430a0Steve McKay                }
780c3c695469715288568a514842b157c05df430a0Steve McKay            }
79ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            throw new IllegalArgumentException("Can't find matching root for id=" + documentId);
800c3c695469715288568a514842b157c05df430a0Steve McKay        } catch (Exception e) {
81ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            throw new RuntimeException("Can't load root for id=" + documentId , e);
820c3c695469715288568a514842b157c05df430a0Steve McKay        } finally {
830c3c695469715288568a514842b157c05df430a0Steve McKay            IoUtils.closeQuietly(cursor);
840c3c695469715288568a514842b157c05df430a0Steve McKay        }
850c3c695469715288568a514842b157c05df430a0Steve McKay    }
860c3c695469715288568a514842b157c05df430a0Steve McKay
870c3c695469715288568a514842b157c05df430a0Steve McKay    public Uri createDocument(Uri parentUri, String mimeType, String name) {
880c3c695469715288568a514842b157c05df430a0Steve McKay        if (name.contains("/")) {
890c3c695469715288568a514842b157c05df430a0Steve McKay            throw new IllegalArgumentException("Name and mimetype probably interposed.");
900c3c695469715288568a514842b157c05df430a0Steve McKay        }
910c3c695469715288568a514842b157c05df430a0Steve McKay        try {
92ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            Uri uri = DocumentsContract.createDocument(mClient, parentUri, mimeType, name);
93ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            return uri;
940c3c695469715288568a514842b157c05df430a0Steve McKay        } catch (RemoteException e) {
950c3c695469715288568a514842b157c05df430a0Steve McKay            throw new RuntimeException("Couldn't create document: " + name + " with mimetype " + mimeType, e);
960c3c695469715288568a514842b157c05df430a0Steve McKay        }
970c3c695469715288568a514842b157c05df430a0Steve McKay    }
980c3c695469715288568a514842b157c05df430a0Steve McKay
99ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public Uri createDocument(String parentId, String mimeType, String name) {
100ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        Uri parentUri = buildDocumentUri(mAuthority, parentId);
101ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        return createDocument(parentUri, mimeType, name);
102ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
103ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
104ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public Uri createDocument(RootInfo root, String mimeType, String name) {
105ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        return createDocument(root.documentId, mimeType, name);
106ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
107ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
1080c3c695469715288568a514842b157c05df430a0Steve McKay    public Uri createFolder(Uri parentUri, String name) {
1090c3c695469715288568a514842b157c05df430a0Steve McKay        return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
1100c3c695469715288568a514842b157c05df430a0Steve McKay    }
1110c3c695469715288568a514842b157c05df430a0Steve McKay
112ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public Uri createFolder(String parentId, String name) {
113ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        Uri parentUri = buildDocumentUri(mAuthority, parentId);
114ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
1150c3c695469715288568a514842b157c05df430a0Steve McKay    }
1160c3c695469715288568a514842b157c05df430a0Steve McKay
1170c3c695469715288568a514842b157c05df430a0Steve McKay    public Uri createFolder(RootInfo root, String name) {
1180c3c695469715288568a514842b157c05df430a0Steve McKay        return createDocument(root, Document.MIME_TYPE_DIR, name);
1190c3c695469715288568a514842b157c05df430a0Steve McKay    }
120ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
121ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void writeDocument(Uri documentUri, byte[] contents)
122ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            throws RemoteException, IOException {
123ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        ParcelFileDescriptor file = mClient.openFile(documentUri, "w", null);
124ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        try (AutoCloseOutputStream out = new AutoCloseOutputStream(file)) {
125ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            out.write(contents, 0, contents.length);
126ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        }
127ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
128ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
129ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public byte[] readDocument(Uri documentUri) throws RemoteException, IOException {
130ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        ParcelFileDescriptor file = mClient.openFile(documentUri, "r", null);
131ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        byte[] buf = null;
132ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        try (AutoCloseInputStream in = new AutoCloseInputStream(file)) {
133ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            buf = Streams.readFully(in);
134ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        }
135ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        return buf;
136ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
137ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
138ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertChildCount(Uri parentUri, int expected) throws Exception {
139ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        List<DocumentInfo> children = listChildren(parentUri);
140ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        assertEquals("Incorrect file count after copy", expected, children.size());
141ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
142ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
143ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertChildCount(String parentId, int expected) throws Exception {
144ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        List<DocumentInfo> children = listChildren(parentId);
145ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        assertEquals("Incorrect file count after copy", expected, children.size());
146ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
147ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
148ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertChildCount(RootInfo root, int expected) throws Exception {
149ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        assertChildCount(root.documentId, expected);
150ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
151ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
152ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertHasFile(Uri parentUri, String name) throws Exception {
153ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        List<DocumentInfo> children = listChildren(parentUri);
154ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        for (DocumentInfo child : children) {
155ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            if (name.equals(child.displayName) && !child.isDirectory()) {
156ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay                return;
157ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            }
158ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        }
159ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        fail("Could not find file named=" + name + " in children " + children);
160ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
161ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
162ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertHasFile(String parentId, String name) throws Exception {
163ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        Uri parentUri = buildDocumentUri(mAuthority, parentId);
164ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        assertHasFile(parentUri, name);
165ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
166ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
167ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertHasFile(RootInfo root, String name) throws Exception {
168ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        assertHasFile(root.documentId, name);
169ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
170ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
171ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertHasDirectory(Uri parentUri, String name) throws Exception {
172ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        List<DocumentInfo> children = listChildren(parentUri);
173ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        for (DocumentInfo child : children) {
174ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            if (name.equals(child.displayName) && child.isDirectory()) {
175ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay                return;
176ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            }
177ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        }
178ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        fail("Could not find name=" + name + " in children " + children);
179ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
180ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
181ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertHasDirectory(String parentId, String name) throws Exception {
182ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        Uri parentUri = buildDocumentUri(mAuthority, parentId);
183ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        assertHasDirectory(parentUri, name);
184ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
185ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
186ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertHasDirectory(RootInfo root, String name) throws Exception {
187ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        assertHasDirectory(root.documentId, name);
188ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
189ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
190ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertDoesNotExist(Uri parentUri, String name) throws Exception {
191ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        List<DocumentInfo> children = listChildren(parentUri);
192ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        for (DocumentInfo child : children) {
193ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            if (name.equals(child.displayName)) {
194ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay                fail("Found name=" + name + " in children " + children);
195ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            }
196ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        }
197ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
198ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
199ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertDoesNotExist(String parentId, String name) throws Exception {
200ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        Uri parentUri = buildDocumentUri(mAuthority, parentId);
201ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        assertDoesNotExist(parentUri, name);
202ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
203ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
204ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertDoesNotExist(RootInfo root, String name) throws Exception {
205ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        assertDoesNotExist(root.getUri(), name);
206ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
207ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
208ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public @Nullable DocumentInfo findFile(String parentId, String name)
209ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            throws Exception {
210ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        List<DocumentInfo> children = listChildren(parentId);
211ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        for (DocumentInfo child : children) {
212ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            if (name.equals(child.displayName)) {
213ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay                return child;
214ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            }
215ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        }
216ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        return null;
217ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
218ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
219ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public DocumentInfo findDocument(String parentId, String name) throws Exception {
220ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        List<DocumentInfo> children = listChildren(parentId);
221ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        for (DocumentInfo child : children) {
222ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            if (name.equals(child.displayName)) {
223ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay                return child;
224ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            }
225ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        }
226ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        return null;
227ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
228ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
229ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public DocumentInfo findDocument(Uri parentUri, String name) throws Exception {
230ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        List<DocumentInfo> children = listChildren(parentUri);
231ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        for (DocumentInfo child : children) {
232ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            if (name.equals(child.displayName)) {
233ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay                return child;
234ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            }
235ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        }
236ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        return null;
237ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
238ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
239ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public List<DocumentInfo> listChildren(Uri parentUri) throws Exception {
240ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        String id = DocumentsContract.getDocumentId(parentUri);
241ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        return listChildren(id);
242ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
243ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
244ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public List<DocumentInfo> listChildren(String documentId) throws Exception {
245ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        Uri uri = buildChildDocumentsUri(mAuthority, documentId);
246ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        List<DocumentInfo> children = new ArrayList<>();
247ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        try (Cursor cursor = mClient.query(uri, null, null, null, null, null)) {
2482ed9f813b0870cfa11032aa9c9c10be0bee4b64bSteve McKay            Cursor wrapper = new RootCursorWrapper(mAuthority, "totally-fake", cursor, 100);
2492ed9f813b0870cfa11032aa9c9c10be0bee4b64bSteve McKay            while (wrapper.moveToNext()) {
2502ed9f813b0870cfa11032aa9c9c10be0bee4b64bSteve McKay                children.add(DocumentInfo.fromDirectoryCursor(wrapper));
251ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            }
252ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        }
253ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        return children;
254ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
255ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
256ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertFileContents(Uri documentUri, byte[] expected) throws Exception {
2572ed9f813b0870cfa11032aa9c9c10be0bee4b64bSteve McKay        MoreAsserts.assertEquals(
2582ed9f813b0870cfa11032aa9c9c10be0bee4b64bSteve McKay                "Copied file contents differ",
2592ed9f813b0870cfa11032aa9c9c10be0bee4b64bSteve McKay                expected, readDocument(documentUri));
260ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
261ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
262ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public void assertFileContents(String parentId, String fileName, byte[] expected)
263ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            throws Exception {
264ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        DocumentInfo file = findFile(parentId, fileName);
265ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        assertNotNull(file);
266ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        assertFileContents(file.derivedUri, expected);
267ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
268ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
269ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    /**
270ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay     * A helper method for StubProvider only. Won't work with other providers.
271ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay     * @throws RemoteException
272ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay     */
273ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    public Uri createVirtualFile(
274ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay            RootInfo root, String path, String mimeType, byte[] content, String... streamTypes)
275ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay                    throws RemoteException {
276ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
277ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        Bundle args = new Bundle();
278ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        args.putString(StubProvider.EXTRA_ROOT, root.rootId);
279ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        args.putString(StubProvider.EXTRA_PATH, path);
280ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        args.putString(Document.COLUMN_MIME_TYPE, mimeType);
281ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        args.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
282ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        args.putByteArray(StubProvider.EXTRA_CONTENT, content);
283ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
284ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        Bundle result = mClient.call("createVirtualFile", null, args);
285ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        String documentId = result.getString(Document.COLUMN_DOCUMENT_ID);
286ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay
287ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay        return DocumentsContract.buildDocumentUri(mAuthority, documentId);
288ecbf3c504c5ec7ccb3e2be7f4dd175ebe634139dSteve McKay    }
2890c3c695469715288568a514842b157c05df430a0Steve McKay}
290