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