Add operationsSupported to device info.

Because not all MTP devices support getPartialObject, we need to check
supported operation of MTP devices. The CL adds operationsSupported
field to MtpDeviceInfo class.

BUG=26147375

Change-Id: Iaad968fb4497a5ad11bf6489097abea99c3cbac7
diff --git a/api/current.txt b/api/current.txt
index e2b1556..6ed8c89 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22456,6 +22456,41 @@
     field public static final int FORMAT_WMV = 47489; // 0xb981
     field public static final int FORMAT_WPL_PLAYLIST = 47632; // 0xba10
     field public static final int FORMAT_XML_DOCUMENT = 47746; // 0xba82
+    field public static final int OPERATION_CLOSE_SESSION = 4099; // 0x1003
+    field public static final int OPERATION_COPY_OBJECT = 4122; // 0x101a
+    field public static final int OPERATION_DELETE_OBJECT = 4107; // 0x100b
+    field public static final int OPERATION_FORMAT_STORE = 4111; // 0x100f
+    field public static final int OPERATION_GET_DEVICE_INFO = 4097; // 0x1001
+    field public static final int OPERATION_GET_DEVICE_PROP_DESC = 4116; // 0x1014
+    field public static final int OPERATION_GET_DEVICE_PROP_VALUE = 4117; // 0x1015
+    field public static final int OPERATION_GET_NUM_OBJECTS = 4102; // 0x1006
+    field public static final int OPERATION_GET_OBJECT = 4105; // 0x1009
+    field public static final int OPERATION_GET_OBJECT_HANDLES = 4103; // 0x1007
+    field public static final int OPERATION_GET_OBJECT_INFO = 4104; // 0x1008
+    field public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 38913; // 0x9801
+    field public static final int OPERATION_GET_OBJECT_PROP_DESC = 38914; // 0x9802
+    field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
+    field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
+    field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+    field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
+    field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
+    field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
+    field public static final int OPERATION_INITIATE_CAPTURE = 4110; // 0x100e
+    field public static final int OPERATION_INITIATE_OPEN_CAPTURE = 4124; // 0x101c
+    field public static final int OPERATION_MOVE_OBJECT = 4121; // 0x1019
+    field public static final int OPERATION_OPEN_SESSION = 4098; // 0x1002
+    field public static final int OPERATION_POWER_DOWN = 4115; // 0x1013
+    field public static final int OPERATION_RESET_DEVICE = 4112; // 0x1010
+    field public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 4119; // 0x1017
+    field public static final int OPERATION_SELF_TEST = 4113; // 0x1011
+    field public static final int OPERATION_SEND_OBJECT = 4109; // 0x100d
+    field public static final int OPERATION_SEND_OBJECT_INFO = 4108; // 0x100c
+    field public static final int OPERATION_SET_DEVICE_PROP_VALUE = 4118; // 0x1016
+    field public static final int OPERATION_SET_OBJECT_PROP_VALUE = 38916; // 0x9804
+    field public static final int OPERATION_SET_OBJECT_PROTECTION = 4114; // 0x1012
+    field public static final int OPERATION_SET_OBJECT_REFERENCES = 38929; // 0x9811
+    field public static final int OPERATION_SKIP = 38944; // 0x9820
+    field public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 4120; // 0x1018
     field public static final int PROTECTION_STATUS_NONE = 0; // 0x0
     field public static final int PROTECTION_STATUS_NON_TRANSFERABLE_DATA = 32771; // 0x8003
     field public static final int PROTECTION_STATUS_READ_ONLY = 32769; // 0x8001
