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

Commit 66fcb4be authored by Daichi Hirono's avatar Daichi Hirono
Browse files

Fix doc flag for device having multiple storages

Previously MtpDocumentsProvider#queryDocument returned
FLAG_DIR_SUPPORTS_CREATE for device having multiple storages.

This was wrong because if the device has multiple storages,
MtpDocumentsProvider places the storages under the device document, thus
users cannot create a document just under the device document.

Bug: 35700994
Test: MtpDocumentsProviderTests
Change-Id: Id73a34a2eaf4e10e23be3c2da7488036cea10000
parent 21689ed8
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -200,10 +200,7 @@ class MtpDatabase {
                    storageCursor.close();
                }

                final RowBuilder row = result.newRow();
                for (final String key : values.keySet()) {
                    row.add(key, values.get(key));
                }
                putValuesToCursor(values, result);
            }

            return result;
@@ -760,7 +757,9 @@ class MtpDatabase {
                Document.MIME_TYPE_DIR,
                0,
                MtpConstants.PROTECTION_STATUS_NONE,
                DOCUMENT_TYPE_DEVICE));
                // Storages are placed under device so we cannot create a document just under
                // device.
                DOCUMENT_TYPE_DEVICE) & ~Document.FLAG_DIR_SUPPORTS_CREATE);
        values.putNull(Document.COLUMN_SIZE);

        extraValues.clear();
@@ -915,6 +914,13 @@ class MtpDatabase {
        return results;
    }

    static void putValuesToCursor(ContentValues values, MatrixCursor cursor) {
        final RowBuilder row = cursor.newRow();
        for (final String name : cursor.getColumnNames()) {
            row.add(values.get(name));
        }
    }

    private static String getIdList(Set<String> ids) {
        String result = "(";
        for (final String id : ids) {
+53 −2
Original line number Diff line number Diff line
@@ -17,11 +17,13 @@
package com.android.mtp;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriPermission;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDiskIOException;
import android.graphics.Point;
@@ -55,7 +57,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;

import libcore.io.IoUtils;

/**
@@ -177,9 +178,59 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        if (projection == null) {
            projection = MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION;
        }
        final Cursor cursor = mDatabase.queryDocument(documentId, projection);
        final int cursorCount = cursor.getCount();
        if (cursorCount == 0) {
            cursor.close();
            throw new FileNotFoundException();
        } else if (cursorCount != 1) {
            cursor.close();
            Log.wtf(TAG, "Unexpected cursor size: " + cursorCount);
            return null;
        }

        final Identifier identifier = mDatabase.createIdentifier(documentId);
        if (identifier.mDocumentType != MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) {
            return cursor;
        }
        final String[] storageDocIds = mDatabase.getStorageDocumentIds(documentId);
        if (storageDocIds.length != 1) {
            return mDatabase.queryDocument(documentId, projection);
        }

        // If the documentId specifies a device having exact one storage, we repalce some device
        // attributes with the storage attributes.
        try {
            final String storageName;
            final int storageFlags;
            try (final Cursor storageCursor = mDatabase.queryDocument(
                    storageDocIds[0],
                    MtpDatabase.strings(Document.COLUMN_DISPLAY_NAME, Document.COLUMN_FLAGS))) {
                if (!storageCursor.moveToNext()) {
                    throw new FileNotFoundException();
                }
                storageName = storageCursor.getString(0);
                storageFlags = storageCursor.getInt(1);
            }

            cursor.moveToNext();
            final ContentValues values = new ContentValues();
            DatabaseUtils.cursorRowToContentValues(cursor, values);
            if (values.containsKey(Document.COLUMN_DISPLAY_NAME)) {
                values.put(Document.COLUMN_DISPLAY_NAME, mResources.getString(
                        R.string.root_name,
                        values.getAsString(Document.COLUMN_DISPLAY_NAME),
                        storageName));
            }
            values.put(Document.COLUMN_FLAGS, storageFlags);
            final MatrixCursor output = new MatrixCursor(projection, 1);
            MtpDatabase.putValuesToCursor(values, output);
            return output;
        } finally {
            cursor.close();
        }
    }

    @Override
    public Cursor queryChildDocuments(String parentDocumentId,
            String[] projection, String sortOrder) throws FileNotFoundException {
+56 −1
Original line number Diff line number Diff line
@@ -368,7 +368,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
        assertEquals(0, cursor.getInt(5));
    }

    public void testQueryDocument_forRoot()
    public void testQueryDocument_forStorage()
            throws IOException, InterruptedException, TimeoutException {
        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
        setupRoots(0, new MtpRoot[] {
@@ -392,6 +392,61 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
        assertEquals(3072, cursor.getInt(5));
    }

    public void testQueryDocument_forDeviceWithSingleStorage()
            throws IOException, InterruptedException, TimeoutException {
        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
        setupRoots(0, new MtpRoot[] {
                new MtpRoot(
                        0 /* deviceId */,
                        1 /* storageId */,
                        "Storage A" /* volume description */,
                        1024 /* free space */,
                        4096 /* total space */,
                        "" /* no volume identifier */)
        });
        final Cursor cursor = mProvider.queryDocument("1", null);
        assertEquals(1, cursor.getCount());

        cursor.moveToNext();
        assertEquals("1", cursor.getString(0));
        assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1));
        assertEquals("Device Storage A", cursor.getString(2));
        assertTrue(cursor.isNull(3));
        assertEquals(DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE, cursor.getInt(4));
        assertTrue(cursor.isNull(5));
    }

    public void testQueryDocument_forDeviceWithTwoStorages()
            throws IOException, InterruptedException, TimeoutException {
        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
        setupRoots(0, new MtpRoot[] {
                new MtpRoot(
                        0 /* deviceId */,
                        1 /* storageId */,
                        "Storage A" /* volume description */,
                        1024 /* free space */,
                        4096 /* total space */,
                        "" /* no volume identifier */),
                new MtpRoot(
                        0 /* deviceId */,
                        2 /* storageId */,
                        "Storage B" /* volume description */,
                        1024 /* free space */,
                        4096 /* total space */,
                        "" /* no volume identifier */)
        });
        final Cursor cursor = mProvider.queryDocument("1", null);
        assertEquals(1, cursor.getCount());

        cursor.moveToNext();
        assertEquals("1", cursor.getString(0));
        assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1));
        assertEquals("Device", cursor.getString(2));
        assertTrue(cursor.isNull(3));
        assertEquals(0, cursor.getInt(4));
        assertTrue(cursor.isNull(5));
    }

    public void testQueryChildDocuments() throws Exception {
        setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
        setupRoots(0, new MtpRoot[] { new MtpRoot(0, 0, "Storage", 1000, 1000, "") });