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

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

Merge "Implement MtpDocuments#openDocument."

parents aa711e17 8ba41911
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -67,6 +67,10 @@ class MtpDocument {
        this.mThumbSize = thumbSize;
    }

    int getSize() {
        return mSize;
    }

    String getMimeType() {
        // TODO: Add complete list of mime types.
        switch (mFormat) {
+19 −6
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {

    private MtpManager mMtpManager;
    private ContentResolver mResolver;
    private PipeManager mPipeManager;

    /**
     * Provides singleton instance to MtpDocumentsService.
@@ -66,6 +67,8 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        sSingleton = this;
        mMtpManager = new MtpManager(getContext());
        mResolver = getContext().getContentResolver();
        mPipeManager = new PipeManager();

        return true;
    }

@@ -156,9 +159,21 @@ public class MtpDocumentsProvider extends DocumentsProvider {
    }

    @Override
    public ParcelFileDescriptor openDocument(String documentId, String mode,
            CancellationSignal signal) throws FileNotFoundException {
        throw new FileNotFoundException();
    public ParcelFileDescriptor openDocument(
            String documentId, String mode, CancellationSignal signal)
                    throws FileNotFoundException {
        if (!"r".equals(mode) && !"w".equals(mode)) {
            // TODO: Support seekable file.
            throw new UnsupportedOperationException("The provider does not support seekable file.");
        }
        final Identifier identifier = Identifier.createFromDocumentId(documentId);
        try {
            final MtpDocument document =
                    mMtpManager.getDocument(identifier.mDeviceId, identifier.mObjectHandle);
            return mPipeManager.readDocument(mMtpManager, identifier, document.getSize());
        } catch (IOException error) {
            throw new FileNotFoundException(error.getMessage());
        }
    }

    void openDevice(int deviceId) throws IOException {
@@ -192,8 +207,6 @@ public class MtpDocumentsProvider extends DocumentsProvider {

    private void notifyRootsChange() {
        mResolver.notifyChange(
                DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY),
                null,
                false);
                DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY), null, false);
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -103,6 +103,12 @@ class MtpManager {
        return new MtpDocument(device.getObjectInfo(objectHandle));
    }

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

    private MtpDevice getDevice(int deviceId) throws IOException {
        final MtpDevice device = mDevices.get(deviceId);
        if (device == null) {
+86 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.mtp;

import android.os.ParcelFileDescriptor;
import android.util.Log;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class PipeManager {
    final ExecutorService mExecutor;

    PipeManager() {
        this(Executors.newCachedThreadPool());
    }

    PipeManager(ExecutorService executor) {
        this.mExecutor = executor;
    }

    ParcelFileDescriptor readDocument(
            final MtpManager model,
            final Identifier identifier,
            final int expectedSize) throws IOException {
        final Task task = new Task() {
            @Override
            byte[] getBytes() throws IOException {
                // TODO: Use importFile to ParcelFileDescripter after implementing this.
                return model.getObject(
                        identifier.mDeviceId, identifier.mObjectHandle, expectedSize);
            }
        };
        mExecutor.execute(task);
        return task.getReadingFileDescriptor();
    }

    private static abstract class Task implements Runnable {
        private final ParcelFileDescriptor[] mDescriptors;

        Task() throws IOException {
            mDescriptors = ParcelFileDescriptor.createReliablePipe();
        }

        abstract byte[] getBytes() throws IOException;

        @Override
        public void run() {
            try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
                    new ParcelFileDescriptor.AutoCloseOutputStream(mDescriptors[1])) {
                try {
                    final byte[] bytes = getBytes();
                    stream.write(bytes);
                } catch (IOException error) {
                    mDescriptors[1].closeWithError("Failed to load bytes.");
                    return;
                }
            } catch (IOException closeError) {
                Log.d(MtpDocumentsProvider.TAG, closeError.getMessage());
            }
        }

        ParcelFileDescriptor getReadingFileDescriptor() {
            return mDescriptors[0];
        }
    }

    void close() {
        mExecutor.shutdown();
    }
}
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.mtp;

import android.os.ParcelFileDescriptor;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@SmallTest
public class PipeManagerTest extends AndroidTestCase {
    public void testReadDocument_basic() throws Exception {
        final TestMtpManager mtpManager = new TestMtpManager(getContext());
        final byte[] expectedBytes = new byte[] { 'h', 'e', 'l', 'l', 'o' };
        mtpManager.setObjectBytes(0, 1, 5, expectedBytes);
        final ExecutorService executor = Executors.newSingleThreadExecutor();
        final PipeManager pipeManager = new PipeManager(executor);
        final ParcelFileDescriptor descriptor = pipeManager.readDocument(
                mtpManager, new Identifier(0, 0, 1), 5);
        try (final ParcelFileDescriptor.AutoCloseInputStream stream =
                new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) {
            final byte[] results = new byte[100];
            assertEquals(5, stream.read(results));
            for (int i = 0; i < 5; i++) {
                assertEquals(expectedBytes[i], results[i]);
            }
        }
    }

    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), 5);
        executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
        try {
            descriptor.checkError();
            fail();
        } catch (Throwable error) {
            assertTrue(error instanceof IOException);
        }
    }
}
Loading