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

Commit 6eed9a23 authored by Daichi Hirono's avatar Daichi Hirono Committed by Android (Google) Code Review
Browse files

Merge "Implement MtpDocumentsProvider#queryChildDocuemnts."

parents dac5a13f 124d060b
Loading
Loading
Loading
Loading
+22 −34
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.mtp;

import android.database.MatrixCursor;
import android.mtp.MtpObjectInfo;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
@@ -67,11 +68,29 @@ class MtpDocument {
        this.mThumbSize = thumbSize;
    }

    int getSize() {
        return mSize;
    void addToCursor(Identifier rootIdentifier, MatrixCursor.RowBuilder builder) {
        final Identifier identifier = new Identifier(
                rootIdentifier.mDeviceId, rootIdentifier.mStorageId, mObjectHandle);

        int flag = 0;
        if (mObjectHandle != DUMMY_HANDLE_FOR_ROOT) {
            flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE;
            if (mThumbSize > 0) {
                flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
            }
        }

    String getMimeType() {
        builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
        builder.add(Document.COLUMN_DISPLAY_NAME, mName);
        builder.add(Document.COLUMN_MIME_TYPE, getMimeType());
        builder.add(
                Document.COLUMN_LAST_MODIFIED,
                mDateModified != null ? mDateModified.getTime() : null);
        builder.add(Document.COLUMN_FLAGS, flag);
        builder.add(Document.COLUMN_SIZE, mSize);
    }

    private String getMimeType() {
        // TODO: Add complete list of mime types.
        switch (mFormat) {
            case 0x3001:
@@ -84,35 +103,4 @@ class MtpDocument {
                return "";
        }
    }

    Object[] getRow(Identifier rootIdentifier, String[] columnNames) {
        final Object[] rows = new Object[columnNames.length];
        for (int i = 0; i < columnNames.length; i++) {
            if (Document.COLUMN_DOCUMENT_ID.equals(columnNames[i])) {
                final Identifier identifier = new Identifier(
                        rootIdentifier.mDeviceId, rootIdentifier.mStorageId, mObjectHandle);
                rows[i] = identifier.toDocumentId();
            } else if (Document.COLUMN_DISPLAY_NAME.equals(columnNames[i])) {
                rows[i] = mName;
            } else if (Document.COLUMN_MIME_TYPE.equals(columnNames[i])) {
                rows[i] = getMimeType();
            } else if (Document.COLUMN_LAST_MODIFIED.equals(columnNames[i])) {
                rows[i] = mDateModified != null ? mDateModified.getTime() : null;
            } else if (Document.COLUMN_FLAGS.equals(columnNames[i])) {
                int flag = 0;
                if (mObjectHandle != DUMMY_HANDLE_FOR_ROOT) {
                    flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE;
                    if (mThumbSize > 0) {
                        flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
                    }
                }
                rows[i] = flag;
            } else if (Document.COLUMN_SIZE.equals(columnNames[i])) {
                rows[i] = mSize;
            } else {
                rows[i] = null;
            }
        }
        return rows;
    }
}
+35 −9
Original line number Diff line number Diff line
@@ -147,17 +147,45 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        }

        final MatrixCursor cursor = new MatrixCursor(projection);
        cursor.addRow(document.getRow(
                new Identifier(identifier.mDeviceId, identifier.mStorageId),
                projection));
        document.addToCursor(
                new Identifier(identifier.mDeviceId, identifier.mStorageId), cursor.newRow());
        return cursor;
    }

    // TODO: Support background loading for large number of files.
    @Override
    public Cursor queryChildDocuments(
            String parentDocumentId, String[] projection, String sortOrder)
                    throws FileNotFoundException {
        throw new FileNotFoundException();
    public Cursor queryChildDocuments(String parentDocumentId,
            String[] projection, String sortOrder) throws FileNotFoundException {
        if (projection == null) {
            projection = MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION;
        }
        final Identifier parentIdentifier = Identifier.createFromDocumentId(parentDocumentId);
        int parentHandle = parentIdentifier.mObjectHandle;
        // Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
        // getObjectHandles if we would like to obtain children under the root.
        if (parentHandle == MtpDocument.DUMMY_HANDLE_FOR_ROOT) {
            parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
        }
        try {
            final MatrixCursor cursor = new MatrixCursor(projection);
            final Identifier rootIdentifier = new Identifier(
                    parentIdentifier.mDeviceId, parentIdentifier.mStorageId);
            final int[] objectHandles = mMtpManager.getObjectHandles(
                    parentIdentifier.mDeviceId, parentIdentifier.mStorageId, parentHandle);
            for (int i = 0; i < objectHandles.length; i++) {
                try {
                    final MtpDocument document = mMtpManager.getDocument(
                            parentIdentifier.mDeviceId,  objectHandles[i]);
                    document.addToCursor(rootIdentifier, cursor.newRow());
                } catch (IOException error) {
                    cursor.close();
                    throw new FileNotFoundException(error.getMessage());
                }
            }
            return cursor;
        } catch (IOException exception) {
            throw new FileNotFoundException(exception.getMessage());
        }
    }

    @Override
@@ -170,8 +198,6 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        }
        final Identifier identifier = Identifier.createFromDocumentId(documentId);
        try {
            final MtpDocument document =
                    mMtpManager.getDocument(identifier.mDeviceId, identifier.mObjectHandle);
            return mPipeManager.readDocument(mMtpManager, identifier);
        } catch (IOException error) {
            throw new FileNotFoundException(error.getMessage());
+8 −0
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ import java.io.IOException;
 * The model wrapping android.mtp API.
 */
class MtpManager {
    final static int OBJECT_HANDLE_ROOT_CHILDREN = -1;

    private final UsbManager mManager;
    // TODO: Save and restore the set of opened device.
    private final SparseArray<MtpDevice> mDevices = new SparseArray<MtpDevice>();
@@ -105,6 +107,12 @@ class MtpManager {
        return new MtpDocument(device.getObjectInfo(objectHandle));
    }

    synchronized int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
            throws IOException {
        final MtpDevice device = getDevice(deviceId);
        return device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle);
    }

    synchronized byte[] getObject(int deviceId, int objectHandle, int expectedSize)
            throws IOException {
        final MtpDevice device = getDevice(deviceId);
+48 −1
Original line number Diff line number Diff line
@@ -217,6 +217,53 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
        assertEquals(3072, cursor.getInt(5));
    }

    public void testQueryChildDocuments() throws Exception {
        mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });

        mMtpManager.setDocument(0, 1, new MtpDocument(
                1 /* object handle */,
                0x3801 /* JPEG */,
                "image.jpg" /* display name */,
                new Date(0) /* modified date */,
                1024 * 1024 * 5 /* file size */,
                1024 * 50 /* thumbnail size */));

        final Cursor cursor = mProvider.queryChildDocuments("0_0_0", null, null);
        assertEquals(1, cursor.getCount());

        assertTrue(cursor.moveToNext());
        assertEquals("0_0_1", cursor.getString(0));
        assertEquals("image/jpeg", cursor.getString(1));
        assertEquals("image.jpg", cursor.getString(2));
        assertEquals(0, cursor.getLong(3));
        assertEquals(
                DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
                DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL,
                cursor.getInt(4));
        assertEquals(1024 * 1024 * 5, cursor.getInt(5));

        assertFalse(cursor.moveToNext());
    }

    public void testQueryChildDocuments_cursorError() throws Exception {
        try {
            mProvider.queryChildDocuments("0_0_0", null, null);
            fail();
        } catch (Throwable error) {
            assertTrue(error instanceof FileNotFoundException);
        }
    }

    public void testQueryChildDocuments_documentError() throws Exception {
        mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
        try {
            mProvider.queryChildDocuments("0_0_0", null, null);
            fail();
        } catch (Throwable error) {
            assertTrue(error instanceof FileNotFoundException);
        }
    }

    public void testDeleteDocument() throws FileNotFoundException {
        mMtpManager.setDocument(0, 1, new MtpDocument(
                1 /* object handle */,
@@ -232,7 +279,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
                        MtpDocumentsProvider.AUTHORITY, "0_0_2")));
    }

    public void testDeleteDocument_error() throws FileNotFoundException {
    public void testDeleteDocument_error() {
        mMtpManager.setParent(0, 1, 2);
        try {
            mProvider.deleteDocument("0_0_1");
+29 −9
Original line number Diff line number Diff line
@@ -32,13 +32,14 @@ public class TestMtpManager extends MtpManager {
        return Arrays.toString(args);
    }

    private final Set<Integer> mValidDevices = new HashSet<Integer>();
    private final Set<Integer> mOpenedDevices = new TreeSet<Integer>();
    private final Map<Integer, MtpRoot[]> mRoots = new HashMap<Integer, MtpRoot[]>();
    private final Map<String, MtpDocument> mDocuments = new HashMap<String, MtpDocument>();
    private final Map<String, byte[]> mThumbnailBytes = new HashMap<String, byte[]>();
    private final Map<String, Integer> mParents = new HashMap<String, Integer>();
    private final Map<String, byte[]> mImportFileBytes = new HashMap<String, byte[]>();
    private final Set<Integer> mValidDevices = new HashSet<>();
    private final Set<Integer> mOpenedDevices = new TreeSet<>();
    private final Map<Integer, MtpRoot[]> mRoots = new HashMap<>();
    private final Map<String, MtpDocument> mDocuments = new HashMap<>();
    private final Map<String, int[]> mObjectHandles = new HashMap<>();
    private final Map<String, byte[]> mThumbnailBytes = new HashMap<>();
    private final Map<String, Integer> mParents = new HashMap<>();
    private final Map<String, byte[]> mImportFileBytes = new HashMap<>();

    TestMtpManager(Context context) {
        super(context);
@@ -48,6 +49,10 @@ public class TestMtpManager extends MtpManager {
        mValidDevices.add(deviceId);
    }

    void setObjectHandles(int deviceId, int storageId, int objectHandle, int[] documents) {
        mObjectHandles.put(pack(deviceId, storageId, objectHandle), documents);
    }

    void setRoots(int deviceId, MtpRoot[] roots) {
        mRoots.put(deviceId, roots);
    }
@@ -94,8 +99,23 @@ public class TestMtpManager extends MtpManager {
    }

    @Override
    MtpDocument getDocument(int deviceId, int objectHandle) {
        return mDocuments.get(pack(deviceId, objectHandle));
    MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
        final String key = pack(deviceId, objectHandle);
        if (mDocuments.containsKey(key)) {
            return mDocuments.get(key);
        } else {
            throw new IOException("getDocument error: " + key);
        }
    }

    @Override
    int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle) throws IOException {
        final String key = pack(deviceId, storageId, parentObjectHandle);
        if (mObjectHandles.containsKey(key)) {
            return mObjectHandles.get(key);
        } else {
            throw new IOException("getObjectHandles error: " + key);
        }
    }

    @Override