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