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