android_mtp_MtpDatabase.cpp 55 KB

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