MtpDocumentsProviderTest.java revision 259ce80132d55774fe599c60b53a9d9dfc1efa65
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.mtp; 18 19import android.database.Cursor; 20import android.mtp.MtpConstants; 21import android.mtp.MtpObjectInfo; 22import android.net.Uri; 23import android.provider.DocumentsContract.Root; 24import android.provider.DocumentsContract; 25import android.test.AndroidTestCase; 26import android.test.suitebuilder.annotation.SmallTest; 27 28import java.io.FileNotFoundException; 29import java.io.IOException; 30import java.util.concurrent.TimeoutException; 31 32import static com.android.mtp.MtpDatabase.strings; 33 34@SmallTest 35public class MtpDocumentsProviderTest extends AndroidTestCase { 36 private final static Uri ROOTS_URI = 37 DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY); 38 private TestContentResolver mResolver; 39 private MtpDocumentsProvider mProvider; 40 private TestMtpManager mMtpManager; 41 private final TestResources mResources = new TestResources(); 42 private MtpDatabase mDatabase; 43 44 @Override 45 public void setUp() throws IOException { 46 mResolver = new TestContentResolver(); 47 mMtpManager = new TestMtpManager(getContext()); 48 mProvider = new MtpDocumentsProvider(); 49 mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); 50 mProvider.onCreateForTesting(mResources, mMtpManager, mResolver, mDatabase); 51 } 52 53 @Override 54 public void tearDown() { 55 mProvider.shutdown(); 56 } 57 58 public void testOpenAndCloseDevice() throws Exception { 59 mMtpManager.addValidDevice(0); 60 mMtpManager.setRoots(0, new MtpRoot[] { 61 new MtpRoot( 62 0 /* deviceId */, 63 1 /* storageId */, 64 "Device A" /* device model name */, 65 "Storage A" /* volume description */, 66 1024 /* free space */, 67 2048 /* total space */, 68 "" /* no volume identifier */) 69 }); 70 71 mProvider.openDevice(0); 72 mResolver.waitForNotification(ROOTS_URI, 1); 73 74 mProvider.closeDevice(0); 75 mResolver.waitForNotification(ROOTS_URI, 2); 76 } 77 78 public void testOpenAndCloseErrorDevice() throws Exception { 79 try { 80 mProvider.openDevice(1); 81 fail(); 82 } catch (Throwable error) { 83 assertTrue(error instanceof IOException); 84 } 85 86 try { 87 mProvider.closeDevice(1); 88 fail(); 89 } catch (Throwable error) { 90 assertTrue(error instanceof IOException); 91 } 92 93 // Check if the following notification is the first one or not. 94 mMtpManager.addValidDevice(0); 95 mMtpManager.setRoots(0, new MtpRoot[] { 96 new MtpRoot( 97 0 /* deviceId */, 98 1 /* storageId */, 99 "Device A" /* device model name */, 100 "Storage A" /* volume description */, 101 1024 /* free space */, 102 2048 /* total space */, 103 "" /* no volume identifier */) 104 }); 105 mProvider.openDevice(0); 106 mResolver.waitForNotification(ROOTS_URI, 1); 107 } 108 109 public void testQueryRoots() throws Exception { 110 mMtpManager.addValidDevice(0); 111 mMtpManager.addValidDevice(1); 112 mMtpManager.setRoots(0, new MtpRoot[] { 113 new MtpRoot( 114 0 /* deviceId */, 115 1 /* storageId */, 116 "Device A" /* device model name */, 117 "Storage A" /* volume description */, 118 1024 /* free space */, 119 2048 /* total space */, 120 "" /* no volume identifier */) 121 }); 122 mMtpManager.setRoots(1, new MtpRoot[] { 123 new MtpRoot( 124 1 /* deviceId */, 125 1 /* storageId */, 126 "Device B" /* device model name */, 127 "Storage B" /* volume description */, 128 2048 /* free space */, 129 4096 /* total space */, 130 "Identifier B" /* no volume identifier */) 131 }); 132 133 { 134 mProvider.openDevice(0); 135 mResolver.waitForNotification(ROOTS_URI, 1); 136 final Cursor cursor = mProvider.queryRoots(null); 137 assertEquals(1, cursor.getCount()); 138 cursor.moveToNext(); 139 assertEquals("1", cursor.getString(0)); 140 assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1)); 141 // TODO: Add storage icon for MTP devices. 142 assertTrue(cursor.isNull(2) /* icon */); 143 assertEquals("Device A Storage A", cursor.getString(3)); 144 assertEquals("1", cursor.getString(4)); 145 assertEquals(1024, cursor.getInt(5)); 146 } 147 148 { 149 mProvider.openDevice(1); 150 mResolver.waitForNotification(ROOTS_URI, 2); 151 final Cursor cursor = mProvider.queryRoots(null); 152 assertEquals(2, cursor.getCount()); 153 cursor.moveToNext(); 154 cursor.moveToNext(); 155 assertEquals("2", cursor.getString(0)); 156 assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1)); 157 // TODO: Add storage icon for MTP devices. 158 assertTrue(cursor.isNull(2) /* icon */); 159 assertEquals("Device B Storage B", cursor.getString(3)); 160 assertEquals("2", cursor.getString(4)); 161 assertEquals(2048, cursor.getInt(5)); 162 } 163 } 164 165 public void testQueryRoots_error() throws Exception { 166 mMtpManager.addValidDevice(0); 167 mMtpManager.addValidDevice(1); 168 // Not set roots for device 0 so that MtpManagerMock#getRoots throws IOException. 169 mMtpManager.setRoots(1, new MtpRoot[] { 170 new MtpRoot( 171 1 /* deviceId */, 172 1 /* storageId */, 173 "Device B" /* device model name */, 174 "Storage B" /* volume description */, 175 2048 /* free space */, 176 4096 /* total space */, 177 "Identifier B" /* no volume identifier */) 178 }); 179 { 180 mProvider.openDevice(0); 181 mProvider.openDevice(1); 182 mResolver.waitForNotification(ROOTS_URI, 1); 183 184 final Cursor cursor = mProvider.queryRoots(null); 185 assertEquals(1, cursor.getCount()); 186 cursor.moveToNext(); 187 assertEquals("1", cursor.getString(0)); 188 assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1)); 189 // TODO: Add storage icon for MTP devices. 190 assertTrue(cursor.isNull(2) /* icon */); 191 assertEquals("Device B Storage B", cursor.getString(3)); 192 assertEquals("1", cursor.getString(4)); 193 assertEquals(2048, cursor.getInt(5)); 194 } 195 } 196 197 public void testQueryDocument() throws IOException, InterruptedException, TimeoutException { 198 mMtpManager.addValidDevice(0); 199 mProvider.openDevice(0); 200 201 setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") }); 202 setupDocuments( 203 0, 204 0, 205 MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, 206 "1", 207 new MtpObjectInfo[] { 208 new MtpObjectInfo.Builder() 209 .setObjectHandle(100) 210 .setFormat(MtpConstants.FORMAT_EXIF_JPEG) 211 .setName("image.jpg") 212 .setDateModified(1422716400000L) 213 .setCompressedSize(1024 * 1024 * 5) 214 .setThumbCompressedSize(50 * 1024) 215 .build() 216 }); 217 218 final Cursor cursor = mProvider.queryDocument("2", null); 219 assertEquals(1, cursor.getCount()); 220 221 cursor.moveToNext(); 222 223 assertEquals("2", cursor.getString(0)); 224 assertEquals("image/jpeg", cursor.getString(1)); 225 assertEquals("image.jpg", cursor.getString(2)); 226 assertEquals(1422716400000L, cursor.getLong(3)); 227 assertEquals( 228 DocumentsContract.Document.FLAG_SUPPORTS_DELETE | 229 DocumentsContract.Document.FLAG_SUPPORTS_WRITE | 230 DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL, 231 cursor.getInt(4)); 232 assertEquals(1024 * 1024 * 5, cursor.getInt(5)); 233 } 234 235 public void testQueryDocument_directory() 236 throws IOException, InterruptedException, TimeoutException { 237 mMtpManager.addValidDevice(0); 238 mProvider.openDevice(0); 239 240 setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") }); 241 setupDocuments( 242 0, 243 0, 244 MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, 245 "1", 246 new MtpObjectInfo[] { 247 new MtpObjectInfo.Builder() 248 .setObjectHandle(2) 249 .setStorageId(1) 250 .setFormat(MtpConstants.FORMAT_ASSOCIATION) 251 .setName("directory") 252 .setDateModified(1422716400000L) 253 .build() 254 }); 255 256 final Cursor cursor = mProvider.queryDocument("2", null); 257 assertEquals(1, cursor.getCount()); 258 259 cursor.moveToNext(); 260 assertEquals("2", cursor.getString(0)); 261 assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1)); 262 assertEquals("directory", cursor.getString(2)); 263 assertEquals(1422716400000L, cursor.getLong(3)); 264 assertEquals( 265 DocumentsContract.Document.FLAG_SUPPORTS_DELETE | 266 DocumentsContract.Document.FLAG_SUPPORTS_WRITE | 267 DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE, 268 cursor.getInt(4)); 269 assertEquals(0, cursor.getInt(5)); 270 } 271 272 public void testQueryDocument_forRoot() 273 throws IOException, InterruptedException, TimeoutException { 274 mMtpManager.addValidDevice(0); 275 mProvider.openDevice(0); 276 277 setupRoots(0, new MtpRoot[] { 278 new MtpRoot( 279 0 /* deviceId */, 280 1 /* storageId */, 281 "Device A" /* device model name */, 282 "Storage A" /* volume description */, 283 1024 /* free space */, 284 4096 /* total space */, 285 "" /* no volume identifier */) 286 }); 287 final Cursor cursor = mProvider.queryDocument("1", null); 288 assertEquals(1, cursor.getCount()); 289 290 cursor.moveToNext(); 291 assertEquals("1", cursor.getString(0)); 292 assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1)); 293 assertEquals("Device A Storage A", cursor.getString(2)); 294 assertTrue(cursor.isNull(3)); 295 assertEquals(0, cursor.getInt(4)); 296 assertEquals(3072, cursor.getInt(5)); 297 } 298 299 public void testQueryChildDocuments() throws Exception { 300 mMtpManager.addValidDevice(0); 301 mProvider.openDevice(0); 302 303 setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") }); 304 setupDocuments( 305 0, 306 0, 307 MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, 308 "1", 309 new MtpObjectInfo[] { 310 new MtpObjectInfo.Builder() 311 .setObjectHandle(100) 312 .setFormat(MtpConstants.FORMAT_EXIF_JPEG) 313 .setName("image.jpg") 314 .setCompressedSize(1024 * 1024 * 5) 315 .setThumbCompressedSize(5 * 1024) 316 .setProtectionStatus(MtpConstants.PROTECTION_STATUS_READ_ONLY) 317 .build() 318 }); 319 320 final Cursor cursor = mProvider.queryChildDocuments("1", null, null); 321 assertEquals(1, cursor.getCount()); 322 323 assertTrue(cursor.moveToNext()); 324 assertEquals("2", cursor.getString(0)); 325 assertEquals("image/jpeg", cursor.getString(1)); 326 assertEquals("image.jpg", cursor.getString(2)); 327 assertEquals(0, cursor.getLong(3)); 328 assertEquals(DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL, cursor.getInt(4)); 329 assertEquals(1024 * 1024 * 5, cursor.getInt(5)); 330 331 cursor.close(); 332 } 333 334 public void testQueryChildDocuments_cursorError() throws Exception { 335 mMtpManager.addValidDevice(0); 336 mProvider.openDevice(0); 337 try { 338 mProvider.queryChildDocuments("1", null, null); 339 fail(); 340 } catch (Throwable error) { 341 assertTrue(error instanceof FileNotFoundException); 342 } 343 } 344 345 public void testQueryChildDocuments_documentError() throws Exception { 346 mMtpManager.addValidDevice(0); 347 mProvider.openDevice(0); 348 setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Device", "Storage", 1000, 1000, "") }); 349 mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 }); 350 try { 351 mProvider.queryChildDocuments("1", null, null); 352 fail(); 353 } catch (Throwable error) { 354 assertTrue(error instanceof FileNotFoundException); 355 } 356 } 357 358 public void testDeleteDocument() throws IOException, InterruptedException, TimeoutException { 359 mMtpManager.addValidDevice(0); 360 mProvider.openDevice(0); 361 setupRoots(0, new MtpRoot[] { 362 new MtpRoot(0, 0, "Device", "Storage", 0, 0, "") 363 }); 364 setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] { 365 new MtpObjectInfo.Builder() 366 .setName("test.txt") 367 .setObjectHandle(1) 368 .setParent(-1) 369 .build() 370 }); 371 372 mProvider.deleteDocument("2"); 373 assertEquals(1, mResolver.getChangeCount( 374 DocumentsContract.buildChildDocumentsUri( 375 MtpDocumentsProvider.AUTHORITY, "1"))); 376 } 377 378 public void testDeleteDocument_error() 379 throws IOException, InterruptedException, TimeoutException { 380 mMtpManager.addValidDevice(0); 381 mProvider.openDevice(0); 382 setupRoots(0, new MtpRoot[] { 383 new MtpRoot(0, 0, "Device", "Storage", 0, 0, "") 384 }); 385 setupDocuments(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, "1", new MtpObjectInfo[] { 386 new MtpObjectInfo.Builder() 387 .setName("test.txt") 388 .setObjectHandle(1) 389 .setParent(-1) 390 .build() 391 }); 392 try { 393 mProvider.deleteDocument("3"); 394 fail(); 395 } catch (Throwable e) { 396 assertTrue(e instanceof IOException); 397 } 398 assertEquals(0, mResolver.getChangeCount( 399 DocumentsContract.buildChildDocumentsUri( 400 MtpDocumentsProvider.AUTHORITY, "1"))); 401 } 402 403 private String[] getStrings(Cursor cursor) { 404 try { 405 final String[] results = new String[cursor.getCount()]; 406 for (int i = 0; cursor.moveToNext(); i++) { 407 results[i] = cursor.getString(0); 408 } 409 return results; 410 } finally { 411 cursor.close(); 412 } 413 } 414 415 private String[] setupRoots(int deviceId, MtpRoot[] roots) 416 throws FileNotFoundException, InterruptedException, TimeoutException { 417 final int changeCount = mResolver.getChangeCount(ROOTS_URI); 418 mMtpManager.setRoots(deviceId, roots); 419 mResolver.waitForNotification(ROOTS_URI, changeCount + 1); 420 return getStrings(mProvider.queryRoots(strings(DocumentsContract.Root.COLUMN_ROOT_ID))); 421 } 422 423 private String[] setupDocuments( 424 int deviceId, 425 int storageId, 426 int parentHandle, 427 String parentDocumentId, 428 MtpObjectInfo[] objects) throws FileNotFoundException { 429 final int[] handles = new int[objects.length]; 430 int i = 0; 431 for (final MtpObjectInfo info : objects) { 432 handles[i] = info.getObjectHandle(); 433 mMtpManager.setObjectInfo(deviceId, info); 434 } 435 mMtpManager.setObjectHandles(deviceId, storageId, parentHandle, handles); 436 return getStrings(mProvider.queryChildDocuments( 437 parentDocumentId, strings(DocumentsContract.Document.COLUMN_DOCUMENT_ID), null)); 438 } 439} 440