android_mtp_MtpDatabase.cpp revision a792c804025e25eb8a110d1db63f26bbd09e0e6b
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 38extern "C" { 39#include "jhead.h" 40} 41 42using namespace android; 43 44// ---------------------------------------------------------------------------- 45 46static jmethodID method_beginSendObject; 47static jmethodID method_endSendObject; 48static jmethodID method_getObjectList; 49static jmethodID method_getNumObjects; 50static jmethodID method_getSupportedPlaybackFormats; 51static jmethodID method_getSupportedCaptureFormats; 52static jmethodID method_getSupportedObjectProperties; 53static jmethodID method_getSupportedDeviceProperties; 54static jmethodID method_setObjectProperty; 55static jmethodID method_getDeviceProperty; 56static jmethodID method_setDeviceProperty; 57static jmethodID method_getObjectPropertyList; 58static jmethodID method_getObjectInfo; 59static jmethodID method_getObjectFilePath; 60static jmethodID method_deleteFile; 61static jmethodID method_getObjectReferences; 62static jmethodID method_setObjectReferences; 63static jmethodID method_sessionStarted; 64static jmethodID method_sessionEnded; 65 66static jfieldID field_context; 67 68// MtpPropertyList fields 69static jfieldID field_mCount; 70static jfieldID field_mResult; 71static jfieldID field_mObjectHandles; 72static jfieldID field_mPropertyCodes; 73static jfieldID field_mDataTypes; 74static jfieldID field_mLongValues; 75static jfieldID field_mStringValues; 76 77 78MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) { 79 return (MtpDatabase *)env->GetIntField(database, field_context); 80} 81 82#ifdef HAVE_ANDROID_OS 83// ---------------------------------------------------------------------------- 84 85class MyMtpDatabase : public MtpDatabase { 86private: 87 jobject mDatabase; 88 jintArray mIntBuffer; 89 jlongArray mLongBuffer; 90 jcharArray mStringBuffer; 91 92public: 93 MyMtpDatabase(JNIEnv *env, jobject client); 94 virtual ~MyMtpDatabase(); 95 void cleanup(JNIEnv *env); 96 97 virtual MtpObjectHandle beginSendObject(const char* path, 98 MtpObjectFormat format, 99 MtpObjectHandle parent, 100 MtpStorageID storage, 101 uint64_t size, 102 time_t modified); 103 104 virtual void endSendObject(const char* path, 105 MtpObjectHandle handle, 106 MtpObjectFormat format, 107 bool succeeded); 108 109 virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID, 110 MtpObjectFormat format, 111 MtpObjectHandle parent); 112 113 virtual int getNumObjects(MtpStorageID storageID, 114 MtpObjectFormat format, 115 MtpObjectHandle parent); 116 117 // callee should delete[] the results from these 118 // results can be NULL 119 virtual MtpObjectFormatList* getSupportedPlaybackFormats(); 120 virtual MtpObjectFormatList* getSupportedCaptureFormats(); 121 virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format); 122 virtual MtpDevicePropertyList* getSupportedDeviceProperties(); 123 124 virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle, 125 MtpObjectProperty property, 126 MtpDataPacket& packet); 127 128 virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle handle, 129 MtpObjectProperty property, 130 MtpDataPacket& packet); 131 132 virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty property, 133 MtpDataPacket& packet); 134 135 virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty property, 136 MtpDataPacket& packet); 137 138 virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty property); 139 140 virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle handle, 141 uint32_t format, uint32_t property, 142 int groupCode, int depth, 143 MtpDataPacket& packet); 144 145 virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle, 146 MtpObjectInfo& info); 147 148 virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize); 149 150 virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle, 151 MtpString& outFilePath, 152 int64_t& outFileLength, 153 MtpObjectFormat& outFormat); 154 virtual MtpResponseCode deleteFile(MtpObjectHandle handle); 155 156 bool getObjectPropertyInfo(MtpObjectProperty property, int& type); 157 bool getDevicePropertyInfo(MtpDeviceProperty property, int& type); 158 159 virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle); 160 161 virtual MtpResponseCode setObjectReferences(MtpObjectHandle handle, 162 MtpObjectHandleList* references); 163 164 virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty property, 165 MtpObjectFormat format); 166 167 virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property); 168 169 virtual void sessionStarted(); 170 171 virtual void sessionEnded(); 172}; 173 174// ---------------------------------------------------------------------------- 175 176static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { 177 if (env->ExceptionCheck()) { 178 LOGE("An exception was thrown by callback '%s'.", methodName); 179 LOGE_EX(env); 180 env->ExceptionClear(); 181 } 182} 183 184// ---------------------------------------------------------------------------- 185 186MyMtpDatabase::MyMtpDatabase(JNIEnv *env, jobject client) 187 : mDatabase(env->NewGlobalRef(client)), 188 mIntBuffer(NULL), 189 mLongBuffer(NULL), 190 mStringBuffer(NULL) 191{ 192 jintArray intArray; 193 jlongArray longArray; 194 jcharArray charArray; 195 196 // create buffers for out arguments 197 // we don't need to be thread-safe so this is OK 198 intArray = env->NewIntArray(3); 199 if (!intArray) 200 goto out_of_memory; 201 mIntBuffer = (jintArray)env->NewGlobalRef(intArray); 202 longArray = env->NewLongArray(2); 203 if (!longArray) 204 goto out_of_memory; 205 mLongBuffer = (jlongArray)env->NewGlobalRef(longArray); 206 charArray = env->NewCharArray(256); 207 if (!charArray) 208 goto out_of_memory; 209 mStringBuffer = (jcharArray)env->NewGlobalRef(charArray); 210 return; 211 212out_of_memory: 213 env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), NULL); 214} 215 216void MyMtpDatabase::cleanup(JNIEnv *env) { 217 env->DeleteGlobalRef(mDatabase); 218 env->DeleteGlobalRef(mIntBuffer); 219 env->DeleteGlobalRef(mLongBuffer); 220 env->DeleteGlobalRef(mStringBuffer); 221} 222 223MyMtpDatabase::~MyMtpDatabase() { 224} 225 226MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path, 227 MtpObjectFormat format, 228 MtpObjectHandle parent, 229 MtpStorageID storage, 230 uint64_t size, 231 time_t modified) { 232 JNIEnv* env = AndroidRuntime::getJNIEnv(); 233 jstring pathStr = env->NewStringUTF(path); 234 MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject, 235 pathStr, (jint)format, (jint)parent, (jint)storage, 236 (jlong)size, (jlong)modified); 237 238 if (pathStr) 239 env->DeleteLocalRef(pathStr); 240 checkAndClearExceptionFromCallback(env, __FUNCTION__); 241 return result; 242} 243 244void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle, 245 MtpObjectFormat format, bool succeeded) { 246 JNIEnv* env = AndroidRuntime::getJNIEnv(); 247 jstring pathStr = env->NewStringUTF(path); 248 env->CallVoidMethod(mDatabase, method_endSendObject, pathStr, 249 (jint)handle, (jint)format, (jboolean)succeeded); 250 251 if (pathStr) 252 env->DeleteLocalRef(pathStr); 253 checkAndClearExceptionFromCallback(env, __FUNCTION__); 254} 255 256MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID, 257 MtpObjectFormat format, 258 MtpObjectHandle parent) { 259 JNIEnv* env = AndroidRuntime::getJNIEnv(); 260 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList, 261 (jint)storageID, (jint)format, (jint)parent); 262 if (!array) 263 return NULL; 264 MtpObjectHandleList* list = new MtpObjectHandleList(); 265 jint* handles = env->GetIntArrayElements(array, 0); 266 jsize length = env->GetArrayLength(array); 267 for (int i = 0; i < length; i++) 268 list->push(handles[i]); 269 env->ReleaseIntArrayElements(array, handles, 0); 270 env->DeleteLocalRef(array); 271 272 checkAndClearExceptionFromCallback(env, __FUNCTION__); 273 return list; 274} 275 276int MyMtpDatabase::getNumObjects(MtpStorageID storageID, 277 MtpObjectFormat format, 278 MtpObjectHandle parent) { 279 JNIEnv* env = AndroidRuntime::getJNIEnv(); 280 int result = env->CallIntMethod(mDatabase, method_getNumObjects, 281 (jint)storageID, (jint)format, (jint)parent); 282 283 checkAndClearExceptionFromCallback(env, __FUNCTION__); 284 return result; 285} 286 287MtpObjectFormatList* MyMtpDatabase::getSupportedPlaybackFormats() { 288 JNIEnv* env = AndroidRuntime::getJNIEnv(); 289 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, 290 method_getSupportedPlaybackFormats); 291 if (!array) 292 return NULL; 293 MtpObjectFormatList* list = new MtpObjectFormatList(); 294 jint* formats = env->GetIntArrayElements(array, 0); 295 jsize length = env->GetArrayLength(array); 296 for (int i = 0; i < length; i++) 297 list->push(formats[i]); 298 env->ReleaseIntArrayElements(array, formats, 0); 299 env->DeleteLocalRef(array); 300 301 checkAndClearExceptionFromCallback(env, __FUNCTION__); 302 return list; 303} 304 305MtpObjectFormatList* MyMtpDatabase::getSupportedCaptureFormats() { 306 JNIEnv* env = AndroidRuntime::getJNIEnv(); 307 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, 308 method_getSupportedCaptureFormats); 309 if (!array) 310 return NULL; 311 MtpObjectFormatList* list = new MtpObjectFormatList(); 312 jint* formats = env->GetIntArrayElements(array, 0); 313 jsize length = env->GetArrayLength(array); 314 for (int i = 0; i < length; i++) 315 list->push(formats[i]); 316 env->ReleaseIntArrayElements(array, formats, 0); 317 env->DeleteLocalRef(array); 318 319 checkAndClearExceptionFromCallback(env, __FUNCTION__); 320 return list; 321} 322 323MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) { 324 JNIEnv* env = AndroidRuntime::getJNIEnv(); 325 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, 326 method_getSupportedObjectProperties, (jint)format); 327 if (!array) 328 return NULL; 329 MtpObjectPropertyList* list = new MtpObjectPropertyList(); 330 jint* properties = env->GetIntArrayElements(array, 0); 331 jsize length = env->GetArrayLength(array); 332 for (int i = 0; i < length; i++) 333 list->push(properties[i]); 334 env->ReleaseIntArrayElements(array, properties, 0); 335 env->DeleteLocalRef(array); 336 337 checkAndClearExceptionFromCallback(env, __FUNCTION__); 338 return list; 339} 340 341MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() { 342 JNIEnv* env = AndroidRuntime::getJNIEnv(); 343 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, 344 method_getSupportedDeviceProperties); 345 if (!array) 346 return NULL; 347 MtpDevicePropertyList* list = new MtpDevicePropertyList(); 348 jint* properties = env->GetIntArrayElements(array, 0); 349 jsize length = env->GetArrayLength(array); 350 for (int i = 0; i < length; i++) 351 list->push(properties[i]); 352 env->ReleaseIntArrayElements(array, properties, 0); 353 env->DeleteLocalRef(array); 354 355 checkAndClearExceptionFromCallback(env, __FUNCTION__); 356 return list; 357} 358 359MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle, 360 MtpObjectProperty property, 361 MtpDataPacket& packet) { 362 JNIEnv* env = AndroidRuntime::getJNIEnv(); 363 jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList, 364 (jlong)handle, 0, (jlong)property, 0, 0); 365 MtpResponseCode result = env->GetIntField(list, field_mResult); 366 int count = env->GetIntField(list, field_mCount); 367 if (result == MTP_RESPONSE_OK && count != 1) 368 result = MTP_RESPONSE_GENERAL_ERROR; 369 370 if (result == MTP_RESPONSE_OK) { 371 jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles); 372 jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes); 373 jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes); 374 jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues); 375 jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues); 376 377 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0); 378 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0); 379 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0); 380 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL); 381 382 int type = dataTypes[0]; 383 jlong longValue = (longValues ? longValues[0] : 0); 384 385 // special case date properties, which are strings to MTP 386 // but stored internally as a uint64 387 if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) { 388 char date[20]; 389 formatDateTime(longValue, date, sizeof(date)); 390 packet.putString(date); 391 goto out; 392 } 393 // release date is stored internally as just the year 394 if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) { 395 char date[20]; 396 snprintf(date, sizeof(date), "%04lld0101T000000", longValue); 397 packet.putString(date); 398 goto out; 399 } 400 401 switch (type) { 402 case MTP_TYPE_INT8: 403 packet.putInt8(longValue); 404 break; 405 case MTP_TYPE_UINT8: 406 packet.putUInt8(longValue); 407 break; 408 case MTP_TYPE_INT16: 409 packet.putInt16(longValue); 410 break; 411 case MTP_TYPE_UINT16: 412 packet.putUInt16(longValue); 413 break; 414 case MTP_TYPE_INT32: 415 packet.putInt32(longValue); 416 break; 417 case MTP_TYPE_UINT32: 418 packet.putUInt32(longValue); 419 break; 420 case MTP_TYPE_INT64: 421 packet.putInt64(longValue); 422 break; 423 case MTP_TYPE_UINT64: 424 packet.putUInt64(longValue); 425 break; 426 case MTP_TYPE_INT128: 427 packet.putInt128(longValue); 428 break; 429 case MTP_TYPE_UINT128: 430 packet.putInt128(longValue); 431 break; 432 case MTP_TYPE_STR: 433 { 434 jstring stringValue = (jstring)env->GetObjectArrayElement(stringValuesArray, 0); 435 if (stringValue) { 436 const char* str = env->GetStringUTFChars(stringValue, NULL); 437 packet.putString(str); 438 env->ReleaseStringUTFChars(stringValue, str); 439 } else { 440 packet.putEmptyString(); 441 } 442 break; 443 } 444 default: 445 LOGE("unsupported type in getObjectPropertyValue\n"); 446 result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT; 447 } 448out: 449 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0); 450 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0); 451 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0); 452 if (longValues) 453 env->ReleaseLongArrayElements(longValuesArray, longValues, 0); 454 455 env->DeleteLocalRef(objectHandlesArray); 456 env->DeleteLocalRef(propertyCodesArray); 457 env->DeleteLocalRef(dataTypesArray); 458 if (longValuesArray) 459 env->DeleteLocalRef(longValuesArray); 460 if (stringValuesArray) 461 env->DeleteLocalRef(stringValuesArray); 462 } 463 464 env->DeleteLocalRef(list); 465 checkAndClearExceptionFromCallback(env, __FUNCTION__); 466 return result; 467} 468 469MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle, 470 MtpObjectProperty property, 471 MtpDataPacket& packet) { 472 int type; 473 474 if (!getObjectPropertyInfo(property, type)) 475 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED; 476 477 JNIEnv* env = AndroidRuntime::getJNIEnv(); 478 jlong longValue = 0; 479 jstring stringValue = NULL; 480 481 switch (type) { 482 case MTP_TYPE_INT8: 483 longValue = packet.getInt8(); 484 break; 485 case MTP_TYPE_UINT8: 486 longValue = packet.getUInt8(); 487 break; 488 case MTP_TYPE_INT16: 489 longValue = packet.getInt16(); 490 break; 491 case MTP_TYPE_UINT16: 492 longValue = packet.getUInt16(); 493 break; 494 case MTP_TYPE_INT32: 495 longValue = packet.getInt32(); 496 break; 497 case MTP_TYPE_UINT32: 498 longValue = packet.getUInt32(); 499 break; 500 case MTP_TYPE_INT64: 501 longValue = packet.getInt64(); 502 break; 503 case MTP_TYPE_UINT64: 504 longValue = packet.getUInt64(); 505 break; 506 case MTP_TYPE_STR: 507 { 508 MtpStringBuffer buffer; 509 packet.getString(buffer); 510 stringValue = env->NewStringUTF((const char *)buffer); 511 break; 512 } 513 default: 514 LOGE("unsupported type in getObjectPropertyValue\n"); 515 return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT; 516 } 517 518 jint result = env->CallIntMethod(mDatabase, method_setObjectProperty, 519 (jint)handle, (jint)property, longValue, stringValue); 520 if (stringValue) 521 env->DeleteLocalRef(stringValue); 522 523 checkAndClearExceptionFromCallback(env, __FUNCTION__); 524 return result; 525} 526 527MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property, 528 MtpDataPacket& packet) { 529 int type; 530 531 if (!getDevicePropertyInfo(property, type)) 532 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED; 533 534 JNIEnv* env = AndroidRuntime::getJNIEnv(); 535 jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty, 536 (jint)property, mLongBuffer, mStringBuffer); 537 if (result != MTP_RESPONSE_OK) { 538 checkAndClearExceptionFromCallback(env, __FUNCTION__); 539 return result; 540 } 541 542 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0); 543 jlong longValue = longValues[0]; 544 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0); 545 546 switch (type) { 547 case MTP_TYPE_INT8: 548 packet.putInt8(longValue); 549 break; 550 case MTP_TYPE_UINT8: 551 packet.putUInt8(longValue); 552 break; 553 case MTP_TYPE_INT16: 554 packet.putInt16(longValue); 555 break; 556 case MTP_TYPE_UINT16: 557 packet.putUInt16(longValue); 558 break; 559 case MTP_TYPE_INT32: 560 packet.putInt32(longValue); 561 break; 562 case MTP_TYPE_UINT32: 563 packet.putUInt32(longValue); 564 break; 565 case MTP_TYPE_INT64: 566 packet.putInt64(longValue); 567 break; 568 case MTP_TYPE_UINT64: 569 packet.putUInt64(longValue); 570 break; 571 case MTP_TYPE_INT128: 572 packet.putInt128(longValue); 573 break; 574 case MTP_TYPE_UINT128: 575 packet.putInt128(longValue); 576 break; 577 case MTP_TYPE_STR: 578 { 579 jchar* str = env->GetCharArrayElements(mStringBuffer, 0); 580 packet.putString(str); 581 env->ReleaseCharArrayElements(mStringBuffer, str, 0); 582 break; 583 } 584 default: 585 LOGE("unsupported type in getDevicePropertyValue\n"); 586 return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT; 587 } 588 589 checkAndClearExceptionFromCallback(env, __FUNCTION__); 590 return MTP_RESPONSE_OK; 591} 592 593MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property, 594 MtpDataPacket& packet) { 595 int type; 596 597 if (!getDevicePropertyInfo(property, type)) 598 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED; 599 600 JNIEnv* env = AndroidRuntime::getJNIEnv(); 601 jlong longValue = 0; 602 jstring stringValue = NULL; 603 604 switch (type) { 605 case MTP_TYPE_INT8: 606 longValue = packet.getInt8(); 607 break; 608 case MTP_TYPE_UINT8: 609 longValue = packet.getUInt8(); 610 break; 611 case MTP_TYPE_INT16: 612 longValue = packet.getInt16(); 613 break; 614 case MTP_TYPE_UINT16: 615 longValue = packet.getUInt16(); 616 break; 617 case MTP_TYPE_INT32: 618 longValue = packet.getInt32(); 619 break; 620 case MTP_TYPE_UINT32: 621 longValue = packet.getUInt32(); 622 break; 623 case MTP_TYPE_INT64: 624 longValue = packet.getInt64(); 625 break; 626 case MTP_TYPE_UINT64: 627 longValue = packet.getUInt64(); 628 break; 629 case MTP_TYPE_STR: 630 { 631 MtpStringBuffer buffer; 632 packet.getString(buffer); 633 stringValue = env->NewStringUTF((const char *)buffer); 634 break; 635 } 636 default: 637 LOGE("unsupported type in setDevicePropertyValue\n"); 638 return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT; 639 } 640 641 jint result = env->CallIntMethod(mDatabase, method_setDeviceProperty, 642 (jint)property, longValue, stringValue); 643 if (stringValue) 644 env->DeleteLocalRef(stringValue); 645 646 checkAndClearExceptionFromCallback(env, __FUNCTION__); 647 return result; 648} 649 650MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty property) { 651 return -1; 652} 653 654MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle, 655 uint32_t format, uint32_t property, 656 int groupCode, int depth, 657 MtpDataPacket& packet) { 658 JNIEnv* env = AndroidRuntime::getJNIEnv(); 659 jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList, 660 (jlong)handle, (jint)format, (jlong)property, (jint)groupCode, (jint)depth); 661 checkAndClearExceptionFromCallback(env, __FUNCTION__); 662 if (!list) 663 return MTP_RESPONSE_GENERAL_ERROR; 664 int count = env->GetIntField(list, field_mCount); 665 MtpResponseCode result = env->GetIntField(list, field_mResult); 666 667 packet.putUInt32(count); 668 if (count > 0) { 669 jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles); 670 jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes); 671 jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes); 672 jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues); 673 jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues); 674 675 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0); 676 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0); 677 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0); 678 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL); 679 680 for (int i = 0; i < count; i++) { 681 packet.putUInt32(objectHandles[i]); 682 packet.putUInt16(propertyCodes[i]); 683 int type = dataTypes[i]; 684 packet.putUInt16(type); 685 686 switch (type) { 687 case MTP_TYPE_INT8: 688 packet.putInt8(longValues[i]); 689 break; 690 case MTP_TYPE_UINT8: 691 packet.putUInt8(longValues[i]); 692 break; 693 case MTP_TYPE_INT16: 694 packet.putInt16(longValues[i]); 695 break; 696 case MTP_TYPE_UINT16: 697 packet.putUInt16(longValues[i]); 698 break; 699 case MTP_TYPE_INT32: 700 packet.putInt32(longValues[i]); 701 break; 702 case MTP_TYPE_UINT32: 703 packet.putUInt32(longValues[i]); 704 break; 705 case MTP_TYPE_INT64: 706 packet.putInt64(longValues[i]); 707 break; 708 case MTP_TYPE_UINT64: 709 packet.putUInt64(longValues[i]); 710 break; 711 case MTP_TYPE_INT128: 712 packet.putInt128(longValues[i]); 713 break; 714 case MTP_TYPE_UINT128: 715 packet.putUInt128(longValues[i]); 716 break; 717 case MTP_TYPE_STR: { 718 jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i); 719 const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL); 720 if (valueStr) { 721 packet.putString(valueStr); 722 env->ReleaseStringUTFChars(value, valueStr); 723 } else { 724 packet.putEmptyString(); 725 } 726 env->DeleteLocalRef(value); 727 break; 728 } 729 default: 730 LOGE("bad or unsupported data type in MyMtpDatabase::getObjectPropertyList"); 731 break; 732 } 733 } 734 735 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0); 736 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0); 737 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0); 738 if (longValues) 739 env->ReleaseLongArrayElements(longValuesArray, longValues, 0); 740 741 env->DeleteLocalRef(objectHandlesArray); 742 env->DeleteLocalRef(propertyCodesArray); 743 env->DeleteLocalRef(dataTypesArray); 744 if (longValuesArray) 745 env->DeleteLocalRef(longValuesArray); 746 if (stringValuesArray) 747 env->DeleteLocalRef(stringValuesArray); 748 } 749 750 env->DeleteLocalRef(list); 751 checkAndClearExceptionFromCallback(env, __FUNCTION__); 752 return result; 753} 754 755MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle, 756 MtpObjectInfo& info) { 757 char date[20]; 758 759 JNIEnv* env = AndroidRuntime::getJNIEnv(); 760 jboolean result = env->CallBooleanMethod(mDatabase, method_getObjectInfo, 761 (jint)handle, mIntBuffer, mStringBuffer, mLongBuffer); 762 if (!result) 763 return MTP_RESPONSE_INVALID_OBJECT_HANDLE; 764 765 jint* intValues = env->GetIntArrayElements(mIntBuffer, 0); 766 info.mStorageID = intValues[0]; 767 info.mFormat = intValues[1]; 768 info.mParent = intValues[2]; 769 env->ReleaseIntArrayElements(mIntBuffer, intValues, 0); 770 771 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0); 772 uint64_t size = longValues[0]; 773 info.mCompressedSize = (size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size); 774 info.mDateModified = longValues[1]; 775 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0); 776 777// info.mAssociationType = (format == MTP_FORMAT_ASSOCIATION ? 778// MTP_ASSOCIATION_TYPE_GENERIC_FOLDER : 779// MTP_ASSOCIATION_TYPE_UNDEFINED); 780 info.mAssociationType = MTP_ASSOCIATION_TYPE_UNDEFINED; 781 782 jchar* str = env->GetCharArrayElements(mStringBuffer, 0); 783 MtpString temp(str); 784 info.mName = strdup((const char *)temp); 785 env->ReleaseCharArrayElements(mStringBuffer, str, 0); 786 787 // read EXIF data for thumbnail information 788 if (info.mFormat == MTP_FORMAT_EXIF_JPEG || info.mFormat == MTP_FORMAT_JFIF) { 789 MtpString path; 790 int64_t length; 791 MtpObjectFormat format; 792 if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK) { 793 ResetJpgfile(); 794 // Start with an empty image information structure. 795 memset(&ImageInfo, 0, sizeof(ImageInfo)); 796 ImageInfo.FlashUsed = -1; 797 ImageInfo.MeteringMode = -1; 798 ImageInfo.Whitebalance = -1; 799 strncpy(ImageInfo.FileName, (const char *)path, PATH_MAX); 800 if (ReadJpegFile((const char*)path, READ_METADATA)) { 801 Section_t* section = FindSection(M_EXIF); 802 if (section) { 803 info.mThumbCompressedSize = ImageInfo.ThumbnailSize; 804 info.mThumbFormat = MTP_FORMAT_EXIF_JPEG; 805 info.mImagePixWidth = ImageInfo.Width; 806 info.mImagePixHeight = ImageInfo.Height; 807 } 808 } 809 DiscardData(); 810 } 811 } 812 813 checkAndClearExceptionFromCallback(env, __FUNCTION__); 814 return MTP_RESPONSE_OK; 815} 816 817void* 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 848MtpResponseCode 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 873MtpResponseCode 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 881struct PropertyTableEntry { 882 MtpObjectProperty property; 883 int type; 884}; 885 886static 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 909static 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 915bool 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 927bool 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 939MtpObjectHandleList* 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 957MtpResponseCode 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 LOGE("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 978MtpProperty* 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 1026MtpProperty* 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 LOGE("unable to read device property, response: %04X", ret); 1051 } 1052 break; 1053 } 1054 1055 checkAndClearExceptionFromCallback(env, __FUNCTION__); 1056 return result; 1057} 1058 1059void MyMtpDatabase::sessionStarted() { 1060 JNIEnv* env = AndroidRuntime::getJNIEnv(); 1061 env->CallVoidMethod(mDatabase, method_sessionStarted); 1062 checkAndClearExceptionFromCallback(env, __FUNCTION__); 1063} 1064 1065void MyMtpDatabase::sessionEnded() { 1066 JNIEnv* env = AndroidRuntime::getJNIEnv(); 1067 env->CallVoidMethod(mDatabase, method_sessionEnded); 1068 checkAndClearExceptionFromCallback(env, __FUNCTION__); 1069} 1070 1071#endif // HAVE_ANDROID_OS 1072 1073// ---------------------------------------------------------------------------- 1074 1075static void 1076android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz) 1077{ 1078#ifdef HAVE_ANDROID_OS 1079 MyMtpDatabase* database = new MyMtpDatabase(env, thiz); 1080 env->SetIntField(thiz, field_context, (int)database); 1081 checkAndClearExceptionFromCallback(env, __FUNCTION__); 1082#endif 1083} 1084 1085static void 1086android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz) 1087{ 1088#ifdef HAVE_ANDROID_OS 1089 MyMtpDatabase* database = (MyMtpDatabase *)env->GetIntField(thiz, field_context); 1090 database->cleanup(env); 1091 delete database; 1092 env->SetIntField(thiz, field_context, 0); 1093 checkAndClearExceptionFromCallback(env, __FUNCTION__); 1094#endif 1095} 1096 1097static jstring 1098android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject thiz, jlong seconds) 1099{ 1100#ifdef HAVE_ANDROID_OS 1101 char date[20]; 1102 formatDateTime(seconds, date, sizeof(date)); 1103 return env->NewStringUTF(date); 1104#else 1105 return NULL; 1106#endif 1107} 1108 1109// ---------------------------------------------------------------------------- 1110 1111static JNINativeMethod gMtpDatabaseMethods[] = { 1112 {"native_setup", "()V", (void *)android_mtp_MtpDatabase_setup}, 1113 {"native_finalize", "()V", (void *)android_mtp_MtpDatabase_finalize}, 1114}; 1115 1116static JNINativeMethod gMtpPropertyGroupMethods[] = { 1117 {"format_date_time", "(J)Ljava/lang/String;", 1118 (void *)android_mtp_MtpPropertyGroup_format_date_time}, 1119}; 1120 1121static const char* const kClassPathName = "android/mtp/MtpDatabase"; 1122 1123int register_android_mtp_MtpDatabase(JNIEnv *env) 1124{ 1125 jclass clazz; 1126 1127 clazz = env->FindClass("android/mtp/MtpDatabase"); 1128 if (clazz == NULL) { 1129 LOGE("Can't find android/mtp/MtpDatabase"); 1130 return -1; 1131 } 1132 method_beginSendObject = env->GetMethodID(clazz, "beginSendObject", "(Ljava/lang/String;IIIJJ)I"); 1133 if (method_beginSendObject == NULL) { 1134 LOGE("Can't find beginSendObject"); 1135 return -1; 1136 } 1137 method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIZ)V"); 1138 if (method_endSendObject == NULL) { 1139 LOGE("Can't find endSendObject"); 1140 return -1; 1141 } 1142 method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I"); 1143 if (method_getObjectList == NULL) { 1144 LOGE("Can't find getObjectList"); 1145 return -1; 1146 } 1147 method_getNumObjects = env->GetMethodID(clazz, "getNumObjects", "(III)I"); 1148 if (method_getNumObjects == NULL) { 1149 LOGE("Can't find getNumObjects"); 1150 return -1; 1151 } 1152 method_getSupportedPlaybackFormats = env->GetMethodID(clazz, "getSupportedPlaybackFormats", "()[I"); 1153 if (method_getSupportedPlaybackFormats == NULL) { 1154 LOGE("Can't find getSupportedPlaybackFormats"); 1155 return -1; 1156 } 1157 method_getSupportedCaptureFormats = env->GetMethodID(clazz, "getSupportedCaptureFormats", "()[I"); 1158 if (method_getSupportedCaptureFormats == NULL) { 1159 LOGE("Can't find getSupportedCaptureFormats"); 1160 return -1; 1161 } 1162 method_getSupportedObjectProperties = env->GetMethodID(clazz, "getSupportedObjectProperties", "(I)[I"); 1163 if (method_getSupportedObjectProperties == NULL) { 1164 LOGE("Can't find getSupportedObjectProperties"); 1165 return -1; 1166 } 1167 method_getSupportedDeviceProperties = env->GetMethodID(clazz, "getSupportedDeviceProperties", "()[I"); 1168 if (method_getSupportedDeviceProperties == NULL) { 1169 LOGE("Can't find getSupportedDeviceProperties"); 1170 return -1; 1171 } 1172 method_setObjectProperty = env->GetMethodID(clazz, "setObjectProperty", "(IIJLjava/lang/String;)I"); 1173 if (method_setObjectProperty == NULL) { 1174 LOGE("Can't find setObjectProperty"); 1175 return -1; 1176 } 1177 method_getDeviceProperty = env->GetMethodID(clazz, "getDeviceProperty", "(I[J[C)I"); 1178 if (method_getDeviceProperty == NULL) { 1179 LOGE("Can't find getDeviceProperty"); 1180 return -1; 1181 } 1182 method_setDeviceProperty = env->GetMethodID(clazz, "setDeviceProperty", "(IJLjava/lang/String;)I"); 1183 if (method_setDeviceProperty == NULL) { 1184 LOGE("Can't find setDeviceProperty"); 1185 return -1; 1186 } 1187 method_getObjectPropertyList = env->GetMethodID(clazz, "getObjectPropertyList", 1188 "(JIJII)Landroid/mtp/MtpPropertyList;"); 1189 if (method_getObjectPropertyList == NULL) { 1190 LOGE("Can't find getObjectPropertyList"); 1191 return -1; 1192 } 1193 method_getObjectInfo = env->GetMethodID(clazz, "getObjectInfo", "(I[I[C[J)Z"); 1194 if (method_getObjectInfo == NULL) { 1195 LOGE("Can't find getObjectInfo"); 1196 return -1; 1197 } 1198 method_getObjectFilePath = env->GetMethodID(clazz, "getObjectFilePath", "(I[C[J)I"); 1199 if (method_getObjectFilePath == NULL) { 1200 LOGE("Can't find getObjectFilePath"); 1201 return -1; 1202 } 1203 method_deleteFile = env->GetMethodID(clazz, "deleteFile", "(I)I"); 1204 if (method_deleteFile == NULL) { 1205 LOGE("Can't find deleteFile"); 1206 return -1; 1207 } 1208 method_getObjectReferences = env->GetMethodID(clazz, "getObjectReferences", "(I)[I"); 1209 if (method_getObjectReferences == NULL) { 1210 LOGE("Can't find getObjectReferences"); 1211 return -1; 1212 } 1213 method_setObjectReferences = env->GetMethodID(clazz, "setObjectReferences", "(I[I)I"); 1214 if (method_setObjectReferences == NULL) { 1215 LOGE("Can't find setObjectReferences"); 1216 return -1; 1217 } 1218 method_sessionStarted = env->GetMethodID(clazz, "sessionStarted", "()V"); 1219 if (method_sessionStarted == NULL) { 1220 LOGE("Can't find sessionStarted"); 1221 return -1; 1222 } 1223 method_sessionEnded = env->GetMethodID(clazz, "sessionEnded", "()V"); 1224 if (method_sessionEnded == NULL) { 1225 LOGE("Can't find sessionEnded"); 1226 return -1; 1227 } 1228 1229 field_context = env->GetFieldID(clazz, "mNativeContext", "I"); 1230 if (field_context == NULL) { 1231 LOGE("Can't find MtpDatabase.mNativeContext"); 1232 return -1; 1233 } 1234 1235 // now set up fields for MtpPropertyList class 1236 clazz = env->FindClass("android/mtp/MtpPropertyList"); 1237 if (clazz == NULL) { 1238 LOGE("Can't find android/mtp/MtpPropertyList"); 1239 return -1; 1240 } 1241 field_mCount = env->GetFieldID(clazz, "mCount", "I"); 1242 if (field_mCount == NULL) { 1243 LOGE("Can't find MtpPropertyList.mCount"); 1244 return -1; 1245 } 1246 field_mResult = env->GetFieldID(clazz, "mResult", "I"); 1247 if (field_mResult == NULL) { 1248 LOGE("Can't find MtpPropertyList.mResult"); 1249 return -1; 1250 } 1251 field_mObjectHandles = env->GetFieldID(clazz, "mObjectHandles", "[I"); 1252 if (field_mObjectHandles == NULL) { 1253 LOGE("Can't find MtpPropertyList.mObjectHandles"); 1254 return -1; 1255 } 1256 field_mPropertyCodes = env->GetFieldID(clazz, "mPropertyCodes", "[I"); 1257 if (field_mPropertyCodes == NULL) { 1258 LOGE("Can't find MtpPropertyList.mPropertyCodes"); 1259 return -1; 1260 } 1261 field_mDataTypes = env->GetFieldID(clazz, "mDataTypes", "[I"); 1262 if (field_mDataTypes == NULL) { 1263 LOGE("Can't find MtpPropertyList.mDataTypes"); 1264 return -1; 1265 } 1266 field_mLongValues = env->GetFieldID(clazz, "mLongValues", "[J"); 1267 if (field_mLongValues == NULL) { 1268 LOGE("Can't find MtpPropertyList.mLongValues"); 1269 return -1; 1270 } 1271 field_mStringValues = env->GetFieldID(clazz, "mStringValues", "[Ljava/lang/String;"); 1272 if (field_mStringValues == NULL) { 1273 LOGE("Can't find MtpPropertyList.mStringValues"); 1274 return -1; 1275 } 1276 1277 if (AndroidRuntime::registerNativeMethods(env, 1278 "android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods))) 1279 return -1; 1280 1281 return AndroidRuntime::registerNativeMethods(env, 1282 "android/mtp/MtpPropertyGroup", gMtpPropertyGroupMethods, NELEM(gMtpPropertyGroupMethods)); 1283} 1284