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"
20 #include "android_media_Utils.h"
22 #include "MtpDatabase.h"
23 #include "MtpDataPacket.h"
24 #include "MtpObjectInfo.h"
25 #include "MtpProperty.h"
26 #include "MtpStringBuffer.h"
29 #include "src/piex_types.h"
33 #include "libexif/exif-content.h"
34 #include "libexif/exif-data.h"
35 #include "libexif/exif-tag.h"
36 #include "libexif/exif-utils.h"
39 #include <android_runtime/AndroidRuntime.h>
40 #include <android_runtime/Log.h>
43 #include <nativehelper/ScopedLocalRef.h>
52 using namespace android;
54 // ----------------------------------------------------------------------------
56 static jmethodID method_beginSendObject;
57 static jmethodID method_endSendObject;
58 static jmethodID method_getObjectList;
59 static jmethodID method_getNumObjects;
60 static jmethodID method_getSupportedPlaybackFormats;
61 static jmethodID method_getSupportedCaptureFormats;
62 static jmethodID method_getSupportedObjectProperties;
63 static jmethodID method_getSupportedDeviceProperties;
64 static jmethodID method_setObjectProperty;
65 static jmethodID method_getDeviceProperty;
66 static jmethodID method_setDeviceProperty;
67 static jmethodID method_getObjectPropertyList;
68 static jmethodID method_getObjectInfo;
69 static jmethodID method_getObjectFilePath;
70 static jmethodID method_deleteFile;
71 static jmethodID method_getObjectReferences;
72 static jmethodID method_setObjectReferences;
73 static jmethodID method_sessionStarted;
74 static jmethodID method_sessionEnded;
76 static jfieldID field_context;
77 static jfieldID field_batteryLevel;
78 static jfieldID field_batteryScale;
80 // MtpPropertyList fields
81 static jfieldID field_mCount;
82 static jfieldID field_mResult;
83 static jfieldID field_mObjectHandles;
84 static jfieldID field_mPropertyCodes;
85 static jfieldID field_mDataTypes;
86 static jfieldID field_mLongValues;
87 static jfieldID field_mStringValues;
90 MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
91 return (MtpDatabase *)env->GetLongField(database, field_context);
94 // ----------------------------------------------------------------------------
96 class MyMtpDatabase : public MtpDatabase {
100 jlongArray mLongBuffer;
101 jcharArray mStringBuffer;
104 MyMtpDatabase(JNIEnv *env, jobject client);
105 virtual ~MyMtpDatabase();
106 void cleanup(JNIEnv *env);
108 virtual MtpObjectHandle beginSendObject(const char* path,
109 MtpObjectFormat format,
110 MtpObjectHandle parent,
111 MtpStorageID storage,
115 virtual void endSendObject(const char* path,
116 MtpObjectHandle handle,
117 MtpObjectFormat format,
120 virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
121 MtpObjectFormat format,
122 MtpObjectHandle parent);
124 virtual int getNumObjects(MtpStorageID storageID,
125 MtpObjectFormat format,
126 MtpObjectHandle parent);
128 // callee should delete[] the results from these
129 // results can be NULL
130 virtual MtpObjectFormatList* getSupportedPlaybackFormats();
131 virtual MtpObjectFormatList* getSupportedCaptureFormats();
132 virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format);
133 virtual MtpDevicePropertyList* getSupportedDeviceProperties();
135 virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle,
136 MtpObjectProperty property,
137 MtpDataPacket& packet);
139 virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle handle,
140 MtpObjectProperty property,
141 MtpDataPacket& packet);
143 virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty property,
144 MtpDataPacket& packet);
146 virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty property,
147 MtpDataPacket& packet);
149 virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty property);
151 virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle handle,
152 uint32_t format, uint32_t property,
153 int groupCode, int depth,
154 MtpDataPacket& packet);
156 virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
157 MtpObjectInfo& info);
159 virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
161 virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
162 MtpString& outFilePath,
163 int64_t& outFileLength,
164 MtpObjectFormat& outFormat);
165 virtual MtpResponseCode deleteFile(MtpObjectHandle handle);
167 bool getObjectPropertyInfo(MtpObjectProperty property, int& type);
168 bool getDevicePropertyInfo(MtpDeviceProperty property, int& type);
170 virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle);
172 virtual MtpResponseCode setObjectReferences(MtpObjectHandle handle,
173 MtpObjectHandleList* references);
175 virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty property,
176 MtpObjectFormat format);
178 virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property);
180 virtual void sessionStarted();
182 virtual void sessionEnded();
185 // ----------------------------------------------------------------------------
187 static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
188 if (env->ExceptionCheck()) {
189 ALOGE("An exception was thrown by callback '%s'.", methodName);
191 env->ExceptionClear();
195 // ----------------------------------------------------------------------------
197 MyMtpDatabase::MyMtpDatabase(JNIEnv *env, jobject client)
198 : mDatabase(env->NewGlobalRef(client)),
203 // create buffers for out arguments
204 // we don't need to be thread-safe so this is OK
205 jintArray intArray = env->NewIntArray(3);
207 return; // Already threw.
209 mIntBuffer = (jintArray)env->NewGlobalRef(intArray);
210 jlongArray longArray = env->NewLongArray(2);
212 return; // Already threw.
214 mLongBuffer = (jlongArray)env->NewGlobalRef(longArray);
215 // Needs to be long enough to hold a file path for getObjectFilePath()
216 jcharArray charArray = env->NewCharArray(PATH_MAX + 1);
218 return; // Already threw.
220 mStringBuffer = (jcharArray)env->NewGlobalRef(charArray);
223 void MyMtpDatabase::cleanup(JNIEnv *env) {
224 env->DeleteGlobalRef(mDatabase);
225 env->DeleteGlobalRef(mIntBuffer);
226 env->DeleteGlobalRef(mLongBuffer);
227 env->DeleteGlobalRef(mStringBuffer);
230 MyMtpDatabase::~MyMtpDatabase() {
233 MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
234 MtpObjectFormat format,
235 MtpObjectHandle parent,
236 MtpStorageID storage,
239 JNIEnv* env = AndroidRuntime::getJNIEnv();
240 jstring pathStr = env->NewStringUTF(path);
241 MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
242 pathStr, (jint)format, (jint)parent, (jint)storage,
243 (jlong)size, (jlong)modified);
246 env->DeleteLocalRef(pathStr);
247 checkAndClearExceptionFromCallback(env, __FUNCTION__);
251 void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
252 MtpObjectFormat format, bool succeeded) {
253 JNIEnv* env = AndroidRuntime::getJNIEnv();
254 jstring pathStr = env->NewStringUTF(path);
255 env->CallVoidMethod(mDatabase, method_endSendObject, pathStr,
256 (jint)handle, (jint)format, (jboolean)succeeded);
259 env->DeleteLocalRef(pathStr);
260 checkAndClearExceptionFromCallback(env, __FUNCTION__);
263 MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
264 MtpObjectFormat format,
265 MtpObjectHandle parent) {
266 JNIEnv* env = AndroidRuntime::getJNIEnv();
267 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList,
268 (jint)storageID, (jint)format, (jint)parent);
271 MtpObjectHandleList* list = new MtpObjectHandleList();
272 jint* handles = env->GetIntArrayElements(array, 0);
273 jsize length = env->GetArrayLength(array);
274 for (int i = 0; i < length; i++)
275 list->push(handles[i]);
276 env->ReleaseIntArrayElements(array, handles, 0);
277 env->DeleteLocalRef(array);
279 checkAndClearExceptionFromCallback(env, __FUNCTION__);
283 int MyMtpDatabase::getNumObjects(MtpStorageID storageID,
284 MtpObjectFormat format,
285 MtpObjectHandle parent) {
286 JNIEnv* env = AndroidRuntime::getJNIEnv();
287 int result = env->CallIntMethod(mDatabase, method_getNumObjects,
288 (jint)storageID, (jint)format, (jint)parent);
290 checkAndClearExceptionFromCallback(env, __FUNCTION__);
294 MtpObjectFormatList* MyMtpDatabase::getSupportedPlaybackFormats() {
295 JNIEnv* env = AndroidRuntime::getJNIEnv();
296 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
297 method_getSupportedPlaybackFormats);
300 MtpObjectFormatList* list = new MtpObjectFormatList();
301 jint* formats = env->GetIntArrayElements(array, 0);
302 jsize length = env->GetArrayLength(array);
303 for (int i = 0; i < length; i++)
304 list->push(formats[i]);
305 env->ReleaseIntArrayElements(array, formats, 0);
306 env->DeleteLocalRef(array);
308 checkAndClearExceptionFromCallback(env, __FUNCTION__);
312 MtpObjectFormatList* MyMtpDatabase::getSupportedCaptureFormats() {
313 JNIEnv* env = AndroidRuntime::getJNIEnv();
314 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
315 method_getSupportedCaptureFormats);
318 MtpObjectFormatList* list = new MtpObjectFormatList();
319 jint* formats = env->GetIntArrayElements(array, 0);
320 jsize length = env->GetArrayLength(array);
321 for (int i = 0; i < length; i++)
322 list->push(formats[i]);
323 env->ReleaseIntArrayElements(array, formats, 0);
324 env->DeleteLocalRef(array);
326 checkAndClearExceptionFromCallback(env, __FUNCTION__);
330 MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
331 JNIEnv* env = AndroidRuntime::getJNIEnv();
332 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
333 method_getSupportedObjectProperties, (jint)format);
336 MtpObjectPropertyList* list = new MtpObjectPropertyList();
337 jint* properties = env->GetIntArrayElements(array, 0);
338 jsize length = env->GetArrayLength(array);
339 for (int i = 0; i < length; i++)
340 list->push(properties[i]);
341 env->ReleaseIntArrayElements(array, properties, 0);
342 env->DeleteLocalRef(array);
344 checkAndClearExceptionFromCallback(env, __FUNCTION__);
348 MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() {
349 JNIEnv* env = AndroidRuntime::getJNIEnv();
350 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
351 method_getSupportedDeviceProperties);
354 MtpDevicePropertyList* list = new MtpDevicePropertyList();
355 jint* properties = env->GetIntArrayElements(array, 0);
356 jsize length = env->GetArrayLength(array);
357 for (int i = 0; i < length; i++)
358 list->push(properties[i]);
359 env->ReleaseIntArrayElements(array, properties, 0);
360 env->DeleteLocalRef(array);
362 checkAndClearExceptionFromCallback(env, __FUNCTION__);
366 MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
367 MtpObjectProperty property,
368 MtpDataPacket& packet) {
369 static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
370 "Casting MtpObjectHandle to jint loses a value");
371 static_assert(sizeof(jint) >= sizeof(MtpObjectProperty),
372 "Casting MtpObjectProperty to jint loses a value");
373 JNIEnv* env = AndroidRuntime::getJNIEnv();
374 jobject list = env->CallObjectMethod(
376 method_getObjectPropertyList,
377 static_cast<jint>(handle),
379 static_cast<jint>(property),
382 MtpResponseCode result = env->GetIntField(list, field_mResult);
383 int count = env->GetIntField(list, field_mCount);
384 if (result == MTP_RESPONSE_OK && count != 1)
385 result = MTP_RESPONSE_GENERAL_ERROR;
387 if (result == MTP_RESPONSE_OK) {
388 jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
389 jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
390 jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
391 jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
392 jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
394 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
395 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
396 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
397 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
399 int type = dataTypes[0];
400 jlong longValue = (longValues ? longValues[0] : 0);
402 // special case date properties, which are strings to MTP
403 // but stored internally as a uint64
404 if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) {
406 formatDateTime(longValue, date, sizeof(date));
407 packet.putString(date);
410 // release date is stored internally as just the year
411 if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) {
413 snprintf(date, sizeof(date), "%04" PRId64 "0101T000000", longValue);
414 packet.putString(date);
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.putInt128(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;
467 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
468 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
469 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
471 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
473 env->DeleteLocalRef(objectHandlesArray);
474 env->DeleteLocalRef(propertyCodesArray);
475 env->DeleteLocalRef(dataTypesArray);
477 env->DeleteLocalRef(longValuesArray);
478 if (stringValuesArray)
479 env->DeleteLocalRef(stringValuesArray);
482 env->DeleteLocalRef(list);
483 checkAndClearExceptionFromCallback(env, __FUNCTION__);
487 static bool readLongValue(int type, MtpDataPacket& packet, jlong& longValue) {
489 case MTP_TYPE_INT8: {
491 if (!packet.getInt8(temp)) return false;
495 case MTP_TYPE_UINT8: {
497 if (!packet.getUInt8(temp)) return false;
501 case MTP_TYPE_INT16: {
503 if (!packet.getInt16(temp)) return false;
507 case MTP_TYPE_UINT16: {
509 if (!packet.getUInt16(temp)) return false;
513 case MTP_TYPE_INT32: {
515 if (!packet.getInt32(temp)) return false;
519 case MTP_TYPE_UINT32: {
521 if (!packet.getUInt32(temp)) return false;
525 case MTP_TYPE_INT64: {
527 if (!packet.getInt64(temp)) return false;
531 case MTP_TYPE_UINT64: {
533 if (!packet.getUInt64(temp)) return false;
538 ALOGE("unsupported type in readLongValue");
544 MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
545 MtpObjectProperty property,
546 MtpDataPacket& packet) {
549 if (!getObjectPropertyInfo(property, type))
550 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
552 JNIEnv* env = AndroidRuntime::getJNIEnv();
554 jstring stringValue = NULL;
555 MtpResponseCode result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
557 if (type == MTP_TYPE_STR) {
558 MtpStringBuffer buffer;
559 if (!packet.getString(buffer)) goto fail;
560 stringValue = env->NewStringUTF((const char *)buffer);
562 if (!readLongValue(type, packet, longValue)) goto fail;
565 result = env->CallIntMethod(mDatabase, method_setObjectProperty,
566 (jint)handle, (jint)property, longValue, stringValue);
568 env->DeleteLocalRef(stringValue);
571 checkAndClearExceptionFromCallback(env, __FUNCTION__);
575 MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
576 MtpDataPacket& packet) {
577 JNIEnv* env = AndroidRuntime::getJNIEnv();
579 if (property == MTP_DEVICE_PROPERTY_BATTERY_LEVEL) {
580 // special case - implemented here instead of Java
581 packet.putUInt8((uint8_t)env->GetIntField(mDatabase, field_batteryLevel));
582 return MTP_RESPONSE_OK;
586 if (!getDevicePropertyInfo(property, type))
587 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
589 jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
590 (jint)property, mLongBuffer, mStringBuffer);
591 if (result != MTP_RESPONSE_OK) {
592 checkAndClearExceptionFromCallback(env, __FUNCTION__);
596 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
597 jlong longValue = longValues[0];
598 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
602 packet.putInt8(longValue);
605 packet.putUInt8(longValue);
608 packet.putInt16(longValue);
610 case MTP_TYPE_UINT16:
611 packet.putUInt16(longValue);
614 packet.putInt32(longValue);
616 case MTP_TYPE_UINT32:
617 packet.putUInt32(longValue);
620 packet.putInt64(longValue);
622 case MTP_TYPE_UINT64:
623 packet.putUInt64(longValue);
625 case MTP_TYPE_INT128:
626 packet.putInt128(longValue);
628 case MTP_TYPE_UINT128:
629 packet.putInt128(longValue);
633 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
634 packet.putString(str);
635 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
639 ALOGE("unsupported type in getDevicePropertyValue\n");
640 return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
643 checkAndClearExceptionFromCallback(env, __FUNCTION__);
644 return MTP_RESPONSE_OK;
648 MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
649 MtpDataPacket& packet) {
652 if (!getDevicePropertyInfo(property, type))
653 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
655 JNIEnv* env = AndroidRuntime::getJNIEnv();
657 jstring stringValue = NULL;
658 MtpResponseCode result = MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
660 if (type == MTP_TYPE_STR) {
661 MtpStringBuffer buffer;
662 if (!packet.getString(buffer)) goto fail;
663 stringValue = env->NewStringUTF((const char *)buffer);
665 if (!readLongValue(type, packet, longValue)) goto fail;
668 result = env->CallIntMethod(mDatabase, method_setDeviceProperty,
669 (jint)property, longValue, stringValue);
671 env->DeleteLocalRef(stringValue);
674 checkAndClearExceptionFromCallback(env, __FUNCTION__);
678 MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty /*property*/) {
682 MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
683 uint32_t format, uint32_t property,
684 int groupCode, int depth,
685 MtpDataPacket& packet) {
686 static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
687 "Casting MtpObjectHandle to jint loses a value");
688 JNIEnv* env = AndroidRuntime::getJNIEnv();
689 jobject list = env->CallObjectMethod(
691 method_getObjectPropertyList,
692 static_cast<jint>(handle),
693 static_cast<jint>(format),
694 static_cast<jint>(property),
695 static_cast<jint>(groupCode),
696 static_cast<jint>(depth));
697 checkAndClearExceptionFromCallback(env, __FUNCTION__);
699 return MTP_RESPONSE_GENERAL_ERROR;
700 int count = env->GetIntField(list, field_mCount);
701 MtpResponseCode result = env->GetIntField(list, field_mResult);
703 packet.putUInt32(count);
705 jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
706 jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
707 jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
708 jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
709 jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
711 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
712 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
713 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
714 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
716 for (int i = 0; i < count; i++) {
717 packet.putUInt32(objectHandles[i]);
718 packet.putUInt16(propertyCodes[i]);
719 int type = dataTypes[i];
720 packet.putUInt16(type);
724 packet.putInt8(longValues[i]);
727 packet.putUInt8(longValues[i]);
730 packet.putInt16(longValues[i]);
732 case MTP_TYPE_UINT16:
733 packet.putUInt16(longValues[i]);
736 packet.putInt32(longValues[i]);
738 case MTP_TYPE_UINT32:
739 packet.putUInt32(longValues[i]);
742 packet.putInt64(longValues[i]);
744 case MTP_TYPE_UINT64:
745 packet.putUInt64(longValues[i]);
747 case MTP_TYPE_INT128:
748 packet.putInt128(longValues[i]);
750 case MTP_TYPE_UINT128:
751 packet.putUInt128(longValues[i]);
754 jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i);
755 const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL);
757 packet.putString(valueStr);
758 env->ReleaseStringUTFChars(value, valueStr);
760 packet.putEmptyString();
762 env->DeleteLocalRef(value);
766 ALOGE("bad or unsupported data type in MyMtpDatabase::getObjectPropertyList");
771 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
772 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
773 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
775 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
777 env->DeleteLocalRef(objectHandlesArray);
778 env->DeleteLocalRef(propertyCodesArray);
779 env->DeleteLocalRef(dataTypesArray);
781 env->DeleteLocalRef(longValuesArray);
782 if (stringValuesArray)
783 env->DeleteLocalRef(stringValuesArray);
786 env->DeleteLocalRef(list);
787 checkAndClearExceptionFromCallback(env, __FUNCTION__);
791 static void foreachentry(ExifEntry *entry, void* /* user */) {
793 ALOGI("entry %x, format %d, size %d: %s",
794 entry->tag, entry->format, entry->size, exif_entry_get_value(entry, buf, sizeof(buf)));
797 static void foreachcontent(ExifContent *content, void *user) {
798 ALOGI("content %d", exif_content_get_ifd(content));
799 exif_content_foreach_entry(content, foreachentry, user);
802 static long getLongFromExifEntry(ExifEntry *e) {
803 ExifByteOrder o = exif_data_get_byte_order(e->parent->parent);
804 return exif_get_long(e->data, o);
807 MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
808 MtpObjectInfo& info) {
811 MtpObjectFormat format;
813 MtpResponseCode result = getObjectFilePath(handle, path, length, format);
814 if (result != MTP_RESPONSE_OK) {
817 info.mCompressedSize = (length > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)length);
819 JNIEnv* env = AndroidRuntime::getJNIEnv();
820 if (!env->CallBooleanMethod(mDatabase, method_getObjectInfo,
821 (jint)handle, mIntBuffer, mStringBuffer, mLongBuffer)) {
822 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
825 jint* intValues = env->GetIntArrayElements(mIntBuffer, 0);
826 info.mStorageID = intValues[0];
827 info.mFormat = intValues[1];
828 info.mParent = intValues[2];
829 env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
831 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
832 info.mDateCreated = longValues[0];
833 info.mDateModified = longValues[1];
834 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
837 info.mAssociationType = (format == MTP_FORMAT_ASSOCIATION ?
838 MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
839 MTP_ASSOCIATION_TYPE_UNDEFINED);
841 info.mAssociationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
843 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
844 MtpString temp(reinterpret_cast<char16_t*>(str));
845 info.mName = strdup((const char *)temp);
846 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
848 // read EXIF data for thumbnail information
849 switch (info.mFormat) {
850 case MTP_FORMAT_EXIF_JPEG:
851 case MTP_FORMAT_JFIF: {
852 ExifData *exifdata = exif_data_new_from_file(path);
855 exif_data_foreach_content(exifdata, foreachcontent, NULL);
858 ExifEntry *w = exif_content_get_entry(
859 exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_X_DIMENSION);
860 ExifEntry *h = exif_content_get_entry(
861 exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_Y_DIMENSION);
862 info.mThumbCompressedSize = exifdata->data ? exifdata->size : 0;
863 info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
864 info.mImagePixWidth = w ? getLongFromExifEntry(w) : 0;
865 info.mImagePixHeight = h ? getLongFromExifEntry(h) : 0;
866 exif_data_unref(exifdata);
871 // Except DNG, all supported RAW image formats are not defined in PTP 1.2 specification.
872 // Most of RAW image formats are based on TIFF or TIFF/EP. To render Fuji's RAF format,
873 // it checks MTP_FORMAT_DEFINED case since it's designed as a custom format.
875 case MTP_FORMAT_TIFF:
876 case MTP_FORMAT_TIFF_EP:
877 case MTP_FORMAT_DEFINED: {
878 std::unique_ptr<FileStream> stream(new FileStream(path));
879 piex::PreviewImageData image_data;
880 if (!GetExifFromRawImage(stream.get(), path, image_data)) {
881 // Couldn't parse EXIF data from a image file via piex.
885 info.mThumbCompressedSize = image_data.thumbnail.length;
886 info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
887 info.mImagePixWidth = image_data.full_width;
888 info.mImagePixHeight = image_data.full_height;
894 checkAndClearExceptionFromCallback(env, __FUNCTION__);
895 return MTP_RESPONSE_OK;
898 void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
901 MtpObjectFormat format;
905 if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK) {
907 case MTP_FORMAT_EXIF_JPEG:
908 case MTP_FORMAT_JFIF: {
909 ExifData *exifdata = exif_data_new_from_file(path);
911 if (exifdata->data) {
912 result = malloc(exifdata->size);
914 memcpy(result, exifdata->data, exifdata->size);
915 outThumbSize = exifdata->size;
918 exif_data_unref(exifdata);
923 // See the above comment on getObjectInfo() method.
925 case MTP_FORMAT_TIFF:
926 case MTP_FORMAT_TIFF_EP:
927 case MTP_FORMAT_DEFINED: {
928 std::unique_ptr<FileStream> stream(new FileStream(path));
929 piex::PreviewImageData image_data;
930 if (!GetExifFromRawImage(stream.get(), path, image_data)) {
931 // Couldn't parse EXIF data from a image file via piex.
935 if (image_data.thumbnail.length == 0
936 || image_data.thumbnail.format != ::piex::Image::kJpegCompressed) {
937 // No thumbnail or non jpeg thumbnail.
941 result = malloc(image_data.thumbnail.length);
943 piex::Error err = stream.get()->GetData(
944 image_data.thumbnail.offset,
945 image_data.thumbnail.length,
946 (std::uint8_t *)result);
947 if (err == piex::Error::kOk) {
948 outThumbSize = image_data.thumbnail.length;
961 MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
962 MtpString& outFilePath,
963 int64_t& outFileLength,
964 MtpObjectFormat& outFormat) {
965 JNIEnv* env = AndroidRuntime::getJNIEnv();
966 jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath,
967 (jint)handle, mStringBuffer, mLongBuffer);
968 if (result != MTP_RESPONSE_OK) {
969 checkAndClearExceptionFromCallback(env, __FUNCTION__);
973 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
974 outFilePath.setTo(reinterpret_cast<char16_t*>(str),
975 strlen16(reinterpret_cast<char16_t*>(str)));
976 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
978 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
979 outFileLength = longValues[0];
980 outFormat = longValues[1];
981 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
983 checkAndClearExceptionFromCallback(env, __FUNCTION__);
987 MtpResponseCode MyMtpDatabase::deleteFile(MtpObjectHandle handle) {
988 JNIEnv* env = AndroidRuntime::getJNIEnv();
989 MtpResponseCode result = env->CallIntMethod(mDatabase, method_deleteFile, (jint)handle);
991 checkAndClearExceptionFromCallback(env, __FUNCTION__);
995 struct PropertyTableEntry {
996 MtpObjectProperty property;
1000 static const PropertyTableEntry kObjectPropertyTable[] = {
1001 { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 },
1002 { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 },
1003 { MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16 },
1004 { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 },
1005 { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR },
1006 { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR },
1007 { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 },
1008 { MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128 },
1009 { MTP_PROPERTY_NAME, MTP_TYPE_STR },
1010 { MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR },
1011 { MTP_PROPERTY_DATE_ADDED, MTP_TYPE_STR },
1012 { MTP_PROPERTY_ARTIST, MTP_TYPE_STR },
1013 { MTP_PROPERTY_ALBUM_NAME, MTP_TYPE_STR },
1014 { MTP_PROPERTY_ALBUM_ARTIST, MTP_TYPE_STR },
1015 { MTP_PROPERTY_TRACK, MTP_TYPE_UINT16 },
1016 { MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_TYPE_STR },
1017 { MTP_PROPERTY_GENRE, MTP_TYPE_STR },
1018 { MTP_PROPERTY_COMPOSER, MTP_TYPE_STR },
1019 { MTP_PROPERTY_DURATION, MTP_TYPE_UINT32 },
1020 { MTP_PROPERTY_DESCRIPTION, MTP_TYPE_STR },
1021 { MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_TYPE_UINT32 },
1022 { MTP_PROPERTY_BITRATE_TYPE, MTP_TYPE_UINT16 },
1023 { MTP_PROPERTY_AUDIO_BITRATE, MTP_TYPE_UINT32 },
1024 { MTP_PROPERTY_NUMBER_OF_CHANNELS,MTP_TYPE_UINT16 },
1025 { MTP_PROPERTY_SAMPLE_RATE, MTP_TYPE_UINT32 },
1028 static const PropertyTableEntry kDevicePropertyTable[] = {
1029 { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_STR },
1030 { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR },
1031 { MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR },
1032 { MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT8 },
1035 bool MyMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
1036 int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
1037 const PropertyTableEntry* entry = kObjectPropertyTable;
1038 for (int i = 0; i < count; i++, entry++) {
1039 if (entry->property == property) {
1047 bool MyMtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
1048 int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
1049 const PropertyTableEntry* entry = kDevicePropertyTable;
1050 for (int i = 0; i < count; i++, entry++) {
1051 if (entry->property == property) {
1059 MtpObjectHandleList* MyMtpDatabase::getObjectReferences(MtpObjectHandle handle) {
1060 JNIEnv* env = AndroidRuntime::getJNIEnv();
1061 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectReferences,
1065 MtpObjectHandleList* list = new MtpObjectHandleList();
1066 jint* handles = env->GetIntArrayElements(array, 0);
1067 jsize length = env->GetArrayLength(array);
1068 for (int i = 0; i < length; i++)
1069 list->push(handles[i]);
1070 env->ReleaseIntArrayElements(array, handles, 0);
1071 env->DeleteLocalRef(array);
1073 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1077 MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
1078 MtpObjectHandleList* references) {
1079 JNIEnv* env = AndroidRuntime::getJNIEnv();
1080 int count = references->size();
1081 jintArray array = env->NewIntArray(count);
1083 ALOGE("out of memory in setObjectReferences");
1086 jint* handles = env->GetIntArrayElements(array, 0);
1087 for (int i = 0; i < count; i++)
1088 handles[i] = (*references)[i];
1089 env->ReleaseIntArrayElements(array, handles, 0);
1090 MtpResponseCode result = env->CallIntMethod(mDatabase, method_setObjectReferences,
1091 (jint)handle, array);
1092 env->DeleteLocalRef(array);
1094 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1098 MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
1099 MtpObjectFormat format) {
1100 static const int channelEnum[] = {
1111 static const int bitrateEnum[] = {
1116 MtpProperty* result = NULL;
1118 case MTP_PROPERTY_OBJECT_FORMAT:
1119 // use format as default value
1120 result = new MtpProperty(property, MTP_TYPE_UINT16, false, format);
1122 case MTP_PROPERTY_PROTECTION_STATUS:
1123 case MTP_PROPERTY_TRACK:
1124 result = new MtpProperty(property, MTP_TYPE_UINT16);
1126 case MTP_PROPERTY_STORAGE_ID:
1127 case MTP_PROPERTY_PARENT_OBJECT:
1128 case MTP_PROPERTY_DURATION:
1129 case MTP_PROPERTY_AUDIO_WAVE_CODEC:
1130 result = new MtpProperty(property, MTP_TYPE_UINT32);
1132 case MTP_PROPERTY_OBJECT_SIZE:
1133 result = new MtpProperty(property, MTP_TYPE_UINT64);
1135 case MTP_PROPERTY_PERSISTENT_UID:
1136 result = new MtpProperty(property, MTP_TYPE_UINT128);
1138 case MTP_PROPERTY_NAME:
1139 case MTP_PROPERTY_DISPLAY_NAME:
1140 case MTP_PROPERTY_ARTIST:
1141 case MTP_PROPERTY_ALBUM_NAME:
1142 case MTP_PROPERTY_ALBUM_ARTIST:
1143 case MTP_PROPERTY_GENRE:
1144 case MTP_PROPERTY_COMPOSER:
1145 case MTP_PROPERTY_DESCRIPTION:
1146 result = new MtpProperty(property, MTP_TYPE_STR);
1148 case MTP_PROPERTY_DATE_MODIFIED:
1149 case MTP_PROPERTY_DATE_ADDED:
1150 case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
1151 result = new MtpProperty(property, MTP_TYPE_STR);
1152 result->setFormDateTime();
1154 case MTP_PROPERTY_OBJECT_FILE_NAME:
1155 // We allow renaming files and folders
1156 result = new MtpProperty(property, MTP_TYPE_STR, true);
1158 case MTP_PROPERTY_BITRATE_TYPE:
1159 result = new MtpProperty(property, MTP_TYPE_UINT16);
1160 result->setFormEnum(bitrateEnum, sizeof(bitrateEnum)/sizeof(bitrateEnum[0]));
1162 case MTP_PROPERTY_AUDIO_BITRATE:
1163 result = new MtpProperty(property, MTP_TYPE_UINT32);
1164 result->setFormRange(1, 1536000, 1);
1166 case MTP_PROPERTY_NUMBER_OF_CHANNELS:
1167 result = new MtpProperty(property, MTP_TYPE_UINT16);
1168 result->setFormEnum(channelEnum, sizeof(channelEnum)/sizeof(channelEnum[0]));
1170 case MTP_PROPERTY_SAMPLE_RATE:
1171 result = new MtpProperty(property, MTP_TYPE_UINT32);
1172 result->setFormRange(8000, 48000, 1);
1179 MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
1180 JNIEnv* env = AndroidRuntime::getJNIEnv();
1181 MtpProperty* result = NULL;
1182 bool writable = false;
1185 case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
1186 case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
1189 case MTP_DEVICE_PROPERTY_IMAGE_SIZE: {
1190 result = new MtpProperty(property, MTP_TYPE_STR, writable);
1192 // get current value
1193 jint ret = env->CallIntMethod(mDatabase, method_getDeviceProperty,
1194 (jint)property, mLongBuffer, mStringBuffer);
1195 if (ret == MTP_RESPONSE_OK) {
1196 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
1197 result->setCurrentValue(str);
1198 // for read-only properties it is safe to assume current value is default value
1200 result->setDefaultValue(str);
1201 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
1203 ALOGE("unable to read device property, response: %04X", ret);
1207 case MTP_DEVICE_PROPERTY_BATTERY_LEVEL:
1208 result = new MtpProperty(property, MTP_TYPE_UINT8);
1209 result->setFormRange(0, env->GetIntField(mDatabase, field_batteryScale), 1);
1210 result->mCurrentValue.u.u8 = (uint8_t)env->GetIntField(mDatabase, field_batteryLevel);
1214 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1218 void MyMtpDatabase::sessionStarted() {
1219 JNIEnv* env = AndroidRuntime::getJNIEnv();
1220 env->CallVoidMethod(mDatabase, method_sessionStarted);
1221 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1224 void MyMtpDatabase::sessionEnded() {
1225 JNIEnv* env = AndroidRuntime::getJNIEnv();
1226 env->CallVoidMethod(mDatabase, method_sessionEnded);
1227 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1230 // ----------------------------------------------------------------------------
1233 android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
1235 MyMtpDatabase* database = new MyMtpDatabase(env, thiz);
1236 env->SetLongField(thiz, field_context, (jlong)database);
1237 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1241 android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
1243 MyMtpDatabase* database = (MyMtpDatabase *)env->GetLongField(thiz, field_context);
1244 database->cleanup(env);
1246 env->SetLongField(thiz, field_context, 0);
1247 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1251 android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject /*thiz*/, jlong seconds)
1254 formatDateTime(seconds, date, sizeof(date));
1255 return env->NewStringUTF(date);
1258 // ----------------------------------------------------------------------------
1260 static const JNINativeMethod gMtpDatabaseMethods[] = {
1261 {"native_setup", "()V", (void *)android_mtp_MtpDatabase_setup},
1262 {"native_finalize", "()V", (void *)android_mtp_MtpDatabase_finalize},
1265 static const JNINativeMethod gMtpPropertyGroupMethods[] = {
1266 {"format_date_time", "(J)Ljava/lang/String;",
1267 (void *)android_mtp_MtpPropertyGroup_format_date_time},
1270 int register_android_mtp_MtpDatabase(JNIEnv *env)
1274 clazz = env->FindClass("android/mtp/MtpDatabase");
1275 if (clazz == NULL) {
1276 ALOGE("Can't find android/mtp/MtpDatabase");
1279 method_beginSendObject = env->GetMethodID(clazz, "beginSendObject", "(Ljava/lang/String;IIIJJ)I");
1280 if (method_beginSendObject == NULL) {
1281 ALOGE("Can't find beginSendObject");
1284 method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIZ)V");
1285 if (method_endSendObject == NULL) {
1286 ALOGE("Can't find endSendObject");
1289 method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I");
1290 if (method_getObjectList == NULL) {
1291 ALOGE("Can't find getObjectList");
1294 method_getNumObjects = env->GetMethodID(clazz, "getNumObjects", "(III)I");
1295 if (method_getNumObjects == NULL) {
1296 ALOGE("Can't find getNumObjects");
1299 method_getSupportedPlaybackFormats = env->GetMethodID(clazz, "getSupportedPlaybackFormats", "()[I");
1300 if (method_getSupportedPlaybackFormats == NULL) {
1301 ALOGE("Can't find getSupportedPlaybackFormats");
1304 method_getSupportedCaptureFormats = env->GetMethodID(clazz, "getSupportedCaptureFormats", "()[I");
1305 if (method_getSupportedCaptureFormats == NULL) {
1306 ALOGE("Can't find getSupportedCaptureFormats");
1309 method_getSupportedObjectProperties = env->GetMethodID(clazz, "getSupportedObjectProperties", "(I)[I");
1310 if (method_getSupportedObjectProperties == NULL) {
1311 ALOGE("Can't find getSupportedObjectProperties");
1314 method_getSupportedDeviceProperties = env->GetMethodID(clazz, "getSupportedDeviceProperties", "()[I");
1315 if (method_getSupportedDeviceProperties == NULL) {
1316 ALOGE("Can't find getSupportedDeviceProperties");
1319 method_setObjectProperty = env->GetMethodID(clazz, "setObjectProperty", "(IIJLjava/lang/String;)I");
1320 if (method_setObjectProperty == NULL) {
1321 ALOGE("Can't find setObjectProperty");
1324 method_getDeviceProperty = env->GetMethodID(clazz, "getDeviceProperty", "(I[J[C)I");
1325 if (method_getDeviceProperty == NULL) {
1326 ALOGE("Can't find getDeviceProperty");
1329 method_setDeviceProperty = env->GetMethodID(clazz, "setDeviceProperty", "(IJLjava/lang/String;)I");
1330 if (method_setDeviceProperty == NULL) {
1331 ALOGE("Can't find setDeviceProperty");
1334 method_getObjectPropertyList = env->GetMethodID(clazz, "getObjectPropertyList",
1335 "(IIIII)Landroid/mtp/MtpPropertyList;");
1336 if (method_getObjectPropertyList == NULL) {
1337 ALOGE("Can't find getObjectPropertyList");
1340 method_getObjectInfo = env->GetMethodID(clazz, "getObjectInfo", "(I[I[C[J)Z");
1341 if (method_getObjectInfo == NULL) {
1342 ALOGE("Can't find getObjectInfo");
1345 method_getObjectFilePath = env->GetMethodID(clazz, "getObjectFilePath", "(I[C[J)I");
1346 if (method_getObjectFilePath == NULL) {
1347 ALOGE("Can't find getObjectFilePath");
1350 method_deleteFile = env->GetMethodID(clazz, "deleteFile", "(I)I");
1351 if (method_deleteFile == NULL) {
1352 ALOGE("Can't find deleteFile");
1355 method_getObjectReferences = env->GetMethodID(clazz, "getObjectReferences", "(I)[I");
1356 if (method_getObjectReferences == NULL) {
1357 ALOGE("Can't find getObjectReferences");
1360 method_setObjectReferences = env->GetMethodID(clazz, "setObjectReferences", "(I[I)I");
1361 if (method_setObjectReferences == NULL) {
1362 ALOGE("Can't find setObjectReferences");
1365 method_sessionStarted = env->GetMethodID(clazz, "sessionStarted", "()V");
1366 if (method_sessionStarted == NULL) {
1367 ALOGE("Can't find sessionStarted");
1370 method_sessionEnded = env->GetMethodID(clazz, "sessionEnded", "()V");
1371 if (method_sessionEnded == NULL) {
1372 ALOGE("Can't find sessionEnded");
1376 field_context = env->GetFieldID(clazz, "mNativeContext", "J");
1377 if (field_context == NULL) {
1378 ALOGE("Can't find MtpDatabase.mNativeContext");
1381 field_batteryLevel = env->GetFieldID(clazz, "mBatteryLevel", "I");
1382 if (field_batteryLevel == NULL) {
1383 ALOGE("Can't find MtpDatabase.mBatteryLevel");
1386 field_batteryScale = env->GetFieldID(clazz, "mBatteryScale", "I");
1387 if (field_batteryScale == NULL) {
1388 ALOGE("Can't find MtpDatabase.mBatteryScale");
1392 // now set up fields for MtpPropertyList class
1393 clazz = env->FindClass("android/mtp/MtpPropertyList");
1394 if (clazz == NULL) {
1395 ALOGE("Can't find android/mtp/MtpPropertyList");
1398 field_mCount = env->GetFieldID(clazz, "mCount", "I");
1399 if (field_mCount == NULL) {
1400 ALOGE("Can't find MtpPropertyList.mCount");
1403 field_mResult = env->GetFieldID(clazz, "mResult", "I");
1404 if (field_mResult == NULL) {
1405 ALOGE("Can't find MtpPropertyList.mResult");
1408 field_mObjectHandles = env->GetFieldID(clazz, "mObjectHandles", "[I");
1409 if (field_mObjectHandles == NULL) {
1410 ALOGE("Can't find MtpPropertyList.mObjectHandles");
1413 field_mPropertyCodes = env->GetFieldID(clazz, "mPropertyCodes", "[I");
1414 if (field_mPropertyCodes == NULL) {
1415 ALOGE("Can't find MtpPropertyList.mPropertyCodes");
1418 field_mDataTypes = env->GetFieldID(clazz, "mDataTypes", "[I");
1419 if (field_mDataTypes == NULL) {
1420 ALOGE("Can't find MtpPropertyList.mDataTypes");
1423 field_mLongValues = env->GetFieldID(clazz, "mLongValues", "[J");
1424 if (field_mLongValues == NULL) {
1425 ALOGE("Can't find MtpPropertyList.mLongValues");
1428 field_mStringValues = env->GetFieldID(clazz, "mStringValues", "[Ljava/lang/String;");
1429 if (field_mStringValues == NULL) {
1430 ALOGE("Can't find MtpPropertyList.mStringValues");
1434 if (AndroidRuntime::registerNativeMethods(env,
1435 "android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods)))
1438 return AndroidRuntime::registerNativeMethods(env,
1439 "android/mtp/MtpPropertyGroup", gMtpPropertyGroupMethods, NELEM(gMtpPropertyGroupMethods));