Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2965776b authored by Daichi Hirono's avatar Daichi Hirono
Browse files

Add error message for locked device.

If the remote MTP device is a smartphone, it does not provide files
until a user unlocks the device. The CL adds specific error message for
the situation.

BUG=26318917

Change-Id: Ic4c34609c55ec9c99b7b8a9143d6dae3835784e3
parent c18f8076
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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>
+11 −10
Original line number Diff line number Diff line
@@ -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;
@@ -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,
@@ -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;
        }
    }

+26 −11
Original line number Diff line number Diff line
@@ -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());
@@ -453,6 +453,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;
+20 −0
Original line number Diff line number Diff line
@@ -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();
+2 −0
Original line number Diff line number Diff line
@@ -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();
    }