@@ -22489,6 +22524,7 @@
   public class MtpDeviceInfo {
     method public final java.lang.String getManufacturer();
     method public final java.lang.String getModel();
+    method public final int[] getOperationsSupported();
     method public final java.lang.String getSerialNumber();
     method public final java.lang.String getVersion();
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index d50a6c9..2779348 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -24002,6 +24002,41 @@
     field public static final int FORMAT_WMV = 47489; // 0xb981
     field public static final int FORMAT_WPL_PLAYLIST = 47632; // 0xba10
     field public static final int FORMAT_XML_DOCUMENT = 47746; // 0xba82
+    field public static final int OPERATION_CLOSE_SESSION = 4099; // 0x1003
+    field public static final int OPERATION_COPY_OBJECT = 4122; // 0x101a
+    field public static final int OPERATION_DELETE_OBJECT = 4107; // 0x100b
+    field public static final int OPERATION_FORMAT_STORE = 4111; // 0x100f
+    field public static final int OPERATION_GET_DEVICE_INFO = 4097; // 0x1001
+    field public static final int OPERATION_GET_DEVICE_PROP_DESC = 4116; // 0x1014
+    field public static final int OPERATION_GET_DEVICE_PROP_VALUE = 4117; // 0x1015
+    field public static final int OPERATION_GET_NUM_OBJECTS = 4102; // 0x1006
+    field public static final int OPERATION_GET_OBJECT = 4105; // 0x1009
+    field public static final int OPERATION_GET_OBJECT_HANDLES = 4103; // 0x1007
+    field public static final int OPERATION_GET_OBJECT_INFO = 4104; // 0x1008
+    field public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 38913; // 0x9801
+    field public static final int OPERATION_GET_OBJECT_PROP_DESC = 38914; // 0x9802
+    field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
+    field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
+    field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+    field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
+    field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
+    field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
+    field public static final int OPERATION_INITIATE_CAPTURE = 4110; // 0x100e
+    field public static final int OPERATION_INITIATE_OPEN_CAPTURE = 4124; // 0x101c
+    field public static final int OPERATION_MOVE_OBJECT = 4121; // 0x1019
+    field public static final int OPERATION_OPEN_SESSION = 4098; // 0x1002
+    field public static final int OPERATION_POWER_DOWN = 4115; // 0x1013
+    field public static final int OPERATION_RESET_DEVICE = 4112; // 0x1010
+    field public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 4119; // 0x1017
+    field public static final int OPERATION_SELF_TEST = 4113; // 0x1011
+    field public static final int OPERATION_SEND_OBJECT = 4109; // 0x100d
+    field public static final int OPERATION_SEND_OBJECT_INFO = 4108; // 0x100c
+    field public static final int OPERATION_SET_DEVICE_PROP_VALUE = 4118; // 0x1016
+    field public static final int OPERATION_SET_OBJECT_PROP_VALUE = 38916; // 0x9804
+    field public static final int OPERATION_SET_OBJECT_PROTECTION = 4114; // 0x1012
+    field public static final int OPERATION_SET_OBJECT_REFERENCES = 38929; // 0x9811
+    field public static final int OPERATION_SKIP = 38944; // 0x9820
+    field public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 4120; // 0x1018
     field public static final int PROTECTION_STATUS_NONE = 0; // 0x0
     field public static final int PROTECTION_STATUS_NON_TRANSFERABLE_DATA = 32771; // 0x8003
     field public static final int PROTECTION_STATUS_READ_ONLY = 32769; // 0x8001
@@ -24035,6 +24070,7 @@
   public class MtpDeviceInfo {
     method public final java.lang.String getManufacturer();
     method public final java.lang.String getModel();
+    method public final int[] getOperationsSupported();
     method public final java.lang.String getSerialNumber();
     method public final java.lang.String getVersion();
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index 80f250a..766e62c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -22464,6 +22464,41 @@
     field public static final int FORMAT_WMV = 47489; // 0xb981
     field public static final int FORMAT_WPL_PLAYLIST = 47632; // 0xba10
     field public static final int FORMAT_XML_DOCUMENT = 47746; // 0xba82
+    field public static final int OPERATION_CLOSE_SESSION = 4099; // 0x1003
+    field public static final int OPERATION_COPY_OBJECT = 4122; // 0x101a
+    field public static final int OPERATION_DELETE_OBJECT = 4107; // 0x100b
+    field public static final int OPERATION_FORMAT_STORE = 4111; // 0x100f
+    field public static final int OPERATION_GET_DEVICE_INFO = 4097; // 0x1001
+    field public static final int OPERATION_GET_DEVICE_PROP_DESC = 4116; // 0x1014
+    field public static final int OPERATION_GET_DEVICE_PROP_VALUE = 4117; // 0x1015
+    field public static final int OPERATION_GET_NUM_OBJECTS = 4102; // 0x1006
+    field public static final int OPERATION_GET_OBJECT = 4105; // 0x1009
+    field public static final int OPERATION_GET_OBJECT_HANDLES = 4103; // 0x1007
+    field public static final int OPERATION_GET_OBJECT_INFO = 4104; // 0x1008
+    field public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 38913; // 0x9801
+    field public static final int OPERATION_GET_OBJECT_PROP_DESC = 38914; // 0x9802
+    field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803
+    field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810
+    field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b
+    field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005
+    field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004
+    field public static final int OPERATION_GET_THUMB = 4106; // 0x100a
+    field public static final int OPERATION_INITIATE_CAPTURE = 4110; // 0x100e
+    field public static final int OPERATION_INITIATE_OPEN_CAPTURE = 4124; // 0x101c
+    field public static final int OPERATION_MOVE_OBJECT = 4121; // 0x1019
+    field public static final int OPERATION_OPEN_SESSION = 4098; // 0x1002
+    field public static final int OPERATION_POWER_DOWN = 4115; // 0x1013
+    field public static final int OPERATION_RESET_DEVICE = 4112; // 0x1010
+    field public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 4119; // 0x1017
+    field public static final int OPERATION_SELF_TEST = 4113; // 0x1011
+    field public static final int OPERATION_SEND_OBJECT = 4109; // 0x100d
+    field public static final int OPERATION_SEND_OBJECT_INFO = 4108; // 0x100c
+    field public static final int OPERATION_SET_DEVICE_PROP_VALUE = 4118; // 0x1016
+    field public static final int OPERATION_SET_OBJECT_PROP_VALUE = 38916; // 0x9804
+    field public static final int OPERATION_SET_OBJECT_PROTECTION = 4114; // 0x1012
+    field public static final int OPERATION_SET_OBJECT_REFERENCES = 38929; // 0x9811
+    field public static final int OPERATION_SKIP = 38944; // 0x9820
+    field public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 4120; // 0x1018
     field public static final int PROTECTION_STATUS_NONE = 0; // 0x0
     field public static final int PROTECTION_STATUS_NON_TRANSFERABLE_DATA = 32771; // 0x8003
     field public static final int PROTECTION_STATUS_READ_ONLY = 32769; // 0x8001
@@ -22497,6 +22532,7 @@
   public class MtpDeviceInfo {
     method public final java.lang.String getManufacturer();
     method public final java.lang.String getModel();
+    method public final int[] getOperationsSupported();
     method public final java.lang.String getSerialNumber();
     method public final java.lang.String getVersion();
   }
diff --git a/media/java/android/mtp/MtpConstants.java b/media/java/android/mtp/MtpConstants.java
index 1657796..b2a5a44 100644
--- a/media/java/android/mtp/MtpConstants.java
+++ b/media/java/android/mtp/MtpConstants.java
@@ -610,4 +610,75 @@
     public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 0xC802;
     /** Event code for OBJECT_REFERENCES_CHANGED event */
     public static final int EVENT_OBJECT_REFERENCES_CHANGED = 0xC803;
+
+    /** Operation code for GetDeviceInfo */
+    public static final int OPERATION_GET_DEVICE_INFO = 0x1001;
+    /** Operation code for OpenSession */
+    public static final int OPERATION_OPEN_SESSION = 0x1002;
+    /** Operation code for CloseSession */
+    public static final int OPERATION_CLOSE_SESSION = 0x1003;
+    /** Operation code for GetStorageIDs */
+    public static final int OPERATION_GET_STORAGE_I_DS = 0x1004;
+    /** Operation code for GetStorageInfo */
+    public static final int OPERATION_GET_STORAGE_INFO = 0x1005;
+    /** Operation code for GetNumObjects */
+    public static final int OPERATION_GET_NUM_OBJECTS = 0x1006;
+    /** Operation code for GetObjectHandles */
+    public static final int OPERATION_GET_OBJECT_HANDLES = 0x1007;
+    /** Operation code for GetObjectInfo */
+    public static final int OPERATION_GET_OBJECT_INFO = 0x1008;
+    /** Operation code for GetObject */
+    public static final int OPERATION_GET_OBJECT = 0x1009;
+    /** Operation code for GetThumb */
+    public static final int OPERATION_GET_THUMB = 0x100A;
+    /** Operation code for DeleteObject */
+    public static final int OPERATION_DELETE_OBJECT = 0x100B;
+    /** Operation code for SendObjectInfo */
+    public static final int OPERATION_SEND_OBJECT_INFO = 0x100C;
+    /** Operation code for SendObject */
+    public static final int OPERATION_SEND_OBJECT = 0x100D;
+    /** Operation code for InitiateCapture */
+    public static final int OPERATION_INITIATE_CAPTURE = 0x100E;
+    /** Operation code for FormatStore */
+    public static final int OPERATION_FORMAT_STORE = 0x100F;
+    /** Operation code for ResetDevice */
+    public static final int OPERATION_RESET_DEVICE = 0x1010;
+    /** Operation code for SelfTest */
+    public static final int OPERATION_SELF_TEST = 0x1011;
+    /** Operation code for SetObjectProtection */
+    public static final int OPERATION_SET_OBJECT_PROTECTION = 0x1012;
+    /** Operation code for PowerDown */
+    public static final int OPERATION_POWER_DOWN = 0x1013;
+    /** Operation code for GetDevicePropDesc */
+    public static final int OPERATION_GET_DEVICE_PROP_DESC = 0x1014;
+    /** Operation code for GetDevicePropValue */
+    public static final int OPERATION_GET_DEVICE_PROP_VALUE = 0x1015;
+    /** Operation code for SetDevicePropValue */
+    public static final int OPERATION_SET_DEVICE_PROP_VALUE = 0x1016;
+    /** Operation code for ResetDevicePropValue */
+    public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 0x1017;
+    /** Operation code for TerminateOpenCapture */
+    public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 0x1018;
+    /** Operation code for MoveObject */
+    public static final int OPERATION_MOVE_OBJECT = 0x1019;
+    /** Operation code for CopyObject */
+    public static final int OPERATION_COPY_OBJECT = 0x101A;
+    /** Operation code for GetPartialObject */
+    public static final int OPERATION_GET_PARTIAL_OBJECT = 0x101B;
+    /** Operation code for InitiateOpenCapture */
+    public static final int OPERATION_INITIATE_OPEN_CAPTURE = 0x101C;
+    /** Operation code for GetObjectPropsSupported */
+    public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 0x9801;
+    /** Operation code for GetObjectPropDesc */
+    public static final int OPERATION_GET_OBJECT_PROP_DESC = 0x9802;
+    /** Operation code for GetObjectPropValue */
+    public static final int OPERATION_GET_OBJECT_PROP_VALUE = 0x9803;
+    /** Operation code for SetObjectPropValue */
+    public static final int OPERATION_SET_OBJECT_PROP_VALUE = 0x9804;
+    /** Operation code for GetObjectReferences */
+    public static final int OPERATION_GET_OBJECT_REFERENCES = 0x9810;
+    /** Operation code for SetObjectReferences */
+    public static final int OPERATION_SET_OBJECT_REFERENCES = 0x9811;
+    /** Operation code for Skip */
+    public static final int OPERATION_SKIP = 0x9820;
 }
diff --git a/media/java/android/mtp/MtpDeviceInfo.java b/media/java/android/mtp/MtpDeviceInfo.java
index ef9436d..1ceca84 100644
--- a/media/java/android/mtp/MtpDeviceInfo.java
+++ b/media/java/android/mtp/MtpDeviceInfo.java
@@ -16,6 +16,8 @@
 
 package android.mtp;
 
+import android.annotation.Nullable;
+
 /**
  * This class encapsulates information about an MTP device.
  * This corresponds to the DeviceInfo Dataset described in
@@ -27,6 +29,7 @@
     private String mModel;
     private String mVersion;
     private String mSerialNumber;
+    private int[] mOperationsSupported;
 
     // only instantiated via JNI
     private MtpDeviceInfo() {
@@ -67,4 +70,13 @@
     public final String getSerialNumber() {
         return mSerialNumber;
     }
-}
\ No newline at end of file
+
+    /**
+     * Returns operation code supported by the device.
+     *
+     * @return supported operation code
+     */
+    public final @Nullable int[] getOperationsSupported() {
+        return mOperationsSupported;
+    }
+}
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 14c15e5..4aa12c2 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -27,6 +27,8 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
+#include "ScopedPrimitiveArray.h"
+
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/Log.h"
 #include "nativehelper/ScopedLocalRef.h"
