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