summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java4
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java25
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java6
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java86
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java62
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java15
6 files changed, 192 insertions, 6 deletions
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
index 5222826bed48..f6e4276c5988 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
@@ -67,6 +67,10 @@ class MtpDocument {
this.mThumbSize = thumbSize;
}
+ int getSize() {
+ return mSize;
+ }
+
String getMimeType() {
// TODO: Add complete list of mime types.
switch (mFormat) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index fab512563448..bbb8063b4832 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -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);
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index e34312c6c3d3..f803744d6ba8 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -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) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
new file mode 100644
index 000000000000..a2c7772fb4db
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -0,0 +1,86 @@
+/*
+ * 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();
+ }
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
new file mode 100644
index 000000000000..3c295eeb2608
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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);
+ }
+ }
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 08ceb293c3a6..43f4bb2d8649 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -35,6 +35,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[]> mObjectBytes = new HashMap<String, byte[]>();
TestMtpManager(Context context) {
super(context);
@@ -52,6 +53,10 @@ public class TestMtpManager extends MtpManager {
mDocuments.put(pack(deviceId, objectHandle), document);
}
+ void setObjectBytes(int deviceId, int objectHandle, int expectedSize, byte[] bytes) {
+ mObjectBytes.put(pack(deviceId, objectHandle, expectedSize), bytes);
+ }
+
@Override
void openDevice(int deviceId) throws IOException {
if (!mValidDevices.contains(deviceId) || mOpenedDevices.contains(deviceId)) {
@@ -83,6 +88,16 @@ public class TestMtpManager extends MtpManager {
}
@Override
+ byte[] getObject(int deviceId, int storageId, int expectedSize) throws IOException {
+ final String key = pack(deviceId, storageId, expectedSize);
+ if (mObjectBytes.containsKey(key)) {
+ return mObjectBytes.get(key);
+ } else {
+ throw new IOException("getObject error: " + key);
+ }
+ }
+
+ @Override
int[] getOpenedDeviceIds() {
int i = 0;
final int[] result = new int[mOpenedDevices.size()];