@@ -63,6 +65,7 @@
 static jfieldID field_deviceInfo_model;
 static jfieldID field_deviceInfo_version;
 static jfieldID field_deviceInfo_serialNumber;
+static jfieldID field_deviceInfo_operationsSupported;
 
 // MtpStorageInfo fields
 static jfieldID field_storageInfo_storageId;
@@ -234,6 +237,17 @@
     if (deviceInfo->mSerial)
         env->SetObjectField(info, field_deviceInfo_serialNumber,
             env->NewStringUTF(deviceInfo->mSerial));
+    if (deviceInfo->mOperations) {
+        const size_t size = deviceInfo->mOperations->size();
+        const jintArray operations = env->NewIntArray(size);
+        {
+            ScopedIntArrayRW elements(env, operations);
+            for (size_t i = 0; i < size; ++i) {
+                elements[i] = deviceInfo->mOperations->itemAt(i);
+            }
+        }
+        env->SetObjectField(info, field_deviceInfo_operationsSupported, operations);
+    }
 
     delete deviceInfo;
     return info;
@@ -647,6 +661,11 @@
         ALOGE("Can't find MtpDeviceInfo.mSerialNumber");
         return -1;
     }
+    field_deviceInfo_operationsSupported = env->GetFieldID(clazz, "mOperationsSupported", "[I");
+    if (field_deviceInfo_operationsSupported == NULL) {
+        ALOGE("Can't find MtpDeviceInfo.mOperationsSupported");
+        return -1;
+    }
     clazz_deviceInfo = (jclass)env->NewGlobalRef(clazz);
 
     clazz = env->FindClass("android/mtp/MtpStorageInfo");
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
index 71df5c1..02d07b9 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java
@@ -21,11 +21,14 @@
     public final String name;
     public final boolean opened;
     public final MtpRoot[] roots;
