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