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