384 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			384 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Java
		
	
	
	
| /*
 | |
|  * 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.content.ContentResolver.wrap;
 | |
| import static android.provider.DocumentsContract.buildChildDocumentsUri;
 | |
| import static android.provider.DocumentsContract.buildDocumentUri;
 | |
| import static android.provider.DocumentsContract.buildRootsUri;
 | |
| 
 | |
| import static androidx.core.util.Preconditions.checkArgument;
 | |
| 
 | |
| import static com.android.documentsui.base.DocumentInfo.getCursorString;
 | |
| 
 | |
| import static junit.framework.Assert.assertEquals;
 | |
| import static junit.framework.Assert.assertNotNull;
 | |
| import static junit.framework.Assert.fail;
 | |
| 
 | |
| import android.content.ContentProviderClient;
 | |
| import android.content.Context;
 | |
| import android.database.Cursor;
 | |
| import android.net.Uri;
 | |
| import android.os.Bundle;
 | |
| import android.os.FileUtils;
 | |
| 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.test.MoreAsserts;
 | |
| import android.text.TextUtils;
 | |
| 
 | |
| import androidx.annotation.Nullable;
 | |
| 
 | |
| import com.android.documentsui.base.DocumentInfo;
 | |
| import com.android.documentsui.base.RootInfo;
 | |
| import com.android.documentsui.base.UserId;
 | |
| import com.android.documentsui.roots.RootCursorWrapper;
 | |
| 
 | |
| import com.google.common.collect.Lists;
 | |
| 
 | |
| import libcore.io.Streams;
 | |
| 
 | |
| import java.io.FileNotFoundException;
 | |
| 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 UserId mUserId;
 | |
|     private final String mAuthority;
 | |
|     private final ContentProviderClient mClient;
 | |
| 
 | |
|     public DocumentsProviderHelper(UserId userId, String authority, Context context, String name) {
 | |
|         checkArgument(!TextUtils.isEmpty(authority));
 | |
|         mUserId = userId;
 | |
|         mAuthority = authority;
 | |
|         mClient = userId.getContentResolver(context).acquireContentProviderClient(name);
 | |
|     }
 | |
| 
 | |
|     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(mUserId, 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 {
 | |
|             FileUtils.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(wrap(mClient), parentUri, mimeType, name);
 | |
|             return uri;
 | |
|         } catch (FileNotFoundException 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,
 | |
|             String... streamTypes)
 | |
|             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);
 | |
|         in.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
 | |
| 
 | |
|         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);
 | |
|         }
 | |
|         waitForWrite();
 | |
|     }
 | |
| 
 | |
|     public void writeAppendDocument(Uri documentUri, byte[] contents, int length)
 | |
|             throws RemoteException, IOException {
 | |
|         ParcelFileDescriptor file = mClient.openFile(documentUri, "wa", null);
 | |
|         try (AutoCloseOutputStream out = new AutoCloseOutputStream(file)) {
 | |
|             out.write(contents, 0, length);
 | |
|         }
 | |
|         waitForWrite();
 | |
|     }
 | |
| 
 | |
|     public void waitForWrite() throws RemoteException {
 | |
|         mClient.call("waitForWrite", null, null);
 | |
|     }
 | |
| 
 | |
|     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, -1);
 | |
|         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 {
 | |
|         return listChildren(documentId, 100);
 | |
|     }
 | |
| 
 | |
|     public List<DocumentInfo> listChildren(Uri parentUri, int maxCount) throws Exception {
 | |
|         String id = DocumentsContract.getDocumentId(parentUri);
 | |
|         return listChildren(id, maxCount);
 | |
|     }
 | |
| 
 | |
|     public List<DocumentInfo> listChildren(String documentId, int maxCount) 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(mUserId, mAuthority, "totally-fake", cursor,
 | |
|                     maxCount);
 | |
|             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);
 | |
|     }
 | |
| 
 | |
|     public void setLoadingDuration(long duration) throws RemoteException {
 | |
|         final Bundle extra = new Bundle();
 | |
|         extra.putLong(DocumentsContract.EXTRA_LOADING, duration);
 | |
|         mClient.call("setLoadingDuration", null, extra);
 | |
|     }
 | |
| 
 | |
|     public void configure(String args, Bundle configuration) throws RemoteException {
 | |
|         mClient.call("configure", args, configuration);
 | |
|     }
 | |
| 
 | |
|     public void simulateReadErrorsForFile(String args, Bundle configuration)
 | |
|             throws RemoteException {
 | |
|         mClient.call("simulateReadErrorsForFile", args, configuration);
 | |
|     }
 | |
| 
 | |
|     public void clear(String args, Bundle configuration) throws RemoteException {
 | |
|         mClient.call("clear", args, configuration);
 | |
|     }
 | |
| 
 | |
|     public List<RootInfo> getRootList() throws RemoteException {
 | |
|         List<RootInfo> list = new ArrayList<>();
 | |
|         final Uri rootsUri = DocumentsContract.buildRootsUri(mAuthority);
 | |
|         Cursor cursor = null;
 | |
|         try {
 | |
|             cursor = mClient.query(rootsUri, null, null, null, null);
 | |
|             while (cursor.moveToNext()) {
 | |
|                 RootInfo rootInfo = RootInfo.fromRootsCursor(mUserId, mAuthority, cursor);
 | |
|                 if (rootInfo != null) {
 | |
|                     list.add(rootInfo);
 | |
|                 }
 | |
|             }
 | |
|         } catch (Exception e) {
 | |
|             throw new RuntimeException("Can't load rootInfo list", e);
 | |
|         } finally {
 | |
|             FileUtils.closeQuietly(cursor);
 | |
|         }
 | |
|         return list;
 | |
|     }
 | |
| 
 | |
|     public void cleanUp() {
 | |
|         mClient.close();
 | |
|     }
 | |
| }
 |