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