Home | History | Annotate | Download | only in documentsui
      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 
     17 package com.android.documentsui;
     18 
     19 import static android.provider.DocumentsContract.buildChildDocumentsUri;
     20 import static android.provider.DocumentsContract.buildDocumentUri;
     21 import static android.provider.DocumentsContract.buildRootsUri;
     22 import static com.android.documentsui.base.DocumentInfo.getCursorString;
     23 import static com.android.internal.util.Preconditions.checkArgument;
     24 import static junit.framework.Assert.assertEquals;
     25 import static junit.framework.Assert.assertNotNull;
     26 import static junit.framework.Assert.fail;
     27 
     28 import android.content.ContentProviderClient;
     29 import android.database.Cursor;
     30 import android.net.Uri;
     31 import android.os.Bundle;
     32 import android.os.ParcelFileDescriptor;
     33 import android.os.ParcelFileDescriptor.AutoCloseInputStream;
     34 import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
     35 import android.os.RemoteException;
     36 import android.provider.DocumentsContract;
     37 import android.provider.DocumentsContract.Document;
     38 import android.provider.DocumentsContract.Root;
     39 import android.support.annotation.Nullable;
     40 import android.test.MoreAsserts;
     41 import android.text.TextUtils;
     42 
     43 import com.android.documentsui.base.DocumentInfo;
     44 import com.android.documentsui.base.RootInfo;
     45 import com.android.documentsui.roots.RootCursorWrapper;
     46 
     47 import com.google.android.collect.Lists;
     48 
     49 import libcore.io.IoUtils;
     50 import libcore.io.Streams;
     51 
     52 import java.io.IOException;
     53 import java.util.ArrayList;
     54 import java.util.List;
     55 
     56 /**
     57  * Provides support for creation of documents in a test settings.
     58  */
     59 public class DocumentsProviderHelper {
     60 
     61     private final String mAuthority;
     62     private final ContentProviderClient mClient;
     63 
     64     public DocumentsProviderHelper(String authority, ContentProviderClient client) {
     65         checkArgument(!TextUtils.isEmpty(authority));
     66         mAuthority = authority;
     67         mClient = client;
     68     }
     69 
     70     public RootInfo getRoot(String documentId) throws RemoteException {
     71         final Uri rootsUri = buildRootsUri(mAuthority);
     72         Cursor cursor = null;
     73         try {
     74             cursor = mClient.query(rootsUri, null, null, null, null);
     75             while (cursor.moveToNext()) {
     76                 if (documentId.equals(getCursorString(cursor, Root.COLUMN_ROOT_ID))) {
     77                     return RootInfo.fromRootsCursor(mAuthority, cursor);
     78                 }
     79             }
     80             throw new IllegalArgumentException("Can't find matching root for id=" + documentId);
     81         } catch (Exception e) {
     82             throw new RuntimeException("Can't load root for id=" + documentId , e);
     83         } finally {
     84             IoUtils.closeQuietly(cursor);
     85         }
     86     }
     87 
     88     public Uri createDocument(Uri parentUri, String mimeType, String name) {
     89         if (name.contains("/")) {
     90             throw new IllegalArgumentException("Name and mimetype probably interposed.");
     91         }
     92         try {
     93             Uri uri = DocumentsContract.createDocument(mClient, parentUri, mimeType, name);
     94             return uri;
     95         } catch (RemoteException e) {
     96             throw new RuntimeException("Couldn't create document: " + name + " with mimetype "
     97                     + mimeType, e);
     98         }
     99     }
    100 
    101     public Uri createDocument(String parentId, String mimeType, String name) {
    102         Uri parentUri = buildDocumentUri(mAuthority, parentId);
    103         return createDocument(parentUri, mimeType, name);
    104     }
    105 
    106     public Uri createDocument(RootInfo root, String mimeType, String name) {
    107         return createDocument(root.documentId, mimeType, name);
    108     }
    109 
    110     public Uri createDocumentWithFlags(String documentId, String mimeType, String name, int flags,
    111             String... streamTypes)
    112             throws RemoteException {
    113         Bundle in = new Bundle();
    114         in.putInt(StubProvider.EXTRA_FLAGS, flags);
    115         in.putString(StubProvider.EXTRA_PARENT_ID, documentId);
    116         in.putString(Document.COLUMN_MIME_TYPE, mimeType);
    117         in.putString(Document.COLUMN_DISPLAY_NAME, name);
    118         in.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
    119 
    120         Bundle out = mClient.call("createDocumentWithFlags", null, in);
    121         Uri uri = out.getParcelable(DocumentsContract.EXTRA_URI);
    122         return uri;
    123     }
    124 
    125     public Uri createFolder(Uri parentUri, String name) {
    126         return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
    127     }
    128 
    129     public Uri createFolder(String parentId, String name) {
    130         Uri parentUri = buildDocumentUri(mAuthority, parentId);
    131         return createDocument(parentUri, Document.MIME_TYPE_DIR, name);
    132     }
    133 
    134     public Uri createFolder(RootInfo root, String name) {
    135         return createDocument(root, Document.MIME_TYPE_DIR, name);
    136     }
    137 
    138     public void writeDocument(Uri documentUri, byte[] contents)
    139             throws RemoteException, IOException {
    140         ParcelFileDescriptor file = mClient.openFile(documentUri, "w", null);
    141         try (AutoCloseOutputStream out = new AutoCloseOutputStream(file)) {
    142             out.write(contents, 0, contents.length);
    143         }
    144         waitForWrite();
    145     }
    146 
    147     public void waitForWrite() throws RemoteException {
    148         mClient.call("waitForWrite", null, null);
    149     }
    150 
    151     public byte[] readDocument(Uri documentUri) throws RemoteException, IOException {
    152         ParcelFileDescriptor file = mClient.openFile(documentUri, "r", null);
    153         byte[] buf = null;
    154         try (AutoCloseInputStream in = new AutoCloseInputStream(file)) {
    155             buf = Streams.readFully(in);
    156         }
    157         return buf;
    158     }
    159 
    160     public void assertChildCount(Uri parentUri, int expected) throws Exception {
    161         List<DocumentInfo> children = listChildren(parentUri);
    162         assertEquals("Incorrect file count after copy", expected, children.size());
    163     }
    164 
    165     public void assertChildCount(String parentId, int expected) throws Exception {
    166         List<DocumentInfo> children = listChildren(parentId, -1);
    167         assertEquals("Incorrect file count after copy", expected, children.size());
    168     }
    169 
    170     public void assertChildCount(RootInfo root, int expected) throws Exception {
    171         assertChildCount(root.documentId, expected);
    172     }
    173 
    174     public void assertHasFile(Uri parentUri, String name) throws Exception {
    175         List<DocumentInfo> children = listChildren(parentUri);
    176         for (DocumentInfo child : children) {
    177             if (name.equals(child.displayName) && !child.isDirectory()) {
    178                 return;
    179             }
    180         }
    181         fail("Could not find file named=" + name + " in children " + children);
    182     }
    183 
    184     public void assertHasFile(String parentId, String name) throws Exception {
    185         Uri parentUri = buildDocumentUri(mAuthority, parentId);
    186         assertHasFile(parentUri, name);
    187     }
    188 
    189     public void assertHasFile(RootInfo root, String name) throws Exception {
    190         assertHasFile(root.documentId, name);
    191     }
    192 
    193     public void assertHasDirectory(Uri parentUri, String name) throws Exception {
    194         List<DocumentInfo> children = listChildren(parentUri);
    195         for (DocumentInfo child : children) {
    196             if (name.equals(child.displayName) && child.isDirectory()) {
    197                 return;
    198             }
    199         }
    200         fail("Could not find name=" + name + " in children " + children);
    201     }
    202 
    203     public void assertHasDirectory(String parentId, String name) throws Exception {
    204         Uri parentUri = buildDocumentUri(mAuthority, parentId);
    205         assertHasDirectory(parentUri, name);
    206     }
    207 
    208     public void assertHasDirectory(RootInfo root, String name) throws Exception {
    209         assertHasDirectory(root.documentId, name);
    210     }
    211 
    212     public void assertDoesNotExist(Uri parentUri, String name) throws Exception {
    213         List<DocumentInfo> children = listChildren(parentUri);
    214         for (DocumentInfo child : children) {
    215             if (name.equals(child.displayName)) {
    216                 fail("Found name=" + name + " in children " + children);
    217             }
    218         }
    219     }
    220 
    221     public void assertDoesNotExist(String parentId, String name) throws Exception {
    222         Uri parentUri = buildDocumentUri(mAuthority, parentId);
    223         assertDoesNotExist(parentUri, name);
    224     }
    225 
    226     public void assertDoesNotExist(RootInfo root, String name) throws Exception {
    227         assertDoesNotExist(root.getUri(), name);
    228     }
    229 
    230     public @Nullable DocumentInfo findFile(String parentId, String name)
    231             throws Exception {
    232         List<DocumentInfo> children = listChildren(parentId);
    233         for (DocumentInfo child : children) {
    234             if (name.equals(child.displayName)) {
    235                 return child;
    236             }
    237         }
    238         return null;
    239     }
    240 
    241     public DocumentInfo findDocument(String parentId, String name) throws Exception {
    242         List<DocumentInfo> children = listChildren(parentId);
    243         for (DocumentInfo child : children) {
    244             if (name.equals(child.displayName)) {
    245                 return child;
    246             }
    247         }
    248         return null;
    249     }
    250 
    251     public DocumentInfo findDocument(Uri parentUri, String name) throws Exception {
    252         List<DocumentInfo> children = listChildren(parentUri);
    253         for (DocumentInfo child : children) {
    254             if (name.equals(child.displayName)) {
    255                 return child;
    256             }
    257         }
    258         return null;
    259     }
    260 
    261     public List<DocumentInfo> listChildren(Uri parentUri) throws Exception {
    262         String id = DocumentsContract.getDocumentId(parentUri);
    263         return listChildren(id);
    264     }
    265 
    266     public List<DocumentInfo> listChildren(String documentId) throws Exception {
    267         return listChildren(documentId, 100);
    268     }
    269 
    270     public List<DocumentInfo> listChildren(Uri parentUri, int maxCount) throws Exception {
    271         String id = DocumentsContract.getDocumentId(parentUri);
    272         return listChildren(id, maxCount);
    273     }
    274 
    275     public List<DocumentInfo> listChildren(String documentId, int maxCount) throws Exception {
    276         Uri uri = buildChildDocumentsUri(mAuthority, documentId);
    277         List<DocumentInfo> children = new ArrayList<>();
    278         try (Cursor cursor = mClient.query(uri, null, null, null, null, null)) {
    279             Cursor wrapper = new RootCursorWrapper(mAuthority, "totally-fake", cursor, maxCount);
    280             while (wrapper.moveToNext()) {
    281                 children.add(DocumentInfo.fromDirectoryCursor(wrapper));
    282             }
    283         }
    284         return children;
    285     }
    286 
    287     public void assertFileContents(Uri documentUri, byte[] expected) throws Exception {
    288         MoreAsserts.assertEquals(
    289                 "Copied file contents differ",
    290                 expected, readDocument(documentUri));
    291     }
    292 
    293     public void assertFileContents(String parentId, String fileName, byte[] expected)
    294             throws Exception {
    295         DocumentInfo file = findFile(parentId, fileName);
    296         assertNotNull(file);
    297         assertFileContents(file.derivedUri, expected);
    298     }
    299 
    300     /**
    301      * A helper method for StubProvider only. Won't work with other providers.
    302      * @throws RemoteException
    303      */
    304     public Uri createVirtualFile(
    305             RootInfo root, String path, String mimeType, byte[] content, String... streamTypes)
    306                     throws RemoteException {
    307 
    308         Bundle args = new Bundle();
    309         args.putString(StubProvider.EXTRA_ROOT, root.rootId);
    310         args.putString(StubProvider.EXTRA_PATH, path);
    311         args.putString(Document.COLUMN_MIME_TYPE, mimeType);
    312         args.putStringArrayList(StubProvider.EXTRA_STREAM_TYPES, Lists.newArrayList(streamTypes));
    313         args.putByteArray(StubProvider.EXTRA_CONTENT, content);
    314 
    315         Bundle result = mClient.call("createVirtualFile", null, args);
    316         String documentId = result.getString(Document.COLUMN_DOCUMENT_ID);
    317 
    318         return DocumentsContract.buildDocumentUri(mAuthority, documentId);
    319     }
    320 
    321     public void setLoadingDuration(long duration) throws RemoteException {
    322         final Bundle extra = new Bundle();
    323         extra.putLong(DocumentsContract.EXTRA_LOADING, duration);
    324         mClient.call("setLoadingDuration", null, extra);
    325     }
    326 
    327     public void configure(String args, Bundle configuration) throws RemoteException {
    328         mClient.call("configure", args, configuration);
    329     }
    330 }
    331