+    public final int[] operationsSupported;
 
-    MtpDeviceRecord(int deviceId, String name, boolean opened, MtpRoot[] roots) {
+    MtpDeviceRecord(
+            int deviceId, String name, boolean opened, MtpRoot[] roots, int[] operationsSupported) {
         this.deviceId = deviceId;
         this.name = name;
         this.opened = opened;
         this.roots = roots;
+        this.operationsSupported = operationsSupported;
     }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 88cab8b..9c726ba 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -24,6 +24,7 @@
 import android.hardware.usb.UsbManager;
 import android.mtp.MtpConstants;
 import android.mtp.MtpDevice;
+import android.mtp.MtpDeviceInfo;
 import android.mtp.MtpEvent;
 import android.mtp.MtpObjectInfo;
 import android.os.CancellationSignal;
@@ -123,9 +124,11 @@
             if (!isMtpDevice(device)) {
                 continue;
             }
-            final boolean opened = mDevices.get(device.getDeviceId()) != null;
+            final MtpDevice mtpDevice = mDevices.get(device.getDeviceId());
+            final boolean opened = mtpDevice != null;
             final String name = device.getProductName();
             MtpRoot[] roots;
+            int[] operationsSupported = null;
             if (opened) {
                 try {
                     roots = getRoots(device.getDeviceId());
@@ -136,10 +139,19 @@
                     // the device is physically connected.
                     roots = new MtpRoot[0];
                 }
+                final MtpDeviceInfo info = mtpDevice.getDeviceInfo();
+                if (info != null) {
+                    operationsSupported = mtpDevice.getDeviceInfo().getOperationsSupported();
+                }
+                if (operationsSupported == null) {
+                    operationsSupported = new int[0];
+                }
             } else {
                 roots = new MtpRoot[0];
+                operationsSupported = new int[0];
             }
-            devices.add(new MtpDeviceRecord(device.getDeviceId(), name, opened, roots));
+            devices.add(new MtpDeviceRecord(
+                    device.getDeviceId(), name, opened, roots, operationsSupported));
         }
         return devices.toArray(new MtpDeviceRecord[devices.size()]);
     }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 1e1ea0a..c39d5b3 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -77,7 +77,7 @@
     public void testPutSingleStorageDocuments() throws Exception {
         mDatabase.getMapper().startAddingDocuments(null);
         mDatabase.getMapper().putDeviceDocument(
-                new MtpDeviceRecord(0, "Device", true, new MtpRoot[0]));
+                new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], new int[0]));
         mDatabase.getMapper().stopAddingDocuments(null);
 
         mDatabase.getMapper().startAddingDocuments("1");
