Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "MtpDatabaseJNI"
     18 #include "utils/Log.h"
     19 
     20 #include <stdio.h>
     21 #include <assert.h>
     22 #include <limits.h>
     23 #include <unistd.h>
     24 #include <fcntl.h>
     25 
     26 #include "jni.h"
     27 #include "JNIHelp.h"
     28 #include "android_runtime/AndroidRuntime.h"
     29 #include "android_runtime/Log.h"
     30 
     31 #include "MtpDatabase.h"
     32 #include "MtpDataPacket.h"
     33 #include "MtpObjectInfo.h"
     34 #include "MtpProperty.h"
     35 #include "MtpStringBuffer.h"
     36 #include "MtpUtils.h"
     37 #include "mtp.h"
     38 
     39 extern "C" {
     40 #include "jhead.h"
     41 }
     42 
     43 using namespace android;
     44 
     45 // ----------------------------------------------------------------------------
     46 
     47 static jmethodID method_beginSendObject;
     48 static jmethodID method_endSendObject;
     49 static jmethodID method_getObjectList;
     50 static jmethodID method_getNumObjects;
     51 static jmethodID method_getSupportedPlaybackFormats;
     52 static jmethodID method_getSupportedCaptureFormats;
     53 static jmethodID method_getSupportedObjectProperties;
     54 static jmethodID method_getSupportedDeviceProperties;
     55 static jmethodID method_setObjectProperty;
     56 static jmethodID method_getDeviceProperty;
     57 static jmethodID method_setDeviceProperty;
     58 static jmethodID method_getObjectPropertyList;
     59 static jmethodID method_getObjectInfo;
     60 static jmethodID method_getObjectFilePath;
     61 static jmethodID method_deleteFile;
     62 static jmethodID method_getObjectReferences;
     63 static jmethodID method_setObjectReferences;
     64 static jmethodID method_sessionStarted;
     65 static jmethodID method_sessionEnded;
     66 
     67 static jfieldID field_context;
     68 
     69 // MtpPropertyList fields
     70 static jfieldID field_mCount;
     71 static jfieldID field_mResult;
     72 static jfieldID field_mObjectHandles;
     73 static jfieldID field_mPropertyCodes;
     74 static jfieldID field_mDataTypes;
     75 static jfieldID field_mLongValues;
     76 static jfieldID field_mStringValues;
     77 
     78 
     79 MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
     80     return (MtpDatabase *)env->GetIntField(database, field_context);
     81 }
     82 
     83 // ----------------------------------------------------------------------------
     84 
     85 class MyMtpDatabase : public MtpDatabase {
     86 private:
     87     jobject         mDatabase;
     88     jintArray       mIntBuffer;
     89     jlongArray      mLongBuffer;
     90     jcharArray      mStringBuffer;
     91 
     92 public:
     93                                     MyMtpDatabase(JNIEnv *env, jobject client);
     94     virtual                         ~MyMtpDatabase();
     95     void                            cleanup(JNIEnv *env);
     96 
     97     virtual MtpObjectHandle         beginSendObject(const char* path,
     98                                             MtpObjectFormat format,
     99                                             MtpObjectHandle parent,
    100                                             MtpStorageID storage,
    101                                             uint64_t size,
    102                                             time_t modified);
    103 
    104     virtual void                    endSendObject(const char* path,
    105                                             MtpObjectHandle handle,
    106                                             MtpObjectFormat format,
    107                                             bool succeeded);
    108 
    109     virtual MtpObjectHandleList*    getObjectList(MtpStorageID storageID,
    110                                     MtpObjectFormat format,
    111                                     MtpObjectHandle parent);
    112 
    113     virtual int                     getNumObjects(MtpStorageID storageID,
    114                                             MtpObjectFormat format,
    115                                             MtpObjectHandle parent);
    116 
    117     // callee should delete[] the results from these
    118     // results can be NULL
    119     virtual MtpObjectFormatList*    getSupportedPlaybackFormats();
    120     virtual MtpObjectFormatList*    getSupportedCaptureFormats();
    121     virtual MtpObjectPropertyList*  getSupportedObjectProperties(MtpObjectFormat format);
    122     virtual MtpDevicePropertyList*  getSupportedDeviceProperties();
    123 
    124     virtual MtpResponseCode         getObjectPropertyValue(MtpObjectHandle handle,
    125                                             MtpObjectProperty property,
    126                                             MtpDataPacket& packet);
    127 
    128     virtual MtpResponseCode         setObjectPropertyValue(MtpObjectHandle handle,
    129                                             MtpObjectProperty property,
    130                                             MtpDataPacket& packet);
    131 
    132     virtual MtpResponseCode         getDevicePropertyValue(MtpDeviceProperty property,
    133                                             MtpDataPacket& packet);
    134 
    135     virtual MtpResponseCode         setDevicePropertyValue(MtpDeviceProperty property,
    136                                             MtpDataPacket& packet);
    137 
    138     virtual MtpResponseCode         resetDeviceProperty(MtpDeviceProperty property);
    139 
    140     virtual MtpResponseCode         getObjectPropertyList(MtpObjectHandle handle,
    141                                             uint32_t format, uint32_t property,
    142                                             int groupCode, int depth,
    143                                             MtpDataPacket& packet);
    144 
    145     virtual MtpResponseCode         getObjectInfo(MtpObjectHandle handle,
    146                                             MtpObjectInfo& info);
    147 
    148     virtual void*                   getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
    149 
    150     virtual MtpResponseCode         getObjectFilePath(MtpObjectHandle handle,
    151                                             MtpString& outFilePath,
    152                                             int64_t& outFileLength,
    153                                             MtpObjectFormat& outFormat);
    154     virtual MtpResponseCode         deleteFile(MtpObjectHandle handle);
    155 
    156     bool                            getObjectPropertyInfo(MtpObjectProperty property, int& type);
    157     bool                            getDevicePropertyInfo(MtpDeviceProperty property, int& type);
    158 
    159     virtual MtpObjectHandleList*    getObjectReferences(MtpObjectHandle handle);
    160 
    161     virtual MtpResponseCode         setObjectReferences(MtpObjectHandle handle,
    162                                             MtpObjectHandleList* references);
    163 
    164     virtual MtpProperty*            getObjectPropertyDesc(MtpObjectProperty property,
    165                                             MtpObjectFormat format);
    166 
    167     virtual MtpProperty*            getDevicePropertyDesc(MtpDeviceProperty property);
    168 
    169     virtual void                    sessionStarted();
    170 
    171     virtual void                    sessionEnded();
    172 };
    173 
    174 // ----------------------------------------------------------------------------
    175 
    176 static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
    177     if (env->ExceptionCheck()) {
    178         ALOGE("An exception was thrown by callback '%s'.", methodName);
    179         LOGE_EX(env);
    180         env->ExceptionClear();
    181     }
    182 }
    183 
    184 // ----------------------------------------------------------------------------
    185 
    186 MyMtpDatabase::MyMtpDatabase(JNIEnv *env, jobject client)
    187     :   mDatabase(env->NewGlobalRef(client)),
    188         mIntBuffer(NULL),
    189         mLongBuffer(NULL),
    190         mStringBuffer(NULL)
    191 {
    192     // create buffers for out arguments
    193     // we don't need to be thread-safe so this is OK
    194     jintArray intArray = env->NewIntArray(3);
    195     if (!intArray) {
    196         return; // Already threw.
    197     }
    198     mIntBuffer = (jintArray)env->NewGlobalRef(intArray);
    199     jlongArray longArray = env->NewLongArray(2);
    200     if (!longArray) {
    201         return; // Already threw.
    202     }
    203     mLongBuffer = (jlongArray)env->NewGlobalRef(longArray);
    204     jcharArray charArray = env->NewCharArray(256);
    205     if (!charArray) {
    206         return; // Already threw.
    207     }
    208     mStringBuffer = (jcharArray)env->NewGlobalRef(charArray);
    209 }
    210 
    211 void MyMtpDatabase::cleanup(JNIEnv *env) {
    212     env->DeleteGlobalRef(mDatabase);
    213     env->DeleteGlobalRef(mIntBuffer);
    214     env->DeleteGlobalRef(mLongBuffer);
    215     env->DeleteGlobalRef(mStringBuffer);
    216 }
    217 
    218 MyMtpDatabase::~MyMtpDatabase() {
    219 }
    220 
    221 MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
    222                                             MtpObjectFormat format,
    223                                             MtpObjectHandle parent,
    224                                             MtpStorageID storage,
    225                                             uint64_t size,
    226                                             time_t modified) {
    227     JNIEnv* env = AndroidRuntime::getJNIEnv();
    228     jstring pathStr = env->NewStringUTF(path);
    229     MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
    230             pathStr, (jint)format, (jint)parent, (jint)storage,
    231             (jlong)size, (jlong)modified);
    232 
    233     if (pathStr)
    234         env->DeleteLocalRef(pathStr);
    235     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    236     return result;
    237 }
    238 
    239 void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
    240                                 MtpObjectFormat format, bool succeeded) {
    241     JNIEnv* env = AndroidRuntime::getJNIEnv();
    242     jstring pathStr = env->NewStringUTF(path);
    243     env->CallVoidMethod(mDatabase, method_endSendObject, pathStr,
    244                         (jint)handle, (jint)format, (jboolean)succeeded);
    245 
    246     if (pathStr)
    247         env->DeleteLocalRef(pathStr);
    248     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    249 }
    250 
    251 MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
    252                                     MtpObjectFormat format,
    253                                     MtpObjectHandle parent) {
    254     JNIEnv* env = AndroidRuntime::getJNIEnv();
    255     jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList,
    256                 (jint)storageID, (jint)format, (jint)parent);
    257     if (!array)
    258         return NULL;
    259     MtpObjectHandleList* list = new MtpObjectHandleList();
    260     jint* handles = env->GetIntArrayElements(array, 0);
    261     jsize length = env->GetArrayLength(array);
    262     for (int i = 0; i < length; i++)
    263         list->push(handles[i]);
    264     env->ReleaseIntArrayElements(array, handles, 0);
    265     env->DeleteLocalRef(array);
    266 
    267     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    268     return list;
    269 }
    270 
    271 int MyMtpDatabase::getNumObjects(MtpStorageID storageID,
    272                                 MtpObjectFormat format,
    273                                 MtpObjectHandle parent) {
    274     JNIEnv* env = AndroidRuntime::getJNIEnv();
    275     int result = env->CallIntMethod(mDatabase, method_getNumObjects,
    276                 (jint)storageID, (jint)format, (jint)parent);
    277 
    278     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    279     return result;
    280 }
    281 
    282 MtpObjectFormatList* MyMtpDatabase::getSupportedPlaybackFormats() {
    283     JNIEnv* env = AndroidRuntime::getJNIEnv();
    284     jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
    285             method_getSupportedPlaybackFormats);
    286     if (!array)
    287         return NULL;
    288     MtpObjectFormatList* list = new MtpObjectFormatList();
    289     jint* formats = env->GetIntArrayElements(array, 0);
    290     jsize length = env->GetArrayLength(array);
    291     for (int i = 0; i < length; i++)
    292         list->push(formats[i]);
    293     env->ReleaseIntArrayElements(array, formats, 0);
    294     env->DeleteLocalRef(array);
    295 
    296     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    297     return list;
    298 }
    299 
    300 MtpObjectFormatList* MyMtpDatabase::getSupportedCaptureFormats() {
    301     JNIEnv* env = AndroidRuntime::getJNIEnv();
    302     jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
    303             method_getSupportedCaptureFormats);
    304     if (!array)
    305         return NULL;
    306     MtpObjectFormatList* list = new MtpObjectFormatList();
    307     jint* formats = env->GetIntArrayElements(array, 0);
    308     jsize length = env->GetArrayLength(array);
    309     for (int i = 0; i < length; i++)
    310         list->push(formats[i]);
    311     env->ReleaseIntArrayElements(array, formats, 0);
    312     env->DeleteLocalRef(array);
    313 
    314     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    315     return list;
    316 }
    317 
    318 MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
    319     JNIEnv* env = AndroidRuntime::getJNIEnv();
    320     jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
    321             method_getSupportedObjectProperties, (jint)format);
    322     if (!array)
    323         return NULL;
    324     MtpObjectPropertyList* list = new MtpObjectPropertyList();
    325     jint* properties = env->GetIntArrayElements(array, 0);
    326     jsize length = env->GetArrayLength(array);
    327     for (int i = 0; i < length; i++)
    328         list->push(properties[i]);
    329     env->ReleaseIntArrayElements(array, properties, 0);
    330     env->DeleteLocalRef(array);
    331 
    332     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    333     return list;
    334 }
    335 
    336 MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() {
    337     JNIEnv* env = AndroidRuntime::getJNIEnv();
    338     jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
    339             method_getSupportedDeviceProperties);
    340     if (!array)
    341         return NULL;
    342     MtpDevicePropertyList* list = new MtpDevicePropertyList();
    343     jint* properties = env->GetIntArrayElements(array, 0);
    344     jsize length = env->GetArrayLength(array);
    345     for (int i = 0; i < length; i++)
    346         list->push(properties[i]);
    347     env->ReleaseIntArrayElements(array, properties, 0);
    348     env->DeleteLocalRef(array);
    349 
    350     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    351     return list;
    352 }
    353 
    354 MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
    355                                             MtpObjectProperty property,
    356                                             MtpDataPacket& packet) {
    357     JNIEnv* env = AndroidRuntime::getJNIEnv();
    358     jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
    359                 (jlong)handle, 0, (jlong)property, 0, 0);
    360     MtpResponseCode result = env->GetIntField(list, field_mResult);
    361     int count = env->GetIntField(list, field_mCount);
    362     if (result == MTP_RESPONSE_OK && count != 1)
    363         result = MTP_RESPONSE_GENERAL_ERROR;
    364 
    365     if (result == MTP_RESPONSE_OK) {
    366         jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
    367         jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
    368         jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
    369         jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
    370         jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
    371 
    372         jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
    373         jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
    374         jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
    375         jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
    376 
    377         int type = dataTypes[0];
    378         jlong longValue = (longValues ? longValues[0] : 0);
    379 
    380         // special case date properties, which are strings to MTP
    381         // but stored internally as a uint64
    382         if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) {
    383             char    date[20];
    384             formatDateTime(longValue, date, sizeof(date));
    385             packet.putString(date);
    386             goto out;
    387         }
    388         // release date is stored internally as just the year
    389         if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) {
    390             char    date[20];
    391             snprintf(date, sizeof(date), "%04lld0101T000000", longValue);
    392             packet.putString(date);
    393             goto out;
    394         }
    395 
    396         switch (type) {
    397             case MTP_TYPE_INT8:
    398                 packet.putInt8(longValue);
    399                 break;
    400             case MTP_TYPE_UINT8:
    401                 packet.putUInt8(longValue);
    402                 break;
    403             case MTP_TYPE_INT16:
    404                 packet.putInt16(longValue);
    405                 break;
    406             case MTP_TYPE_UINT16:
    407                 packet.putUInt16(longValue);
    408                 break;
    409             case MTP_TYPE_INT32:
    410                 packet.putInt32(longValue);
    411                 break;
    412             case MTP_TYPE_UINT32:
    413                 packet.putUInt32(longValue);
    414                 break;
    415             case MTP_TYPE_INT64:
    416                 packet.putInt64(longValue);
    417                 break;
    418             case MTP_TYPE_UINT64:
    419                 packet.putUInt64(longValue);
    420                 break;
    421             case MTP_TYPE_INT128:
    422                 packet.putInt128(longValue);
    423                 break;
    424             case MTP_TYPE_UINT128:
    425                 packet.putInt128(longValue);
    426                 break;
    427             case MTP_TYPE_STR:
    428             {
    429                 jstring stringValue = (jstring)env->GetObjectArrayElement(stringValuesArray, 0);
    430                 if (stringValue) {
    431                     const char* str = env->GetStringUTFChars(stringValue, NULL);
    432                     if (str == NULL) {
    433                         return MTP_RESPONSE_GENERAL_ERROR;
    434                     }
    435                     packet.putString(str);
    436                     env->ReleaseStringUTFChars(stringValue, str);
    437                 } else {
    438                     packet.putEmptyString();
    439                 }
    440                 break;
    441              }
    442             default:
    443                 ALOGE("unsupported type in getObjectPropertyValue\n");
    444                 result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
    445         }
    446 out:
    447         env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
    448         env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
    449         env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
    450         if (longValues)
    451             env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
    452 
    453         env->DeleteLocalRef(objectHandlesArray);
    454         env->DeleteLocalRef(propertyCodesArray);
    455         env->DeleteLocalRef(dataTypesArray);
    456         if (longValuesArray)
    457             env->DeleteLocalRef(longValuesArray);
    458         if (stringValuesArray)
    459             env->DeleteLocalRef(stringValuesArray);
    460     }
    461 
    462     env->DeleteLocalRef(list);
    463     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    464     return result;
    465 }
    466 
    467 MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
    468                                             MtpObjectProperty property,
    469                                             MtpDataPacket& packet) {
    470     int         type;
    471 
    472     if (!getObjectPropertyInfo(property, type))
    473         return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
    474 
    475     JNIEnv* env = AndroidRuntime::getJNIEnv();
    476     jlong longValue = 0;
    477     jstring stringValue = NULL;
    478 
    479     switch (type) {
    480         case MTP_TYPE_INT8:
    481             longValue = packet.getInt8();
    482             break;
    483         case MTP_TYPE_UINT8:
    484             longValue = packet.getUInt8();
    485             break;
    486         case MTP_TYPE_INT16:
    487             longValue = packet.getInt16();
    488             break;
    489         case MTP_TYPE_UINT16:
    490             longValue = packet.getUInt16();
    491             break;
    492         case MTP_TYPE_INT32:
    493             longValue = packet.getInt32();
    494             break;
    495         case MTP_TYPE_UINT32:
    496             longValue = packet.getUInt32();
    497             break;
    498         case MTP_TYPE_INT64:
    499             longValue = packet.getInt64();
    500             break;
    501         case MTP_TYPE_UINT64:
    502             longValue = packet.getUInt64();
    503             break;
    504         case MTP_TYPE_STR:
    505         {
    506             MtpStringBuffer buffer;
    507             packet.getString(buffer);
    508             stringValue = env->NewStringUTF((const char *)buffer);
    509             break;
    510          }
    511         default:
    512             ALOGE("unsupported type in getObjectPropertyValue\n");
    513             return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
    514     }
    515 
    516     jint result = env->CallIntMethod(mDatabase, method_setObjectProperty,
    517                 (jint)handle, (jint)property, longValue, stringValue);
    518     if (stringValue)
    519         env->DeleteLocalRef(stringValue);
    520 
    521     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    522     return result;
    523 }
    524 
    525 MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
    526                                             MtpDataPacket& packet) {
    527     int         type;
    528 
    529     if (!getDevicePropertyInfo(property, type))
    530         return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
    531 
    532     JNIEnv* env = AndroidRuntime::getJNIEnv();
    533     jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
    534                 (jint)property, mLongBuffer, mStringBuffer);
    535     if (result != MTP_RESPONSE_OK) {
    536         checkAndClearExceptionFromCallback(env, __FUNCTION__);
    537         return result;
    538     }
    539 
    540     jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
    541     jlong longValue = longValues[0];
    542     env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
    543 
    544     switch (type) {
    545         case MTP_TYPE_INT8:
    546             packet.putInt8(longValue);
    547             break;
    548         case MTP_TYPE_UINT8:
    549             packet.putUInt8(longValue);
    550             break;
    551         case MTP_TYPE_INT16:
    552             packet.putInt16(longValue);
    553             break;
    554         case MTP_TYPE_UINT16:
    555             packet.putUInt16(longValue);
    556             break;
    557         case MTP_TYPE_INT32:
    558             packet.putInt32(longValue);
    559             break;
    560         case MTP_TYPE_UINT32:
    561             packet.putUInt32(longValue);
    562             break;
    563         case MTP_TYPE_INT64:
    564             packet.putInt64(longValue);
    565             break;
    566         case MTP_TYPE_UINT64:
    567             packet.putUInt64(longValue);
    568             break;
    569         case MTP_TYPE_INT128:
    570             packet.putInt128(longValue);
    571             break;
    572         case MTP_TYPE_UINT128:
    573             packet.putInt128(longValue);
    574             break;
    575         case MTP_TYPE_STR:
    576         {
    577             jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
    578             packet.putString(str);
    579             env->ReleaseCharArrayElements(mStringBuffer, str, 0);
    580             break;
    581          }
    582         default:
    583             ALOGE("unsupported type in getDevicePropertyValue\n");
    584             return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
    585     }
    586 
    587     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    588     return MTP_RESPONSE_OK;
    589 }
    590 
    591 MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
    592                                             MtpDataPacket& packet) {
    593     int         type;
    594 
    595     if (!getDevicePropertyInfo(property, type))
    596         return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
    597 
    598     JNIEnv* env = AndroidRuntime::getJNIEnv();
    599     jlong longValue = 0;
    600     jstring stringValue = NULL;
    601 
    602     switch (type) {
    603         case MTP_TYPE_INT8:
    604             longValue = packet.getInt8();
    605             break;
    606         case MTP_TYPE_UINT8:
    607             longValue = packet.getUInt8();
    608             break;
    609         case MTP_TYPE_INT16:
    610             longValue = packet.getInt16();
    611             break;
    612         case MTP_TYPE_UINT16:
    613             longValue = packet.getUInt16();
    614             break;
    615         case MTP_TYPE_INT32:
    616             longValue = packet.getInt32();
    617             break;
    618         case MTP_TYPE_UINT32:
    619             longValue = packet.getUInt32();
    620             break;
    621         case MTP_TYPE_INT64:
    622             longValue = packet.getInt64();
    623             break;
    624         case MTP_TYPE_UINT64:
    625             longValue = packet.getUInt64();
    626             break;
    627         case MTP_TYPE_STR:
    628         {
    629             MtpStringBuffer buffer;
    630             packet.getString(buffer);
    631             stringValue = env->NewStringUTF((const char *)buffer);
    632             break;
    633          }
    634         default:
    635             ALOGE("unsupported type in setDevicePropertyValue\n");
    636             return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
    637     }
    638 
    639     jint result = env->CallIntMethod(mDatabase, method_setDeviceProperty,
    640                 (jint)property, longValue, stringValue);
    641     if (stringValue)
    642         env->DeleteLocalRef(stringValue);
    643 
    644     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    645     return result;
    646 }
    647 
    648 MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty property) {
    649     return -1;
    650 }
    651 
    652 MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
    653                                             uint32_t format, uint32_t property,
    654                                             int groupCode, int depth,
    655                                             MtpDataPacket& packet) {
    656     JNIEnv* env = AndroidRuntime::getJNIEnv();
    657     jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
    658                 (jlong)handle, (jint)format, (jlong)property, (jint)groupCode, (jint)depth);
    659     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    660     if (!list)
    661         return MTP_RESPONSE_GENERAL_ERROR;
    662     int count = env->GetIntField(list, field_mCount);
    663     MtpResponseCode result = env->GetIntField(list, field_mResult);
    664 
    665     packet.putUInt32(count);
    666     if (count > 0) {
    667         jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
    668         jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
    669         jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
    670         jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
    671         jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
    672 
    673         jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
    674         jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
    675         jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
    676         jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
    677 
    678         for (int i = 0; i < count; i++) {
    679             packet.putUInt32(objectHandles[i]);
    680             packet.putUInt16(propertyCodes[i]);
    681             int type = dataTypes[i];
    682             packet.putUInt16(type);
    683 
    684             switch (type) {
    685                 case MTP_TYPE_INT8:
    686                     packet.putInt8(longValues[i]);
    687                     break;
    688                 case MTP_TYPE_UINT8:
    689                     packet.putUInt8(longValues[i]);
    690                     break;
    691                 case MTP_TYPE_INT16:
    692                     packet.putInt16(longValues[i]);
    693                     break;
    694                 case MTP_TYPE_UINT16:
    695                     packet.putUInt16(longValues[i]);
    696                     break;
    697                 case MTP_TYPE_INT32:
    698                     packet.putInt32(longValues[i]);
    699                     break;
    700                 case MTP_TYPE_UINT32:
    701                     packet.putUInt32(longValues[i]);
    702                     break;
    703                 case MTP_TYPE_INT64:
    704                     packet.putInt64(longValues[i]);
    705                     break;
    706                 case MTP_TYPE_UINT64:
    707                     packet.putUInt64(longValues[i]);
    708                     break;
    709                 case MTP_TYPE_INT128:
    710                     packet.putInt128(longValues[i]);
    711                     break;
    712                 case MTP_TYPE_UINT128:
    713                     packet.putUInt128(longValues[i]);
    714                     break;
    715                 case MTP_TYPE_STR: {
    716                     jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i);
    717                     const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL);
    718                     if (valueStr) {
    719                         packet.putString(valueStr);
    720                         env->ReleaseStringUTFChars(value, valueStr);
    721                     } else {
    722                         packet.putEmptyString();
    723                     }
    724                     env->DeleteLocalRef(value);
    725                     break;
    726                 }
    727                 default:
    728                     ALOGE("bad or unsupported data type in MyMtpDatabase::getObjectPropertyList");
    729                     break;
    730             }
    731         }
    732 
    733         env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
    734         env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
    735         env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
    736         if (longValues)
    737             env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
    738 
    739         env->DeleteLocalRef(objectHandlesArray);
    740         env->DeleteLocalRef(propertyCodesArray);
    741         env->DeleteLocalRef(dataTypesArray);
    742         if (longValuesArray)
    743             env->DeleteLocalRef(longValuesArray);
    744         if (stringValuesArray)
    745             env->DeleteLocalRef(stringValuesArray);
    746     }
    747 
    748     env->DeleteLocalRef(list);
    749     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    750     return result;
    751 }
    752 
    753 MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
    754                                             MtpObjectInfo& info) {
    755     char            date[20];
    756     MtpString       path;
    757     int64_t         length;
    758     MtpObjectFormat format;
    759 
    760     MtpResponseCode result = getObjectFilePath(handle, path, length, format);
    761     if (result != MTP_RESPONSE_OK) {
    762         return result;
    763     }
    764     info.mCompressedSize = (length > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)length);
    765 
    766     JNIEnv* env = AndroidRuntime::getJNIEnv();
    767     if (!env->CallBooleanMethod(mDatabase, method_getObjectInfo,
    768                 (jint)handle, mIntBuffer, mStringBuffer, mLongBuffer)) {
    769         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
    770     }
    771 
    772     jint* intValues = env->GetIntArrayElements(mIntBuffer, 0);
    773     info.mStorageID = intValues[0];
    774     info.mFormat = intValues[1];
    775     info.mParent = intValues[2];
    776     env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
    777 
    778     jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
    779     info.mDateCreated = longValues[0];
    780     info.mDateModified = longValues[1];
    781     env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
    782 
    783 //    info.mAssociationType = (format == MTP_FORMAT_ASSOCIATION ?
    784 //                            MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
    785 //                            MTP_ASSOCIATION_TYPE_UNDEFINED);
    786     info.mAssociationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
    787 
    788     jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
    789     MtpString temp(str);
    790     info.mName = strdup((const char *)temp);
    791     env->ReleaseCharArrayElements(mStringBuffer, str, 0);
    792 
    793     // read EXIF data for thumbnail information
    794     if (info.mFormat == MTP_FORMAT_EXIF_JPEG || info.mFormat == MTP_FORMAT_JFIF) {
    795         ResetJpgfile();
    796          // Start with an empty image information structure.
    797         memset(&ImageInfo, 0, sizeof(ImageInfo));
    798         ImageInfo.FlashUsed = -1;
    799         ImageInfo.MeteringMode = -1;
    800         ImageInfo.Whitebalance = -1;
    801         strncpy(ImageInfo.FileName, (const char *)path, PATH_MAX);
    802         if (ReadJpegFile((const char*)path, READ_METADATA)) {
    803             Section_t* section = FindSection(M_EXIF);
    804             if (section) {
    805                 info.mThumbCompressedSize = ImageInfo.ThumbnailSize;
    806                 info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
    807                 info.mImagePixWidth = ImageInfo.Width;
    808                 info.mImagePixHeight = ImageInfo.Height;
    809             }
    810         }
    811         DiscardData();
    812     }
    813 
    814     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    815     return MTP_RESPONSE_OK;
    816 }
    817 
    818 void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
    819     MtpString path;
    820     int64_t length;
    821     MtpObjectFormat format;
    822     void* result = NULL;
    823     outThumbSize = 0;
    824 
    825     if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK
    826             && (format == MTP_FORMAT_EXIF_JPEG || format == MTP_FORMAT_JFIF)) {
    827         ResetJpgfile();
    828          // Start with an empty image information structure.
    829         memset(&ImageInfo, 0, sizeof(ImageInfo));
    830         ImageInfo.FlashUsed = -1;
    831         ImageInfo.MeteringMode = -1;
    832         ImageInfo.Whitebalance = -1;
    833         strncpy(ImageInfo.FileName, (const char *)path, PATH_MAX);
    834         if (ReadJpegFile((const char*)path, READ_METADATA)) {
    835             Section_t* section = FindSection(M_EXIF);
    836             if (section) {
    837                 outThumbSize = ImageInfo.ThumbnailSize;
    838                 result = malloc(outThumbSize);
    839                 if (result)
    840                     memcpy(result, section->Data + ImageInfo.ThumbnailOffset + 8, outThumbSize);
    841             }
    842             DiscardData();
    843         }
    844     }
    845 
    846     return result;
    847 }
    848 
    849 MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
    850                                             MtpString& outFilePath,
    851                                             int64_t& outFileLength,
    852                                             MtpObjectFormat& outFormat) {
    853     JNIEnv* env = AndroidRuntime::getJNIEnv();
    854     jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath,
    855                 (jint)handle, mStringBuffer, mLongBuffer);
    856     if (result != MTP_RESPONSE_OK) {
    857         checkAndClearExceptionFromCallback(env, __FUNCTION__);
    858         return result;
    859     }
    860 
    861     jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
    862     outFilePath.setTo(str, strlen16(str));
    863     env->ReleaseCharArrayElements(mStringBuffer, str, 0);
    864 
    865     jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
    866     outFileLength = longValues[0];
    867     outFormat = longValues[1];
    868     env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
    869 
    870     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    871     return result;
    872 }
    873 
    874 MtpResponseCode MyMtpDatabase::deleteFile(MtpObjectHandle handle) {
    875     JNIEnv* env = AndroidRuntime::getJNIEnv();
    876     MtpResponseCode result = env->CallIntMethod(mDatabase, method_deleteFile, (jint)handle);
    877 
    878     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    879     return result;
    880 }
    881 
    882 struct PropertyTableEntry {
    883     MtpObjectProperty   property;
    884     int                 type;
    885 };
    886 
    887 static const PropertyTableEntry   kObjectPropertyTable[] = {
    888     {   MTP_PROPERTY_STORAGE_ID,        MTP_TYPE_UINT32     },
    889     {   MTP_PROPERTY_OBJECT_FORMAT,     MTP_TYPE_UINT16     },
    890     {   MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16     },
    891     {   MTP_PROPERTY_OBJECT_SIZE,       MTP_TYPE_UINT64     },
    892     {   MTP_PROPERTY_OBJECT_FILE_NAME,  MTP_TYPE_STR        },
    893     {   MTP_PROPERTY_DATE_MODIFIED,     MTP_TYPE_STR        },
    894     {   MTP_PROPERTY_PARENT_OBJECT,     MTP_TYPE_UINT32     },
    895     {   MTP_PROPERTY_PERSISTENT_UID,    MTP_TYPE_UINT128    },
    896     {   MTP_PROPERTY_NAME,              MTP_TYPE_STR        },
    897     {   MTP_PROPERTY_DISPLAY_NAME,      MTP_TYPE_STR        },
    898     {   MTP_PROPERTY_DATE_ADDED,        MTP_TYPE_STR        },
    899     {   MTP_PROPERTY_ARTIST,            MTP_TYPE_STR        },
    900     {   MTP_PROPERTY_ALBUM_NAME,        MTP_TYPE_STR        },
    901     {   MTP_PROPERTY_ALBUM_ARTIST,      MTP_TYPE_STR        },
    902     {   MTP_PROPERTY_TRACK,             MTP_TYPE_UINT16     },
    903     {   MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_TYPE_STR    },
    904     {   MTP_PROPERTY_GENRE,             MTP_TYPE_STR        },
    905     {   MTP_PROPERTY_COMPOSER,          MTP_TYPE_STR        },
    906     {   MTP_PROPERTY_DURATION,          MTP_TYPE_UINT32     },
    907     {   MTP_PROPERTY_DESCRIPTION,       MTP_TYPE_STR        },
    908 };
    909 
    910 static const PropertyTableEntry   kDevicePropertyTable[] = {
    911     {   MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER,    MTP_TYPE_STR },
    912     {   MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME,       MTP_TYPE_STR },
    913     {   MTP_DEVICE_PROPERTY_IMAGE_SIZE,                 MTP_TYPE_STR },
    914 };
    915 
    916 bool MyMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
    917     int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
    918     const PropertyTableEntry* entry = kObjectPropertyTable;
    919     for (int i = 0; i < count; i++, entry++) {
    920         if (entry->property == property) {
    921             type = entry->type;
    922             return true;
    923         }
    924     }
    925     return false;
    926 }
    927 
    928 bool MyMtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
    929     int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
    930     const PropertyTableEntry* entry = kDevicePropertyTable;
    931     for (int i = 0; i < count; i++, entry++) {
    932         if (entry->property == property) {
    933             type = entry->type;
    934             return true;
    935         }
    936     }
    937     return false;
    938 }
    939 
    940 MtpObjectHandleList* MyMtpDatabase::getObjectReferences(MtpObjectHandle handle) {
    941     JNIEnv* env = AndroidRuntime::getJNIEnv();
    942     jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectReferences,
    943                 (jint)handle);
    944     if (!array)
    945         return NULL;
    946     MtpObjectHandleList* list = new MtpObjectHandleList();
    947     jint* handles = env->GetIntArrayElements(array, 0);
    948     jsize length = env->GetArrayLength(array);
    949     for (int i = 0; i < length; i++)
    950         list->push(handles[i]);
    951     env->ReleaseIntArrayElements(array, handles, 0);
    952     env->DeleteLocalRef(array);
    953 
    954     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    955     return list;
    956 }
    957 
    958 MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
    959                                                     MtpObjectHandleList* references) {
    960     JNIEnv* env = AndroidRuntime::getJNIEnv();
    961     int count = references->size();
    962     jintArray array = env->NewIntArray(count);
    963     if (!array) {
    964         ALOGE("out of memory in setObjectReferences");
    965         return false;
    966     }
    967     jint* handles = env->GetIntArrayElements(array, 0);
    968      for (int i = 0; i < count; i++)
    969         handles[i] = (*references)[i];
    970     env->ReleaseIntArrayElements(array, handles, 0);
    971     MtpResponseCode result = env->CallIntMethod(mDatabase, method_setObjectReferences,
    972                 (jint)handle, array);
    973     env->DeleteLocalRef(array);
    974 
    975     checkAndClearExceptionFromCallback(env, __FUNCTION__);
    976     return result;
    977 }
    978 
    979 MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
    980                                             MtpObjectFormat format) {
    981     MtpProperty* result = NULL;
    982     switch (property) {
    983         case MTP_PROPERTY_OBJECT_FORMAT:
    984             // use format as default value
    985             result = new MtpProperty(property, MTP_TYPE_UINT16, false, format);
    986             break;
    987         case MTP_PROPERTY_PROTECTION_STATUS:
    988         case MTP_PROPERTY_TRACK:
    989             result = new MtpProperty(property, MTP_TYPE_UINT16);
    990             break;
    991         case MTP_PROPERTY_STORAGE_ID:
    992         case MTP_PROPERTY_PARENT_OBJECT:
    993         case MTP_PROPERTY_DURATION:
    994             result = new MtpProperty(property, MTP_TYPE_UINT32);
    995             break;
    996         case MTP_PROPERTY_OBJECT_SIZE:
    997             result = new MtpProperty(property, MTP_TYPE_UINT64);
    998             break;
    999         case MTP_PROPERTY_PERSISTENT_UID:
   1000             result = new MtpProperty(property, MTP_TYPE_UINT128);
   1001             break;
   1002         case MTP_PROPERTY_NAME:
   1003         case MTP_PROPERTY_DISPLAY_NAME:
   1004         case MTP_PROPERTY_ARTIST:
   1005         case MTP_PROPERTY_ALBUM_NAME:
   1006         case MTP_PROPERTY_ALBUM_ARTIST:
   1007         case MTP_PROPERTY_GENRE:
   1008         case MTP_PROPERTY_COMPOSER:
   1009         case MTP_PROPERTY_DESCRIPTION:
   1010             result = new MtpProperty(property, MTP_TYPE_STR);
   1011             break;
   1012         case MTP_PROPERTY_DATE_MODIFIED:
   1013         case MTP_PROPERTY_DATE_ADDED:
   1014         case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
   1015             result = new MtpProperty(property, MTP_TYPE_STR);
   1016             result->setFormDateTime();
   1017             break;
   1018         case MTP_PROPERTY_OBJECT_FILE_NAME:
   1019             // We allow renaming files and folders
   1020             result = new MtpProperty(property, MTP_TYPE_STR, true);
   1021             break;
   1022     }
   1023 
   1024     return result;
   1025 }
   1026 
   1027 MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
   1028     JNIEnv* env = AndroidRuntime::getJNIEnv();
   1029     MtpProperty* result = NULL;
   1030     bool writable = false;
   1031 
   1032     switch (property) {
   1033         case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
   1034         case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
   1035             writable = true;
   1036             // fall through
   1037         case MTP_DEVICE_PROPERTY_IMAGE_SIZE:
   1038             result = new MtpProperty(property, MTP_TYPE_STR, writable);
   1039 
   1040             // get current value
   1041             jint ret = env->CallIntMethod(mDatabase, method_getDeviceProperty,
   1042                         (jint)property, mLongBuffer, mStringBuffer);
   1043             if (ret == MTP_RESPONSE_OK) {
   1044                 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
   1045                 result->setCurrentValue(str);
   1046                 // for read-only properties it is safe to assume current value is default value
   1047                 if (!writable)
   1048                     result->setDefaultValue(str);
   1049                 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
   1050             } else {
   1051                 ALOGE("unable to read device property, response: %04X", ret);
   1052             }
   1053             break;
   1054     }
   1055 
   1056     checkAndClearExceptionFromCallback(env, __FUNCTION__);
   1057     return result;
   1058 }
   1059 
   1060 void MyMtpDatabase::sessionStarted() {
   1061     JNIEnv* env = AndroidRuntime::getJNIEnv();
   1062     env->CallVoidMethod(mDatabase, method_sessionStarted);
   1063     checkAndClearExceptionFromCallback(env, __FUNCTION__);
   1064 }
   1065 
   1066 void MyMtpDatabase::sessionEnded() {
   1067     JNIEnv* env = AndroidRuntime::getJNIEnv();
   1068     env->CallVoidMethod(mDatabase, method_sessionEnded);
   1069     checkAndClearExceptionFromCallback(env, __FUNCTION__);
   1070 }
   1071 
   1072 // ----------------------------------------------------------------------------
   1073 
   1074 static void
   1075 android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
   1076 {
   1077     MyMtpDatabase* database = new MyMtpDatabase(env, thiz);
   1078     env->SetIntField(thiz, field_context, (int)database);
   1079     checkAndClearExceptionFromCallback(env, __FUNCTION__);
   1080 }
   1081 
   1082 static void
   1083 android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
   1084 {
   1085     MyMtpDatabase* database = (MyMtpDatabase *)env->GetIntField(thiz, field_context);
   1086     database->cleanup(env);
   1087     delete database;
   1088     env->SetIntField(thiz, field_context, 0);
   1089     checkAndClearExceptionFromCallback(env, __FUNCTION__);
   1090 }
   1091 
   1092 static jstring
   1093 android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject thiz, jlong seconds)
   1094 {
   1095     char    date[20];
   1096     formatDateTime(seconds, date, sizeof(date));
   1097     return env->NewStringUTF(date);
   1098 }
   1099 
   1100 // ----------------------------------------------------------------------------
   1101 
   1102 static JNINativeMethod gMtpDatabaseMethods[] = {
   1103     {"native_setup",            "()V",  (void *)android_mtp_MtpDatabase_setup},
   1104     {"native_finalize",         "()V",  (void *)android_mtp_MtpDatabase_finalize},
   1105 };
   1106 
   1107 static JNINativeMethod gMtpPropertyGroupMethods[] = {
   1108     {"format_date_time",        "(J)Ljava/lang/String;",
   1109                                         (void *)android_mtp_MtpPropertyGroup_format_date_time},
   1110 };
   1111 
   1112 static const char* const kClassPathName = "android/mtp/MtpDatabase";
   1113 
   1114 int register_android_mtp_MtpDatabase(JNIEnv *env)
   1115 {
   1116     jclass clazz;
   1117 
   1118     clazz = env->FindClass("android/mtp/MtpDatabase");
   1119     if (clazz == NULL) {
   1120         ALOGE("Can't find android/mtp/MtpDatabase");
   1121         return -1;
   1122     }
   1123     method_beginSendObject = env->GetMethodID(clazz, "beginSendObject", "(Ljava/lang/String;IIIJJ)I");
   1124     if (method_beginSendObject == NULL) {
   1125         ALOGE("Can't find beginSendObject");
   1126         return -1;
   1127     }
   1128     method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIZ)V");
   1129     if (method_endSendObject == NULL) {
   1130         ALOGE("Can't find endSendObject");
   1131         return -1;
   1132     }
   1133     method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I");
   1134     if (method_getObjectList == NULL) {
   1135         ALOGE("Can't find getObjectList");
   1136         return -1;
   1137     }
   1138     method_getNumObjects = env->GetMethodID(clazz, "getNumObjects", "(III)I");
   1139     if (method_getNumObjects == NULL) {
   1140         ALOGE("Can't find getNumObjects");
   1141         return -1;
   1142     }
   1143     method_getSupportedPlaybackFormats = env->GetMethodID(clazz, "getSupportedPlaybackFormats", "()[I");
   1144     if (method_getSupportedPlaybackFormats == NULL) {
   1145         ALOGE("Can't find getSupportedPlaybackFormats");
   1146         return -1;
   1147     }
   1148     method_getSupportedCaptureFormats = env->GetMethodID(clazz, "getSupportedCaptureFormats", "()[I");
   1149     if (method_getSupportedCaptureFormats == NULL) {
   1150         ALOGE("Can't find getSupportedCaptureFormats");
   1151         return -1;
   1152     }
   1153     method_getSupportedObjectProperties = env->GetMethodID(clazz, "getSupportedObjectProperties", "(I)[I");
   1154     if (method_getSupportedObjectProperties == NULL) {
   1155         ALOGE("Can't find getSupportedObjectProperties");
   1156         return -1;
   1157     }
   1158     method_getSupportedDeviceProperties = env->GetMethodID(clazz, "getSupportedDeviceProperties", "()[I");
   1159     if (method_getSupportedDeviceProperties == NULL) {
   1160         ALOGE("Can't find getSupportedDeviceProperties");
   1161         return -1;
   1162     }
   1163     method_setObjectProperty = env->GetMethodID(clazz, "setObjectProperty", "(IIJLjava/lang/String;)I");
   1164     if (method_setObjectProperty == NULL) {
   1165         ALOGE("Can't find setObjectProperty");
   1166         return -1;
   1167     }
   1168     method_getDeviceProperty = env->GetMethodID(clazz, "getDeviceProperty", "(I[J[C)I");
   1169     if (method_getDeviceProperty == NULL) {
   1170         ALOGE("Can't find getDeviceProperty");
   1171         return -1;
   1172     }
   1173     method_setDeviceProperty = env->GetMethodID(clazz, "setDeviceProperty", "(IJLjava/lang/String;)I");
   1174     if (method_setDeviceProperty == NULL) {
   1175         ALOGE("Can't find setDeviceProperty");
   1176         return -1;
   1177     }
   1178     method_getObjectPropertyList = env->GetMethodID(clazz, "getObjectPropertyList",
   1179             "(JIJII)Landroid/mtp/MtpPropertyList;");
   1180     if (method_getObjectPropertyList == NULL) {
   1181         ALOGE("Can't find getObjectPropertyList");
   1182         return -1;
   1183     }
   1184     method_getObjectInfo = env->GetMethodID(clazz, "getObjectInfo", "(I[I[C[J)Z");
   1185     if (method_getObjectInfo == NULL) {
   1186         ALOGE("Can't find getObjectInfo");
   1187         return -1;
   1188     }
   1189     method_getObjectFilePath = env->GetMethodID(clazz, "getObjectFilePath", "(I[C[J)I");
   1190     if (method_getObjectFilePath == NULL) {
   1191         ALOGE("Can't find getObjectFilePath");
   1192         return -1;
   1193     }
   1194     method_deleteFile = env->GetMethodID(clazz, "deleteFile", "(I)I");
   1195     if (method_deleteFile == NULL) {
   1196         ALOGE("Can't find deleteFile");
   1197         return -1;
   1198     }
   1199     method_getObjectReferences = env->GetMethodID(clazz, "getObjectReferences", "(I)[I");
   1200     if (method_getObjectReferences == NULL) {
   1201         ALOGE("Can't find getObjectReferences");
   1202         return -1;
   1203     }
   1204     method_setObjectReferences = env->GetMethodID(clazz, "setObjectReferences", "(I[I)I");
   1205     if (method_setObjectReferences == NULL) {
   1206         ALOGE("Can't find setObjectReferences");
   1207         return -1;
   1208     }
   1209     method_sessionStarted = env->GetMethodID(clazz, "sessionStarted", "()V");
   1210     if (method_sessionStarted == NULL) {
   1211         ALOGE("Can't find sessionStarted");
   1212         return -1;
   1213     }
   1214     method_sessionEnded = env->GetMethodID(clazz, "sessionEnded", "()V");
   1215     if (method_sessionEnded == NULL) {
   1216         ALOGE("Can't find sessionEnded");
   1217         return -1;
   1218     }
   1219 
   1220     field_context = env->GetFieldID(clazz, "mNativeContext", "I");
   1221     if (field_context == NULL) {
   1222         ALOGE("Can't find MtpDatabase.mNativeContext");
   1223         return -1;
   1224     }
   1225 
   1226     // now set up fields for MtpPropertyList class
   1227     clazz = env->FindClass("android/mtp/MtpPropertyList");
   1228     if (clazz == NULL) {
   1229         ALOGE("Can't find android/mtp/MtpPropertyList");
   1230         return -1;
   1231     }
   1232     field_mCount = env->GetFieldID(clazz, "mCount", "I");
   1233     if (field_mCount == NULL) {
   1234         ALOGE("Can't find MtpPropertyList.mCount");
   1235         return -1;
   1236     }
   1237     field_mResult = env->GetFieldID(clazz, "mResult", "I");
   1238     if (field_mResult == NULL) {
   1239         ALOGE("Can't find MtpPropertyList.mResult");
   1240         return -1;
   1241     }
   1242     field_mObjectHandles = env->GetFieldID(clazz, "mObjectHandles", "[I");
   1243     if (field_mObjectHandles == NULL) {
   1244         ALOGE("Can't find MtpPropertyList.mObjectHandles");
   1245         return -1;
   1246     }
   1247     field_mPropertyCodes = env->GetFieldID(clazz, "mPropertyCodes", "[I");
   1248     if (field_mPropertyCodes == NULL) {
   1249         ALOGE("Can't find MtpPropertyList.mPropertyCodes");
   1250         return -1;
   1251     }
   1252     field_mDataTypes = env->GetFieldID(clazz, "mDataTypes", "[I");
   1253     if (field_mDataTypes == NULL) {
   1254         ALOGE("Can't find MtpPropertyList.mDataTypes");
   1255         return -1;
   1256     }
   1257     field_mLongValues = env->GetFieldID(clazz, "mLongValues", "[J");
   1258     if (field_mLongValues == NULL) {
   1259         ALOGE("Can't find MtpPropertyList.mLongValues");
   1260         return -1;
   1261     }
   1262     field_mStringValues = env->GetFieldID(clazz, "mStringValues", "[Ljava/lang/String;");
   1263     if (field_mStringValues == NULL) {
   1264         ALOGE("Can't find MtpPropertyList.mStringValues");
   1265         return -1;
   1266     }
   1267 
   1268     if (AndroidRuntime::registerNativeMethods(env,
   1269                 "android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods)))
   1270         return -1;
   1271 
   1272     return AndroidRuntime::registerNativeMethods(env,
   1273                 "android/mtp/MtpPropertyGroup", gMtpPropertyGroupMethods, NELEM(gMtpPropertyGroupMethods));
   1274 }
   1275