Add MtpStorageManager for monitoring filesystem events

MtpStorageManager keeps track of file information and
send notifications for new files. MtpDatabase now uses
this instead of MediaProvider for getting object information,
although some operations are still reflected into MP.

Since MtpStorageManager handles storage ids, remove
that field from StorageVolume and VolumeInfo.

Clean up a lot of the jni code for MtpDatabase.

Bug: 63143623
Test: Test every MtpOperation in a variety of situations on Linux and
Windows. Also use the shell to manipulate files. Verify that the cache
is consistent throughout, and the operations behave as expected. Verify
files created by the shell appear.
Test: adb shell am instrument -w android.mtp /android.support.test.runner.AndroidJUnitRunner
Change-Id: Id4ea810047b0c323399cd833047733e5daafb30a
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 4e8c72b..23ef84f6 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -19,7 +19,7 @@
 
 #include "android_media_Utils.h"
 #include "mtp.h"
-#include "MtpDatabase.h"
+#include "IMtpDatabase.h"
 #include "MtpDataPacket.h"
 #include "MtpObjectInfo.h"
 #include "MtpProperty.h"
@@ -55,7 +55,7 @@
 
 static jmethodID method_beginSendObject;
 static jmethodID method_endSendObject;
-static jmethodID method_doScanDirectory;
+static jmethodID method_rescanFile;
 static jmethodID method_getObjectList;
 static jmethodID method_getNumObjects;
 static jmethodID method_getSupportedPlaybackFormats;
@@ -68,35 +68,34 @@
 static jmethodID method_getObjectPropertyList;
 static jmethodID method_getObjectInfo;
 static jmethodID method_getObjectFilePath;
-static jmethodID method_deleteFile;
-static jmethodID method_moveObject;
+static jmethodID method_beginDeleteObject;
+static jmethodID method_endDeleteObject;
+static jmethodID method_beginMoveObject;
+static jmethodID method_endMoveObject;
+static jmethodID method_beginCopyObject;
+static jmethodID method_endCopyObject;
 static jmethodID method_getObjectReferences;
 static jmethodID method_setObjectReferences;
-static jmethodID method_sessionStarted;
-static jmethodID method_sessionEnded;
 
 static jfieldID field_context;
-static jfieldID field_batteryLevel;
-static jfieldID field_batteryScale;
-static jfieldID field_deviceType;
 
-// MtpPropertyList fields
-static jfieldID field_mCount;
-static jfieldID field_mResult;
-static jfieldID field_mObjectHandles;
-static jfieldID field_mPropertyCodes;
-static jfieldID field_mDataTypes;
-static jfieldID field_mLongValues;
-static jfieldID field_mStringValues;
+// MtpPropertyList methods
+static jmethodID method_getCode;
+static jmethodID method_getCount;
+static jmethodID method_getObjectHandles;
+static jmethodID method_getPropertyCodes;
+static jmethodID method_getDataTypes;
+static jmethodID method_getLongValues;
+static jmethodID method_getStringValues;
 
 
-MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
-    return (MtpDatabase *)env->GetLongField(database, field_context);
+IMtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
+    return (IMtpDatabase *)env->GetLongField(database, field_context);
 }
 
 // ----------------------------------------------------------------------------
 
-class MyMtpDatabase : public MtpDatabase {
+class MtpDatabase : public IMtpDatabase {
 private:
     jobject         mDatabase;
     jintArray       mIntBuffer;
@@ -104,23 +103,20 @@
     jcharArray      mStringBuffer;
 
 public:
-                                    MyMtpDatabase(JNIEnv *env, jobject client);
-    virtual                         ~MyMtpDatabase();
+                                    MtpDatabase(JNIEnv *env, jobject client);
+    virtual                         ~MtpDatabase();
     void                            cleanup(JNIEnv *env);
 
     virtual MtpObjectHandle         beginSendObject(const char* path,
                                             MtpObjectFormat format,
                                             MtpObjectHandle parent,
-                                            MtpStorageID storage,
-                                            uint64_t size,
-                                            time_t modified);
+                                            MtpStorageID storage);
 
-    virtual void                    endSendObject(const char* path,
+    virtual void                    endSendObject(MtpObjectHandle handle, bool succeeded);
+
+    virtual void                    rescanFile(const char* path,
                                             MtpObjectHandle handle,
-                                            MtpObjectFormat format,
-                                            bool succeeded);
-
-    virtual void                    doScanDirectory(const char* path);
+                                            MtpObjectFormat format);
 
     virtual MtpObjectHandleList*    getObjectList(MtpStorageID storageID,
                                     MtpObjectFormat format,
@@ -167,7 +163,8 @@
                                             MtpString& outFilePath,
                                             int64_t& outFileLength,
                                             MtpObjectFormat& outFormat);
-    virtual MtpResponseCode         deleteFile(MtpObjectHandle handle);
+    virtual MtpResponseCode         beginDeleteObject(MtpObjectHandle handle);
+    virtual void                    endDeleteObject(MtpObjectHandle handle, bool succeeded);
 
     bool                            getObjectPropertyInfo(MtpObjectProperty property, int& type);
     bool                            getDevicePropertyInfo(MtpDeviceProperty property, int& type);
@@ -182,12 +179,17 @@
 
     virtual MtpProperty*            getDevicePropertyDesc(MtpDeviceProperty property);
 
-    virtual MtpResponseCode         moveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
-                                            MtpStorageID newStorage, MtpString& newPath);
+    virtual MtpResponseCode         beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+                                            MtpStorageID newStorage);
 