@@ -425,9 +425,9 @@
         };
         mDatabase.getMapper().startAddingDocuments(null);
         mDatabase.getMapper().putDeviceDocument(
-                new MtpDeviceRecord(0, "Device A", true, new MtpRoot[0]));
+                new MtpDeviceRecord(0, "Device A", true, new MtpRoot[0], new int[0]));
         mDatabase.getMapper().putDeviceDocument(
-                new MtpDeviceRecord(1, "Device B", true, new MtpRoot[0]));
+                new MtpDeviceRecord(1, "Device B", true, new MtpRoot[0], new int[0]));
         mDatabase.getMapper().stopAddingDocuments(null);
 
         mDatabase.getMapper().startAddingDocuments("1");
@@ -562,7 +562,7 @@
 
         mDatabase.getMapper().startAddingDocuments(null);
         mDatabase.getMapper().putDeviceDocument(
-                new MtpDeviceRecord(0, "Device",  false,  new MtpRoot[0]));
+                new MtpDeviceRecord(0, "Device",  false,  new MtpRoot[0], new int[0]));
         mDatabase.getMapper().stopAddingDocuments(null);
 
         mDatabase.getMapper().startAddingDocuments("1");
@@ -640,7 +640,7 @@
     public void testReplaceExistingRoots() {
         mDatabase.getMapper().startAddingDocuments(null);
         mDatabase.getMapper().putDeviceDocument(
-                new MtpDeviceRecord(0, "Device", true, new MtpRoot[0]));
+                new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], new int[0]));
         mDatabase.getMapper().stopAddingDocuments(null);
 
         // The client code should be able to replace existing rows with new information.
