199bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay/*
299bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay * Copyright (C) 2015 The Android Open Source Project
399bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay *
499bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay * Licensed under the Apache License, Version 2.0 (the "License");
599bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay * you may not use this file except in compliance with the License.
699bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay * You may obtain a copy of the License at
799bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay *
899bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay *      http://www.apache.org/licenses/LICENSE-2.0
999bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay *
1099bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay * Unless required by applicable law or agreed to in writing, software
1199bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay * distributed under the License is distributed on an "AS IS" BASIS,
1299bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1399bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay * See the License for the specific language governing permissions and
1499bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay * limitations under the License.
1599bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay */
1699bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
1799bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKaypackage com.android.documentsui;
1899bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
19bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport static android.provider.DocumentsContract.buildChildDocumentsUri;
20bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport static android.provider.DocumentsContract.buildDocumentUri;
21bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport static android.provider.DocumentsContract.buildRootsUri;
22d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport static com.android.documentsui.base.DocumentInfo.getCursorString;
2322797f589b5251585b069622de0417a0c240ac35Steve McKayimport static com.android.internal.util.Preconditions.checkArgument;
24bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport static junit.framework.Assert.assertEquals;
25bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport static junit.framework.Assert.assertNotNull;
26bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport static junit.framework.Assert.fail;
2799bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
2899bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKayimport android.content.ContentProviderClient;
2999bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKayimport android.database.Cursor;
3099bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKayimport android.net.Uri;
31bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport android.os.Bundle;
32bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport android.os.ParcelFileDescriptor;
33bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport android.os.ParcelFileDescriptor.AutoCloseInputStream;
34bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport android.os.ParcelFileDescriptor.AutoCloseOutputStream;
3599bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKayimport android.os.RemoteException;
3699bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKayimport android.provider.DocumentsContract;
3799bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKayimport android.provider.DocumentsContract.Document;
3899bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKayimport android.provider.DocumentsContract.Root;
39bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport android.support.annotation.Nullable;
40bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport android.test.MoreAsserts;
4122797f589b5251585b069622de0417a0c240ac35Steve McKayimport android.text.TextUtils;
4299bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
43d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport com.android.documentsui.base.DocumentInfo;
44d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport com.android.documentsui.base.RootInfo;
45d9caa6ab53aa784acaf241c0ded3c4ae2d342bf8Steve McKayimport com.android.documentsui.roots.RootCursorWrapper;
4699bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
47bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport com.google.android.collect.Lists;
48bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
4999bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKayimport libcore.io.IoUtils;
50bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport libcore.io.Streams;
51bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
52bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport java.io.IOException;
53bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport java.util.ArrayList;
54bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKayimport java.util.List;
5599bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
5699bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay/**
5799bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay * Provides support for creation of documents in a test settings.
5899bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay */
5999bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKaypublic class DocumentsProviderHelper {
6099bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
6199bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay    private final String mAuthority;
62bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    private final ContentProviderClient mClient;
6399bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
6499bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay    public DocumentsProviderHelper(String authority, ContentProviderClient client) {
6522797f589b5251585b069622de0417a0c240ac35Steve McKay        checkArgument(!TextUtils.isEmpty(authority));
6699bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        mAuthority = authority;
67bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        mClient = client;
6899bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay    }
6999bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
70bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public RootInfo getRoot(String documentId) throws RemoteException {
71bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        final Uri rootsUri = buildRootsUri(mAuthority);
7299bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        Cursor cursor = null;
7399bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        try {
7499bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay            cursor = mClient.query(rootsUri, null, null, null, null);
7599bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay            while (cursor.moveToNext()) {
76bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay                if (documentId.equals(getCursorString(cursor, Root.COLUMN_ROOT_ID))) {
7799bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay                    return RootInfo.fromRootsCursor(mAuthority, cursor);
7899bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay                }
7999bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay            }
80bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            throw new IllegalArgumentException("Can't find matching root for id=" + documentId);
8199bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        } catch (Exception e) {
82bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            throw new RuntimeException("Can't load root for id=" + documentId , e);
8399bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        } finally {
8499bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay            IoUtils.closeQuietly(cursor);
8599bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        }
8699bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay    }
8799bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
8899bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay    public Uri createDocument(Uri parentUri, String mimeType, String name) {
8999bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        if (name.contains("/")) {
9099bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay            throw new IllegalArgumentException("Name and mimetype probably interposed.");
9199bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        }
9299bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        try {
93bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            Uri uri = DocumentsContract.createDocument(mClient, parentUri, mimeType, name);
94bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            return uri;
9599bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        } catch (RemoteException e) {
96a2ad8dfc42a4fcd5391423605b5d48fa28ee7fc5Tomasz Mikolajewski            throw new RuntimeException("Couldn't create document: " + name + " with mimetype "
97a2ad8dfc42a4fcd5391423605b5d48fa28ee7fc5Tomasz Mikolajewski                    + mimeType, e);
9899bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        }
9999bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay    }
10099bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
101bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public Uri createDocument(String parentId, String mimeType, String name) {
102bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        Uri parentUri = buildDocumentUri(mAuthority, parentId);
103bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        return createDocument(parentUri, mimeType, name);
104bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
105bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
106bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public Uri createDocument(RootInfo root, String mimeType, String name) {
107bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        return createDocument(root.documentId, mimeType, name);
108bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
109bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
110fe7f53647db0b1b50dff9489a77656046c20bf7bTomasz Mikolajewski    public Uri createDocumentWithFlags(String documentId, String mimeType, String name, int flags,
111fe7f53647db0b1b50dff9489a77656046c20bf7bTomasz Mikolajewski            String... streamTypes)
11218410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska            throws RemoteException {
11318410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska        Bundle in = new Bundle();
11418410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska        in.putInt(StubProvider.EXTRA_FLAGS, flags);
11518410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska        in.putString(StubProvider.EXTRA_PARENT_ID, documentId);
11618410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska        in.putString(Document.COLUMN_MIME_TYPE, mimeType);
11718410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska        in.putString(Document.COLUMN_DISPLAY_NAME, name);
118fe7f53647db0b1b50dff9489a77656046c20bf7bTomasz Mikolajewski        in.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
11918410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska
12018410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska        Bundle out = mClient.call("createDocumentWithFlags", null, in);
12118410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska        Uri uri = out.getParcelable(DocumentsContract.EXTRA_URI);
12218410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska        return uri;
12318410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska    }
12418410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska
12599bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay    public Uri createFolder(Uri parentUri, String name) {
12699bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
12799bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay    }
12899bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
129bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public Uri createFolder(String parentId, String name) {
130bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        Uri parentUri = buildDocumentUri(mAuthority, parentId);
131bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
13299bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay    }
13399bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay
13499bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay    public Uri createFolder(RootInfo root, String name) {
13599bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay        return createDocument(root, Document.MIME_TYPE_DIR, name);
13699bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay    }
137bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
138bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void writeDocument(Uri documentUri, byte[] contents)
139bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            throws RemoteException, IOException {
140bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        ParcelFileDescriptor file = mClient.openFile(documentUri, "w", null);
141bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        try (AutoCloseOutputStream out = new AutoCloseOutputStream(file)) {
142bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            out.write(contents, 0, contents.length);
143bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        }
144ca92ecf53ae5f1c3399b50c488b51018f8c93e5bGarfield Tan        waitForWrite();
145ca92ecf53ae5f1c3399b50c488b51018f8c93e5bGarfield Tan    }
146ca92ecf53ae5f1c3399b50c488b51018f8c93e5bGarfield Tan
147ca92ecf53ae5f1c3399b50c488b51018f8c93e5bGarfield Tan    public void waitForWrite() throws RemoteException {
1481e80be78050dcf5b73b2eb2011a5ce109bf2a277Garfield Tan        mClient.call("waitForWrite", null, null);
149bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
150bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
151bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public byte[] readDocument(Uri documentUri) throws RemoteException, IOException {
152bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        ParcelFileDescriptor file = mClient.openFile(documentUri, "r", null);
153bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        byte[] buf = null;
154bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        try (AutoCloseInputStream in = new AutoCloseInputStream(file)) {
155bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            buf = Streams.readFully(in);
156bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        }
157bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        return buf;
158bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
159bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
160bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertChildCount(Uri parentUri, int expected) throws Exception {
161bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        List<DocumentInfo> children = listChildren(parentUri);
162bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        assertEquals("Incorrect file count after copy", expected, children.size());
163bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
164bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
165bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertChildCount(String parentId, int expected) throws Exception {
166ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan        List<DocumentInfo> children = listChildren(parentId, -1);
167bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        assertEquals("Incorrect file count after copy", expected, children.size());
168bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
169bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
170bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertChildCount(RootInfo root, int expected) throws Exception {
171bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        assertChildCount(root.documentId, expected);
172bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
173bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
174bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertHasFile(Uri parentUri, String name) throws Exception {
175bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        List<DocumentInfo> children = listChildren(parentUri);
176bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        for (DocumentInfo child : children) {
177bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            if (name.equals(child.displayName) && !child.isDirectory()) {
178bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay                return;
179bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            }
180bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        }
181bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        fail("Could not find file named=" + name + " in children " + children);
182bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
183bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
184bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertHasFile(String parentId, String name) throws Exception {
185bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        Uri parentUri = buildDocumentUri(mAuthority, parentId);
186bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        assertHasFile(parentUri, name);
187bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
188bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
189bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertHasFile(RootInfo root, String name) throws Exception {
190bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        assertHasFile(root.documentId, name);
191bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
192bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
193bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertHasDirectory(Uri parentUri, String name) throws Exception {
194bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        List<DocumentInfo> children = listChildren(parentUri);
195bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        for (DocumentInfo child : children) {
196bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            if (name.equals(child.displayName) && child.isDirectory()) {
197bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay                return;
198bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            }
199bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        }
200bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        fail("Could not find name=" + name + " in children " + children);
201bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
202bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
203bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertHasDirectory(String parentId, String name) throws Exception {
204bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        Uri parentUri = buildDocumentUri(mAuthority, parentId);
205bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        assertHasDirectory(parentUri, name);
206bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
207bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
208bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertHasDirectory(RootInfo root, String name) throws Exception {
209bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        assertHasDirectory(root.documentId, name);
210bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
211bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
212bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertDoesNotExist(Uri parentUri, String name) throws Exception {
213bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        List<DocumentInfo> children = listChildren(parentUri);
214bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        for (DocumentInfo child : children) {
215bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            if (name.equals(child.displayName)) {
216bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay                fail("Found name=" + name + " in children " + children);
217bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            }
218bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        }
219bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
220bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
221bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertDoesNotExist(String parentId, String name) throws Exception {
222bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        Uri parentUri = buildDocumentUri(mAuthority, parentId);
223bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        assertDoesNotExist(parentUri, name);
224bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
225bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
226bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertDoesNotExist(RootInfo root, String name) throws Exception {
227bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        assertDoesNotExist(root.getUri(), name);
228bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
229bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
230bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public @Nullable DocumentInfo findFile(String parentId, String name)
231bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            throws Exception {
232bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        List<DocumentInfo> children = listChildren(parentId);
233bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        for (DocumentInfo child : children) {
234bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            if (name.equals(child.displayName)) {
235bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay                return child;
236bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            }
237bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        }
238bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        return null;
239bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
240bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
241bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public DocumentInfo findDocument(String parentId, String name) throws Exception {
242bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        List<DocumentInfo> children = listChildren(parentId);
243bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        for (DocumentInfo child : children) {
244bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            if (name.equals(child.displayName)) {
245bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay                return child;
246bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            }
247bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        }
248bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        return null;
249bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
250bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
251bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public DocumentInfo findDocument(Uri parentUri, String name) throws Exception {
252bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        List<DocumentInfo> children = listChildren(parentUri);
253bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        for (DocumentInfo child : children) {
254bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            if (name.equals(child.displayName)) {
255bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay                return child;
256bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            }
257bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        }
258bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        return null;
259bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
260bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
261bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public List<DocumentInfo> listChildren(Uri parentUri) throws Exception {
262bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        String id = DocumentsContract.getDocumentId(parentUri);
263bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        return listChildren(id);
264bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
265bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
266bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public List<DocumentInfo> listChildren(String documentId) throws Exception {
267ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan        return listChildren(documentId, 100);
268ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan    }
269ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan
270ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan    public List<DocumentInfo> listChildren(Uri parentUri, int maxCount) throws Exception {
271ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan        String id = DocumentsContract.getDocumentId(parentUri);
272ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan        return listChildren(id, maxCount);
273ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan    }
274ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan
275ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan    public List<DocumentInfo> listChildren(String documentId, int maxCount) throws Exception {
276bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        Uri uri = buildChildDocumentsUri(mAuthority, documentId);
277bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        List<DocumentInfo> children = new ArrayList<>();
278bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        try (Cursor cursor = mClient.query(uri, null, null, null, null, null)) {
279ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan            Cursor wrapper = new RootCursorWrapper(mAuthority, "totally-fake", cursor, maxCount);
28022797f589b5251585b069622de0417a0c240ac35Steve McKay            while (wrapper.moveToNext()) {
28122797f589b5251585b069622de0417a0c240ac35Steve McKay                children.add(DocumentInfo.fromDirectoryCursor(wrapper));
282bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            }
283bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        }
284bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        return children;
285bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
286bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
287bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertFileContents(Uri documentUri, byte[] expected) throws Exception {
28822797f589b5251585b069622de0417a0c240ac35Steve McKay        MoreAsserts.assertEquals(
28922797f589b5251585b069622de0417a0c240ac35Steve McKay                "Copied file contents differ",
29022797f589b5251585b069622de0417a0c240ac35Steve McKay                expected, readDocument(documentUri));
291bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
292bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
293bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public void assertFileContents(String parentId, String fileName, byte[] expected)
294bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            throws Exception {
295bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        DocumentInfo file = findFile(parentId, fileName);
296bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        assertNotNull(file);
297bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        assertFileContents(file.derivedUri, expected);
298bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
299bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
300bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    /**
301bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay     * A helper method for StubProvider only. Won't work with other providers.
302bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay     * @throws RemoteException
303bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay     */
304bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    public Uri createVirtualFile(
305bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay            RootInfo root, String path, String mimeType, byte[] content, String... streamTypes)
306bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay                    throws RemoteException {
307bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
308bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        Bundle args = new Bundle();
309bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        args.putString(StubProvider.EXTRA_ROOT, root.rootId);
310bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        args.putString(StubProvider.EXTRA_PATH, path);
311bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        args.putString(Document.COLUMN_MIME_TYPE, mimeType);
312bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        args.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
313bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        args.putByteArray(StubProvider.EXTRA_CONTENT, content);
314bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
315bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        Bundle result = mClient.call("createVirtualFile", null, args);
316bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        String documentId = result.getString(Document.COLUMN_DOCUMENT_ID);
317bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay
318bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay        return DocumentsContract.buildDocumentUri(mAuthority, documentId);
319bbeba5265c5baa42c6db93fc8030c6055747da4dSteve McKay    }
32018410b7e10fb6e5841c1a309e706aa2d68552a6bAga Wronska
3211566618f399086abfd360ad4f0797793744e98d7Garfield Tan    public void setLoadingDuration(long duration) throws RemoteException {
3221566618f399086abfd360ad4f0797793744e98d7Garfield Tan        final Bundle extra = new Bundle();
3231566618f399086abfd360ad4f0797793744e98d7Garfield Tan        extra.putLong(DocumentsContract.EXTRA_LOADING, duration);
3241566618f399086abfd360ad4f0797793744e98d7Garfield Tan        mClient.call("setLoadingDuration", null, extra);
3251566618f399086abfd360ad4f0797793744e98d7Garfield Tan    }
326ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan
327ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan    public void configure(String args, Bundle configuration) throws RemoteException {
328ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan        mClient.call("configure", args, configuration);
329ceedd1fb5c9e34096bbe1c11e79fa0d96471611eGarfield Tan    }
33099bcc6aa4dbcfaf6206d9bee496f7388fa9ab17cSteve McKay}
331