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