@@ -691,7 +691,7 @@
         // Add one.
         mDatabase.getMapper().startAddingDocuments(null);
         mDatabase.getMapper().putDeviceDocument(
-                new MtpDeviceRecord(0, "Device", true, new MtpRoot[0]));
+                new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], new int[0]));
         mDatabase.getMapper().stopAddingDocuments(null);
 
         mDatabase.getMapper().startAddingDocuments("1");
@@ -745,7 +745,7 @@
         // Add device document.
         mDatabase.getMapper().startAddingDocuments(null);
         mDatabase.getMapper().putDeviceDocument(
-                new MtpDeviceRecord(0, "Device", false, new MtpRoot[0]));
+                new MtpDeviceRecord(0, "Device", false, new MtpRoot[0], new int[0]));
         mDatabase.getMapper().stopAddingDocuments(null);
 
         // It the device does not have storages, it shows a device root.
@@ -895,7 +895,7 @@
     public void testGetDocumentIdForDevice() {
         mDatabase.getMapper().startAddingDocuments(null);
         mDatabase.getMapper().putDeviceDocument(
-                new MtpDeviceRecord(100, "Device", true, new MtpRoot[0]));
+                new MtpDeviceRecord(100, "Device", true, new MtpRoot[0], new int[0]));
         mDatabase.getMapper().stopAddingDocuments(null);
         assertEquals("1", mDatabase.getDocumentIdForDevice(100));
     }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 71c4897..44841af 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -68,7 +68,8 @@
                             1024 /* free space */,
                             2048 /* total space */,
                             "" /* no volume identifier */)
