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