summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java19
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java62
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java94
-rw-r--r--packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java2
-rw-r--r--packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java22
5 files changed, 128 insertions, 71 deletions
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index d4c4331267a0..0d4265a6417c 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -91,12 +91,12 @@ class DocumentLoader {
return task.createCursor(mResolver, columnNames);
}
- synchronized void clearTasks(int deviceId) {
- mTaskList.clearTaskForDevice(deviceId);
+ synchronized void clearTasks() {
+ mTaskList.clear();
}
synchronized void clearCompletedTasks() {
- mTaskList.clearCompletedTask();
+ mTaskList.clearCompletedTasks();
}
synchronized void clearTask(Identifier parentIdentifier) {
@@ -162,18 +162,7 @@ class DocumentLoader {
return null;
}
- void clearTaskForDevice(int deviceId) {
- int i = 0;
- while (i < size()) {
- if (get(i).mIdentifier.mDeviceId == deviceId) {
- remove(i);
- } else {
- i++;
- }
- }
- }
-
- void clearCompletedTask() {
+ void clearCompletedTasks() {
int i = 0;
while (i < size()) {
if (get(i).completed()) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 78ed161d47f4..a1a43c18a72f 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -34,6 +34,8 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
/**
* DocumentsProvider for MTP devices.
@@ -56,8 +58,8 @@ public class MtpDocumentsProvider extends DocumentsProvider {
private MtpManager mMtpManager;
private ContentResolver mResolver;
- private PipeManager mPipeManager;
- private DocumentLoader mDocumentLoader;
+ private Map<Integer, DeviceToolkit> mDeviceToolkits;
+ private DocumentLoader mDocumentLoaders;
private RootScanner mRootScanner;
/**
@@ -72,8 +74,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
sSingleton = this;
mMtpManager = new MtpManager(getContext());
mResolver = getContext().getContentResolver();
- mPipeManager = new PipeManager();
- mDocumentLoader = new DocumentLoader(mMtpManager, mResolver);
+ mDeviceToolkits = new HashMap<Integer, DeviceToolkit>();
mRootScanner = new RootScanner(mResolver, mMtpManager);
return true;
}
@@ -82,7 +83,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
void onCreateForTesting(MtpManager mtpManager, ContentResolver resolver) {
mMtpManager = mtpManager;
mResolver = resolver;
- mDocumentLoader = new DocumentLoader(mMtpManager, mResolver);
+ mDeviceToolkits = new HashMap<Integer, DeviceToolkit>();
mRootScanner = new RootScanner(mResolver, mMtpManager);
}
@@ -158,7 +159,8 @@ public class MtpDocumentsProvider extends DocumentsProvider {
}
final Identifier parentIdentifier = Identifier.createFromDocumentId(parentDocumentId);
try {
- return mDocumentLoader.queryChildDocuments(projection, parentIdentifier);
+ return getDocumentLoader(parentIdentifier).queryChildDocuments(
+ projection, parentIdentifier);
} catch (IOException exception) {
throw new FileNotFoundException(exception.getMessage());
}
@@ -172,11 +174,12 @@ public class MtpDocumentsProvider extends DocumentsProvider {
try {
switch (mode) {
case "r":
- return mPipeManager.readDocument(mMtpManager, identifier);
+ return getPipeManager(identifier).readDocument(mMtpManager, identifier);
case "w":
// TODO: Clear the parent document loader task (if exists) and call notify
// when writing is completed.
- return mPipeManager.writeDocument(getContext(), mMtpManager, identifier);
+ return getPipeManager(identifier).writeDocument(
+ getContext(), mMtpManager, identifier);
default:
// TODO: Add support for seekable files.
throw new UnsupportedOperationException(
@@ -195,7 +198,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
final Identifier identifier = Identifier.createFromDocumentId(documentId);
try {
return new AssetFileDescriptor(
- mPipeManager.readThumbnail(mMtpManager, identifier),
+ getPipeManager(identifier).readThumbnail(mMtpManager, identifier),
0, // Start offset.
AssetFileDescriptor.UNKNOWN_LENGTH);
} catch (IOException error) {
@@ -212,7 +215,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
final Identifier parentIdentifier = new Identifier(
identifier.mDeviceId, identifier.mStorageId, parentHandle);
- mDocumentLoader.clearTask(parentIdentifier);
+ getDocumentLoader(parentIdentifier).clearTask(parentIdentifier);
notifyChildDocumentsChange(parentIdentifier.toDocumentId());
} catch (IOException error) {
throw new FileNotFoundException(error.getMessage());
@@ -221,7 +224,9 @@ public class MtpDocumentsProvider extends DocumentsProvider {
@Override
public void onTrimMemory(int level) {
- mDocumentLoader.clearCompletedTasks();
+ for (final DeviceToolkit toolkit : mDeviceToolkits.values()) {
+ toolkit.mDocumentLoader.clearCompletedTasks();
+ }
}
@Override
@@ -241,7 +246,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
.build(), pipe[1]);
final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
objectHandle).toDocumentId();
- mDocumentLoader.clearTask(parentId);
+ getDocumentLoader(parentId).clearTask(parentId);
notifyChildDocumentsChange(parentDocumentId);
return documentId;
} catch (IOException error) {
@@ -252,12 +257,15 @@ public class MtpDocumentsProvider extends DocumentsProvider {
void openDevice(int deviceId) throws IOException {
mMtpManager.openDevice(deviceId);
+ mDeviceToolkits.put(deviceId, new DeviceToolkit(mMtpManager, mResolver));
mRootScanner.scanNow();
}
void closeDevice(int deviceId) throws IOException {
+ // TODO: Flush the device before closing (if not closed externally).
+ getDeviceToolkit(deviceId).mDocumentLoader.clearTasks();
+ mDeviceToolkits.remove(deviceId);
mMtpManager.closeDevice(deviceId);
- mDocumentLoader.clearTasks(deviceId);
mRootScanner.scanNow();
}
@@ -266,7 +274,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
for (int deviceId : mMtpManager.getOpenedDeviceIds()) {
try {
mMtpManager.closeDevice(deviceId);
- mDocumentLoader.clearTasks(deviceId);
+ getDeviceToolkit(deviceId).mDocumentLoader.clearTasks();
closed = true;
} catch (IOException d) {
Log.d(TAG, "Failed to close the MTP device: " + deviceId);
@@ -287,4 +295,30 @@ public class MtpDocumentsProvider extends DocumentsProvider {
null,
false);
}
+
+ private DeviceToolkit getDeviceToolkit(int deviceId) throws FileNotFoundException {
+ final DeviceToolkit toolkit = mDeviceToolkits.get(deviceId);
+ if (toolkit == null) {
+ throw new FileNotFoundException();
+ }
+ return toolkit;
+ }
+
+ private PipeManager getPipeManager(Identifier identifier) throws FileNotFoundException {
+ return getDeviceToolkit(identifier.mDeviceId).mPipeManager;
+ }
+
+ private DocumentLoader getDocumentLoader(Identifier identifier) throws FileNotFoundException {
+ return getDeviceToolkit(identifier.mDeviceId).mDocumentLoader;
+ }
+
+ private static class DeviceToolkit {
+ public final PipeManager mPipeManager;
+ public final DocumentLoader mDocumentLoader;
+
+ public DeviceToolkit(MtpManager manager, ContentResolver resolver) {
+ mPipeManager = new PipeManager();
+ mDocumentLoader = new DocumentLoader(manager, resolver);
+ }
+ }
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index ca78a3e1b775..7cc7413bab3d 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -42,7 +42,7 @@ class MtpManager {
private final SparseArray<MtpDevice> mDevices = new SparseArray<>();
MtpManager(Context context) {
- mManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
+ mManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
}
synchronized void openDevice(int deviceId) throws IOException {
@@ -96,78 +96,96 @@ class MtpManager {
return result;
}
- synchronized MtpRoot[] getRoots(int deviceId) throws IOException {
+ MtpRoot[] getRoots(int deviceId) throws IOException {
final MtpDevice device = getDevice(deviceId);
- final int[] storageIds = device.getStorageIds();
- if (storageIds == null) {
- throw new IOException("Failed to obtain storage IDs.");
- }
- final MtpRoot[] results = new MtpRoot[storageIds.length];
- for (int i = 0; i < storageIds.length; i++) {
- results[i] = new MtpRoot(deviceId, device.getStorageInfo(storageIds[i]));
+ synchronized (device) {
+ final int[] storageIds = device.getStorageIds();
+ if (storageIds == null) {
+ throw new IOException("Failed to obtain storage IDs.");
+ }
+ final MtpRoot[] results = new MtpRoot[storageIds.length];
+ for (int i = 0; i < storageIds.length; i++) {
+ results[i] = new MtpRoot(deviceId, device.getStorageInfo(storageIds[i]));
+ }
+ return results;
}
- return results;
}
- synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
+ MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
throws IOException {
final MtpDevice device = getDevice(deviceId);
- return device.getObjectInfo(objectHandle);
+ synchronized (device) {
+ return device.getObjectInfo(objectHandle);
+ }
}
- synchronized int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
+ int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
throws IOException {
final MtpDevice device = getDevice(deviceId);
- return device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle);
+ synchronized (device) {
+ return device.getObjectHandles(storageId, 0 /* all format */, parentObjectHandle);
+ }
}
- synchronized byte[] getObject(int deviceId, int objectHandle, int expectedSize)
+ byte[] getObject(int deviceId, int objectHandle, int expectedSize)
throws IOException {
final MtpDevice device = getDevice(deviceId);
- return device.getObject(objectHandle, expectedSize);
+ synchronized (device) {
+ return device.getObject(objectHandle, expectedSize);
+ }
}
- synchronized byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
+ byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
- return device.getThumbnail(objectHandle);
+ synchronized (device) {
+ return device.getThumbnail(objectHandle);
+ }
}
- synchronized void deleteDocument(int deviceId, int objectHandle) throws IOException {
+ void deleteDocument(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
- if (!device.deleteObject(objectHandle)) {
- throw new IOException("Failed to delete document");
+ synchronized (device) {
+ if (!device.deleteObject(objectHandle)) {
+ throw new IOException("Failed to delete document");
+ }
}
}
- synchronized int createDocument(int deviceId, MtpObjectInfo objectInfo,
+ int createDocument(int deviceId, MtpObjectInfo objectInfo,
ParcelFileDescriptor source) throws IOException {
final MtpDevice device = getDevice(deviceId);
- final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
- if (sendObjectInfoResult == null) {
- throw new IOException("Failed to create a document");
- }
- if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
- if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
- sendObjectInfoResult.getCompressedSize(), source)) {
- throw new IOException("Failed to send contents of a document");
+ synchronized (device) {
+ final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
+ if (sendObjectInfoResult == null) {
+ throw new IOException("Failed to create a document");
+ }
+ if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
+ if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
+ sendObjectInfoResult.getCompressedSize(), source)) {
+ throw new IOException("Failed to send contents of a document");
+ }
}
+ return sendObjectInfoResult.getObjectHandle();
}
- return sendObjectInfoResult.getObjectHandle();
}
- synchronized int getParent(int deviceId, int objectHandle) throws IOException {
+ int getParent(int deviceId, int objectHandle) throws IOException {
final MtpDevice device = getDevice(deviceId);
- final int result = (int) device.getParent(objectHandle);
- if (result < 0) {
- throw new FileNotFoundException("Not found parent object");
+ synchronized (device) {
+ final int result = (int) device.getParent(objectHandle);
+ if (result < 0) {
+ throw new FileNotFoundException("Not found parent object");
+ }
+ return result;
}
- return result;
}
- synchronized void importFile(int deviceId, int objectHandle, ParcelFileDescriptor target)
+ void importFile(int deviceId, int objectHandle, ParcelFileDescriptor target)
throws IOException {
final MtpDevice device = getDevice(deviceId);
- device.importFile(objectHandle, target);
+ synchronized (device) {
+ device.importFile(objectHandle, target);
+ }
}
private MtpDevice getDevice(int deviceId) throws IOException {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index cd38f1e852b5..affaebd05c16 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -33,7 +33,7 @@ class PipeManager {
final ExecutorService mExecutor;
PipeManager() {
- this(Executors.newCachedThreadPool());
+ this(Executors.newSingleThreadExecutor());
}
PipeManager(ExecutorService executor) {
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 9b316be48a15..4b3a5cd061bf 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -39,7 +39,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
private TestMtpManager mMtpManager;
@Override
- public void setUp() {
+ public void setUp() throws IOException {
mResolver = new TestContentResolver();
mMtpManager = new TestMtpManager(getContext());
mProvider = new MtpDocumentsProvider();
@@ -207,6 +207,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryDocument() throws IOException {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
.setObjectHandle(2)
.setFormat(MtpConstants.FORMAT_EXIF_JPEG)
@@ -232,6 +234,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryDocument_directory() throws IOException {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
.setObjectHandle(2)
.setFormat(MtpConstants.FORMAT_ASSOCIATION)
@@ -255,6 +259,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryDocument_forRoot() throws IOException {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setRoots(0, new MtpRoot[] {
new MtpRoot(
0 /* deviceId */,
@@ -277,6 +283,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryChildDocuments() throws Exception {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
@@ -303,6 +311,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryChildDocuments_cursorError() throws Exception {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
try {
mProvider.queryChildDocuments("0_0_0", null, null);
fail();
@@ -312,6 +322,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
public void testQueryChildDocuments_documentError() throws Exception {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
try {
mProvider.queryChildDocuments("0_0_0", null, null);
@@ -321,7 +333,9 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
}
}
- public void testDeleteDocument() throws FileNotFoundException {
+ public void testDeleteDocument() throws IOException {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
.setObjectHandle(1)
.setParent(2)
@@ -332,7 +346,9 @@ public class MtpDocumentsProviderTest extends AndroidTestCase {
MtpDocumentsProvider.AUTHORITY, "0_0_2")));
}
- public void testDeleteDocument_error() {
+ public void testDeleteDocument_error() throws IOException {
+ mMtpManager.addValidDevice(0);
+ mProvider.openDevice(0);
mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
.setObjectHandle(2)
.build());