-                }));
+                },
+                new int[0]));
 
         mProvider.openDevice(0);
         mResolver.waitForNotification(ROOTS_URI, 1);
@@ -107,7 +108,8 @@
                             1024 /* free space */,
                             2048 /* total space */,
                             "" /* no volume identifier */)
-                }));
+                },
+                new int[0]));
         mProvider.openDevice(0);
         mResolver.waitForNotification(ROOTS_URI, 1);
     }
@@ -127,7 +129,8 @@
                                 1024 /* free space */,
                                 2048 /* total space */,
                                 "" /* no volume identifier */)
-                }));
+                },
+                new int[0]));
         mMtpManager.addValidDevice(new MtpDeviceRecord(
                 1,
                 "Device",
@@ -141,7 +144,8 @@
                             2048 /* free space */,
                             4096 /* total space */,
                             "Identifier B" /* no volume identifier */)
-                }));
+                },
+                new int[0]));
 
         {
             mProvider.openDevice(0);
@@ -175,8 +179,8 @@
 
     public void testQueryRoots_error() throws Exception {
         setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY);
-        mMtpManager.addValidDevice(
-                new MtpDeviceRecord(0, "Device A", false /* unopened */, new MtpRoot[0]));
+        mMtpManager.addValidDevice(new MtpDeviceRecord(
+                0, "Device A", false /* unopened */, new MtpRoot[0], new int[0]));
         mMtpManager.addValidDevice(new MtpDeviceRecord(
                 1,
                 "Device",
@@ -190,7 +194,8 @@
                             2048 /* free space */,
                             4096 /* total space */,
                             "Identifier B" /* no volume identifier */)
-                }));
+                },
+                new int[0]));
         {
             mProvider.openDevice(0);
             mProvider.openDevice(1);
@@ -433,7 +438,7 @@
             throws InterruptedException, TimeoutException, IOException {
         final int changeCount = mResolver.getChangeCount(ROOTS_URI);
         mMtpManager.addValidDevice(
-                new MtpDeviceRecord(deviceId, "Device", false /* unopened */, roots));
+                new MtpDeviceRecord(deviceId, "Device", false /* unopened */, roots, new int[0]));
         mProvider.openDevice(deviceId);
         mResolver.waitForNotification(ROOTS_URI, changeCount + 1);
         return getStrings(mProvider.queryRoots(strings(DocumentsContract.Root.COLUMN_ROOT_ID)));
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
index 5e95e4f..49b48c5 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
@@ -21,9 +21,11 @@
 import android.hardware.usb.UsbManager;
 import android.os.CancellationSignal;
 import android.os.OperationCanceledException;
+import android.os.SystemClock;
 import android.test.InstrumentationTestCase;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.concurrent.Callable;
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
@@ -71,11 +73,18 @@
                 });
         final Thread thread = new Thread(future);
         thread.start();
