Merge "Implement openDevice/closeDevice method of MtpManager."
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index eea38b1..466a3ac 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -17,6 +17,11 @@
 package com.android.mtp;
 
 import android.content.Context;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbManager;
+import android.mtp.MtpDevice;
+import android.util.SparseArray;
 
 import java.io.IOException;
 
@@ -24,19 +29,66 @@
  * The model wrapping android.mtp API.
  */
 class MtpManager {
+    private final UsbManager mManager;
+    // TODO: Save and restore the set of opened device.
+    private final SparseArray<MtpDevice> mDevices = new SparseArray<MtpDevice>();
+
     MtpManager(Context context) {
+        mManager = (UsbManager)context.getSystemService(Context.USB_SERVICE);
     }
 
-    void openDevice(int deviceId) throws IOException {
-        // TODO: Implement this method.
+    synchronized void openDevice(int deviceId) throws IOException {
+        UsbDevice rawDevice = null;
+        for (final UsbDevice candidate : mManager.getDeviceList().values()) {
+            if (candidate.getDeviceId() == deviceId) {
+                rawDevice = candidate;
+                break;
+            }
+        }
+
+        if (rawDevice == null) {
+            throw new IOException("Not found USB device: " + deviceId);
+        }
+
+        if (!mManager.hasPermission(rawDevice)) {
+            // Permission should be obtained via app selection dialog for intent.
+            throw new IOException("No parmission to operate USB device.");
+        }
+
+        final MtpDevice device = new MtpDevice(rawDevice);
+
+        final UsbDeviceConnection connection = mManager.openDevice(rawDevice);
+        if (connection == null) {
+            throw new IOException("Failed to open a USB connection.");
+        }
+
+        if (!device.open(connection)) {
+            throw new IOException("Failed to open a MTP device.");
+        }
+
+        // Handle devices that fail to obtain storages just after opening a MTP session.
+        final int[] storageIds = device.getStorageIds();
+        if (storageIds == null || storageIds.length == 0) {
+            throw new IOException("Not found MTP storages in the device.");
+        }
+
+        mDevices.put(deviceId, device);
     }
 
-    void closeDevice(int deviceId) throws IOException {
-        // TODO: Implement this method.
+    synchronized void closeDevice(int deviceId) throws IOException {
+        final MtpDevice device = mDevices.get(deviceId);
+        if (device == null) {
+            throw new IOException("USB device " + deviceId + " is not opened.");
+        }
+        mDevices.get(deviceId).close();
+        mDevices.remove(deviceId);
     }
 
-    int[] getOpenedDeviceIds() {
-        // TODO: Implement this method.
-        return null;
+    synchronized int[] getOpenedDeviceIds() {
+        final int[] result = new int[mDevices.size()];
+        for (int i = 0; i < result.length; i++) {
+            result[i] = mDevices.keyAt(i);
+        }
+        return result;
     }
 }