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

Commit 3faa43a4 authored by Daichi Hirono's avatar Daichi Hirono
Browse files

Implement MtpDocumentsProvider#openDocumentThumbnail.

BUG=20274999
Change-Id: I4ee43d94d92735e07786dfe557eaca69e8bff6c3
parent ebcfc90c
Loading
Loading
Loading
Loading
+32 −14
Original line number Diff line number Diff line
@@ -17,8 +17,10 @@
package com.android.mtp;

import android.content.ContentResolver;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.graphics.Point;
import android.os.CancellationSignal;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract;
@@ -176,6 +178,36 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        }
    }

    @Override
    public AssetFileDescriptor openDocumentThumbnail(
            String documentId,
            Point sizeHint,
            CancellationSignal signal) throws FileNotFoundException {
        final Identifier identifier = Identifier.createFromDocumentId(documentId);
        try {
            return new AssetFileDescriptor(
                    mPipeManager.readThumbnail(mMtpManager, identifier),
                    0,
                    AssetFileDescriptor.UNKNOWN_LENGTH);
        } catch (IOException error) {
            throw new FileNotFoundException(error.getMessage());
        }
    }

    @Override
    public void deleteDocument(String documentId) throws FileNotFoundException {
        try {
            final Identifier identifier = Identifier.createFromDocumentId(documentId);
            final int parentHandle =
                    mMtpManager.getParent(identifier.mDeviceId, identifier.mObjectHandle);
            mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
            notifyChildDocumentsChange(new Identifier(
                    identifier.mDeviceId, identifier.mStorageId, parentHandle).toDocumentId());
        } catch (IOException error) {
            throw new FileNotFoundException(error.getMessage());
        }
    }

    void openDevice(int deviceId) throws IOException {
        mMtpManager.openDevice(deviceId);
        notifyRootsChange();
@@ -201,20 +233,6 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        }
    }

    @Override
    public void deleteDocument(String documentId) throws FileNotFoundException {
        try {
            final Identifier identifier = Identifier.createFromDocumentId(documentId);
            final int parentHandle =
                    mMtpManager.getParent(identifier.mDeviceId, identifier.mObjectHandle);
            mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
            notifyChildDocumentsChange(new Identifier(
                    identifier.mDeviceId, identifier.mStorageId, parentHandle).toDocumentId());
        } catch (IOException error) {
            throw new FileNotFoundException(error.getMessage());
        }
    }

    boolean hasOpenedDevices() {
        return mMtpManager.getOpenedDeviceIds().length != 0;
    }
