Loading packages/MtpDocumentsProvider/res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -27,4 +27,6 @@ <string name="accessing_notification_description">Don\'t disconnect the device</string> <!-- Error message shown in Files app when the connected MTP device is busy. [CHAR LIMIT=150]--> <string name="error_busy_device">The other device is busy. You can\'t transfer files until it\'s available.</string> <!-- Error message shown in Files app when the connected MTP device may be locked. [CHAR LIMIT=150]--> <string name="error_locked_device">No files found. The other device may be locked. If so, unlock it and try again.</string> </resources> packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +11 −10 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.io.FileNotFoundException; import java.util.Objects; Loading Loading @@ -244,15 +245,16 @@ class MtpDatabase { } /** * Returns identifier of single storage if given document points device and it has only one * storage. Otherwise null. * Returns document IDs of storages under the given device document. * * @param documentId Document ID that may point a device. * @return Identifier for single storage or null. * @param documentId Document ID that points a device. * @return Storage document IDs. * @throws FileNotFoundException The given document ID is not registered in database. */ @Nullable Identifier getSingleStorageIdentifier(String documentId) String[] getStorageDocumentIds(String documentId) throws FileNotFoundException { Preconditions.checkArgument(createIdentifier(documentId).mDocumentType == DOCUMENT_TYPE_DEVICE); // Check if the parent document is device that has single storage. try (final Cursor cursor = mDatabase.query( TABLE_DOCUMENTS, Loading @@ -267,12 +269,11 @@ class MtpDatabase { null, null, null)) { if (cursor.getCount() == 1) { cursor.moveToNext(); return createIdentifier(cursor.getString(0)); } else { return null; final String[] ids = new String[cursor.getCount()]; for (int i = 0; cursor.moveToNext(); i++) { ids[i] = cursor.getString(0); } return ids; } } Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +26 −11 Original line number Diff line number Diff line Loading @@ -166,25 +166,25 @@ public class MtpDocumentsProvider extends DocumentsProvider { try { openDevice(parentIdentifier.mDeviceId); if (parentIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) { final Identifier singleStorageIdentifier = mDatabase.getSingleStorageIdentifier(parentDocumentId); if (singleStorageIdentifier == null) { final String[] storageDocIds = mDatabase.getStorageDocumentIds(parentDocumentId); if (storageDocIds.length == 0) { // Remote device does not provide storages. Maybe it is locked. return createErrorCursor(projection, R.string.error_locked_device); } else if (storageDocIds.length > 1) { // Returns storage list from database. return mDatabase.queryChildDocuments(projection, parentDocumentId); } parentIdentifier = singleStorageIdentifier; // Exact one storage is found. Skip storage and returns object in the single // storage. parentIdentifier = mDatabase.createIdentifier(storageDocIds[0]); } // Returns object list from document loader. return getDocumentLoader(parentIdentifier).queryChildDocuments( projection, parentIdentifier); } catch (BusyDeviceException exception) { final Bundle bundle = new Bundle(); bundle.putString( DocumentsContract.EXTRA_ERROR, mResources.getString(R.string.error_busy_device)); final Cursor cursor = new MatrixCursor(projection); cursor.setExtras(bundle); return cursor; return createErrorCursor(projection, R.string.error_busy_device); } catch (IOException exception) { Log.e(MtpDocumentsProvider.TAG, "queryChildDocuments", exception); throw new FileNotFoundException(exception.getMessage()); Loading Loading @@ -463,6 +463,21 @@ public class MtpDocumentsProvider extends DocumentsProvider { } } /** * Creates empty cursor with specific error message. * * @param projection Column names. * @param stringResId String resource ID of error message. * @return Empty cursor with error message. */ private Cursor createErrorCursor(String[] projection, int stringResId) { final Bundle bundle = new Bundle(); bundle.putString(DocumentsContract.EXTRA_ERROR, mResources.getString(stringResId)); final Cursor cursor = new MatrixCursor(projection); cursor.setExtras(bundle); return cursor; } private static class DeviceToolkit { public final PipeManager mPipeManager; public final DocumentLoader mDocumentLoader; Loading packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java +20 −0 Original line number Diff line number Diff line Loading @@ -554,6 +554,26 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { } } public void testLockedDevice() throws Exception { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); mMtpManager.addValidDevice(new MtpDeviceRecord( 0, "Device A", false /* unopened */, new MtpRoot[0], null, null)); mProvider.resumeRootScanner(); mResolver.waitForNotification(ROOTS_URI, 1); try (final Cursor cursor = mProvider.queryRoots(null)) { assertEquals(1, cursor.getCount()); } try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) { assertEquals(0, cursor.getCount()); assertEquals( "error_locked_device", cursor.getExtras().getString(DocumentsContract.EXTRA_ERROR)); } } private void setupProvider(int flag) { mDatabase = new MtpDatabase(getContext(), flag); mProvider = new MtpDocumentsProvider(); Loading packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java +2 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ class TestResources extends MockResources { return "%1$s %2$s"; case R.string.error_busy_device: return "error_busy_device"; case R.string.error_locked_device: return "error_locked_device"; } throw new NotFoundException(); } Loading Loading
packages/MtpDocumentsProvider/res/values/strings.xml +2 −0 Original line number Diff line number Diff line Loading @@ -27,4 +27,6 @@ <string name="accessing_notification_description">Don\'t disconnect the device</string> <!-- Error message shown in Files app when the connected MTP device is busy. [CHAR LIMIT=150]--> <string name="error_busy_device">The other device is busy. You can\'t transfer files until it\'s available.</string> <!-- Error message shown in Files app when the connected MTP device may be locked. [CHAR LIMIT=150]--> <string name="error_locked_device">No files found. The other device may be locked. If so, unlock it and try again.</string> </resources>
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java +11 −10 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.io.FileNotFoundException; import java.util.Objects; Loading Loading @@ -244,15 +245,16 @@ class MtpDatabase { } /** * Returns identifier of single storage if given document points device and it has only one * storage. Otherwise null. * Returns document IDs of storages under the given device document. * * @param documentId Document ID that may point a device. * @return Identifier for single storage or null. * @param documentId Document ID that points a device. * @return Storage document IDs. * @throws FileNotFoundException The given document ID is not registered in database. */ @Nullable Identifier getSingleStorageIdentifier(String documentId) String[] getStorageDocumentIds(String documentId) throws FileNotFoundException { Preconditions.checkArgument(createIdentifier(documentId).mDocumentType == DOCUMENT_TYPE_DEVICE); // Check if the parent document is device that has single storage. try (final Cursor cursor = mDatabase.query( TABLE_DOCUMENTS, Loading @@ -267,12 +269,11 @@ class MtpDatabase { null, null, null)) { if (cursor.getCount() == 1) { cursor.moveToNext(); return createIdentifier(cursor.getString(0)); } else { return null; final String[] ids = new String[cursor.getCount()]; for (int i = 0; cursor.moveToNext(); i++) { ids[i] = cursor.getString(0); } return ids; } } Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +26 −11 Original line number Diff line number Diff line Loading @@ -166,25 +166,25 @@ public class MtpDocumentsProvider extends DocumentsProvider { try { openDevice(parentIdentifier.mDeviceId); if (parentIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) { final Identifier singleStorageIdentifier = mDatabase.getSingleStorageIdentifier(parentDocumentId); if (singleStorageIdentifier == null) { final String[] storageDocIds = mDatabase.getStorageDocumentIds(parentDocumentId); if (storageDocIds.length == 0) { // Remote device does not provide storages. Maybe it is locked. return createErrorCursor(projection, R.string.error_locked_device); } else if (storageDocIds.length > 1) { // Returns storage list from database. return mDatabase.queryChildDocuments(projection, parentDocumentId); } parentIdentifier = singleStorageIdentifier; // Exact one storage is found. Skip storage and returns object in the single // storage. parentIdentifier = mDatabase.createIdentifier(storageDocIds[0]); } // Returns object list from document loader. return getDocumentLoader(parentIdentifier).queryChildDocuments( projection, parentIdentifier); } catch (BusyDeviceException exception) { final Bundle bundle = new Bundle(); bundle.putString( DocumentsContract.EXTRA_ERROR, mResources.getString(R.string.error_busy_device)); final Cursor cursor = new MatrixCursor(projection); cursor.setExtras(bundle); return cursor; return createErrorCursor(projection, R.string.error_busy_device); } catch (IOException exception) { Log.e(MtpDocumentsProvider.TAG, "queryChildDocuments", exception); throw new FileNotFoundException(exception.getMessage()); Loading Loading @@ -463,6 +463,21 @@ public class MtpDocumentsProvider extends DocumentsProvider { } } /** * Creates empty cursor with specific error message. * * @param projection Column names. * @param stringResId String resource ID of error message. * @return Empty cursor with error message. */ private Cursor createErrorCursor(String[] projection, int stringResId) { final Bundle bundle = new Bundle(); bundle.putString(DocumentsContract.EXTRA_ERROR, mResources.getString(stringResId)); final Cursor cursor = new MatrixCursor(projection); cursor.setExtras(bundle); return cursor; } private static class DeviceToolkit { public final PipeManager mPipeManager; public final DocumentLoader mDocumentLoader; Loading
packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java +20 −0 Original line number Diff line number Diff line Loading @@ -554,6 +554,26 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { } } public void testLockedDevice() throws Exception { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); mMtpManager.addValidDevice(new MtpDeviceRecord( 0, "Device A", false /* unopened */, new MtpRoot[0], null, null)); mProvider.resumeRootScanner(); mResolver.waitForNotification(ROOTS_URI, 1); try (final Cursor cursor = mProvider.queryRoots(null)) { assertEquals(1, cursor.getCount()); } try (final Cursor cursor = mProvider.queryChildDocuments("1", null, null)) { assertEquals(0, cursor.getCount()); assertEquals( "error_locked_device", cursor.getExtras().getString(DocumentsContract.EXTRA_ERROR)); } } private void setupProvider(int flag) { mDatabase = new MtpDatabase(getContext(), flag); mProvider = new MtpDocumentsProvider(); Loading
packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java +2 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ class TestResources extends MockResources { return "%1$s %2$s"; case R.string.error_busy_device: return "error_busy_device"; case R.string.error_locked_device: return "error_locked_device"; } throw new NotFoundException(); } Loading