-    virtual void                    sessionStarted();
+    virtual void                    endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
+                                            MtpStorageID oldStorage, MtpStorageID newStorage,
+                                             MtpObjectHandle handle, bool succeeded);
 
-    virtual void                    sessionEnded();
+    virtual MtpResponseCode         beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+                                            MtpStorageID newStorage);
+    virtual void                    endCopyObject(MtpObjectHandle handle, bool succeeded);
+
 };
 
 // ----------------------------------------------------------------------------
@@ -202,7 +204,7 @@
 
 // ----------------------------------------------------------------------------
 
-MyMtpDatabase::MyMtpDatabase(JNIEnv *env, jobject client)
+MtpDatabase::MtpDatabase(JNIEnv *env, jobject client)
     :   mDatabase(env->NewGlobalRef(client)),
         mIntBuffer(NULL),
         mLongBuffer(NULL),
@@ -228,27 +230,24 @@
     mStringBuffer = (jcharArray)env->NewGlobalRef(charArray);
 }
 
-void MyMtpDatabase::cleanup(JNIEnv *env) {
+void MtpDatabase::cleanup(JNIEnv *env) {
     env->DeleteGlobalRef(mDatabase);
     env->DeleteGlobalRef(mIntBuffer);
     env->DeleteGlobalRef(mLongBuffer);
     env->DeleteGlobalRef(mStringBuffer);
 }
 
-MyMtpDatabase::~MyMtpDatabase() {
+MtpDatabase::~MtpDatabase() {
 }
 
-MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
+MtpObjectHandle MtpDatabase::beginSendObject(const char* path,
                                                MtpObjectFormat format,
                                                MtpObjectHandle parent,
-                                               MtpStorageID storage,
-                                               uint64_t size,
-                                               time_t modified) {
+                                               MtpStorageID storage) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jstring pathStr = env->NewStringUTF(path);
     MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
-            pathStr, (jint)format, (jint)parent, (jint)storage,
-            (jlong)size, (jlong)modified);
+            pathStr, (jint)format, (jint)parent, (jint)storage);
 
     if (pathStr)
         env->DeleteLocalRef(pathStr);
@@ -256,29 +255,26 @@
     return result;
 }
 
-void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
-                                  MtpObjectFormat format, bool succeeded) {
+void MtpDatabase::endSendObject(MtpObjectHandle handle, bool succeeded) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mDatabase, method_endSendObject, (jint)handle, (jboolean)succeeded);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+void MtpDatabase::rescanFile(const char* path, MtpObjectHandle handle,
+                                  MtpObjectFormat format) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jstring pathStr = env->NewStringUTF(path);
-    env->CallVoidMethod(mDatabase, method_endSendObject, pathStr,
-                        (jint)handle, (jint)format, (jboolean)succeeded);
+    env->CallVoidMethod(mDatabase, method_rescanFile, pathStr,
+                        (jint)handle, (jint)format);
 
     if (pathStr)
         env->DeleteLocalRef(pathStr);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
-void MyMtpDatabase::doScanDirectory(const char* path) {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jstring pathStr = env->NewStringUTF(path);
-    env->CallVoidMethod(mDatabase, method_doScanDirectory, pathStr);
-
-    if (pathStr)
-        env->DeleteLocalRef(pathStr);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
+MtpObjectHandleList* MtpDatabase::getObjectList(MtpStorageID storageID,
                                                   MtpObjectFormat format,
                                                   MtpObjectHandle parent) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -298,7 +294,7 @@
     return list;
 }
 
-int MyMtpDatabase::getNumObjects(MtpStorageID storageID,
+int MtpDatabase::getNumObjects(MtpStorageID storageID,
                                  MtpObjectFormat format,
                                  MtpObjectHandle parent) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -309,7 +305,7 @@
     return result;
 }
 
-MtpObjectFormatList* MyMtpDatabase::getSupportedPlaybackFormats() {
+MtpObjectFormatList* MtpDatabase::getSupportedPlaybackFormats() {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
             method_getSupportedPlaybackFormats);
@@ -327,7 +323,7 @@
     return list;
 }
 
-MtpObjectFormatList* MyMtpDatabase::getSupportedCaptureFormats() {
+MtpObjectFormatList* MtpDatabase::getSupportedCaptureFormats() {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
             method_getSupportedCaptureFormats);
@@ -345,7 +341,7 @@
     return list;
 }
 
-MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
+MtpObjectPropertyList* MtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
             method_getSupportedObjectProperties, (jint)format);
@@ -363,7 +359,7 @@
     return list;
 }
 
-MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() {
+MtpDevicePropertyList* MtpDatabase::getSupportedDeviceProperties() {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
             method_getSupportedDeviceProperties);
@@ -381,7 +377,7 @@
     return list;
 }
 
-MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
+MtpResponseCode MtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
                                                       MtpObjectProperty property,
                                                       MtpDataPacket& packet) {
     static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
@@ -397,42 +393,26 @@
             static_cast<jint>(property),
             0,
             0);
-    MtpResponseCode result = env->GetIntField(list, field_mResult);
-    int count = env->GetIntField(list, field_mCount);
-    if (result == MTP_RESPONSE_OK && count != 1)
+    MtpResponseCode result = env->CallIntMethod(list, method_getCode);
+    jint count = env->CallIntMethod(list, method_getCount);
+    if (count != 1)
         result = MTP_RESPONSE_GENERAL_ERROR;
 
     if (result == MTP_RESPONSE_OK) {
-        jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
-        jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
-        jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
-        jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
-        jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
+        jintArray objectHandlesArray = (jintArray)env->CallObjectMethod(list, method_getObjectHandles);
+        jintArray propertyCodesArray = (jintArray)env->CallObjectMethod(list, method_getPropertyCodes);
+        jintArray dataTypesArray = (jintArray)env->CallObjectMethod(list, method_getDataTypes);
+        jlongArray longValuesArray = (jlongArray)env->CallObjectMethod(list, method_getLongValues);
+        jobjectArray stringValuesArray = (jobjectArray)env->CallObjectMethod(list, method_getStringValues);
 
         jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
         jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
         jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
-        jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
+        jlong* longValues = env->GetLongArrayElements(longValuesArray, 0);
 
         int type = dataTypes[0];
         jlong longValue = (longValues ? longValues[0] : 0);
 
-        // special case date properties, which are strings to MTP
-        // but stored internally as a uint64
-        if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) {
-            char    date[20];
-            formatDateTime(longValue, date, sizeof(date));
-            packet.putString(date);
-            goto out;
-        }
-        // release date is stored internally as just the year
-        if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) {
-            char    date[20];
-            snprintf(date, sizeof(date), "%04" PRId64 "0101T000000", longValue);
-            packet.putString(date);
-            goto out;
-        }
-
         switch (type) {
             case MTP_TYPE_INT8:
                 packet.putInt8(longValue);
@@ -481,20 +461,16 @@
                 ALOGE("unsupported type in getObjectPropertyValue\n");
                 result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
         }
-out:
         env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
         env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
         env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
-        if (longValues)
-            env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
+        env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
 
         env->DeleteLocalRef(objectHandlesArray);
         env->DeleteLocalRef(propertyCodesArray);
         env->DeleteLocalRef(dataTypesArray);
-        if (longValuesArray)
-            env->DeleteLocalRef(longValuesArray);
-        if (stringValuesArray)
-            env->DeleteLocalRef(stringValuesArray);
+        env->DeleteLocalRef(longValuesArray);
+        env->DeleteLocalRef(stringValuesArray);
     }
 
     env->DeleteLocalRef(list);
@@ -559,7 +535,7 @@
     return true;
 }
 
-MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
+MtpResponseCode MtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
                                                       MtpObjectProperty property,
                                                       MtpDataPacket& packet) {
     int         type;
@@ -590,80 +566,73 @@
     return result;
 }
 
-MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
+MtpResponseCode MtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
                                                       MtpDataPacket& packet) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
+    int type;
 
-    if (property == MTP_DEVICE_PROPERTY_BATTERY_LEVEL) {
-        // special case - implemented here instead of Java
-        packet.putUInt8((uint8_t)env->GetIntField(mDatabase, field_batteryLevel));
-        return MTP_RESPONSE_OK;
-    } else {
-        int type;
+    if (!getDevicePropertyInfo(property, type))
+        return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
 
-        if (!getDevicePropertyInfo(property, type))
-            return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
-
-        jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
-                    (jint)property, mLongBuffer, mStringBuffer);
-        if (result != MTP_RESPONSE_OK) {
-            checkAndClearExceptionFromCallback(env, __FUNCTION__);
-            return result;
-        }
-
-        jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
-        jlong longValue = longValues[0];
-        env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
-
-        switch (type) {
-            case MTP_TYPE_INT8:
-                packet.putInt8(longValue);
-                break;
-            case MTP_TYPE_UINT8:
-                packet.putUInt8(longValue);
-                break;
-            case MTP_TYPE_INT16:
-                packet.putInt16(longValue);
-                break;
-            case MTP_TYPE_UINT16:
-                packet.putUInt16(longValue);
-                break;
-            case MTP_TYPE_INT32:
-                packet.putInt32(longValue);
-                break;
-            case MTP_TYPE_UINT32:
-                packet.putUInt32(longValue);
-                break;
-            case MTP_TYPE_INT64:
-                packet.putInt64(longValue);
-                break;
-            case MTP_TYPE_UINT64:
-                packet.putUInt64(longValue);
-                break;
-            case MTP_TYPE_INT128:
-                packet.putInt128(longValue);
-                break;
-            case MTP_TYPE_UINT128:
-                packet.putInt128(longValue);
-                break;
-            case MTP_TYPE_STR:
-            {
-                jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
-                packet.putString(str);
-                env->ReleaseCharArrayElements(mStringBuffer, str, 0);
-                break;
-             }
-            default:
-                ALOGE("unsupported type in getDevicePropertyValue\n");
-                return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
-        }
-
+    jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
+                (jint)property, mLongBuffer, mStringBuffer);
+    if (result != MTP_RESPONSE_OK) {
         checkAndClearExceptionFromCallback(env, __FUNCTION__);
-        return MTP_RESPONSE_OK;
+        return result;
     }
