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