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