2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "MtpDatabaseJNI"
18 #include "utils/Log.h"
19 #include "utils/String8.h"
21 #include "android_media_Utils.h"
23 #include "IMtpDatabase.h"
24 #include "MtpDataPacket.h"
25 #include "MtpObjectInfo.h"
26 #include "MtpProperty.h"
27 #include "MtpStringBuffer.h"
30 #include "src/piex_types.h"
34 #include "libexif/exif-content.h"
35 #include "libexif/exif-data.h"
36 #include "libexif/exif-tag.h"
37 #include "libexif/exif-utils.h"
40 #include <android_runtime/AndroidRuntime.h>
41 #include <android_runtime/Log.h>
43 #include <media/stagefright/NuMediaExtractor.h>
44 #include <nativehelper/JNIHelp.h>
45 #include <nativehelper/ScopedLocalRef.h>
54 using namespace android;
56 // ----------------------------------------------------------------------------
58 static jmethodID method_beginSendObject;
59 static jmethodID method_endSendObject;
60 static jmethodID method_rescanFile;
61 static jmethodID method_getObjectList;
62 static jmethodID method_getNumObjects;
63 static jmethodID method_getSupportedPlaybackFormats;
64 static jmethodID method_getSupportedCaptureFormats;
65 static jmethodID method_getSupportedObjectProperties;
66 static jmethodID method_getSupportedDeviceProperties;
67 static jmethodID method_setObjectProperty;
68 static jmethodID method_getDeviceProperty;
69 static jmethodID method_setDeviceProperty;
70 static jmethodID method_getObjectPropertyList;
71 static jmethodID method_getObjectInfo;
72 static jmethodID method_getObjectFilePath;
73 static jmethodID method_beginDeleteObject;
74 static jmethodID method_endDeleteObject;
75 static jmethodID method_beginMoveObject;
76 static jmethodID method_endMoveObject;
77 static jmethodID method_beginCopyObject;
78 static jmethodID method_endCopyObject;
79 static jmethodID method_getObjectReferences;
80 static jmethodID method_setObjectReferences;
82 static jfieldID field_context;
84 // MtpPropertyList methods
85 static jmethodID method_getCode;
86 static jmethodID method_getCount;
87 static jmethodID method_getObjectHandles;
88 static jmethodID method_getPropertyCodes;
89 static jmethodID method_getDataTypes;
90 static jmethodID method_getLongValues;
91 static jmethodID method_getStringValues;
94 IMtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
95 return (IMtpDatabase *)env->GetLongField(database, field_context);
98 // ----------------------------------------------------------------------------
100 class MtpDatabase : public IMtpDatabase {
103 jintArray mIntBuffer;
104 jlongArray mLongBuffer;
105 jcharArray mStringBuffer;
108 MtpDatabase(JNIEnv *env, jobject client);
109 virtual ~MtpDatabase();
110 void cleanup(JNIEnv *env);
112 virtual MtpObjectHandle beginSendObject(const char* path,
113 MtpObjectFormat format,
114 MtpObjectHandle parent,
115 MtpStorageID storage);
117 virtual void endSendObject(MtpObjectHandle handle, bool succeeded);
119 virtual void rescanFile(const char* path,
120 MtpObjectHandle handle,
121 MtpObjectFormat format);
123 virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
124 MtpObjectFormat format,
125 MtpObjectHandle parent);
127 virtual int getNumObjects(MtpStorageID storageID,
128 MtpObjectFormat format,
129 MtpObjectHandle parent);
131 // callee should delete[] the results from these
132 // results can be NULL
133 virtual MtpObjectFormatList* getSupportedPlaybackFormats();
134 virtual MtpObjectFormatList* getSupportedCaptureFormats();
135 virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format);
136 virtual MtpDevicePropertyList* getSupportedDeviceProperties();
138 virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle,
139 MtpObjectProperty property,
140 MtpDataPacket& packet);
142 virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle handle,
143 MtpObjectProperty property,
144 MtpDataPacket& packet);
146 virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty property,
147 MtpDataPacket& packet);
149 virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty property,
150 MtpDataPacket& packet);
152 virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty property);
154 virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle handle,
155 uint32_t format, uint32_t property,
156 int groupCode, int depth,
157 MtpDataPacket& packet);
159 virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
160 MtpObjectInfo& info);
162 virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
164 virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
165 MtpStringBuffer& outFilePath,
166 int64_t& outFileLength,
167 MtpObjectFormat& outFormat);
168 virtual MtpResponseCode beginDeleteObject(MtpObjectHandle handle);
169 virtual void endDeleteObject(MtpObjectHandle handle, bool succeeded);
171 bool getObjectPropertyInfo(MtpObjectProperty property, int& type);
172 bool getDevicePropertyInfo(MtpDeviceProperty property, int& type);
174 virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle);
176 virtual MtpResponseCode setObjectReferences(MtpObjectHandle handle,
177 MtpObjectHandleList* references);
179 virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty property,
180 MtpObjectFormat format);
182 virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property);
184 virtual MtpResponseCode beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
185 MtpStorageID newStorage);
187 virtual void endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
188 MtpStorageID oldStorage, MtpStorageID newStorage,
189 MtpObjectHandle handle, bool succeeded);
191 virtual MtpResponseCode beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
192 MtpStorageID newStorage);
193 virtual void endCopyObject(MtpObjectHandle handle, bool succeeded);
197 // ----------------------------------------------------------------------------
199 static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
200 if (env->ExceptionCheck()) {
201 ALOGE("An exception was thrown by callback '%s'.", methodName);
203 env->ExceptionClear();
207 // ----------------------------------------------------------------------------
209 MtpDatabase::MtpDatabase(JNIEnv *env, jobject client)
210 : mDatabase(env->NewGlobalRef(client)),
215 // create buffers for out arguments
216 // we don't need to be thread-safe so this is OK
217 jintArray intArray = env->NewIntArray(3);
219 return; // Already threw.
221 mIntBuffer = (jintArray)env->NewGlobalRef(intArray);
222 jlongArray longArray = env->NewLongArray(2);
224 return; // Already threw.
226 mLongBuffer = (jlongArray)env->NewGlobalRef(longArray);
227 // Needs to be long enough to hold a file path for getObjectFilePath()
228 jcharArray charArray = env->NewCharArray(PATH_MAX + 1);
230 return; // Already threw.
232 mStringBuffer = (jcharArray)env->NewGlobalRef(charArray);
235 void MtpDatabase::cleanup(JNIEnv *env) {
236 env->DeleteGlobalRef(mDatabase);
237 env->DeleteGlobalRef(mIntBuffer);
238 env->DeleteGlobalRef(mLongBuffer);
239 env->DeleteGlobalRef(mStringBuffer);
242 MtpDatabase::~MtpDatabase() {
245 MtpObjectHandle MtpDatabase::beginSendObject(const char* path,
246 MtpObjectFormat format,
247 MtpObjectHandle parent,
248 MtpStorageID storage) {
249 JNIEnv* env = AndroidRuntime::getJNIEnv();
250 jstring pathStr = env->NewStringUTF(path);
251 MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
252 pathStr, (jint)format, (jint)parent, (jint)storage);
255 env->DeleteLocalRef(pathStr);
256 checkAndClearExceptionFromCallback(env, __FUNCTION__);
260 void MtpDatabase::endSendObject(MtpObjectHandle handle, bool succeeded) {
261 JNIEnv* env = AndroidRuntime::getJNIEnv();
262 env->CallVoidMethod(mDatabase, method_endSendObject, (jint)handle, (jboolean)succeeded);
264 checkAndClearExceptionFromCallback(env, __FUNCTION__);
267 void MtpDatabase::rescanFile(const char* path, MtpObjectHandle handle,
268 MtpObjectFormat format) {
269 JNIEnv* env = AndroidRuntime::getJNIEnv();
270 jstring pathStr = env->NewStringUTF(path);
271 env->CallVoidMethod(mDatabase, method_rescanFile, pathStr,
272 (jint)handle, (jint)format);
275 env->DeleteLocalRef(pathStr);
276 checkAndClearExceptionFromCallback(env, __FUNCTION__);
279 MtpObjectHandleList* MtpDatabase::getObjectList(MtpStorageID storageID,
280 MtpObjectFormat format,
281 MtpObjectHandle parent) {
282 JNIEnv* env = AndroidRuntime::getJNIEnv();
283 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList,
284 (jint)storageID, (jint)format, (jint)parent);
287 MtpObjectHandleList* list = new MtpObjectHandleList();
288 jint* handles = env->GetIntArrayElements(array, 0);
289 jsize length = env->GetArrayLength(array);
290 for (int i = 0; i < length; i++)
291 list->push_back(handles[i]);
292 env->ReleaseIntArrayElements(array, handles, 0);
293 env->DeleteLocalRef(array);
295 checkAndClearExceptionFromCallback(env, __FUNCTION__);
299 int MtpDatabase::getNumObjects(MtpStorageID storageID,
300 MtpObjectFormat format,
301 MtpObjectHandle parent) {
302 JNIEnv* env = AndroidRuntime::getJNIEnv();
303 int result = env->CallIntMethod(mDatabase, method_getNumObjects,
304 (jint)storageID, (jint)format, (jint)parent);
306 checkAndClearExceptionFromCallback(env, __FUNCTION__);
310 MtpObjectFormatList* MtpDatabase::getSupportedPlaybackFormats() {
311 JNIEnv* env = AndroidRuntime::getJNIEnv();
312 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
313 method_getSupportedPlaybackFormats);
316 MtpObjectFormatList* list = new MtpObjectFormatList();
317 jint* formats = env->GetIntArrayElements(array, 0);
318 jsize length = env->GetArrayLength(array);
319 for (int i = 0; i < length; i++)
320 list->push_back(formats[i]);
321 env->ReleaseIntArrayElements(array, formats, 0);
322 env->DeleteLocalRef(array);
324 checkAndClearExceptionFromCallback(env, __FUNCTION__);
328 MtpObjectFormatList* MtpDatabase::getSupportedCaptureFormats() {
329 JNIEnv* env = AndroidRuntime::getJNIEnv();
330 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
331 method_getSupportedCaptureFormats);
334 MtpObjectFormatList* list = new MtpObjectFormatList();
335 jint* formats = env->GetIntArrayElements(array, 0);
336 jsize length = env->GetArrayLength(array);
337 for (int i = 0; i < length; i++)
338 list->push_back(formats[i]);
339 env->ReleaseIntArrayElements(array, formats, 0);
340 env->DeleteLocalRef(array);
342 checkAndClearExceptionFromCallback(env, __FUNCTION__);
346 MtpObjectPropertyList* MtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
347 JNIEnv* env = AndroidRuntime::getJNIEnv();
348 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
349 method_getSupportedObjectProperties, (jint)format);
352 MtpObjectPropertyList* list = new MtpObjectPropertyList();
353 jint* properties = env->GetIntArrayElements(array, 0);
354 jsize length = env->GetArrayLength(array);
355 for (int i = 0; i < length; i++)
356 list->push_back(properties[i]);
357 env->ReleaseIntArrayElements(array, properties, 0);
358 env->DeleteLocalRef(array);
360 checkAndClearExceptionFromCallback(env, __FUNCTION__);
364 MtpDevicePropertyList* MtpDatabase::getSupportedDeviceProperties() {
365 JNIEnv* env = AndroidRuntime::getJNIEnv();
366 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
367 method_getSupportedDeviceProperties);
370 MtpDevicePropertyList* list = new MtpDevicePropertyList();
371 jint* properties = env->GetIntArrayElements(array, 0);
372 jsize length = env->GetArrayLength(array);
373 for (int i = 0; i < length; i++)
374 list->push_back(properties[i]);
375 env->ReleaseIntArrayElements(array, properties, 0);
376 env->DeleteLocalRef(array);
378 checkAndClearExceptionFromCallback(env, __FUNCTION__);
382 MtpResponseCode MtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
383 MtpObjectProperty property,
384 MtpDataPacket& packet) {
385 static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
386 "Casting MtpObjectHandle to jint loses a value");
387 static_assert(sizeof(jint) >= sizeof(MtpObjectProperty),
388 "Casting MtpObjectProperty to jint loses a value");
389 JNIEnv* env = AndroidRuntime::getJNIEnv();
390 jobject list = env->CallObjectMethod(
392 method_getObjectPropertyList,
393 static_cast<jint>(handle),
395 static_cast<jint>(property),
398 MtpResponseCode result = env->CallIntMethod(list, method_getCode);
399 jint count = env->CallIntMethod(list, method_getCount);
401 result = MTP_RESPONSE_GENERAL_ERROR;
403 if (result == MTP_RESPONSE_OK) {
404 jintArray objectHandlesArray = (jintArray)env->CallObjectMethod(list, method_getObjectHandles);
405 jintArray propertyCodesArray = (jintArray)env->CallObjectMethod(list, method_getPropertyCodes);
406 jintArray dataTypesArray = (jintArray)env->CallObjectMethod(list, method_getDataTypes);
407 jlongArray longValuesArray = (jlongArray)env->CallObjectMethod(list, method_getLongValues);
408 jobjectArray stringValuesArray = (jobjectArray)env->CallObjectMethod(list, method_getStringValues);
410 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
411 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
412 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
413 jlong* longValues = env->GetLongArrayElements(longValuesArray, 0);
415 int type = dataTypes[0];
416 jlong longValue = (longValues ? longValues[0] : 0);
420 packet.putInt8(longValue);
423 packet.putUInt8(longValue);
426 packet.putInt16(longValue);
428 case MTP_TYPE_UINT16:
429 packet.putUInt16(longValue);
432 packet.putInt32(longValue);
434 case MTP_TYPE_UINT32:
435 packet.putUInt32(longValue);
438 packet.putInt64(longValue);
440 case MTP_TYPE_UINT64:
441 packet.putUInt64(longValue);
443 case MTP_TYPE_INT128:
444 packet.putInt128(longValue);
446 case MTP_TYPE_UINT128:
447 packet.putUInt128(longValue);
451 jstring stringValue = (jstring)env->GetObjectArrayElement(stringValuesArray, 0);
452 const char* str = (stringValue ? env->GetStringUTFChars(stringValue, NULL) : NULL);
454 packet.putString(str);
455 env->ReleaseStringUTFChars(stringValue, str);
457 packet.putEmptyString();
459 env->DeleteLocalRef(stringValue);
463 ALOGE("unsupported type in getObjectPropertyValue\n");
464 result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
466 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
467 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
468 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
469 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
471 env->DeleteLocalRef(objectHandlesArray);
472 env->DeleteLocalRef(propertyCodesArray);
473 env->DeleteLocalRef(dataTypesArray);
474 env->DeleteLocalRef(longValuesArray);
475 env->DeleteLocalRef(stringValuesArray);
478 env->DeleteLocalRef(list);
479 checkAndClearExceptionFromCallback(env, __FUNCTION__);
483 static bool readLongValue(int type, MtpDataPacket& packet, jlong& longValue) {
485 case MTP_TYPE_INT8: {
487 if (!packet.getInt8(temp)) return false;
491 case MTP_TYPE_UINT8: {
493 if (!packet.getUInt8(temp)) return false;
497 case MTP_TYPE_INT16: {
499 if (!packet.getInt16(temp)) return false;
503 case MTP_TYPE_UINT16: {
505 if (!packet.getUInt16(temp)) return false;
509 case MTP_TYPE_INT32: {
511 if (!packet.getInt32(temp)) return false;
515 case MTP_TYPE_UINT32: {
517 if (!packet.getUInt32(temp)) return false;
521 case MTP_TYPE_INT64: {
523 if (!packet.getInt64(temp)) return false;
527 case MTP_TYPE_UINT64: {
529 if (!packet.getUInt64(temp)) return false;
534 ALOGE("unsupported type in readLongValue");
540 MtpResponseCode MtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
541 MtpObjectProperty property,
542 MtpDataPacket& packet) {
545 if (!getObjectPropertyInfo(property, type))
546 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
548 JNIEnv* env = AndroidRuntime::getJNIEnv();
550 jstring stringValue = NULL;
551 MtpResponseCode result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
553 if (type == MTP_TYPE_STR) {
554 MtpStringBuffer buffer;
555 if (!packet.getString(buffer)) goto fail;
556 stringValue = env->NewStringUTF((const char *)buffer);
558 if (!readLongValue(type, packet, longValue)) goto fail;
561 result = env->CallIntMethod(mDatabase, method_setObjectProperty,
562 (jint)handle, (jint)property, longValue, stringValue);
564 env->DeleteLocalRef(stringValue);
567 checkAndClearExceptionFromCallback(env, __FUNCTION__);
571 MtpResponseCode MtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
572 MtpDataPacket& packet) {
573 JNIEnv* env = AndroidRuntime::getJNIEnv();
576 if (!getDevicePropertyInfo(property, type))
577 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
579 jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
580 (jint)property, mLongBuffer, mStringBuffer);
581 if (result != MTP_RESPONSE_OK) {
582 checkAndClearExceptionFromCallback(env, __FUNCTION__);
586 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
587 jlong longValue = longValues[0];
588 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
592 packet.putInt8(longValue);
595 packet.putUInt8(longValue);
598 packet.putInt16(longValue);
600 case MTP_TYPE_UINT16:
601 packet.putUInt16(longValue);
604 packet.putInt32(longValue);
606 case MTP_TYPE_UINT32:
607 packet.putUInt32(longValue);
610 packet.putInt64(longValue);
612 case MTP_TYPE_UINT64:
613 packet.putUInt64(longValue);
615 case MTP_TYPE_INT128:
616 packet.putInt128(longValue);
618 case MTP_TYPE_UINT128:
619 packet.putInt128(longValue);
623 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
624 packet.putString(str);
625 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
629 ALOGE("unsupported type in getDevicePropertyValue\n");
630 return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
633 checkAndClearExceptionFromCallback(env, __FUNCTION__);
634 return MTP_RESPONSE_OK;
637 MtpResponseCode MtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
638 MtpDataPacket& packet) {
641 if (!getDevicePropertyInfo(property, type))
642 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
644 JNIEnv* env = AndroidRuntime::getJNIEnv();
646 jstring stringValue = NULL;
647 MtpResponseCode result = MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
649 if (type == MTP_TYPE_STR) {
650 MtpStringBuffer buffer;
651 if (!packet.getString(buffer)) goto fail;
652 stringValue = env->NewStringUTF((const char *)buffer);
654 if (!readLongValue(type, packet, longValue)) goto fail;
657 result = env->CallIntMethod(mDatabase, method_setDeviceProperty,
658 (jint)property, longValue, stringValue);
660 env->DeleteLocalRef(stringValue);
663 checkAndClearExceptionFromCallback(env, __FUNCTION__);
667 MtpResponseCode MtpDatabase::resetDeviceProperty(MtpDeviceProperty /*property*/) {
671 MtpResponseCode MtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
672 uint32_t format, uint32_t property,
673 int groupCode, int depth,
674 MtpDataPacket& packet) {
675 static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
676 "Casting MtpObjectHandle to jint loses a value");
677 JNIEnv* env = AndroidRuntime::getJNIEnv();
678 jobject list = env->CallObjectMethod(
680 method_getObjectPropertyList,
681 static_cast<jint>(handle),
682 static_cast<jint>(format),
683 static_cast<jint>(property),
684 static_cast<jint>(groupCode),
685 static_cast<jint>(depth));
686 checkAndClearExceptionFromCallback(env, __FUNCTION__);
688 return MTP_RESPONSE_GENERAL_ERROR;
689 int count = env->CallIntMethod(list, method_getCount);
690 MtpResponseCode result = env->CallIntMethod(list, method_getCode);
692 packet.putUInt32(count);
694 jintArray objectHandlesArray = (jintArray)env->CallObjectMethod(list, method_getObjectHandles);
695 jintArray propertyCodesArray = (jintArray)env->CallObjectMethod(list, method_getPropertyCodes);
696 jintArray dataTypesArray = (jintArray)env->CallObjectMethod(list, method_getDataTypes);
697 jlongArray longValuesArray = (jlongArray)env->CallObjectMethod(list, method_getLongValues);
698 jobjectArray stringValuesArray = (jobjectArray)env->CallObjectMethod(list, method_getStringValues);
700 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
701 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
702 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
703 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
705 for (int i = 0; i < count; i++) {
706 packet.putUInt32(objectHandles[i]);
707 packet.putUInt16(propertyCodes[i]);
708 int type = dataTypes[i];
709 packet.putUInt16(type);
713 packet.putInt8(longValues[i]);
716 packet.putUInt8(longValues[i]);
719 packet.putInt16(longValues[i]);
721 case MTP_TYPE_UINT16:
722 packet.putUInt16(longValues[i]);
725 packet.putInt32(longValues[i]);
727 case MTP_TYPE_UINT32:
728 packet.putUInt32(longValues[i]);
731 packet.putInt64(longValues[i]);
733 case MTP_TYPE_UINT64:
734 packet.putUInt64(longValues[i]);
736 case MTP_TYPE_INT128:
737 packet.putInt128(longValues[i]);
739 case MTP_TYPE_UINT128:
740 packet.putUInt128(longValues[i]);
743 jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i);
744 const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL);
746 packet.putString(valueStr);
747 env->ReleaseStringUTFChars(value, valueStr);
749 packet.putEmptyString();
751 env->DeleteLocalRef(value);
755 ALOGE("bad or unsupported data type in MtpDatabase::getObjectPropertyList");
760 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
761 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
762 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
763 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
765 env->DeleteLocalRef(objectHandlesArray);
766 env->DeleteLocalRef(propertyCodesArray);
767 env->DeleteLocalRef(dataTypesArray);
768 env->DeleteLocalRef(longValuesArray);
769 env->DeleteLocalRef(stringValuesArray);
772 env->DeleteLocalRef(list);
773 checkAndClearExceptionFromCallback(env, __FUNCTION__);
777 static void foreachentry(ExifEntry *entry, void* /* user */) {
779 ALOGI("entry %x, format %d, size %d: %s",
780 entry->tag, entry->format, entry->size, exif_entry_get_value(entry, buf, sizeof(buf)));
783 static void foreachcontent(ExifContent *content, void *user) {
784 ALOGI("content %d", exif_content_get_ifd(content));
785 exif_content_foreach_entry(content, foreachentry, user);
788 static long getLongFromExifEntry(ExifEntry *e) {
789 ExifByteOrder o = exif_data_get_byte_order(e->parent->parent);
790 return exif_get_long(e->data, o);
793 static ExifData *getExifFromExtractor(const char *path) {
794 std::unique_ptr<uint8_t[]> exifBuf;
795 ExifData *exifdata = NULL;
797 FILE *fp = fopen (path, "rb");
799 ALOGE("failed to open file");
803 sp<NuMediaExtractor> extractor = new NuMediaExtractor();
804 fseek(fp, 0L, SEEK_END);
805 if (extractor->setDataSource(fileno(fp), 0, ftell(fp)) != OK) {
806 ALOGE("failed to setDataSource");
813 if (extractor->getExifOffsetSize(&offset, &size) != OK) {
818 exifBuf.reset(new uint8_t[size]);
819 fseek(fp, offset, SEEK_SET);
820 if (fread(exifBuf.get(), 1, size, fp) == size) {
821 exifdata = exif_data_new_from_data(exifBuf.get(), size);
828 MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
829 MtpObjectInfo& info) {
830 MtpStringBuffer path;
832 MtpObjectFormat format;
834 MtpResponseCode result = getObjectFilePath(handle, path, length, format);
835 if (result != MTP_RESPONSE_OK) {
838 info.mCompressedSize = (length > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)length);
840 JNIEnv* env = AndroidRuntime::getJNIEnv();
841 if (!env->CallBooleanMethod(mDatabase, method_getObjectInfo,
842 (jint)handle, mIntBuffer, mStringBuffer, mLongBuffer)) {
843 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
846 jint* intValues = env->GetIntArrayElements(mIntBuffer, 0);
847 info.mStorageID = intValues[0];
848 info.mFormat = intValues[1];
849 info.mParent = intValues[2];
850 env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
852 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
853 info.mDateCreated = longValues[0];
854 info.mDateModified = longValues[1];
855 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
858 info.mAssociationType = (format == MTP_FORMAT_ASSOCIATION ?
859 MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
860 MTP_ASSOCIATION_TYPE_UNDEFINED);
862 info.mAssociationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
864 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
865 MtpStringBuffer temp(str);
866 info.mName = strdup(temp);
867 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
869 // read EXIF data for thumbnail information
870 switch (info.mFormat) {
871 case MTP_FORMAT_EXIF_JPEG:
872 case MTP_FORMAT_HEIF:
873 case MTP_FORMAT_JFIF: {
875 if (info.mFormat == MTP_FORMAT_HEIF) {
876 exifdata = getExifFromExtractor(path);
878 exifdata = exif_data_new_from_file(path);
882 exif_data_foreach_content(exifdata, foreachcontent, NULL);
885 ExifEntry *w = exif_content_get_entry(
886 exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_X_DIMENSION);
887 ExifEntry *h = exif_content_get_entry(
888 exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_Y_DIMENSION);
889 info.mThumbCompressedSize = exifdata->data ? exifdata->size : 0;
890 info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
891 info.mImagePixWidth = w ? getLongFromExifEntry(w) : 0;
892 info.mImagePixHeight = h ? getLongFromExifEntry(h) : 0;
893 exif_data_unref(exifdata);
898 // Except DNG, all supported RAW image formats are not defined in PTP 1.2 specification.
899 // Most of RAW image formats are based on TIFF or TIFF/EP. To render Fuji's RAF format,
900 // it checks MTP_FORMAT_DEFINED case since it's designed as a custom format.
902 case MTP_FORMAT_TIFF:
903 case MTP_FORMAT_TIFF_EP:
904 case MTP_FORMAT_DEFINED: {
906 std::unique_ptr<FileStream> stream(new FileStream(temp));
907 piex::PreviewImageData image_data;
908 if (!GetExifFromRawImage(stream.get(), temp, image_data)) {
909 // Couldn't parse EXIF data from a image file via piex.
913 info.mThumbCompressedSize = image_data.thumbnail.length;
914 info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
915 info.mImagePixWidth = image_data.full_width;
916 info.mImagePixHeight = image_data.full_height;
922 checkAndClearExceptionFromCallback(env, __FUNCTION__);
923 return MTP_RESPONSE_OK;
926 void* MtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
927 MtpStringBuffer path;
929 MtpObjectFormat format;
933 if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK) {
935 case MTP_FORMAT_EXIF_JPEG:
936 case MTP_FORMAT_HEIF:
937 case MTP_FORMAT_JFIF: {
939 if (format == MTP_FORMAT_HEIF) {
940 exifdata = getExifFromExtractor(path);
942 exifdata = exif_data_new_from_file(path);
945 if (exifdata->data) {
946 result = malloc(exifdata->size);
948 memcpy(result, exifdata->data, exifdata->size);
949 outThumbSize = exifdata->size;
952 exif_data_unref(exifdata);
957 // See the above comment on getObjectInfo() method.
959 case MTP_FORMAT_TIFF:
960 case MTP_FORMAT_TIFF_EP:
961 case MTP_FORMAT_DEFINED: {
963 std::unique_ptr<FileStream> stream(new FileStream(temp));
964 piex::PreviewImageData image_data;
965 if (!GetExifFromRawImage(stream.get(), temp, image_data)) {
966 // Couldn't parse EXIF data from a image file via piex.
970 if (image_data.thumbnail.length == 0
971 || image_data.thumbnail.format != ::piex::Image::kJpegCompressed) {
972 // No thumbnail or non jpeg thumbnail.
976 result = malloc(image_data.thumbnail.length);
978 piex::Error err = stream.get()->GetData(
979 image_data.thumbnail.offset,
980 image_data.thumbnail.length,
981 (std::uint8_t *)result);
982 if (err == piex::Error::kOk) {
983 outThumbSize = image_data.thumbnail.length;
997 MtpResponseCode MtpDatabase::getObjectFilePath(MtpObjectHandle handle,
998 MtpStringBuffer& outFilePath,
999 int64_t& outFileLength,
1000 MtpObjectFormat& outFormat) {
1001 JNIEnv* env = AndroidRuntime::getJNIEnv();
1002 jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath,
1003 (jint)handle, mStringBuffer, mLongBuffer);
1004 if (result != MTP_RESPONSE_OK) {
1005 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1009 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
1010 outFilePath.set(str);
1011 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
1013 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
1014 outFileLength = longValues[0];
1015 outFormat = longValues[1];
1016 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
1018 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1022 MtpResponseCode MtpDatabase::beginDeleteObject(MtpObjectHandle handle) {
1023 JNIEnv* env = AndroidRuntime::getJNIEnv();
1024 MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginDeleteObject, (jint)handle);
1026 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1030 void MtpDatabase::endDeleteObject(MtpObjectHandle handle, bool succeeded) {
1031 JNIEnv* env = AndroidRuntime::getJNIEnv();
1032 env->CallVoidMethod(mDatabase, method_endDeleteObject, (jint)handle, (jboolean) succeeded);
1034 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1037 MtpResponseCode MtpDatabase::beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
1038 MtpStorageID newStorage) {
1039 JNIEnv* env = AndroidRuntime::getJNIEnv();
1040 MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginMoveObject,
1041 (jint)handle, (jint)newParent, (jint) newStorage);
1043 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1047 void MtpDatabase::endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
1048 MtpStorageID oldStorage, MtpStorageID newStorage,
1049 MtpObjectHandle handle, bool succeeded) {
1050 JNIEnv* env = AndroidRuntime::getJNIEnv();
1051 env->CallVoidMethod(mDatabase, method_endMoveObject,
1052 (jint)oldParent, (jint) newParent, (jint) oldStorage, (jint) newStorage,
1053 (jint) handle, (jboolean) succeeded);
1055 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1058 MtpResponseCode MtpDatabase::beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
1059 MtpStorageID newStorage) {
1060 JNIEnv* env = AndroidRuntime::getJNIEnv();
1061 MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginCopyObject,
1062 (jint)handle, (jint)newParent, (jint) newStorage);
1064 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1068 void MtpDatabase::endCopyObject(MtpObjectHandle handle, bool succeeded) {
1069 JNIEnv* env = AndroidRuntime::getJNIEnv();
1070 env->CallVoidMethod(mDatabase, method_endCopyObject, (jint)handle, (jboolean)succeeded);
1072 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1076 struct PropertyTableEntry {
1077 MtpObjectProperty property;
1081 static const PropertyTableEntry kObjectPropertyTable[] = {
1082 { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 },
1083 { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 },
1084 { MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16 },
1085 { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 },
1086 { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR },
1087 { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR },
1088 { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 },
1089 { MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128 },
1090 { MTP_PROPERTY_NAME, MTP_TYPE_STR },
1091 { MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR },
1092 { MTP_PROPERTY_DATE_ADDED, MTP_TYPE_STR },
1093 { MTP_PROPERTY_ARTIST, MTP_TYPE_STR },
1094 { MTP_PROPERTY_ALBUM_NAME, MTP_TYPE_STR },
1095 { MTP_PROPERTY_ALBUM_ARTIST, MTP_TYPE_STR },
1096 { MTP_PROPERTY_TRACK, MTP_TYPE_UINT16 },
1097 { MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_TYPE_STR },
1098 { MTP_PROPERTY_GENRE, MTP_TYPE_STR },
1099 { MTP_PROPERTY_COMPOSER, MTP_TYPE_STR },
1100 { MTP_PROPERTY_DURATION, MTP_TYPE_UINT32 },
1101 { MTP_PROPERTY_DESCRIPTION, MTP_TYPE_STR },
1102 { MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_TYPE_UINT32 },
1103 { MTP_PROPERTY_BITRATE_TYPE, MTP_TYPE_UINT16 },
1104 { MTP_PROPERTY_AUDIO_BITRATE, MTP_TYPE_UINT32 },
1105 { MTP_PROPERTY_NUMBER_OF_CHANNELS,MTP_TYPE_UINT16 },
1106 { MTP_PROPERTY_SAMPLE_RATE, MTP_TYPE_UINT32 },
1109 static const PropertyTableEntry kDevicePropertyTable[] = {
1110 { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_STR },
1111 { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR },
1112 { MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR },
1113 { MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT8 },
1114 { MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE, MTP_TYPE_UINT32 },
1117 bool MtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
1118 int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
1119 const PropertyTableEntry* entry = kObjectPropertyTable;
1120 for (int i = 0; i < count; i++, entry++) {
1121 if (entry->property == property) {
1129 bool MtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
1130 int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
1131 const PropertyTableEntry* entry = kDevicePropertyTable;
1132 for (int i = 0; i < count; i++, entry++) {
1133 if (entry->property == property) {
1141 MtpObjectHandleList* MtpDatabase::getObjectReferences(MtpObjectHandle handle) {
1142 JNIEnv* env = AndroidRuntime::getJNIEnv();
1143 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectReferences,
1147 MtpObjectHandleList* list = new MtpObjectHandleList();
1148 jint* handles = env->GetIntArrayElements(array, 0);
1149 jsize length = env->GetArrayLength(array);
1150 for (int i = 0; i < length; i++)
1151 list->push_back(handles[i]);
1152 env->ReleaseIntArrayElements(array, handles, 0);
1153 env->DeleteLocalRef(array);
1155 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1159 MtpResponseCode MtpDatabase::setObjectReferences(MtpObjectHandle handle,
1160 MtpObjectHandleList* references) {
1161 JNIEnv* env = AndroidRuntime::getJNIEnv();
1162 int count = references->size();
1163 jintArray array = env->NewIntArray(count);
1165 ALOGE("out of memory in setObjectReferences");
1168 jint* handles = env->GetIntArrayElements(array, 0);
1169 for (int i = 0; i < count; i++)
1170 handles[i] = (*references)[i];
1171 env->ReleaseIntArrayElements(array, handles, 0);
1172 MtpResponseCode result = env->CallIntMethod(mDatabase, method_setObjectReferences,
1173 (jint)handle, array);
1174 env->DeleteLocalRef(array);
1176 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1180 MtpProperty* MtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
1181 MtpObjectFormat format) {
1182 static const int channelEnum[] = {
1193 static const int bitrateEnum[] = {
1198 MtpProperty* result = NULL;
1200 case MTP_PROPERTY_OBJECT_FORMAT:
1201 // use format as default value
1202 result = new MtpProperty(property, MTP_TYPE_UINT16, false, format);
1204 case MTP_PROPERTY_PROTECTION_STATUS:
1205 case MTP_PROPERTY_TRACK:
1206 result = new MtpProperty(property, MTP_TYPE_UINT16);
1208 case MTP_PROPERTY_STORAGE_ID:
1209 case MTP_PROPERTY_PARENT_OBJECT:
1210 case MTP_PROPERTY_DURATION:
1211 case MTP_PROPERTY_AUDIO_WAVE_CODEC:
1212 result = new MtpProperty(property, MTP_TYPE_UINT32);
1214 case MTP_PROPERTY_OBJECT_SIZE:
1215 result = new MtpProperty(property, MTP_TYPE_UINT64);
1217 case MTP_PROPERTY_PERSISTENT_UID:
1218 result = new MtpProperty(property, MTP_TYPE_UINT128);
1220 case MTP_PROPERTY_NAME:
1221 case MTP_PROPERTY_DISPLAY_NAME:
1222 case MTP_PROPERTY_ARTIST:
1223 case MTP_PROPERTY_ALBUM_NAME:
1224 case MTP_PROPERTY_ALBUM_ARTIST:
1225 case MTP_PROPERTY_GENRE:
1226 case MTP_PROPERTY_COMPOSER:
1227 case MTP_PROPERTY_DESCRIPTION:
1228 result = new MtpProperty(property, MTP_TYPE_STR);
1230 case MTP_PROPERTY_DATE_MODIFIED:
1231 case MTP_PROPERTY_DATE_ADDED:
1232 case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
1233 result = new MtpProperty(property, MTP_TYPE_STR);
1234 result->setFormDateTime();
1236 case MTP_PROPERTY_OBJECT_FILE_NAME:
1237 // We allow renaming files and folders
1238 result = new MtpProperty(property, MTP_TYPE_STR, true);
1240 case MTP_PROPERTY_BITRATE_TYPE:
1241 result = new MtpProperty(property, MTP_TYPE_UINT16);
1242 result->setFormEnum(bitrateEnum, sizeof(bitrateEnum)/sizeof(bitrateEnum[0]));
1244 case MTP_PROPERTY_AUDIO_BITRATE:
1245 result = new MtpProperty(property, MTP_TYPE_UINT32);
1246 result->setFormRange(1, 1536000, 1);
1248 case MTP_PROPERTY_NUMBER_OF_CHANNELS:
1249 result = new MtpProperty(property, MTP_TYPE_UINT16);
1250 result->setFormEnum(channelEnum, sizeof(channelEnum)/sizeof(channelEnum[0]));
1252 case MTP_PROPERTY_SAMPLE_RATE:
1253 result = new MtpProperty(property, MTP_TYPE_UINT32);
1254 result->setFormRange(8000, 48000, 1);
1261 MtpProperty* MtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
1262 JNIEnv* env = AndroidRuntime::getJNIEnv();
1263 MtpProperty* result = NULL;
1264 bool writable = false;
1266 // get current value
1267 jint ret = env->CallIntMethod(mDatabase, method_getDeviceProperty,
1268 (jint)property, mLongBuffer, mStringBuffer);
1269 if (ret == MTP_RESPONSE_OK) {
1271 case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
1272 case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
1275 case MTP_DEVICE_PROPERTY_IMAGE_SIZE:
1277 result = new MtpProperty(property, MTP_TYPE_STR, writable);
1278 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
1279 result->setCurrentValue(str);
1280 // for read-only properties it is safe to assume current value is default value
1282 result->setDefaultValue(str);
1283 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
1286 case MTP_DEVICE_PROPERTY_BATTERY_LEVEL:
1288 result = new MtpProperty(property, MTP_TYPE_UINT8);
1289 jlong* arr = env->GetLongArrayElements(mLongBuffer, 0);
1290 result->setFormRange(0, arr[1], 1);
1291 result->mCurrentValue.u.u8 = (uint8_t) arr[0];
1292 env->ReleaseLongArrayElements(mLongBuffer, arr, 0);
1295 case MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE:
1297 jlong* arr = env->GetLongArrayElements(mLongBuffer, 0);
1298 result = new MtpProperty(property, MTP_TYPE_UINT32);
1299 result->mCurrentValue.u.u32 = (uint32_t) arr[0];
1300 env->ReleaseLongArrayElements(mLongBuffer, arr, 0);
1304 ALOGE("Unrecognized property %x", property);
1307 ALOGE("unable to read device property, response: %04X", ret);
1310 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1314 // ----------------------------------------------------------------------------
1317 android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
1319 MtpDatabase* database = new MtpDatabase(env, thiz);
1320 env->SetLongField(thiz, field_context, (jlong)database);
1321 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1325 android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
1327 MtpDatabase* database = (MtpDatabase *)env->GetLongField(thiz, field_context);
1328 database->cleanup(env);
1330 env->SetLongField(thiz, field_context, 0);
1331 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1335 android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject /*thiz*/, jlong seconds)
1338 formatDateTime(seconds, date, sizeof(date));
1339 return env->NewStringUTF(date);
1342 // ----------------------------------------------------------------------------
1344 static const JNINativeMethod gMtpDatabaseMethods[] = {
1345 {"native_setup", "()V", (void *)android_mtp_MtpDatabase_setup},
1346 {"native_finalize", "()V", (void *)android_mtp_MtpDatabase_finalize},
1349 static const JNINativeMethod gMtpPropertyGroupMethods[] = {
1350 {"format_date_time", "(J)Ljava/lang/String;",
1351 (void *)android_mtp_MtpPropertyGroup_format_date_time},
1354 #define GET_METHOD_ID(name, jclass, signature) \
1355 method_##name = env->GetMethodID(jclass, #name, signature); \
1356 if (method_##name == NULL) { \
1357 ALOGE("Can't find " #name); \
1361 int register_android_mtp_MtpDatabase(JNIEnv *env)
1365 clazz = env->FindClass("android/mtp/MtpDatabase");
1366 if (clazz == NULL) {
1367 ALOGE("Can't find android/mtp/MtpDatabase");
1370 GET_METHOD_ID(beginSendObject, clazz, "(Ljava/lang/String;III)I");
1371 GET_METHOD_ID(endSendObject, clazz, "(IZ)V");
1372 GET_METHOD_ID(rescanFile, clazz, "(Ljava/lang/String;II)V");
1373 GET_METHOD_ID(getObjectList, clazz, "(III)[I");
1374 GET_METHOD_ID(getNumObjects, clazz, "(III)I");
1375 GET_METHOD_ID(getSupportedPlaybackFormats, clazz, "()[I");
1376 GET_METHOD_ID(getSupportedCaptureFormats, clazz, "()[I");
1377 GET_METHOD_ID(getSupportedObjectProperties, clazz, "(I)[I");
1378 GET_METHOD_ID(getSupportedDeviceProperties, clazz, "()[I");
1379 GET_METHOD_ID(setObjectProperty, clazz, "(IIJLjava/lang/String;)I");
1380 GET_METHOD_ID(getDeviceProperty, clazz, "(I[J[C)I");
1381 GET_METHOD_ID(setDeviceProperty, clazz, "(IJLjava/lang/String;)I");
1382 GET_METHOD_ID(getObjectPropertyList, clazz, "(IIIII)Landroid/mtp/MtpPropertyList;");
1383 GET_METHOD_ID(getObjectInfo, clazz, "(I[I[C[J)Z");
1384 GET_METHOD_ID(getObjectFilePath, clazz, "(I[C[J)I");
1385 GET_METHOD_ID(beginDeleteObject, clazz, "(I)I");
1386 GET_METHOD_ID(endDeleteObject, clazz, "(IZ)V");
1387 GET_METHOD_ID(beginMoveObject, clazz, "(III)I");
1388 GET_METHOD_ID(endMoveObject, clazz, "(IIIIIZ)V");
1389 GET_METHOD_ID(beginCopyObject, clazz, "(III)I");
1390 GET_METHOD_ID(endCopyObject, clazz, "(IZ)V");
1391 GET_METHOD_ID(getObjectReferences, clazz, "(I)[I");
1392 GET_METHOD_ID(setObjectReferences, clazz, "(I[I)I");
1394 field_context = env->GetFieldID(clazz, "mNativeContext", "J");
1395 if (field_context == NULL) {
1396 ALOGE("Can't find MtpDatabase.mNativeContext");
1400 clazz = env->FindClass("android/mtp/MtpPropertyList");
1401 if (clazz == NULL) {
1402 ALOGE("Can't find android/mtp/MtpPropertyList");
1405 GET_METHOD_ID(getCode, clazz, "()I");
1406 GET_METHOD_ID(getCount, clazz, "()I");
1407 GET_METHOD_ID(getObjectHandles, clazz, "()[I");
1408 GET_METHOD_ID(getPropertyCodes, clazz, "()[I");
1409 GET_METHOD_ID(getDataTypes, clazz, "()[I");
1410 GET_METHOD_ID(getLongValues, clazz, "()[J");
1411 GET_METHOD_ID(getStringValues, clazz, "()[Ljava/lang/String;");
1413 if (AndroidRuntime::registerNativeMethods(env,
1414 "android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods)))
1417 return AndroidRuntime::registerNativeMethods(env,
1418 "android/mtp/MtpPropertyGroup", gMtpPropertyGroupMethods, NELEM(gMtpPropertyGroupMethods));