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