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