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