+
+    jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
+    jlong longValue = longValues[0];
+    env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
+
+    switch (type) {
+        case MTP_TYPE_INT8:
+            packet.putInt8(longValue);
+            break;
+        case MTP_TYPE_UINT8:
+            packet.putUInt8(longValue);
+            break;
+        case MTP_TYPE_INT16:
+            packet.putInt16(longValue);
+            break;
+        case MTP_TYPE_UINT16:
+            packet.putUInt16(longValue);
+            break;
+        case MTP_TYPE_INT32:
+            packet.putInt32(longValue);
+            break;
+        case MTP_TYPE_UINT32:
+            packet.putUInt32(longValue);
+            break;
+        case MTP_TYPE_INT64:
+            packet.putInt64(longValue);
+            break;
+        case MTP_TYPE_UINT64:
+            packet.putUInt64(longValue);
+            break;
+        case MTP_TYPE_INT128:
+            packet.putInt128(longValue);
+            break;
+        case MTP_TYPE_UINT128:
+            packet.putInt128(longValue);
+            break;
+        case MTP_TYPE_STR:
+        {
+            jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
+            packet.putString(str);
+            env->ReleaseCharArrayElements(mStringBuffer, str, 0);
+            break;
+        }
+        default:
+            ALOGE("unsupported type in getDevicePropertyValue\n");
+            return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
+    }
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return MTP_RESPONSE_OK;
 }
 
-MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
+MtpResponseCode MtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
                                                       MtpDataPacket& packet) {
     int         type;
 
@@ -693,11 +662,11 @@
     return result;
 }
 
-MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty /*property*/) {
+MtpResponseCode MtpDatabase::resetDeviceProperty(MtpDeviceProperty /*property*/) {
     return -1;
 }
 
-MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
+MtpResponseCode MtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
                                                      uint32_t format, uint32_t property,
                                                      int groupCode, int depth,
                                                      MtpDataPacket& packet) {
@@ -715,16 +684,16 @@
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     if (!list)
         return MTP_RESPONSE_GENERAL_ERROR;
-    int count = env->GetIntField(list, field_mCount);
-    MtpResponseCode result = env->GetIntField(list, field_mResult);
+    int count = env->CallIntMethod(list, method_getCount);
+    MtpResponseCode result = env->CallIntMethod(list, method_getCode);
 
     packet.putUInt32(count);
     if (count > 0) {
-        jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
-        jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
-        jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
-        jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
-        jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
+        jintArray objectHandlesArray = (jintArray)env->CallObjectMethod(list, method_getObjectHandles);
+        jintArray propertyCodesArray = (jintArray)env->CallObjectMethod(list, method_getPropertyCodes);
+        jintArray dataTypesArray = (jintArray)env->CallObjectMethod(list, method_getDataTypes);
+        jlongArray longValuesArray = (jlongArray)env->CallObjectMethod(list, method_getLongValues);
+        jobjectArray stringValuesArray = (jobjectArray)env->CallObjectMethod(list, method_getStringValues);
 
         jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
         jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
@@ -781,7 +750,7 @@
                     break;
                 }
                 default:
-                    ALOGE("bad or unsupported data type in MyMtpDatabase::getObjectPropertyList");
+                    ALOGE("bad or unsupported data type in MtpDatabase::getObjectPropertyList");
                     break;
             }
         }
@@ -789,16 +758,13 @@
         env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
         env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
         env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
-        if (longValues)
-            env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
+        env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
 
         env->DeleteLocalRef(objectHandlesArray);
         env->DeleteLocalRef(propertyCodesArray);
         env->DeleteLocalRef(dataTypesArray);
