16baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono/* 26baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * Copyright (C) 2015 The Android Open Source Project 36baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * 46baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * Licensed under the Apache License, Version 2.0 (the "License"); 56baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * you may not use this file except in compliance with the License. 66baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * You may obtain a copy of the License at 76baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * 86baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * http://www.apache.org/licenses/LICENSE-2.0 96baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * 106baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * Unless required by applicable law or agreed to in writing, software 116baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * distributed under the License is distributed on an "AS IS" BASIS, 126baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * See the License for the specific language governing permissions and 146baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono * limitations under the License. 156baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono */ 166baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 176baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hironopackage com.android.mtp; 186baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 196baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hironoimport android.content.Context; 206baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hironoimport android.database.Cursor; 21bb430fa930fa0d0700e46e7b4881de2a252223ddTomasz Mikolajewskiimport android.mtp.MtpObjectInfo; 226baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hironoimport android.net.Uri; 236baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hironoimport android.provider.DocumentsContract; 2476be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hironoimport android.provider.DocumentsContract.Document; 256baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hironoimport android.test.AndroidTestCase; 264604b74603ea951c0f0d0fc2d9b6bd46ae54e245Daichi Hironoimport android.test.suitebuilder.annotation.MediumTest; 276baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 286baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hironoimport java.io.IOException; 296baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hironoimport java.util.HashMap; 306baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hironoimport java.util.Map; 316baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hironoimport java.util.concurrent.CountDownLatch; 3276be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hironoimport java.util.concurrent.TimeoutException; 336baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 344604b74603ea951c0f0d0fc2d9b6bd46ae54e245Daichi Hirono@MediumTest 356baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hironopublic class DocumentLoaderTest extends AndroidTestCase { 3647eb192b2704e27272ca94a95680cac40b6bff3fDaichi Hirono private MtpDatabase mDatabase; 37bb430fa930fa0d0700e46e7b4881de2a252223ddTomasz Mikolajewski private BlockableTestMtpManager mManager; 386baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono private TestContentResolver mResolver; 396baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono private DocumentLoader mLoader; 406a5ea7eae8a70bced97ceef051c965c27cb642caDaichi Hirono final private Identifier mParentIdentifier = new Identifier( 41619afdaae1ec7dcbd71bb1f698a0901a1fa290feDaichi Hirono 0, 0, 0, "2", MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE); 426baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 436baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono @Override 44619afdaae1ec7dcbd71bb1f698a0901a1fa290feDaichi Hirono public void setUp() throws Exception { 4547eb192b2704e27272ca94a95680cac40b6bff3fDaichi Hirono mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); 46619afdaae1ec7dcbd71bb1f698a0901a1fa290feDaichi Hirono 47619afdaae1ec7dcbd71bb1f698a0901a1fa290feDaichi Hirono mDatabase.getMapper().startAddingDocuments(null); 48619afdaae1ec7dcbd71bb1f698a0901a1fa290feDaichi Hirono mDatabase.getMapper().putDeviceDocument( 494e94b8deaa646f176bad9b80d5924ce64142743eDaichi Hirono new MtpDeviceRecord(0, "Device", null, true, new MtpRoot[0], null, null)); 50619afdaae1ec7dcbd71bb1f698a0901a1fa290feDaichi Hirono mDatabase.getMapper().stopAddingDocuments(null); 51619afdaae1ec7dcbd71bb1f698a0901a1fa290feDaichi Hirono 52619afdaae1ec7dcbd71bb1f698a0901a1fa290feDaichi Hirono mDatabase.getMapper().startAddingDocuments("1"); 530f32537e40ee2662d4f0b7b625ee280ca9c02066Daichi Hirono mDatabase.getMapper().putStorageDocuments("1", new int[0], new MtpRoot[] { 54f83ccbd7edd32e728785fb7aad44f11886e79645Daichi Hirono new MtpRoot(0, 0, "Storage", 1000, 1000, "") 5547eb192b2704e27272ca94a95680cac40b6bff3fDaichi Hirono }); 56619afdaae1ec7dcbd71bb1f698a0901a1fa290feDaichi Hirono mDatabase.getMapper().stopAddingDocuments("1"); 57619afdaae1ec7dcbd71bb1f698a0901a1fa290feDaichi Hirono 58bb430fa930fa0d0700e46e7b4881de2a252223ddTomasz Mikolajewski mManager = new BlockableTestMtpManager(getContext()); 596baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mResolver = new TestContentResolver(); 6047eb192b2704e27272ca94a95680cac40b6bff3fDaichi Hirono } 6147eb192b2704e27272ca94a95680cac40b6bff3fDaichi Hirono 6247eb192b2704e27272ca94a95680cac40b6bff3fDaichi Hirono @Override 634e94b8deaa646f176bad9b80d5924ce64142743eDaichi Hirono public void tearDown() throws Exception { 644e94b8deaa646f176bad9b80d5924ce64142743eDaichi Hirono mLoader.close(); 6547eb192b2704e27272ca94a95680cac40b6bff3fDaichi Hirono mDatabase.close(); 666baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 676baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 688b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono public void testBasic() throws Exception { 69678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono setUpLoader(); 70678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono 716baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono final Uri uri = DocumentsContract.buildChildDocumentsUri( 729e8a4fa78f5b9e3964dca84ad4047210d35c4013Daichi Hirono MtpDocumentsProvider.AUTHORITY, mParentIdentifier.mDocumentId); 736baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono setUpDocument(mManager, 40); 746baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mManager.blockDocument(0, 15); 756baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mManager.blockDocument(0, 35); 766baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 776baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono { 786baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono final Cursor cursor = mLoader.queryChildDocuments( 796baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier); 806baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono assertEquals(DocumentLoader.NUM_INITIAL_ENTRIES, cursor.getCount()); 816baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 826baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 836baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono Thread.sleep(DocumentLoader.NOTIFY_PERIOD_MS); 846baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mManager.unblockDocument(0, 15); 856baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mResolver.waitForNotification(uri, 1); 866baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 876baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono { 886baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono final Cursor cursor = mLoader.queryChildDocuments( 896baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier); 906baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono assertEquals( 916baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono DocumentLoader.NUM_INITIAL_ENTRIES + DocumentLoader.NUM_LOADING_ENTRIES, 926baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono cursor.getCount()); 936baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 946baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 956baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mManager.unblockDocument(0, 35); 966baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mResolver.waitForNotification(uri, 2); 976baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 986baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono { 996baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono final Cursor cursor = mLoader.queryChildDocuments( 1006baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier); 1016baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono assertEquals(40, cursor.getCount()); 1026baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 1036baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 1046baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono assertEquals(2, mResolver.getChangeCount(uri)); 1056baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 1066baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 107678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono public void testError_GetObjectHandles() throws Exception { 108678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono mManager = new BlockableTestMtpManager(getContext()) { 109678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono @Override 110678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle) 111678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono throws IOException { 112678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono throw new IOException(); 113678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono } 114678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono }; 115678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono setUpLoader(); 116678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono mManager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, null); 117678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono try { 118678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono try (final Cursor cursor = mLoader.queryChildDocuments( 119678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) {} 120678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono fail(); 121678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono } catch (IOException exception) { 122678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono // Expect exception. 123678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono } 124678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono } 125678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono 126678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono public void testError_GetObjectInfo() throws Exception { 127678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono mManager = new BlockableTestMtpManager(getContext()) { 128678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono @Override 129678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException { 130678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono if (objectHandle == DocumentLoader.NUM_INITIAL_ENTRIES) { 131678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono throw new IOException(); 132678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono } else { 133678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono return super.getObjectInfo(deviceId, objectHandle); 134678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono } 135678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono } 136678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono }; 137678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono setUpLoader(); 138678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono setUpDocument(mManager, DocumentLoader.NUM_INITIAL_ENTRIES); 139678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono try (final Cursor cursor = mLoader.queryChildDocuments( 140678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) { 141678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono // Even if MtpManager returns an error for a document, loading must complete. 142678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono assertFalse(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING)); 143678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono } 144678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono } 145678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono 1463edcde295326db07520ed5eedde087c24c16dfd0Daichi Hirono public void testCancelTask() throws IOException, InterruptedException, TimeoutException { 14776be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono setUpDocument(mManager, 1483edcde295326db07520ed5eedde087c24c16dfd0Daichi Hirono DocumentLoader.NUM_INITIAL_ENTRIES + 1); 14976be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono 15076be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono // Block the first iteration in the background thread. 15176be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono mManager.blockDocument( 15276be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono 0, DocumentLoader.NUM_INITIAL_ENTRIES + 1); 15376be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono setUpLoader(); 15476be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono try (final Cursor cursor = mLoader.queryChildDocuments( 15576be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) { 15676be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono assertTrue(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING)); 15776be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono } 1583edcde295326db07520ed5eedde087c24c16dfd0Daichi Hirono 1593edcde295326db07520ed5eedde087c24c16dfd0Daichi Hirono final Uri uri = DocumentsContract.buildChildDocumentsUri( 1603edcde295326db07520ed5eedde087c24c16dfd0Daichi Hirono MtpDocumentsProvider.AUTHORITY, mParentIdentifier.mDocumentId); 1613edcde295326db07520ed5eedde087c24c16dfd0Daichi Hirono assertEquals(0, mResolver.getChangeCount(uri)); 16276be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono 16376be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono // Clear task while the first iteration is being blocked. 1643edcde295326db07520ed5eedde087c24c16dfd0Daichi Hirono mLoader.cancelTask(mParentIdentifier); 16576be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono mManager.unblockDocument( 16676be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono 0, DocumentLoader.NUM_INITIAL_ENTRIES + 1); 1673edcde295326db07520ed5eedde087c24c16dfd0Daichi Hirono Thread.sleep(DocumentLoader.NOTIFY_PERIOD_MS); 1683edcde295326db07520ed5eedde087c24c16dfd0Daichi Hirono assertEquals(0, mResolver.getChangeCount(uri)); 16976be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono 17076be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono // Check if it's OK to query invalidated task. 17176be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono try (final Cursor cursor = mLoader.queryChildDocuments( 17276be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION, mParentIdentifier)) { 1733edcde295326db07520ed5eedde087c24c16dfd0Daichi Hirono assertTrue(cursor.getExtras().getBoolean(DocumentsContract.EXTRA_LOADING)); 17476be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono } 1753edcde295326db07520ed5eedde087c24c16dfd0Daichi Hirono mResolver.waitForNotification(uri, 1); 17676be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono } 17776be46f4d9314fd7daca0985a0a7e02126d85975Daichi Hirono 178678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono private void setUpLoader() { 179678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono mLoader = new DocumentLoader( 180678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono new MtpDeviceRecord( 181678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono 0, "Device", "Key", true, new MtpRoot[0], 182678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono TestUtil.OPERATIONS_SUPPORTED, new int[0]), 183678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono mManager, 184678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono mResolver, 185678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono mDatabase); 186678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono } 187678ed36bebb7b0f5ff342e9da30d693bffb8aeb2Daichi Hirono 1886baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono private void setUpDocument(TestMtpManager manager, int count) { 1896baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono int[] childDocuments = new int[count]; 1906baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono for (int i = 0; i < childDocuments.length; i++) { 1916baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono final int objectHandle = i + 1; 1926baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono childDocuments[i] = objectHandle; 193bb430fa930fa0d0700e46e7b4881de2a252223ddTomasz Mikolajewski manager.setObjectInfo(0, new MtpObjectInfo.Builder() 194bb430fa930fa0d0700e46e7b4881de2a252223ddTomasz Mikolajewski .setObjectHandle(objectHandle) 19547eb192b2704e27272ca94a95680cac40b6bff3fDaichi Hirono .setName(Integer.toString(i)) 196bb430fa930fa0d0700e46e7b4881de2a252223ddTomasz Mikolajewski .build()); 1976baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 1986baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments); 1996baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 2006baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 201bb430fa930fa0d0700e46e7b4881de2a252223ddTomasz Mikolajewski private static class BlockableTestMtpManager extends TestMtpManager { 2026baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono final private Map<String, CountDownLatch> blockedDocuments = new HashMap<>(); 2036baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 204bb430fa930fa0d0700e46e7b4881de2a252223ddTomasz Mikolajewski BlockableTestMtpManager(Context context) { 2056baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono super(context); 2066baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 2076baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 2086baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono void blockDocument(int deviceId, int objectHandle) { 2096baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono blockedDocuments.put(pack(deviceId, objectHandle), new CountDownLatch(1)); 2106baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 2116baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 2126baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono void unblockDocument(int deviceId, int objectHandle) { 2136baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono blockedDocuments.get(pack(deviceId, objectHandle)).countDown(); 2146baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 2156baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 2166baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono @Override 217bb430fa930fa0d0700e46e7b4881de2a252223ddTomasz Mikolajewski MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException { 2186baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono final CountDownLatch latch = blockedDocuments.get(pack(deviceId, objectHandle)); 2196baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono if (latch != null) { 2206baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono try { 2216baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono latch.await(); 2226baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } catch(InterruptedException e) { 2236baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono fail(); 2246baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 2256baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 226bb430fa930fa0d0700e46e7b4881de2a252223ddTomasz Mikolajewski return super.getObjectInfo(deviceId, objectHandle); 2276baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 2286baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 2296baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono} 230