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