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