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 60 public void setUp() { 61 mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); 62 } 63 64 @Override 65 public void tearDown() { 66 mDatabase.close(); 67 mDatabase = null; 68 } 69 70 private static int getInt(Cursor cursor, String columnName) { 71 return cursor.getInt(cursor.getColumnIndex(columnName)); 72 } 73 74 private static boolean isNull(Cursor cursor, String columnName) { 75 return cursor.isNull(cursor.getColumnIndex(columnName)); 76 } 77 78 private static String getString(Cursor cursor, String columnName) { 79 return cursor.getString(cursor.getColumnIndex(columnName)); 80 } 81 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 946 public void testGetDocumentIdForDevice() throws Exception { 947 addTestDevice(); 948 assertEquals("1", mDatabase.getDocumentIdForDevice(0)); 949 } 950 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 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 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 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 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 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. 1058 mDatabase.cleanDatabase(new Uri[] { 1059 DocumentsContract.buildDocumentUri(MtpDocumentsProvider.AUTHORITY, "3") 1060 }); 1061 1062 // Add tree again. 1063 addTestDevice(); 1064 addTestStorage("1"); 1065 mDatabase.getMapper().startAddingDocuments("2"); 1066 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 1067 createDocument(100, "apple.txt", MtpConstants.FORMAT_TEXT, 1024), 1068 createDocument(101, "orange.txt", MtpConstants.FORMAT_TEXT, 1024), 1069 }, new long[] { 1024L, 1024L }); 1070 mDatabase.getMapper().stopAddingDocuments("2"); 1071 1072 try (final Cursor cursor = mDatabase.queryChildDocuments( 1073 strings(COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME), "2")) { 1074 assertEquals(2, cursor.getCount()); 1075 1076 // Persistent uri uses the same ID. 1077 cursor.moveToNext(); 1078 assertEquals("3", cursor.getString(0)); 1079 assertEquals("apple.txt", cursor.getString(1)); 1080 1081 // Others does not. 1082 cursor.moveToNext(); 1083 assertEquals("5", cursor.getString(0)); 1084 assertEquals("orange.txt", cursor.getString(1)); 1085 } 1086 } 1087 1088 public void testFormatCodeForMpeg() throws FileNotFoundException { 1089 addTestDevice(); 1090 addTestStorage("1"); 1091 mDatabase.getMapper().startAddingDocuments("2"); 1092 mDatabase.getMapper().putChildDocuments(0, "2", OPERATIONS_SUPPORTED, new MtpObjectInfo[] { 1093 createDocument(100, "audio.m4a", MtpConstants.FORMAT_MPEG, 1000), 1094 createDocument(101, "video.m4v", MtpConstants.FORMAT_MPEG, 1000), 1095 createDocument(102, "unknown.mp4", MtpConstants.FORMAT_MPEG, 1000), 1096 createDocument(103, "inconsistent.txt", MtpConstants.FORMAT_MPEG, 1000), 1097 createDocument(104, "noext", MtpConstants.FORMAT_UNDEFINED, 1000), 1098 }, new long[] { 1000L, 1000L, 1000L, 1000L, 1000L }); 1099 mDatabase.getMapper().stopAddingDocuments("2"); 1100 try (final Cursor cursor = mDatabase.queryChildDocuments( 1101 strings(COLUMN_DISPLAY_NAME, COLUMN_MIME_TYPE), 1102 "2")) { 1103 assertEquals(5, cursor.getCount()); 1104 cursor.moveToNext(); 1105 assertEquals("audio.m4a", cursor.getString(0)); 1106 assertEquals("audio/mp4", cursor.getString(1)); 1107 cursor.moveToNext(); 1108 assertEquals("video.m4v", cursor.getString(0)); 1109 assertEquals("video/mp4", cursor.getString(1)); 1110 cursor.moveToNext(); 1111 // Assume that the file is video as we don't have any hints to find out if the file is 1112 // video or audio. 1113 assertEquals("unknown.mp4", cursor.getString(0)); 1114 assertEquals("video/mp4", cursor.getString(1)); 1115 // Don't return mime type that is inconsistent with format code. 1116 cursor.moveToNext(); 1117 assertEquals("inconsistent.txt", cursor.getString(0)); 1118 assertEquals("video/mp4", cursor.getString(1)); 1119 cursor.moveToNext(); 1120 assertEquals("noext", cursor.getString(0)); 1121 assertEquals("application/octet-stream", cursor.getString(1)); 1122 } 1123 } 1124 1125 private void addTestDevice() throws FileNotFoundException { 1126 TestUtil.addTestDevice(mDatabase); 1127 } 1128 1129 private void addTestStorage(String parentId) throws FileNotFoundException { 1130 TestUtil.addTestStorage(mDatabase, parentId); 1131 } 1132 } 1133