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