-        if (longValuesArray)
-            env->DeleteLocalRef(longValuesArray);
-        if (stringValuesArray)
-            env->DeleteLocalRef(stringValuesArray);
+        env->DeleteLocalRef(longValuesArray);
+        env->DeleteLocalRef(stringValuesArray);
     }
 
     env->DeleteLocalRef(list);
@@ -822,7 +788,7 @@
     return exif_get_long(e->data, o);
 }
 
-MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
+MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
                                              MtpObjectInfo& info) {
     MtpString       path;
     int64_t         length;
@@ -914,7 +880,7 @@
     return MTP_RESPONSE_OK;
 }
 
-void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
+void* MtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
     MtpString path;
     int64_t length;
     MtpObjectFormat format;
@@ -979,7 +945,7 @@
     return result;
 }
 
-MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
+MtpResponseCode MtpDatabase::getObjectFilePath(MtpObjectHandle handle,
                                                  MtpString& outFilePath,
                                                  int64_t& outFileLength,
                                                  MtpObjectFormat& outFormat) {
@@ -1005,26 +971,60 @@
     return result;
 }
 
-MtpResponseCode MyMtpDatabase::deleteFile(MtpObjectHandle handle) {
+MtpResponseCode MtpDatabase::beginDeleteObject(MtpObjectHandle handle) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    MtpResponseCode result = env->CallIntMethod(mDatabase, method_deleteFile, (jint)handle);
+    MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginDeleteObject, (jint)handle);
 
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return result;
 }
 
-MtpResponseCode MyMtpDatabase::moveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
-        MtpStorageID newStorage, MtpString &newPath) {
+void MtpDatabase::endDeleteObject(MtpObjectHandle handle, bool succeeded) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jstring stringValue = env->NewStringUTF((const char *) newPath);
-    MtpResponseCode result = env->CallIntMethod(mDatabase, method_moveObject,
-                (jint)handle, (jint)newParent, (jint) newStorage, stringValue);
+    env->CallVoidMethod(mDatabase, method_endDeleteObject, (jint)handle, (jboolean) succeeded);
 
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
-    env->DeleteLocalRef(stringValue);
+}
+
+MtpResponseCode MtpDatabase::beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+        MtpStorageID newStorage) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginMoveObject,
+                (jint)handle, (jint)newParent, (jint) newStorage);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return result;
 }
 
+void MtpDatabase::endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
+                                            MtpStorageID oldStorage, MtpStorageID newStorage,
+                                             MtpObjectHandle handle, bool succeeded) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mDatabase, method_endMoveObject,
+                (jint)oldParent, (jint) newParent, (jint) oldStorage, (jint) newStorage,
+                (jint) handle, (jboolean) succeeded);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+MtpResponseCode MtpDatabase::beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+        MtpStorageID newStorage) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginCopyObject,
+                (jint)handle, (jint)newParent, (jint) newStorage);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+    return result;
+}
+
+void MtpDatabase::endCopyObject(MtpObjectHandle handle, bool succeeded) {
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mDatabase, method_endCopyObject, (jint)handle, (jboolean)succeeded);
+
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
+
 struct PropertyTableEntry {
     MtpObjectProperty   property;
     int                 type;
@@ -1066,7 +1066,7 @@
     {   MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE,      MTP_TYPE_UINT32 },
 };
 
-bool MyMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
+bool MtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
     int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
     const PropertyTableEntry* entry = kObjectPropertyTable;
     for (int i = 0; i < count; i++, entry++) {
@@ -1078,7 +1078,7 @@
     return false;
 }
 
-bool MyMtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
+bool MtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
     int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
     const PropertyTableEntry* entry = kDevicePropertyTable;
     for (int i = 0; i < count; i++, entry++) {
@@ -1090,7 +1090,7 @@
     return false;
 }
 
-MtpObjectHandleList* MyMtpDatabase::getObjectReferences(MtpObjectHandle handle) {
+MtpObjectHandleList* MtpDatabase::getObjectReferences(MtpObjectHandle handle) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectReferences,
                 (jint)handle);
@@ -1108,7 +1108,7 @@
     return list;
 }
 
-MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
+MtpResponseCode MtpDatabase::setObjectReferences(MtpObjectHandle handle,
                                                    MtpObjectHandleList* references) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     int count = references->size();
@@ -1129,7 +1129,7 @@
     return result;
 }
 
-MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
+MtpProperty* MtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
                                                   MtpObjectFormat format) {
     static const int channelEnum[] = {
                                         1,  // mono
@@ -1210,67 +1210,65 @@
     return result;
 }
 
-MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
+MtpProperty* MtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     MtpProperty* result = NULL;
     bool writable = false;
 
-    switch (property) {
-        case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
-        case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
-            writable = true;
-            // fall through
-        case MTP_DEVICE_PROPERTY_IMAGE_SIZE: {
-            result = new MtpProperty(property, MTP_TYPE_STR, writable);
-
-            // get current value
-            jint ret = env->CallIntMethod(mDatabase, method_getDeviceProperty,
-                        (jint)property, mLongBuffer, mStringBuffer);
-            if (ret == MTP_RESPONSE_OK) {
+    // get current value
+    jint ret = env->CallIntMethod(mDatabase, method_getDeviceProperty,
+        (jint)property, mLongBuffer, mStringBuffer);
+    if (ret == MTP_RESPONSE_OK) {
+        switch (property) {
+            case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
+            case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
+                writable = true;
+                // fall through
+            case MTP_DEVICE_PROPERTY_IMAGE_SIZE:
+            {
+                result = new MtpProperty(property, MTP_TYPE_STR, writable);
                 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
                 result->setCurrentValue(str);
                 // for read-only properties it is safe to assume current value is default value
                 if (!writable)
                     result->setDefaultValue(str);
                 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
-            } else {
-                ALOGE("unable to read device property, response: %04X", ret);
+                break;
             }
-            break;
+            case MTP_DEVICE_PROPERTY_BATTERY_LEVEL:
+            {
+                result = new MtpProperty(property, MTP_TYPE_UINT8);
+                jlong* arr = env->GetLongArrayElements(mLongBuffer, 0);
+                result->setFormRange(0, arr[1], 1);
+                result->mCurrentValue.u.u8 = (uint8_t) arr[0];
+                env->ReleaseLongArrayElements(mLongBuffer, arr, 0);
+                break;
+            }
+            case MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE:
+            {
+                jlong* arr = env->GetLongArrayElements(mLongBuffer, 0);
+                result = new MtpProperty(property, MTP_TYPE_UINT32);
+                result->mCurrentValue.u.u32 = (uint32_t) arr[0];
+                env->ReleaseLongArrayElements(mLongBuffer, arr, 0);
+                break;
+            }
+            default:
+                ALOGE("Unrecognized property %x", property);
         }
-        case MTP_DEVICE_PROPERTY_BATTERY_LEVEL:
-            result = new MtpProperty(property, MTP_TYPE_UINT8);
-            result->setFormRange(0, env->GetIntField(mDatabase, field_batteryScale), 1);
-            result->mCurrentValue.u.u8 = (uint8_t)env->GetIntField(mDatabase, field_batteryLevel);
-            break;
-        case MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE:
-            result = new MtpProperty(property, MTP_TYPE_UINT32);
-            result->mCurrentValue.u.u32 = (uint32_t)env->GetIntField(mDatabase, field_deviceType);
-            break;
+    } else {
+        ALOGE("unable to read device property, response: %04X", ret);
     }
 
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     return result;
 }
 
-void MyMtpDatabase::sessionStarted() {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mDatabase, method_sessionStarted);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
-void MyMtpDatabase::sessionEnded() {
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mDatabase, method_sessionEnded);
-    checkAndClearExceptionFromCallback(env, __FUNCTION__);
-}
-
 // ----------------------------------------------------------------------------
 
 static void
 android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
 {
-    MyMtpDatabase* database = new MyMtpDatabase(env, thiz);
+    MtpDatabase* database = new MtpDatabase(env, thiz);
     env->SetLongField(thiz, field_context, (jlong)database);
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
@@ -1278,7 +1276,7 @@
 static void
 android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
 {
-    MyMtpDatabase* database = (MyMtpDatabase *)env->GetLongField(thiz, field_context);
+    MtpDatabase* database = (MtpDatabase *)env->GetLongField(thiz, field_context);
     database->cleanup(env);
     delete database;
     env->SetLongField(thiz, field_context, 0);
@@ -1305,6 +1303,13 @@
                                         (void *)android_mtp_MtpPropertyGroup_format_date_time},
 };
 
+#define GET_METHOD_ID(name, jclass, signature)                              \
+    method_##name = env->GetMethodID(jclass, #name, signature);             \
+    if (method_##name == NULL) {                                            \
+        ALOGE("Can't find " #name);                                         \
+        return -1;                                                          \
+    }                                                                       \
+
 int register_android_mtp_MtpDatabase(JNIEnv *env)
 {
     jclass clazz;
@@ -1314,175 +1319,48 @@
         ALOGE("Can't find android/mtp/MtpDatabase");
         return -1;
     }
-    method_beginSendObject = env->GetMethodID(clazz, "beginSendObject", "(Ljava/lang/String;IIIJJ)I");
-    if (method_beginSendObject == NULL) {
-        ALOGE("Can't find beginSendObject");
-        return -1;
-    }
-    method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIZ)V");
-    if (method_endSendObject == NULL) {
-        ALOGE("Can't find endSendObject");
-        return -1;
-    }
-    method_doScanDirectory = env->GetMethodID(clazz, "doScanDirectory", "(Ljava/lang/String;)V");
-    if (method_doScanDirectory == NULL) {
-        ALOGE("Can't find doScanDirectory");
-        return -1;
-    }
-    method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I");
-    if (method_getObjectList == NULL) {
-        ALOGE("Can't find getObjectList");
-        return -1;
-    }
-    method_getNumObjects = env->GetMethodID(clazz, "getNumObjects", "(III)I");
-    if (method_getNumObjects == NULL) {
-        ALOGE("Can't find getNumObjects");
-        return -1;
-    }
-    method_getSupportedPlaybackFormats = env->GetMethodID(clazz, "getSupportedPlaybackFormats", "()[I");
-    if (method_getSupportedPlaybackFormats == NULL) {
-        ALOGE("Can't find getSupportedPlaybackFormats");
-        return -1;
-    }
-    method_getSupportedCaptureFormats = env->GetMethodID(clazz, "getSupportedCaptureFormats", "()[I");
-    if (method_getSupportedCaptureFormats == NULL) {
-        ALOGE("Can't find getSupportedCaptureFormats");
-        return -1;
-    }
-    method_getSupportedObjectProperties = env->GetMethodID(clazz, "getSupportedObjectProperties", "(I)[I");
-    if (method_getSupportedObjectProperties == NULL) {
-        ALOGE("Can't find getSupportedObjectProperties");
-        return -1;
-    }
-    method_getSupportedDeviceProperties = env->GetMethodID(clazz, "getSupportedDeviceProperties", "()[I");
-    if (method_getSupportedDeviceProperties == NULL) {
-        ALOGE("Can't find getSupportedDeviceProperties");
-        return -1;
-    }
-    method_setObjectProperty = env->GetMethodID(clazz, "setObjectProperty", "(IIJLjava/lang/String;)I");
-    if (method_setObjectProperty == NULL) {
-        ALOGE("Can't find setObjectProperty");
-        return -1;
-    }
-    method_getDeviceProperty = env->GetMethodID(clazz, "getDeviceProperty", "(I[J[C)I");
-    if (method_getDeviceProperty == NULL) {
-        ALOGE("Can't find getDeviceProperty");
-        return -1;
-    }
-    method_setDeviceProperty = env->GetMethodID(clazz, "setDeviceProperty", "(IJLjava/lang/String;)I");
-    if (method_setDeviceProperty == NULL) {
-        ALOGE("Can't find setDeviceProperty");
-        return -1;
-    }
-    method_getObjectPropertyList = env->GetMethodID(clazz, "getObjectPropertyList",
-            "(IIIII)Landroid/mtp/MtpPropertyList;");
-    if (method_getObjectPropertyList == NULL) {
-        ALOGE("Can't find getObjectPropertyList");
-        return -1;
-    }
-    method_getObjectInfo = env->GetMethodID(clazz, "getObjectInfo", "(I[I[C[J)Z");
-    if (method_getObjectInfo == NULL) {
-        ALOGE("Can't find getObjectInfo");
-        return -1;
-    }
-    method_getObjectFilePath = env->GetMethodID(clazz, "getObjectFilePath", "(I[C[J)I");
-    if (method_getObjectFilePath == NULL) {
-        ALOGE("Can't find getObjectFilePath");
-        return -1;
-    }
-    method_deleteFile = env->GetMethodID(clazz, "deleteFile", "(I)I");
-    if (method_deleteFile == NULL) {
-        ALOGE("Can't find deleteFile");
-        return -1;
-    }
-    method_moveObject = env->GetMethodID(clazz, "moveObject", "(IIILjava/lang/String;)I");
-    if (method_moveObject == NULL) {
-        ALOGE("Can't find moveObject");
-        return -1;
-    }
-    method_getObjectReferences = env->GetMethodID(clazz, "getObjectReferences", "(I)[I");
-    if (method_getObjectReferences == NULL) {
-        ALOGE("Can't find getObjectReferences");
-        return -1;
-    }
-    method_setObjectReferences = env->GetMethodID(clazz, "setObjectReferences", "(I[I)I");
-    if (method_setObjectReferences == NULL) {
-        ALOGE("Can't find setObjectReferences");
-        return -1;
-    }
-    method_sessionStarted = env->GetMethodID(clazz, "sessionStarted", "()V");
-    if (method_sessionStarted == NULL) {
-        ALOGE("Can't find sessionStarted");
-        return -1;
-    }
-    method_sessionEnded = env->GetMethodID(clazz, "sessionEnded", "()V");
-    if (method_sessionEnded == NULL) {
-        ALOGE("Can't find sessionEnded");
-        return -1;
-    }
+    GET_METHOD_ID(beginSendObject, clazz, "(Ljava/lang/String;III)I");
+    GET_METHOD_ID(endSendObject, clazz, "(IZ)V");
+    GET_METHOD_ID(rescanFile, clazz, "(Ljava/lang/String;II)V");
+    GET_METHOD_ID(getObjectList, clazz, "(III)[I");
+    GET_METHOD_ID(getNumObjects, clazz, "(III)I");
+    GET_METHOD_ID(getSupportedPlaybackFormats, clazz, "()[I");
+    GET_METHOD_ID(getSupportedCaptureFormats, clazz, "()[I");
+    GET_METHOD_ID(getSupportedObjectProperties, clazz, "(I)[I");
+    GET_METHOD_ID(getSupportedDeviceProperties, clazz, "()[I");
+    GET_METHOD_ID(setObjectProperty, clazz, "(IIJLjava/lang/String;)I");
+    GET_METHOD_ID(getDeviceProperty, clazz, "(I[J[C)I");
+    GET_METHOD_ID(setDeviceProperty, clazz, "(IJLjava/lang/String;)I");
+    GET_METHOD_ID(getObjectPropertyList, clazz, "(IIIII)Landroid/mtp/MtpPropertyList;");
+    GET_METHOD_ID(getObjectInfo, clazz, "(I[I[C[J)Z");
+    GET_METHOD_ID(getObjectFilePath, clazz, "(I[C[J)I");
+    GET_METHOD_ID(beginDeleteObject, clazz, "(I)I");
+    GET_METHOD_ID(endDeleteObject, clazz, "(IZ)V");
+    GET_METHOD_ID(beginMoveObject, clazz, "(III)I");
+    GET_METHOD_ID(endMoveObject, clazz, "(IIIIIZ)V");
+    GET_METHOD_ID(beginCopyObject, clazz, "(III)I");
+    GET_METHOD_ID(endCopyObject, clazz, "(IZ)V");
+    GET_METHOD_ID(getObjectReferences, clazz, "(I)[I");
+    GET_METHOD_ID(setObjectReferences, clazz, "(I[I)I");
 
     field_context = env->GetFieldID(clazz, "mNativeContext", "J");
     if (field_context == NULL) {
         ALOGE("Can't find MtpDatabase.mNativeContext");
         return -1;
     }
-    field_batteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I");
-    if (field_batteryLevel == NULL) {
-        ALOGE("Can't find MtpDatabase.mBatteryLevel");
-        return -1;
-    }
-    field_batteryScale = env->GetFieldID(clazz, "mBatteryScale", "I");
-    if (field_batteryScale == NULL) {
-        ALOGE("Can't find MtpDatabase.mBatteryScale");
-        return -1;
-    }
-    field_deviceType = env->GetFieldID(clazz, "mDeviceType", "I");
-    if (field_deviceType == NULL) {
-        ALOGE("Can't find MtpDatabase.mDeviceType");
-        return -1;
-    }
 
-    // now set up fields for MtpPropertyList class
     clazz = env->FindClass("android/mtp/MtpPropertyList");
     if (clazz == NULL) {
         ALOGE("Can't find android/mtp/MtpPropertyList");
         return -1;
     }
-    field_mCount = env->GetFieldID(clazz, "mCount", "I");
-    if (field_mCount == NULL) {
-        ALOGE("Can't find MtpPropertyList.mCount");
-        return -1;
-    }
-    field_mResult = env->GetFieldID(clazz, "mResult", "I");
-    if (field_mResult == NULL) {
-        ALOGE("Can't find MtpPropertyList.mResult");
-        return -1;
-    }
-    field_mObjectHandles = env->GetFieldID(clazz, "mObjectHandles", "[I");
-    if (field_mObjectHandles == NULL) {
-        ALOGE("Can't find MtpPropertyList.mObjectHandles");
-        return -1;
-    }
-    field_mPropertyCodes = env->GetFieldID(clazz, "mPropertyCodes", "[I");
-    if (field_mPropertyCodes == NULL) {
-        ALOGE("Can't find MtpPropertyList.mPropertyCodes");
-        return -1;
-    }
-    field_mDataTypes = env->GetFieldID(clazz, "mDataTypes", "[I");
-    if (field_mDataTypes == NULL) {
-        ALOGE("Can't find MtpPropertyList.mDataTypes");
-        return -1;
-    }
-    field_mLongValues = env->GetFieldID(clazz, "mLongValues", "[J");
-    if (field_mLongValues == NULL) {
-        ALOGE("Can't find MtpPropertyList.mLongValues");
-        return -1;
-    }
-    field_mStringValues = env->GetFieldID(clazz, "mStringValues", "[Ljava/lang/String;");
-    if (field_mStringValues == NULL) {
-        ALOGE("Can't find MtpPropertyList.mStringValues");
-        return -1;
-    }
+    GET_METHOD_ID(getCode, clazz, "()I");
+    GET_METHOD_ID(getCount, clazz, "()I");
+    GET_METHOD_ID(getObjectHandles, clazz, "()[I");
+    GET_METHOD_ID(getPropertyCodes, clazz, "()[I");
+    GET_METHOD_ID(getDataTypes, clazz, "()[I");
+    GET_METHOD_ID(getLongValues, clazz, "()[J");
+    GET_METHOD_ID(getStringValues, clazz, "()[Ljava/lang/String;");
 
     if (AndroidRuntime::registerNativeMethods(env,
                 "android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods)))