-        Thread.sleep(TIMEOUT_MS);
+        SystemClock.sleep(TIMEOUT_MS);
         signal.cancel();
         assertTrue(future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
+    public void testOperationsSupported() {
+        final MtpDeviceRecord[] records = mManager.getDevices();
+        assertEquals(1, records.length);
+        assertNotNull(records[0].operationsSupported);
+        getInstrumentation().show(Arrays.toString(records[0].operationsSupported));
+    }
+
     private Context getContext() {
         return getInstrumentation().getContext();
     }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 9a97659..3934b88 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -76,7 +76,7 @@
                 result[i] = device;
             } else {
                 result[i] = new MtpDeviceRecord(
-                        device.deviceId, device.name, device.opened, new MtpRoot[0]);
+                        device.deviceId, device.name, device.opened, new MtpRoot[0], new int[0]);
             }
         }
         return result;
@@ -90,7 +90,7 @@
         }
         mDevices.put(
                 deviceId,
-                new MtpDeviceRecord(device.deviceId, device.name, true, device.roots));
+                new MtpDeviceRecord(device.deviceId, device.name, true, device.roots, new int[0]));
     }
 
     @Override
@@ -101,7 +101,7 @@
         }
         mDevices.put(
                 deviceId,
-                new MtpDeviceRecord(device.deviceId, device.name, false, device.roots));
+                new MtpDeviceRecord(device.deviceId, device.name, false, device.roots, new int[0]));
     }
 
     @Override
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
index 9a40081..2935267 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java
@@ -19,9 +19,12 @@
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbDeviceConnection;
 import android.hardware.usb.UsbManager;
+import android.os.SystemClock;
 
 import java.io.IOException;
 import java.util.HashMap;
+import java.util.Objects;
+
 import junit.framework.Assert;
 
 /**
@@ -37,31 +40,33 @@
     static UsbDevice setupMtpDevice(
             TestResultInstrumentation instrumentation,
             UsbManager usbManager,
-            MtpManager manager) throws InterruptedException, IOException {
-        for (int i = 0; i < 2; i++) {
+            MtpManager manager) {
+        while (true) {
             final UsbDevice device = findMtpDevice(instrumentation, usbManager, manager);
             try {
+                manager.openDevice(device.getDeviceId());
                 waitForStorages(instrumentation, manager, device.getDeviceId());
                 return device;
             } catch (IOException exp) {
+                instrumentation.show(Objects.toString(exp.getMessage()));
+                SystemClock.sleep(1000);
                 // When the MTP device is Android, and it changes the USB device type from
                 // "Charging" to "MTP", the device ID will be updated. We need to find a device
                 // again.
                 continue;
             }
         }
-        throw new IOException("Failed to obtain MTP devices");
     }
 
     private static UsbDevice findMtpDevice(
             TestResultInstrumentation instrumentation,
             UsbManager usbManager,
-            MtpManager manager) throws InterruptedException {
+            MtpManager manager) {
         while (true) {
             final HashMap<String,UsbDevice> devices = usbManager.getDeviceList();
             if (devices.size() == 0) {
                 instrumentation.show("Wait for devices.");
-                Thread.sleep(1000);
+                SystemClock.sleep(1000);
                 continue;
             }
             final UsbDevice device = devices.values().iterator().next();
@@ -84,7 +89,7 @@
                     connection.releaseInterface(device.getInterface(i));
                 }
                 connection.close();
-                Thread.sleep(1000);
+                SystemClock.sleep(1000);
                 continue;
             }
             return device;
@@ -94,7 +99,7 @@
     private static void waitForStorages(
             TestResultInstrumentation instrumentation,
             MtpManager manager,
-            int deviceId) throws InterruptedException, IOException {
+            int deviceId) throws IOException {
         while (true) {
             MtpDeviceRecord device = null;
             for (final MtpDeviceRecord deviceCandidate : manager.getDevices()) {
@@ -108,7 +113,7 @@
             }
             if (device.roots.length == 0) {
                 instrumentation.show("Wait for storages.");
-                Thread.sleep(1000);
+                SystemClock.sleep(1000);
                 continue;
             }
             return;