| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.documentsui; |
| |
| import static android.provider.DocumentsContract.buildChildDocumentsUri; |
| import static android.provider.DocumentsContract.buildDocumentUri; |
| import static android.provider.DocumentsContract.buildRootsUri; |
| import static com.android.documentsui.model.DocumentInfo.getCursorString; |
| import static com.android.internal.util.Preconditions.checkArgument; |
| import static junit.framework.Assert.assertEquals; |
| import static junit.framework.Assert.assertNotNull; |
| import static junit.framework.Assert.fail; |
| |
| import android.content.ContentProviderClient; |
| import android.database.Cursor; |
| import android.net.Uri; |
| import android.os.Bundle; |
| import android.os.ParcelFileDescriptor; |
| import android.os.ParcelFileDescriptor.AutoCloseInputStream; |
| import android.os.ParcelFileDescriptor.AutoCloseOutputStream; |
| import android.os.RemoteException; |
| import android.provider.DocumentsContract; |
| import android.provider.DocumentsContract.Document; |
| import android.provider.DocumentsContract.Root; |
| import android.support.annotation.Nullable; |
| import android.test.MoreAsserts; |
| import android.text.TextUtils; |
| |
| import com.android.documentsui.model.DocumentInfo; |
| import com.android.documentsui.model.RootInfo; |
| |
| import com.google.android.collect.Lists; |
| |
| import libcore.io.IoUtils; |
| import libcore.io.Streams; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Provides support for creation of documents in a test settings. |
| */ |
| public class DocumentsProviderHelper { |
| |
| private final String mAuthority; |
| private final ContentProviderClient mClient; |
| |
| public DocumentsProviderHelper(String authority, ContentProviderClient client) { |
| checkArgument(!TextUtils.isEmpty(authority)); |
| mAuthority = authority; |
| mClient = client; |
| } |
| |
| public RootInfo getRoot(String documentId) throws RemoteException { |
| final Uri rootsUri = buildRootsUri(mAuthority); |
| Cursor cursor = null; |
| try { |
| cursor = mClient.query(rootsUri, null, null, null, null); |
| while (cursor.moveToNext()) { |
| if (documentId.equals(getCursorString(cursor, Root.COLUMN_ROOT_ID))) { |
| return RootInfo.fromRootsCursor(mAuthority, cursor); |
| } |
| } |
| throw new IllegalArgumentException("Can't find matching root for id=" + documentId); |
| } catch (Exception e) { |
| throw new RuntimeException("Can't load root for id=" + documentId , e); |
| } finally { |
| IoUtils.closeQuietly(cursor); |
| } |
| } |
| |
| public Uri createDocument(Uri parentUri, String mimeType, String name) { |
| if (name.contains("/")) { |
| throw new IllegalArgumentException("Name and mimetype probably interposed."); |
| } |
| try { |
| Uri uri = DocumentsContract.createDocument(mClient, parentUri, mimeType, name); |
| return uri; |
| } catch (RemoteException e) { |
| throw new RuntimeException("Couldn't create document: " + name + " with mimetype " |
| + mimeType, e); |
| } |
| } |
| |
| public Uri createDocument(String parentId, String mimeType, String name) { |
| Uri parentUri = buildDocumentUri(mAuthority, parentId); |
| return createDocument(parentUri, mimeType, name); |
| } |
| |
| public Uri createDocument(RootInfo root, String mimeType, String name) { |
| return createDocument(root.documentId, mimeType, name); |
| } |
| |
| public Uri createDocumentWithFlags(String documentId, String mimeType, String name, int flags) |
| throws RemoteException { |
| Bundle in = new Bundle(); |
| in.putInt(StubProvider.EXTRA_FLAGS, flags); |
| in.putString(StubProvider.EXTRA_PARENT_ID, documentId); |
| in.putString(Document.COLUMN_MIME_TYPE, mimeType); |
| in.putString(Document.COLUMN_DISPLAY_NAME, name); |
| |
| Bundle out = mClient.call("createDocumentWithFlags", null, in); |
| Uri uri = out.getParcelable(DocumentsContract.EXTRA_URI); |
| return uri; |
| } |
| |
| public Uri createFolder(Uri parentUri, String name) { |
| return createDocument(parentUri, Document.MIME_TYPE_DIR, name); |
| } |
| |
| public Uri createFolder(String parentId, String name) { |
| Uri parentUri = buildDocumentUri(mAuthority, parentId); |
| return createDocument(parentUri, Document.MIME_TYPE_DIR, name); |
| } |
| |
| public Uri createFolder(RootInfo root, String name) { |
| return createDocument(root, Document.MIME_TYPE_DIR, name); |
| } |
| |
| public void writeDocument(Uri documentUri, byte[] contents) |
| throws RemoteException, IOException { |
| ParcelFileDescriptor file = mClient.openFile(documentUri, "w", null); |
| try (AutoCloseOutputStream out = new AutoCloseOutputStream(file)) { |
| out.write(contents, 0, contents.length); |
| } |
| } |
| |
| public byte[] readDocument(Uri documentUri) throws RemoteException, IOException { |
| ParcelFileDescriptor file = mClient.openFile(documentUri, "r", null); |
| byte[] buf = null; |
| try (AutoCloseInputStream in = new AutoCloseInputStream(file)) { |
| buf = Streams.readFully(in); |
| } |
| return buf; |
| } |
| |
| public void assertChildCount(Uri parentUri, int expected) throws Exception { |
| List<DocumentInfo> children = listChildren(parentUri); |
| assertEquals("Incorrect file count after copy", expected, children.size()); |
| } |
| |
| public void assertChildCount(String parentId, int expected) throws Exception { |
| List<DocumentInfo> children = listChildren(parentId); |
| assertEquals("Incorrect file count after copy", expected, children.size()); |
| } |
| |
| public void assertChildCount(RootInfo root, int expected) throws Exception { |
| assertChildCount(root.documentId, expected); |
| } |
| |
| public void assertHasFile(Uri parentUri, String name) throws Exception { |
| List<DocumentInfo> children = listChildren(parentUri); |
| for (DocumentInfo child : children) { |
| if (name.equals(child.displayName) && !child.isDirectory()) { |
| return; |
| } |
| } |
| fail("Could not find file named=" + name + " in children " + children); |
| } |
| |
| public void assertHasFile(String parentId, String name) throws Exception { |
| Uri parentUri = buildDocumentUri(mAuthority, parentId); |
| assertHasFile(parentUri, name); |
| } |
| |
| public void assertHasFile(RootInfo root, String name) throws Exception { |
| assertHasFile(root.documentId, name); |
| } |
| |
| public void assertHasDirectory(Uri parentUri, String name) throws Exception { |
| List<DocumentInfo> children = listChildren(parentUri); |
| for (DocumentInfo child : children) { |
| if (name.equals(child.displayName) && child.isDirectory()) { |
| return; |
| } |
| } |
| fail("Could not find name=" + name + " in children " + children); |
| } |
| |
| public void assertHasDirectory(String parentId, String name) throws Exception { |
| Uri parentUri = buildDocumentUri(mAuthority, parentId); |
| assertHasDirectory(parentUri, name); |
| } |
| |
| public void assertHasDirectory(RootInfo root, String name) throws Exception { |
| assertHasDirectory(root.documentId, name); |
| } |
| |
| public void assertDoesNotExist(Uri parentUri, String name) throws Exception { |
| List<DocumentInfo> children = listChildren(parentUri); |
| for (DocumentInfo child : children) { |
| if (name.equals(child.displayName)) { |
| fail("Found name=" + name + " in children " + children); |
| } |
| } |
| } |
| |
| public void assertDoesNotExist(String parentId, String name) throws Exception { |
| Uri parentUri = buildDocumentUri(mAuthority, parentId); |
| assertDoesNotExist(parentUri, name); |
| } |
| |
| public void assertDoesNotExist(RootInfo root, String name) throws Exception { |
| assertDoesNotExist(root.getUri(), name); |
| } |
| |
| public @Nullable DocumentInfo findFile(String parentId, String name) |
| throws Exception { |
| List<DocumentInfo> children = listChildren(parentId); |
| for (DocumentInfo child : children) { |
| if (name.equals(child.displayName)) { |
| return child; |
| } |
| } |
| return null; |
| } |
| |
| public DocumentInfo findDocument(String parentId, String name) throws Exception { |
| List<DocumentInfo> children = listChildren(parentId); |
| for (DocumentInfo child : children) { |
| if (name.equals(child.displayName)) { |
| return child; |
| } |
| } |
| return null; |
| } |
| |
| public DocumentInfo findDocument(Uri parentUri, String name) throws Exception { |
| List<DocumentInfo> children = listChildren(parentUri); |
| for (DocumentInfo child : children) { |
| if (name.equals(child.displayName)) { |
| return child; |
| } |
| } |
| return null; |
| } |
| |
| public List<DocumentInfo> listChildren(Uri parentUri) throws Exception { |
| String id = DocumentsContract.getDocumentId(parentUri); |
| return listChildren(id); |
| } |
| |
| public List<DocumentInfo> listChildren(String documentId) throws Exception { |
| Uri uri = buildChildDocumentsUri(mAuthority, documentId); |
| List<DocumentInfo> children = new ArrayList<>(); |
| try (Cursor cursor = mClient.query(uri, null, null, null, null, null)) { |
| Cursor wrapper = new RootCursorWrapper(mAuthority, "totally-fake", cursor, 100); |
| while (wrapper.moveToNext()) { |
| children.add(DocumentInfo.fromDirectoryCursor(wrapper)); |
| } |
| } |
| return children; |
| } |
| |
| public void assertFileContents(Uri documentUri, byte[] expected) throws Exception { |
| MoreAsserts.assertEquals( |
| "Copied file contents differ", |
| expected, readDocument(documentUri)); |
| } |
| |
| public void assertFileContents(String parentId, String fileName, byte[] expected) |
| throws Exception { |
| DocumentInfo file = findFile(parentId, fileName); |
| assertNotNull(file); |
| assertFileContents(file.derivedUri, expected); |
| } |
| |
| /** |
| * A helper method for StubProvider only. Won't work with other providers. |
| * @throws RemoteException |
| */ |
| public Uri createVirtualFile( |
| RootInfo root, String path, String mimeType, byte[] content, String... streamTypes) |
| throws RemoteException { |
| |
| Bundle args = new Bundle(); |
| args.putString(StubProvider.EXTRA_ROOT, root.rootId); |
| args.putString(StubProvider.EXTRA_PATH, path); |
| args.putString(Document.COLUMN_MIME_TYPE, mimeType); |
| args.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes)); |
| args.putByteArray(StubProvider.EXTRA_CONTENT, content); |
| |
| Bundle result = mClient.call("createVirtualFile", null, args); |
| String documentId = result.getString(Document.COLUMN_DOCUMENT_ID); |
| |
| return DocumentsContract.buildDocumentUri(mAuthority, documentId); |
| } |
| |
| } |