Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java +4 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,10 @@ class MtpDocument { this.mThumbSize = thumbSize; } int getSize() { return mSize; } String getMimeType() { // TODO: Add complete list of mime types. switch (mFormat) { Loading packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +19 −6 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { private MtpManager mMtpManager; private ContentResolver mResolver; private PipeManager mPipeManager; /** * Provides singleton instance to MtpDocumentsService. Loading @@ -66,6 +67,8 @@ public class MtpDocumentsProvider extends DocumentsProvider { sSingleton = this; mMtpManager = new MtpManager(getContext()); mResolver = getContext().getContentResolver(); mPipeManager = new PipeManager(); return true; } Loading Loading @@ -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 { Loading Loading @@ -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); } } packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java +6 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java 0 → 100644 +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(); } } packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java 0 → 100644 +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
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java +4 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,10 @@ class MtpDocument { this.mThumbSize = thumbSize; } int getSize() { return mSize; } String getMimeType() { // TODO: Add complete list of mime types. switch (mFormat) { Loading
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java +19 −6 Original line number Diff line number Diff line Loading @@ -53,6 +53,7 @@ public class MtpDocumentsProvider extends DocumentsProvider { private MtpManager mMtpManager; private ContentResolver mResolver; private PipeManager mPipeManager; /** * Provides singleton instance to MtpDocumentsService. Loading @@ -66,6 +67,8 @@ public class MtpDocumentsProvider extends DocumentsProvider { sSingleton = this; mMtpManager = new MtpManager(getContext()); mResolver = getContext().getContentResolver(); mPipeManager = new PipeManager(); return true; } Loading Loading @@ -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 { Loading Loading @@ -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); } }
packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java +6 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading
packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java 0 → 100644 +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(); } }
packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java 0 → 100644 +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); } } }