+5 −0
Original line number Diff line number Diff line
@@ -111,6 +111,11 @@ class MtpManager {
        return device.getObject(objectHandle, expectedSize);
    }

    synchronized byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
        final MtpDevice device = getDevice(deviceId);
        return device.getThumbnail(objectHandle);
    }

    synchronized void deleteDocument(int deviceId, int objectHandle) throws IOException {
        final MtpDevice device = getDevice(deviceId);
        if (!device.deleteObject(objectHandle)) {
+32 −4
Original line number Diff line number Diff line
@@ -34,14 +34,18 @@ class PipeManager {
        this.mExecutor = executor;
    }

    ParcelFileDescriptor readDocument(
            final MtpManager model,
            final Identifier identifier) throws IOException {
    ParcelFileDescriptor readDocument(MtpManager model, Identifier identifier) throws IOException {
        final Task task = new ImportFileTask(model, identifier);
        mExecutor.execute(task);
        return task.getReadingFileDescriptor();
    }

    ParcelFileDescriptor readThumbnail(MtpManager model, Identifier identifier) throws IOException {
        final Task task = new GetThumbnailTask(model, identifier);
        mExecutor.execute(task);
        return task.getReadingFileDescriptor();
    }

    private static abstract class Task implements Runnable {
        protected final MtpManager mModel;
        protected final Identifier mIdentifier;
@@ -66,7 +70,8 @@ class PipeManager {
        @Override
        public void run() {
            try {
                mModel.importFile(mIdentifier.mDeviceId, mIdentifier.mObjectHandle, mDescriptors[1]);
                mModel.importFile(
                        mIdentifier.mDeviceId, mIdentifier.mObjectHandle, mDescriptors[1]);
                mDescriptors[1].close();
            } catch (IOException error) {
                try {
@@ -78,6 +83,29 @@ class PipeManager {
        }
    }

    private static class GetThumbnailTask extends Task {
        GetThumbnailTask(MtpManager model, Identifier identifier) throws IOException {
            super(model, identifier);
        }

        @Override
        public void run() {
            try {
                try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
                        new ParcelFileDescriptor.AutoCloseOutputStream(mDescriptors[1])) {
                    try {
                        stream.write(mModel.getThumbnail(
                                mIdentifier.mDeviceId, mIdentifier.mObjectHandle));
                    } catch (IOException error) {
                        mDescriptors[1].closeWithError("Failed to stream a thumbnail.");
                    }
                }
            } catch (IOException closeError) {
                Log.w(MtpDocumentsProvider.TAG, closeError.getMessage());
            }
        }
    }

    void close() {
        mExecutor.shutdown();
    }
+42 −12
Original line number Diff line number Diff line
@@ -27,17 +27,51 @@ import java.util.concurrent.TimeUnit;

@SmallTest
public class PipeManagerTest extends AndroidTestCase {
    private static final byte[] HELLO_BYTES = new byte[] { 'h', 'e', 'l', 'l', 'o' };

    private TestMtpManager mtpManager;
    private ExecutorService executor;
    private PipeManager pipeManager;

    @Override
    public void setUp() {
        mtpManager = new TestMtpManager(getContext());
        executor = Executors.newSingleThreadExecutor();
        pipeManager = new PipeManager(executor);
    }

    public void testReadDocument_basic() throws Exception {
        final TestMtpManager mtpManager = new TestMtpManager(getContext());
        final byte[] expectedBytes = new byte[] { 'h', 'e', 'l', 'l', 'o' };
        mtpManager.setImportFileBytes(0, 1, expectedBytes);
        final ExecutorService executor = Executors.newSingleThreadExecutor();
        final PipeManager pipeManager = new PipeManager(executor);
        mtpManager.setImportFileBytes(0, 1, HELLO_BYTES);
        final ParcelFileDescriptor descriptor = pipeManager.readDocument(
                mtpManager, new Identifier(0, 0, 1));
        assertDescriptor(descriptor, HELLO_BYTES);
    }

    public void testReadDocument_error() throws Exception {
        final ParcelFileDescriptor descriptor =
                pipeManager.readDocument(mtpManager, new Identifier(0, 0, 1));
        assertDescriptorError(descriptor);
    }

    public void testReadThumbnail_basic() throws Exception {
        mtpManager.setThumbnail(0, 1, HELLO_BYTES);
        final ParcelFileDescriptor descriptor = pipeManager.readThumbnail(
                mtpManager, new Identifier(0, 0, 1));
        assertDescriptor(descriptor, HELLO_BYTES);
    }

    public void testReadThumbnail_error() throws Exception {
        final ParcelFileDescriptor descriptor =
                pipeManager.readThumbnail(mtpManager, new Identifier(0, 0, 1));
        assertDescriptorError(descriptor);
    }

    private void assertDescriptor(ParcelFileDescriptor descriptor, byte[] expectedBytes)
            throws IOException, InterruptedException {
        executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
        try (final ParcelFileDescriptor.AutoCloseInputStream stream =
                new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) {
            final byte[] results = new byte[100];
            byte[] results = new byte[100];
            assertEquals(expectedBytes.length, stream.read(results));
            for (int i = 0; i < expectedBytes.length; i++) {
                assertEquals(expectedBytes[i], results[i]);
@@ -45,12 +79,8 @@ public class PipeManagerTest extends AndroidTestCase {
        }
    }

    public void testReadDocument_error() throws Exception {
        final TestMtpManager mtpManager = new TestMtpManager(getContext());
        final ExecutorService executor = Executors.newSingleThreadExecutor();
        final PipeManager pipeManager = new PipeManager(executor);
        final ParcelFileDescriptor descriptor =
                pipeManager.readDocument(mtpManager, new Identifier(0, 0, 1));
    private void assertDescriptorError(ParcelFileDescriptor descriptor)
            throws InterruptedException {
        executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
        try {
            descriptor.checkError();
+15 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ public class TestMtpManager extends MtpManager {
    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[]>();

@@ -59,6 +60,10 @@ public class TestMtpManager extends MtpManager {
        mImportFileBytes.put(pack(deviceId, objectHandle), bytes);
    }

    void setThumbnail(int deviceId, int objectHandle, byte[] bytes) {
        mThumbnailBytes.put(pack(deviceId, objectHandle), bytes);
    }

    void setParent(int deviceId, int objectHandle, int parentObjectHandle) {
        mParents.put(pack(deviceId, objectHandle), parentObjectHandle);
    }
@@ -106,6 +111,16 @@ public class TestMtpManager extends MtpManager {
        }
    }

    @Override
    byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
        final String key = pack(deviceId, objectHandle);
        if (mThumbnailBytes.containsKey(key)) {
            return mThumbnailBytes.get(key);
        } else {
            throw new IOException("getThumbnail error: " + key);
        }
    }

    @Override
    void deleteDocument(int deviceId, int objectHandle) throws IOException {
        final String key = pack(deviceId, objectHandle);