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