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.mtp; 18 19 import android.database.Cursor; 20 import android.media.MediaFile; 21 import android.media.MediaFile.MediaFileType; 22 import android.mtp.MtpConstants; 23 import android.mtp.MtpObjectInfo; 24 import android.net.Uri; 25 import android.provider.DocumentsContract; 26 import android.provider.DocumentsContract.Document; 27 import android.provider.DocumentsContract.Root; 28 import android.test.AndroidTestCase; 29 import android.test.suitebuilder.annotation.SmallTest; 30 31 import java.io.FileNotFoundException; 32 import java.util.Arrays; 33 34 import static android.provider.DocumentsContract.Document.*; 35 import static com.android.mtp.MtpDatabase.strings; 36 import static com.android.mtp.MtpDatabaseConstants.*; 37 import static com.android.mtp.TestUtil.OPERATIONS_SUPPORTED; 38 39 @SmallTest 40 public class MtpDatabaseTest extends AndroidTestCase { 41 private static final String[] COLUMN_NAMES = new String[] { 42 DocumentsContract.Document.COLUMN_DOCUMENT_ID, 43 MtpDatabaseConstants.COLUMN_DEVICE_ID, 44 MtpDatabaseConstants.COLUMN_STORAGE_ID, 45 MtpDatabaseConstants.COLUMN_OBJECT_HANDLE, 46 DocumentsContract.Document.COLUMN_MIME_TYPE, 47 DocumentsContract.Document.COLUMN_DISPLAY_NAME, 48 DocumentsContract.Document.COLUMN_SUMMARY, 49 DocumentsContract.Document.COLUMN_LAST_MODIFIED, 50 DocumentsContract.Document.COLUMN_ICON, 51 DocumentsContract.Document.COLUMN_FLAGS, 52 DocumentsContract.Document.COLUMN_SIZE, 53 MtpDatabaseConstants.COLUMN_DOCUMENT_TYPE 54 }; 55 56 private final TestResources resources = new TestResources(); 57 MtpDatabase mDatabase; 58 59 @Override setUp()60 public void setUp() { 61 mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); 62 } 63 64 @Override tearDown()65 public void tearDown() { 66 mDatabase.close(); 67 mDatabase = null; 68 } 69 getInt(Cursor cursor, String columnName)70 private static int getInt(Cursor cursor, String columnName) { 71 return cursor.getInt(cursor.getColumnIndex(columnName)); 72 } 73 isNull(Cursor cursor, String columnName)74 private static boolean isNull(Cursor cursor, String columnName) { 75 return cursor.isNull(cursor.getColumnIndex(columnName)); 76 } 77 getString(Cursor cursor, String columnName)78 private static String getString(Cursor cursor, String columnName) { 79 return cursor.getString(cursor.getColumnIndex(columnName)); 80 } 81 testPutSingleStorageDocuments()82 public void testPutSingleStorageDocuments() throws Exception { 83 addTestDevice(); 84 85 mDatabase.getMapper().startAddingDocuments("1"); 86 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 87 new MtpRoot(0, 1, "Storage", 1000, 2000, "") 88 }); 89 mDatabase.getMapper().stopAddingDocuments("1"); 90 91 { 92 final Cursor cursor = mDatabase.queryRootDocuments(COLUMN_NAMES); 93 assertEquals(1, cursor.getCount()); 94 95 cursor.moveToNext(); 96 assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); 97 assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID)); 98 assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID)); 99 assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE)); 100 assertEquals( 101 DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE)); 102 assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); 103 assertTrue(isNull(cursor, COLUMN_SUMMARY)); 104 assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED)); 105 assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON)); 106 assertEquals(Document.FLAG_DIR_SUPPORTS_CREATE, getInt(cursor, COLUMN_FLAGS)); 107 assertEquals(1000, getInt(cursor, COLUMN_SIZE)); 108 assertEquals( 109 MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, 110 getInt(cursor, COLUMN_DOCUMENT_TYPE)); 111 112 cursor.close(); 113 } 114 115 { 116 final Cursor cursor = mDatabase.queryRoots(resources, new String [] { 117 Root.COLUMN_ROOT_ID, 118 Root.COLUMN_FLAGS, 119 Root.COLUMN_ICON, 120 Root.COLUMN_TITLE, 121 Root.COLUMN_SUMMARY, 122 Root.COLUMN_DOCUMENT_ID, 123 Root.COLUMN_AVAILABLE_BYTES, 124 Root.COLUMN_CAPACITY_BYTES 125 }); 126 assertEquals(1, cursor.getCount()); 127 128 cursor.moveToNext(); 129 assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID)); 130 assertEquals( 131 Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY, 132 getInt(cursor, Root.COLUMN_FLAGS)); 133 assertEquals(R.drawable.ic_root_mtp, getInt(cursor, Root.COLUMN_ICON)); 134 assertEquals("Device Storage", getString(cursor, Root.COLUMN_TITLE)); 135 assertTrue(isNull(cursor, Root.COLUMN_SUMMARY)); 136 assertEquals(1, getInt(cursor, Root.COLUMN_DOCUMENT_ID)); 137 assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES)); 138 assertEquals(2000, getInt(cursor, Root.COLUMN_CAPACITY_BYTES)); 139 140 cursor.close(); 141 } 142 } 143 testPutStorageDocuments()144 public void testPutStorageDocuments() throws Exception { 145 addTestDevice(); 146 147 mDatabase.getMapper().startAddingDocuments("1"); 148 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 149 new MtpRoot(0, 1, "Storage", 1000, 2000, ""), 150 new MtpRoot(0, 2, "Storage", 2000, 4000, ""), 151 new MtpRoot(0, 3, "/@#%&<>Storage", 3000, 6000,"") 152 }); 153 154 { 155 final Cursor cursor = mDatabase.queryRootDocuments(COLUMN_NAMES); 156 assertEquals(3, cursor.getCount()); 157 158 cursor.moveToNext(); 159 assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); 160 assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID)); 161 assertEquals(1, getInt(cursor, COLUMN_STORAGE_ID)); 162 assertTrue(isNull(cursor, COLUMN_OBJECT_HANDLE)); 163 assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, getString(cursor, COLUMN_MIME_TYPE)); 164 assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); 165 assertTrue(isNull(cursor, COLUMN_SUMMARY)); 166 assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED)); 167 assertEquals(R.drawable.ic_root_mtp, getInt(cursor, COLUMN_ICON)); 168 assertEquals(Document.FLAG_DIR_SUPPORTS_CREATE, getInt(cursor, COLUMN_FLAGS)); 169 assertEquals(1000, getInt(cursor, COLUMN_SIZE)); 170 assertEquals( 171 MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE, getInt(cursor, COLUMN_DOCUMENT_TYPE)); 172 173 cursor.moveToNext(); 174 assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID)); 175 assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); 176 177 cursor.moveToNext(); 178 assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID)); 179 assertEquals("/@#%&<>Storage", getString(cursor, COLUMN_DISPLAY_NAME)); 180 181 cursor.close(); 182 } 183 } 184 createDocument(int objectHandle, String name, int format, int size)185 private MtpObjectInfo createDocument(int objectHandle, String name, int format, int size) { 186 final MtpObjectInfo.Builder builder = new MtpObjectInfo.Builder(); 187 builder.setObjectHandle(objectHandle); 188 builder.setName(name); 189 builder.setFormat(format); 190 builder.setCompressedSize(size); 191 return builder.build(); 192 } 193 testPutChildDocuments()194 public void testPutChildDocuments() throws Exception { 195 addTestDevice(); 196 addTestStorage("1"); 197 198 mDatabase.getMapper().startAddingDocuments("2"); 199 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 200 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024), 201 createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024), 202 createDocument(102, "music.mp3", MtpConstants.FORMAT_MP3, 3 * 1024 * 1024) 203 }, new long[] { 1024L, 2L * 1024L * 1024L, 3L * 1024L * 1024L}); 204 205 final Cursor cursor = mDatabase.queryChildDocuments(COLUMN_NAMES, "2"); 206 assertEquals(3, cursor.getCount()); 207 208 cursor.moveToNext(); 209 assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID)); 210 assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID)); 211 assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID)); 212 assertEquals(100, getInt(cursor, COLUMN_OBJECT_HANDLE)); 213 assertEquals("text/plain", getString(cursor, COLUMN_MIME_TYPE)); 214 assertEquals("note.txt", getString(cursor, COLUMN_DISPLAY_NAME)); 215 assertTrue(isNull(cursor, COLUMN_SUMMARY)); 216 assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED)); 217 assertTrue(isNull(cursor, COLUMN_ICON)); 218 assertEquals( 219 COLUMN_FLAGS, 220 DocumentsContract.Document.FLAG_SUPPORTS_DELETE | 221 DocumentsContract.Document.FLAG_SUPPORTS_WRITE, 222 cursor.getInt(9)); 223 assertEquals(1024, getInt(cursor, COLUMN_SIZE)); 224 assertEquals( 225 MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE)); 226 227 cursor.moveToNext(); 228 assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID)); 229 assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID)); 230 assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID)); 231 assertEquals(101, getInt(cursor, COLUMN_OBJECT_HANDLE)); 232 assertEquals("image/jpeg", getString(cursor, COLUMN_MIME_TYPE)); 233 assertEquals("image.jpg", getString(cursor, COLUMN_DISPLAY_NAME)); 234 assertTrue(isNull(cursor, COLUMN_SUMMARY)); 235 assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED)); 236 assertTrue(isNull(cursor, COLUMN_ICON)); 237 assertEquals( 238 COLUMN_FLAGS, 239 DocumentsContract.Document.FLAG_SUPPORTS_DELETE | 240 DocumentsContract.Document.FLAG_SUPPORTS_WRITE | 241 DocumentsContract.Document.FLAG_SUPPORTS_METADATA, 242 cursor.getInt(9)); 243 assertEquals(2 * 1024 * 1024, getInt(cursor, COLUMN_SIZE)); 244 assertEquals( 245 MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE)); 246 247 cursor.moveToNext(); 248 assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID)); 249 assertEquals(0, getInt(cursor, COLUMN_DEVICE_ID)); 250 assertEquals(0, getInt(cursor, COLUMN_STORAGE_ID)); 251 assertEquals(102, getInt(cursor, COLUMN_OBJECT_HANDLE)); 252 assertEquals("audio/mpeg", getString(cursor, COLUMN_MIME_TYPE)); 253 assertEquals("music.mp3", getString(cursor, COLUMN_DISPLAY_NAME)); 254 assertTrue(isNull(cursor, COLUMN_SUMMARY)); 255 assertTrue(isNull(cursor, COLUMN_LAST_MODIFIED)); 256 assertTrue(isNull(cursor, COLUMN_ICON)); 257 assertEquals( 258 COLUMN_FLAGS, 259 DocumentsContract.Document.FLAG_SUPPORTS_DELETE | 260 DocumentsContract.Document.FLAG_SUPPORTS_WRITE, 261 cursor.getInt(9)); 262 assertEquals(3 * 1024 * 1024, getInt(cursor, COLUMN_SIZE)); 263 assertEquals( 264 MtpDatabaseConstants.DOCUMENT_TYPE_OBJECT, getInt(cursor, COLUMN_DOCUMENT_TYPE)); 265 266 cursor.close(); 267 } 268 testPutChildDocuments_operationsSupported()269 public void testPutChildDocuments_operationsSupported() throws Exception { 270 addTestDevice(); 271 addTestStorage("1"); 272 273 // Put a document with empty supported operations. 274 mDatabase.getMapper().startAddingDocuments("2"); 275 mDatabase.getMapper().putChildDocuments(0, "2", new int[0], new MtpObjectInfo[] { 276 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024) 277 }, new long[] { 1024L }); 278 mDatabase.getMapper().stopAddingDocuments("2"); 279 280 try (final Cursor cursor = 281 mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) { 282 assertEquals(1, cursor.getCount()); 283 cursor.moveToNext(); 284 assertEquals(0, cursor.getInt(0)); 285 } 286 287 // Put a document with writable operations. 288 mDatabase.getMapper().startAddingDocuments("2"); 289 mDatabase.getMapper().putChildDocuments(0, "2", new int[] { 290 MtpConstants.OPERATION_SEND_OBJECT, 291 MtpConstants.OPERATION_SEND_OBJECT_INFO, 292 }, new MtpObjectInfo[] { 293 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024) 294 }, new long[] { 1024L }); 295 mDatabase.getMapper().stopAddingDocuments("2"); 296 297 try (final Cursor cursor = 298 mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) { 299 assertEquals(1, cursor.getCount()); 300 cursor.moveToNext(); 301 assertEquals(Document.FLAG_SUPPORTS_WRITE, cursor.getInt(0)); 302 } 303 304 // Put a document with deletable operations. 305 mDatabase.getMapper().startAddingDocuments("2"); 306 mDatabase.getMapper().putChildDocuments(0, "2", new int[] { 307 MtpConstants.OPERATION_DELETE_OBJECT 308 }, new MtpObjectInfo[] { 309 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024) 310 }, new long[] { 1024L }); 311 mDatabase.getMapper().stopAddingDocuments("2"); 312 313 try (final Cursor cursor = 314 mDatabase.queryChildDocuments(strings(Document.COLUMN_FLAGS), "2")) { 315 assertEquals(1, cursor.getCount()); 316 cursor.moveToNext(); 317 assertEquals(Document.FLAG_SUPPORTS_DELETE, cursor.getInt(0)); 318 } 319 } 320 testRestoreIdForRootDocuments()321 public void testRestoreIdForRootDocuments() throws Exception { 322 final String[] columns = new String[] { 323 DocumentsContract.Document.COLUMN_DOCUMENT_ID, 324 MtpDatabaseConstants.COLUMN_STORAGE_ID, 325 DocumentsContract.Document.COLUMN_DISPLAY_NAME 326 }; 327 328 // Add device and two storages. 329 addTestDevice(); 330 mDatabase.getMapper().startAddingDocuments("1"); 331 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 332 new MtpRoot(0, 100, "Storage A", 1000, 0, ""), 333 new MtpRoot(0, 101, "Storage B", 1001, 0, "") 334 }); 335 336 { 337 final Cursor cursor = mDatabase.queryRootDocuments(columns); 338 assertEquals(2, cursor.getCount()); 339 cursor.moveToNext(); 340 assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); 341 assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID)); 342 assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME)); 343 cursor.moveToNext(); 344 assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID)); 345 assertEquals(101, getInt(cursor, COLUMN_STORAGE_ID)); 346 assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME)); 347 cursor.close(); 348 } 349 350 // Clear mapping and add a device. 351 mDatabase.getMapper().clearMapping(); 352 addTestDevice(); 353 354 { 355 final Cursor cursor = mDatabase.queryRootDocuments(columns); 356 assertEquals(0, cursor.getCount()); 357 cursor.close(); 358 } 359 360 // Add two storages, but one's name is different from previous one. 361 mDatabase.getMapper().startAddingDocuments("1"); 362 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 363 new MtpRoot(0, 200, "Storage A", 2000, 0, ""), 364 new MtpRoot(0, 202, "Storage C", 2002, 0, "") 365 }); 366 mDatabase.getMapper().stopAddingDocuments("1"); 367 368 { 369 // After compeleting mapping, Storage A can be obtained with new storage ID. 370 final Cursor cursor = mDatabase.queryRootDocuments(columns); 371 assertEquals(2, cursor.getCount()); 372 cursor.moveToNext(); 373 assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); 374 assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID)); 375 assertEquals("Storage A", getString(cursor, COLUMN_DISPLAY_NAME)); 376 cursor.moveToNext(); 377 assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID)); 378 assertEquals(202, getInt(cursor, COLUMN_STORAGE_ID)); 379 assertEquals("Storage C", getString(cursor, COLUMN_DISPLAY_NAME)); 380 cursor.close(); 381 } 382 } 383 testRestoreIdForChildDocuments()384 public void testRestoreIdForChildDocuments() throws Exception { 385 final String[] columns = new String[] { 386 DocumentsContract.Document.COLUMN_DOCUMENT_ID, 387 MtpDatabaseConstants.COLUMN_OBJECT_HANDLE, 388 DocumentsContract.Document.COLUMN_DISPLAY_NAME 389 }; 390 391 addTestDevice(); 392 addTestStorage("1"); 393 394 mDatabase.getMapper().startAddingDocuments("2"); 395 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 396 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024), 397 createDocument(101, "image.jpg", MtpConstants.FORMAT_EXIF_JPEG, 2 * 1024 * 1024), 398 createDocument(102, "music.mp3", MtpConstants.FORMAT_MP3, 3 * 1024 * 1024) 399 }, new long[] { 1024L, 2L * 1024L * 1024L, 3L * 1024L * 1024L}); 400 mDatabase.getMapper().clearMapping(); 401 402 addTestDevice(); 403 addTestStorage("1"); 404 405 { 406 // Don't return objects that lost MTP object handles. 407 final Cursor cursor = mDatabase.queryChildDocuments(columns, "2"); 408 assertEquals(0, cursor.getCount()); 409 cursor.close(); 410 } 411 412 mDatabase.getMapper().startAddingDocuments("2"); 413 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 414 createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024), 415 createDocument(203, "video.mp4", MtpConstants.FORMAT_MP4_CONTAINER, 1024), 416 }, new long[] { 1024L, 1024L }); 417 mDatabase.getMapper().stopAddingDocuments("2"); 418 419 { 420 final Cursor cursor = mDatabase.queryChildDocuments(columns, "2"); 421 assertEquals(2, cursor.getCount()); 422 423 cursor.moveToNext(); 424 assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID)); 425 assertEquals(200, getInt(cursor, COLUMN_OBJECT_HANDLE)); 426 assertEquals("note.txt", getString(cursor, COLUMN_DISPLAY_NAME)); 427 428 cursor.moveToNext(); 429 assertEquals(6, getInt(cursor, COLUMN_DOCUMENT_ID)); 430 assertEquals(203, getInt(cursor, COLUMN_OBJECT_HANDLE)); 431 assertEquals("video.mp4", getString(cursor, COLUMN_DISPLAY_NAME)); 432 433 cursor.close(); 434 } 435 } 436 testRestoreIdForDifferentDevices()437 public void testRestoreIdForDifferentDevices() throws Exception { 438 final String[] columns = new String[] { 439 DocumentsContract.Document.COLUMN_DOCUMENT_ID, 440 MtpDatabaseConstants.COLUMN_STORAGE_ID, 441 DocumentsContract.Document.COLUMN_DISPLAY_NAME 442 }; 443 final String[] rootColumns = new String[] { 444 Root.COLUMN_ROOT_ID, 445 Root.COLUMN_AVAILABLE_BYTES 446 }; 447 mDatabase.getMapper().startAddingDocuments(null); 448 mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( 449 0, "Device A", "Device key A", true, new MtpRoot[0], null, null)); 450 mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( 451 1, "Device B", "Device key B", true, new MtpRoot[0], null, null)); 452 mDatabase.getMapper().stopAddingDocuments(null); 453 454 mDatabase.getMapper().startAddingDocuments("1"); 455 mDatabase.getMapper().startAddingDocuments("2"); 456 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 457 new MtpRoot(0, 100, "Storage", 0, 0, "") 458 }); 459 mDatabase.getMapper().putStorageDocuments("2", OPERATIONS_SUPPORTED, new MtpRoot[] { 460 new MtpRoot(1, 100, "Storage", 0, 0, "") 461 }); 462 463 { 464 final Cursor cursor = mDatabase.queryRootDocuments(columns); 465 assertEquals(2, cursor.getCount()); 466 cursor.moveToNext(); 467 assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID)); 468 assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID)); 469 assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); 470 cursor.moveToNext(); 471 assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID)); 472 assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID)); 473 assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); 474 cursor.close(); 475 } 476 477 { 478 final Cursor cursor = mDatabase.queryRoots(resources, rootColumns); 479 assertEquals(2, cursor.getCount()); 480 cursor.moveToNext(); 481 assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID)); 482 assertEquals(0, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES)); 483 cursor.moveToNext(); 484 assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID)); 485 assertEquals(0, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES)); 486 cursor.close(); 487 } 488 489 mDatabase.getMapper().clearMapping(); 490 491 mDatabase.getMapper().startAddingDocuments(null); 492 mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( 493 0, "Device A", "Device key A", true, new MtpRoot[0], null, null)); 494 mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( 495 1, "Device B", "Device key B", true, new MtpRoot[0], null, null)); 496 mDatabase.getMapper().stopAddingDocuments(null); 497 498 mDatabase.getMapper().startAddingDocuments("1"); 499 mDatabase.getMapper().startAddingDocuments("2"); 500 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 501 new MtpRoot(0, 200, "Storage", 2000, 0, "") 502 }); 503 mDatabase.getMapper().putStorageDocuments("2", OPERATIONS_SUPPORTED, new MtpRoot[] { 504 new MtpRoot(1, 300, "Storage", 3000, 0, "") 505 }); 506 mDatabase.getMapper().stopAddingDocuments("1"); 507 mDatabase.getMapper().stopAddingDocuments("2"); 508 509 { 510 final Cursor cursor = mDatabase.queryRootDocuments(columns); 511 assertEquals(2, cursor.getCount()); 512 cursor.moveToNext(); 513 assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID)); 514 assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID)); 515 assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); 516 cursor.moveToNext(); 517 assertEquals(4, getInt(cursor, COLUMN_DOCUMENT_ID)); 518 assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID)); 519 assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); 520 cursor.close(); 521 } 522 523 { 524 final Cursor cursor = mDatabase.queryRoots(resources, rootColumns); 525 assertEquals(2, cursor.getCount()); 526 cursor.moveToNext(); 527 assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID)); 528 assertEquals(2000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES)); 529 cursor.moveToNext(); 530 assertEquals(2, getInt(cursor, Root.COLUMN_ROOT_ID)); 531 assertEquals(3000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES)); 532 cursor.close(); 533 } 534 } 535 testRestoreIdForDifferentParents()536 public void testRestoreIdForDifferentParents() throws Exception { 537 final String[] columns = new String[] { 538 DocumentsContract.Document.COLUMN_DOCUMENT_ID, 539 MtpDatabaseConstants.COLUMN_OBJECT_HANDLE 540 }; 541 542 // Add device, storage, and two directories. 543 addTestDevice(); 544 addTestStorage("1"); 545 mDatabase.getMapper().startAddingDocuments("2"); 546 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 547 createDocument(50, "A", MtpConstants.FORMAT_ASSOCIATION, 0), 548 createDocument(51, "B", MtpConstants.FORMAT_ASSOCIATION, 0), 549 }, new long[] { 0L, 0L }); 550 mDatabase.getMapper().stopAddingDocuments("2"); 551 552 // Put note.txt in each directory. 553 mDatabase.getMapper().startAddingDocuments("3"); 554 mDatabase.getMapper().startAddingDocuments("4"); 555 mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 556 createDocument(100, "note.txt", MtpConstants.FORMAT_TEXT, 1024), 557 }, new long[] { 1024L }); 558 mDatabase.getMapper().putChildDocuments(0, "4", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 559 createDocument(101, "note.txt", MtpConstants.FORMAT_TEXT, 1024), 560 }, new long[] { 1024L }); 561 562 // Clear mapping. 563 mDatabase.getMapper().clearMapping(); 564 565 // Add device, storage, and two directories again. 566 addTestDevice(); 567 addTestStorage("1"); 568 mDatabase.getMapper().startAddingDocuments("2"); 569 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 570 createDocument(50, "A", MtpConstants.FORMAT_ASSOCIATION, 0), 571 createDocument(51, "B", MtpConstants.FORMAT_ASSOCIATION, 0), 572 }, new long[] { 0L, 0L }); 573 mDatabase.getMapper().stopAddingDocuments("2"); 574 575 // Add note.txt in each directory again. 576 mDatabase.getMapper().startAddingDocuments("3"); 577 mDatabase.getMapper().startAddingDocuments("4"); 578 mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 579 createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024), 580 }, new long[] { 1024L }); 581 mDatabase.getMapper().putChildDocuments(0, "4", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 582 createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024), 583 }, new long[] { 1024L }); 584 mDatabase.getMapper().stopAddingDocuments("3"); 585 mDatabase.getMapper().stopAddingDocuments("4"); 586 587 // Check if the two note.txt are mapped correctly. 588 { 589 final Cursor cursor = mDatabase.queryChildDocuments(columns, "3"); 590 assertEquals(1, cursor.getCount()); 591 cursor.moveToNext(); 592 assertEquals(5, getInt(cursor, COLUMN_DOCUMENT_ID)); 593 assertEquals(200, getInt(cursor, COLUMN_OBJECT_HANDLE)); 594 cursor.close(); 595 } 596 { 597 final Cursor cursor = mDatabase.queryChildDocuments(columns, "4"); 598 assertEquals(1, cursor.getCount()); 599 cursor.moveToNext(); 600 assertEquals(6, getInt(cursor, COLUMN_DOCUMENT_ID)); 601 assertEquals(201, getInt(cursor, COLUMN_OBJECT_HANDLE)); 602 cursor.close(); 603 } 604 } 605 testClearMtpIdentifierBeforeResolveRootDocuments()606 public void testClearMtpIdentifierBeforeResolveRootDocuments() throws Exception { 607 final String[] columns = new String[] { 608 DocumentsContract.Document.COLUMN_DOCUMENT_ID, 609 MtpDatabaseConstants.COLUMN_STORAGE_ID, 610 DocumentsContract.Document.COLUMN_DISPLAY_NAME 611 }; 612 final String[] rootColumns = new String[] { 613 Root.COLUMN_ROOT_ID, 614 Root.COLUMN_AVAILABLE_BYTES 615 }; 616 617 addTestDevice(); 618 619 mDatabase.getMapper().startAddingDocuments("1"); 620 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 621 new MtpRoot(0, 100, "Storage", 0, 0, ""), 622 }); 623 mDatabase.getMapper().clearMapping(); 624 625 addTestDevice(); 626 627 try (final Cursor cursor = mDatabase.queryRoots(resources, rootColumns)) { 628 assertEquals(1, cursor.getCount()); 629 cursor.moveToNext(); 630 assertEquals("1", getString(cursor, Root.COLUMN_ROOT_ID)); 631 } 632 633 mDatabase.getMapper().startAddingDocuments("1"); 634 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 635 new MtpRoot(0, 200, "Storage", 2000, 0, ""), 636 }); 637 mDatabase.getMapper().clearMapping(); 638 639 addTestDevice(); 640 641 mDatabase.getMapper().startAddingDocuments("1"); 642 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 643 new MtpRoot(0, 300, "Storage", 3000, 0, ""), 644 }); 645 mDatabase.getMapper().stopAddingDocuments("1"); 646 647 { 648 final Cursor cursor = mDatabase.queryRootDocuments(columns); 649 assertEquals(1, cursor.getCount()); 650 cursor.moveToNext(); 651 assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); 652 assertEquals(300, getInt(cursor, COLUMN_STORAGE_ID)); 653 assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); 654 cursor.close(); 655 } 656 { 657 final Cursor cursor = mDatabase.queryRoots(resources, rootColumns); 658 assertEquals(1, cursor.getCount()); 659 cursor.moveToNext(); 660 assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID)); 661 assertEquals(3000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES)); 662 cursor.close(); 663 } 664 } 665 testPutSameNameRootsAfterClearing()666 public void testPutSameNameRootsAfterClearing() throws Exception { 667 final String[] columns = new String[] { 668 DocumentsContract.Document.COLUMN_DOCUMENT_ID, 669 MtpDatabaseConstants.COLUMN_STORAGE_ID, 670 DocumentsContract.Document.COLUMN_DISPLAY_NAME 671 }; 672 673 // Add a device and a storage. 674 addTestDevice(); 675 addTestStorage("1"); 676 677 // Disconnect devices. 678 mDatabase.getMapper().clearMapping(); 679 680 // Add a device and two storages that has same name. 681 addTestDevice(); 682 mDatabase.getMapper().startAddingDocuments("1"); 683 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 684 new MtpRoot(0, 200, "Storage", 2000, 0, ""), 685 new MtpRoot(0, 201, "Storage", 2001, 0, ""), 686 }); 687 mDatabase.getMapper().stopAddingDocuments("1"); 688 689 { 690 final Cursor cursor = mDatabase.queryRootDocuments(columns); 691 assertEquals(2, cursor.getCount()); 692 693 // First storage reuse document ID of previous storage. 694 cursor.moveToNext(); 695 // One reuses exisitng document ID 1. 696 assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); 697 assertEquals(200, getInt(cursor, COLUMN_STORAGE_ID)); 698 assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); 699 700 // Second one has new document ID. 701 cursor.moveToNext(); 702 assertEquals(3, getInt(cursor, COLUMN_DOCUMENT_ID)); 703 assertEquals(201, getInt(cursor, COLUMN_STORAGE_ID)); 704 assertEquals("Storage", getString(cursor, COLUMN_DISPLAY_NAME)); 705 706 cursor.close(); 707 } 708 } 709 testReplaceExistingRoots()710 public void testReplaceExistingRoots() throws Exception { 711 addTestDevice(); 712 713 // The client code should be able to replace existing rows with new information. 714 // Add one. 715 mDatabase.getMapper().startAddingDocuments("1"); 716 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 717 new MtpRoot(0, 100, "Storage A", 0, 0, ""), 718 }); 719 mDatabase.getMapper().stopAddingDocuments("1"); 720 // Replace it. 721 mDatabase.getMapper().startAddingDocuments("1"); 722 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 723 new MtpRoot(0, 100, "Storage B", 1000, 1000, ""), 724 }); 725 mDatabase.getMapper().stopAddingDocuments("1"); 726 { 727 final String[] columns = new String[] { 728 DocumentsContract.Document.COLUMN_DOCUMENT_ID, 729 MtpDatabaseConstants.COLUMN_STORAGE_ID, 730 DocumentsContract.Document.COLUMN_DISPLAY_NAME 731 }; 732 final Cursor cursor = mDatabase.queryRootDocuments(columns); 733 assertEquals(1, cursor.getCount()); 734 cursor.moveToNext(); 735 assertEquals(2, getInt(cursor, COLUMN_DOCUMENT_ID)); 736 assertEquals(100, getInt(cursor, COLUMN_STORAGE_ID)); 737 assertEquals("Storage B", getString(cursor, COLUMN_DISPLAY_NAME)); 738 cursor.close(); 739 } 740 { 741 final String[] columns = new String[] { 742 Root.COLUMN_ROOT_ID, 743 Root.COLUMN_TITLE, 744 Root.COLUMN_AVAILABLE_BYTES 745 }; 746 final Cursor cursor = mDatabase.queryRoots(resources, columns); 747 assertEquals(1, cursor.getCount()); 748 cursor.moveToNext(); 749 assertEquals(1, getInt(cursor, Root.COLUMN_ROOT_ID)); 750 assertEquals("Device Storage B", getString(cursor, Root.COLUMN_TITLE)); 751 assertEquals(1000, getInt(cursor, Root.COLUMN_AVAILABLE_BYTES)); 752 cursor.close(); 753 } 754 } 755 testFailToReplaceExisitingUnmappedRoots()756 public void testFailToReplaceExisitingUnmappedRoots() throws Exception { 757 // The client code should not be able to replace rows before resolving 'unmapped' rows. 758 // Add one. 759 addTestDevice(); 760 mDatabase.getMapper().startAddingDocuments("1"); 761 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 762 new MtpRoot(0, 100, "Storage A", 0, 0, ""), 763 }); 764 mDatabase.getMapper().clearMapping(); 765 766 addTestDevice(); 767 try (final Cursor oldCursor = 768 mDatabase.queryRoots(resources, strings(Root.COLUMN_ROOT_ID))) { 769 assertEquals(1, oldCursor.getCount()); 770 oldCursor.moveToNext(); 771 assertEquals("1", getString(oldCursor, Root.COLUMN_ROOT_ID)); 772 773 // Add one. 774 mDatabase.getMapper().startAddingDocuments("1"); 775 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 776 new MtpRoot(0, 101, "Storage B", 1000, 1000, ""), 777 }); 778 // Add one more before resolving unmapped documents. 779 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 780 new MtpRoot(0, 102, "Storage B", 1000, 1000, ""), 781 }); 782 mDatabase.getMapper().stopAddingDocuments("1"); 783 784 // Because the roots shares the same name, the roots should have new IDs. 785 try (final Cursor newCursor = mDatabase.queryChildDocuments( 786 strings(Document.COLUMN_DOCUMENT_ID), "1")) { 787 assertEquals(2, newCursor.getCount()); 788 newCursor.moveToNext(); 789 assertFalse(oldCursor.getString(0).equals(newCursor.getString(0))); 790 newCursor.moveToNext(); 791 assertFalse(oldCursor.getString(0).equals(newCursor.getString(0))); 792 } 793 } 794 } 795 testQueryDocuments()796 public void testQueryDocuments() throws Exception { 797 addTestDevice(); 798 addTestStorage("1"); 799 800 final Cursor cursor = mDatabase.queryDocument("2", strings(Document.COLUMN_DISPLAY_NAME)); 801 assertEquals(1, cursor.getCount()); 802 cursor.moveToNext(); 803 assertEquals("Storage", getString(cursor, Document.COLUMN_DISPLAY_NAME)); 804 cursor.close(); 805 } 806 testQueryRoots()807 public void testQueryRoots() throws Exception { 808 // Add device document. 809 addTestDevice(); 810 811 // It the device does not have storages, it shows a device root. 812 { 813 final Cursor cursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_TITLE)); 814 assertEquals(1, cursor.getCount()); 815 cursor.moveToNext(); 816 assertEquals("Device", cursor.getString(0)); 817 cursor.close(); 818 } 819 820 mDatabase.getMapper().startAddingDocuments("1"); 821 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 822 new MtpRoot(0, 100, "Storage A", 0, 0, "") 823 }); 824 mDatabase.getMapper().stopAddingDocuments("1"); 825 826 // It the device has single storage, it shows a storage root. 827 { 828 final Cursor cursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_TITLE)); 829 assertEquals(1, cursor.getCount()); 830 cursor.moveToNext(); 831 assertEquals("Device Storage A", cursor.getString(0)); 832 cursor.close(); 833 } 834 835 mDatabase.getMapper().startAddingDocuments("1"); 836 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 837 new MtpRoot(0, 100, "Storage A", 0, 0, ""), 838 new MtpRoot(0, 101, "Storage B", 0, 0, "") 839 }); 840 mDatabase.getMapper().stopAddingDocuments("1"); 841 842 // It the device has multiple storages, it shows a device root. 843 { 844 final Cursor cursor = mDatabase.queryRoots(resources, strings(Root.COLUMN_TITLE)); 845 assertEquals(1, cursor.getCount()); 846 cursor.moveToNext(); 847 assertEquals("Device", cursor.getString(0)); 848 cursor.close(); 849 } 850 } 851 testGetParentId()852 public void testGetParentId() throws FileNotFoundException { 853 addTestDevice(); 854 855 mDatabase.getMapper().startAddingDocuments("1"); 856 mDatabase.getMapper().putStorageDocuments("1", OPERATIONS_SUPPORTED, new MtpRoot[] { 857 new MtpRoot(0, 100, "Storage A", 0, 0, ""), 858 }); 859 mDatabase.getMapper().stopAddingDocuments("1"); 860 861 mDatabase.getMapper().startAddingDocuments("2"); 862 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 863 createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024), 864 }, new long[] { 1024L }); 865 mDatabase.getMapper().stopAddingDocuments("2"); 866 867 assertEquals("2", mDatabase.getParentIdentifier("3").mDocumentId); 868 } 869 testDeleteDocument()870 public void testDeleteDocument() throws Exception { 871 addTestDevice(); 872 addTestStorage("1"); 873 874 mDatabase.getMapper().startAddingDocuments("2"); 875 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 876 createDocument(200, "dir", MtpConstants.FORMAT_ASSOCIATION, 1024), 877 }, new long[] { 1024L }); 878 mDatabase.getMapper().stopAddingDocuments("2"); 879 880 mDatabase.getMapper().startAddingDocuments("3"); 881 mDatabase.getMapper().putChildDocuments(0, "3", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 882 createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024), 883 }, new long[] { 1024L }); 884 mDatabase.getMapper().stopAddingDocuments("3"); 885 886 mDatabase.deleteDocument("3"); 887 888 { 889 // Do not query deleted documents. 890 final Cursor cursor = 891 mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2"); 892 assertEquals(0, cursor.getCount()); 893 cursor.close(); 894 } 895 896 { 897 // Child document should be deleted also. 898 final Cursor cursor = 899 mDatabase.queryDocument("4", strings(Document.COLUMN_DOCUMENT_ID)); 900 assertEquals(0, cursor.getCount()); 901 cursor.close(); 902 } 903 } 904 testPutNewDocument()905 public void testPutNewDocument() throws Exception { 906 addTestDevice(); 907 addTestStorage("1"); 908 909 assertEquals( 910 "3", 911 mDatabase.putNewDocument( 912 0, "2", OPERATIONS_SUPPORTED, 913 createDocument(200, "note.txt", MtpConstants.FORMAT_TEXT, 1024), 914 1024L)); 915 916 { 917 final Cursor cursor = 918 mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2"); 919 assertEquals(1, cursor.getCount()); 920 cursor.moveToNext(); 921 assertEquals("3", cursor.getString(0)); 922 cursor.close(); 923 } 924 925 // The new document should not be mapped with existing invalidated document. 926 mDatabase.getMapper().clearMapping(); 927 addTestDevice(); 928 addTestStorage("1"); 929 930 mDatabase.getMapper().startAddingDocuments("2"); 931 mDatabase.putNewDocument( 932 0, "2", OPERATIONS_SUPPORTED, 933 createDocument(201, "note.txt", MtpConstants.FORMAT_TEXT, 1024), 934 1024L); 935 mDatabase.getMapper().stopAddingDocuments("2"); 936 937 { 938 final Cursor cursor = 939 mDatabase.queryChildDocuments(strings(Document.COLUMN_DOCUMENT_ID), "2"); 940 assertEquals(1, cursor.getCount()); 941 cursor.moveToNext(); 942 assertEquals("4", cursor.getString(0)); 943 cursor.close(); 944 } 945 } 946 testGetDocumentIdForDevice()947 public void testGetDocumentIdForDevice() throws Exception { 948 addTestDevice(); 949 assertEquals("1", mDatabase.getDocumentIdForDevice(0)); 950 } 951 testGetClosedDevice()952 public void testGetClosedDevice() throws Exception { 953 mDatabase.getMapper().startAddingDocuments(null); 954 mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( 955 0, "Device", null /* deviceKey */, /* opened is */ false, new MtpRoot[0], null, 956 null)); 957 mDatabase.getMapper().stopAddingDocuments(null); 958 959 final String[] columns = new String [] { 960 DocumentsContract.Root.COLUMN_ROOT_ID, 961 DocumentsContract.Root.COLUMN_TITLE, 962 DocumentsContract.Root.COLUMN_AVAILABLE_BYTES 963 }; 964 try (final Cursor cursor = mDatabase.queryRoots(resources, columns)) { 965 assertEquals(1, cursor.getCount()); 966 assertTrue(cursor.moveToNext()); 967 assertEquals(1, cursor.getLong(0)); 968 assertEquals("Device", cursor.getString(1)); 969 assertTrue(cursor.isNull(2)); 970 } 971 } 972 testMappingWithoutKey()973 public void testMappingWithoutKey() throws FileNotFoundException { 974 mDatabase.getMapper().startAddingDocuments(null); 975 mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( 976 0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null, 977 null)); 978 mDatabase.getMapper().stopAddingDocuments(null); 979 980 mDatabase.getMapper().startAddingDocuments(null); 981 mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( 982 0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null, 983 null)); 984 mDatabase.getMapper().stopAddingDocuments(null); 985 986 try (final Cursor cursor = 987 mDatabase.queryRoots(resources, strings(DocumentsContract.Root.COLUMN_ROOT_ID))) { 988 assertEquals(1, cursor.getCount()); 989 assertTrue(cursor.moveToNext()); 990 assertEquals(1, cursor.getLong(0)); 991 } 992 } 993 testMappingFailsWithoutKey()994 public void testMappingFailsWithoutKey() throws FileNotFoundException { 995 mDatabase.getMapper().startAddingDocuments(null); 996 mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( 997 0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null, 998 null)); 999 mDatabase.getMapper().stopAddingDocuments(null); 1000 1001 // MTP identifier is cleared here. Mapping no longer works without device key. 1002 mDatabase.getMapper().startAddingDocuments(null); 1003 mDatabase.getMapper().stopAddingDocuments(null); 1004 1005 mDatabase.getMapper().startAddingDocuments(null); 1006 mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( 1007 0, "Device", null /* device key */, /* opened is */ true, new MtpRoot[0], null, 1008 null)); 1009 mDatabase.getMapper().stopAddingDocuments(null); 1010 1011 try (final Cursor cursor = 1012 mDatabase.queryRoots(resources, strings(DocumentsContract.Root.COLUMN_ROOT_ID))) { 1013 assertEquals(1, cursor.getCount()); 1014 assertTrue(cursor.moveToNext()); 1015 assertEquals(2, cursor.getLong(0)); 1016 } 1017 } 1018 testUpdateDocumentWithoutChange()1019 public void testUpdateDocumentWithoutChange() throws FileNotFoundException { 1020 mDatabase.getMapper().startAddingDocuments(null); 1021 assertTrue(mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( 1022 0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], null, 1023 null))); 1024 assertFalse(mDatabase.getMapper().stopAddingDocuments(null)); 1025 1026 mDatabase.getMapper().startAddingDocuments(null); 1027 assertFalse(mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord( 1028 0, "Device", "device_key", /* opened is */ true, new MtpRoot[0], null, 1029 null))); 1030 assertFalse(mDatabase.getMapper().stopAddingDocuments(null)); 1031 } 1032 testSetBootCount()1033 public void testSetBootCount() { 1034 assertEquals(0, mDatabase.getLastBootCount()); 1035 mDatabase.setLastBootCount(10); 1036 assertEquals(10, mDatabase.getLastBootCount()); 1037 try { 1038 mDatabase.setLastBootCount(-1); 1039 fail(); 1040 } catch (IllegalArgumentException e) {} 1041 } 1042 testCleanDatabase()1043 public void testCleanDatabase() throws FileNotFoundException { 1044 // Add tree. 1045 addTestDevice(); 1046 addTestStorage("1"); 1047 mDatabase.getMapper().startAddingDocuments("2"); 1048 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 1049 createDocument(100, "apple.txt", MtpConstants.FORMAT_TEXT, 1024), 1050 createDocument(101, "orange.txt", MtpConstants.FORMAT_TEXT, 1024), 1051 }, new long[] { 1024L, 1024L }); 1052 mDatabase.getMapper().stopAddingDocuments("2"); 1053 1054 // Disconnect the device. 1055 mDatabase.getMapper().startAddingDocuments(null); 1056 mDatabase.getMapper().stopAddingDocuments(null); 1057 1058 // Clean database. 1059 mDatabase.cleanDatabase(new Uri[] { 1060 DocumentsContract.buildDocumentUri(MtpDocumentsProvider.AUTHORITY, "3") 1061 }); 1062 1063 // Add tree again. 1064 addTestDevice(); 1065 addTestStorage("1"); 1066 mDatabase.getMapper().startAddingDocuments("2"); 1067 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 1068 createDocument(100, "apple.txt", MtpConstants.FORMAT_TEXT, 1024), 1069 createDocument(101, "orange.txt", MtpConstants.FORMAT_TEXT, 1024), 1070 }, new long[] { 1024L, 1024L }); 1071 mDatabase.getMapper().stopAddingDocuments("2"); 1072 1073 try (final Cursor cursor = mDatabase.queryChildDocuments( 1074 strings(COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME), "2")) { 1075 assertEquals(2, cursor.getCount()); 1076 1077 // Persistent uri uses the same ID. 1078 cursor.moveToNext(); 1079 assertEquals("3", cursor.getString(0)); 1080 assertEquals("apple.txt", cursor.getString(1)); 1081 1082 // Others does not. 1083 cursor.moveToNext(); 1084 assertEquals("5", cursor.getString(0)); 1085 assertEquals("orange.txt", cursor.getString(1)); 1086 } 1087 } 1088 testFormatCodeForMpeg()1089 public void testFormatCodeForMpeg() throws FileNotFoundException { 1090 addTestDevice(); 1091 addTestStorage("1"); 1092 mDatabase.getMapper().startAddingDocuments("2"); 1093 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 1094 createDocument(100, "audio.m4a", MtpConstants.FORMAT_MPEG, 1000), 1095 createDocument(101, "video.m4v", MtpConstants.FORMAT_MPEG, 1000), 1096 createDocument(102, "unknown.mp4", MtpConstants.FORMAT_MPEG, 1000), 1097 createDocument(103, "inconsistent.txt", MtpConstants.FORMAT_MPEG, 1000), 1098 createDocument(104, "noext", MtpConstants.FORMAT_UNDEFINED, 1000), 1099 }, new long[] { 1000L, 1000L, 1000L, 1000L, 1000L }); 1100 mDatabase.getMapper().stopAddingDocuments("2"); 1101 try (final Cursor cursor = mDatabase.queryChildDocuments( 1102 strings(COLUMN_DISPLAY_NAME, COLUMN_MIME_TYPE), 1103 "2")) { 1104 assertEquals(5, cursor.getCount()); 1105 cursor.moveToNext(); 1106 assertEquals("audio.m4a", cursor.getString(0)); 1107 assertEquals("audio/mp4", cursor.getString(1)); 1108 cursor.moveToNext(); 1109 assertEquals("video.m4v", cursor.getString(0)); 1110 assertEquals("video/mp4", cursor.getString(1)); 1111 cursor.moveToNext(); 1112 // Assume that the file is video as we don't have any hints to find out if the file is 1113 // video or audio. 1114 assertEquals("unknown.mp4", cursor.getString(0)); 1115 assertEquals("video/mp4", cursor.getString(1)); 1116 // Don't return mime type that is inconsistent with format code. 1117 cursor.moveToNext(); 1118 assertEquals("inconsistent.txt", cursor.getString(0)); 1119 assertEquals("video/mpeg", cursor.getString(1)); 1120 cursor.moveToNext(); 1121 assertEquals("noext", cursor.getString(0)); 1122 assertEquals("application/octet-stream", cursor.getString(1)); 1123 } 1124 } 1125 addTestDevice()1126 private void addTestDevice() throws FileNotFoundException { 1127 TestUtil.addTestDevice(mDatabase); 1128 } 1129 addTestStorage(String parentId)1130 private void addTestStorage(String parentId) throws FileNotFoundException { 1131 TestUtil.addTestStorage(mDatabase, parentId); 1132 } 1133 } 1134