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