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