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