blob: 12d7440e3762f05ca5badcad8a85cd6d6074d54c [file] [log] [blame]
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001/*
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
Jaesung Chung8409c062016-01-19 10:48:30 +090020#include "android_media_Utils.h"
21#include "mtp.h"
Jerry Zhangf9c5c252017-08-16 18:07:51 -070022#include "IMtpDatabase.h"
Mike Lockwoodd21eac92010-07-03 00:44:05 -040023#include "MtpDataPacket.h"
Mike Lockwood9df53fae2011-04-21 17:05:55 -070024#include "MtpObjectInfo.h"
Mike Lockwood828d19d2010-08-10 15:20:35 -040025#include "MtpProperty.h"
Mike Lockwood59e3f0d2010-09-02 14:57:30 -040026#include "MtpStringBuffer.h"
Mike Lockwoodd21eac92010-07-03 00:44:05 -040027#include "MtpUtils.h"
Jaesung Chung8409c062016-01-19 10:48:30 +090028
29#include "src/piex_types.h"
30#include "src/piex.h"
Mike Lockwoodd21eac92010-07-03 00:44:05 -040031
Mike Lockwoodc89f2222011-04-24 18:40:17 -070032extern "C" {
Marco Nelissen3cd393c2014-01-10 10:39:27 -080033#include "libexif/exif-content.h"
34#include "libexif/exif-data.h"
35#include "libexif/exif-tag.h"
36#include "libexif/exif-utils.h"
Mike Lockwoodc89f2222011-04-24 18:40:17 -070037}
38
Jaesung Chung8409c062016-01-19 10:48:30 +090039#include <android_runtime/AndroidRuntime.h>
40#include <android_runtime/Log.h>
41#include <jni.h>
Chong Zhang63f81922018-03-14 18:57:05 -070042#include <media/stagefright/NuMediaExtractor.h>
Steven Moreland2279b252017-07-19 09:50:45 -070043#include <nativehelper/JNIHelp.h>
Jaesung Chung8409c062016-01-19 10:48:30 +090044#include <nativehelper/ScopedLocalRef.h>
45
46#include <assert.h>
47#include <fcntl.h>
48#include <inttypes.h>
49#include <limits.h>
50#include <stdio.h>
51#include <unistd.h>
52
Mike Lockwoodd21eac92010-07-03 00:44:05 -040053using namespace android;
54
55// ----------------------------------------------------------------------------
56
Mike Lockwoodd815f792010-07-12 08:49:01 -040057static jmethodID method_beginSendObject;
58static jmethodID method_endSendObject;
Jerry Zhangf9c5c252017-08-16 18:07:51 -070059static jmethodID method_rescanFile;
Mike Lockwoodd21eac92010-07-03 00:44:05 -040060static jmethodID method_getObjectList;
Mike Lockwood7a047c82010-08-02 10:52:20 -040061static jmethodID method_getNumObjects;
Mike Lockwood4b322ce2010-08-10 07:37:50 -040062static jmethodID method_getSupportedPlaybackFormats;
63static jmethodID method_getSupportedCaptureFormats;
64static jmethodID method_getSupportedObjectProperties;
65static jmethodID method_getSupportedDeviceProperties;
Mike Lockwood828d19d2010-08-10 15:20:35 -040066static jmethodID method_setObjectProperty;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -040067static jmethodID method_getDeviceProperty;
68static jmethodID method_setDeviceProperty;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -040069static jmethodID method_getObjectPropertyList;
Mike Lockwoodd21eac92010-07-03 00:44:05 -040070static jmethodID method_getObjectInfo;
71static jmethodID method_getObjectFilePath;
Jerry Zhangf9c5c252017-08-16 18:07:51 -070072static jmethodID method_beginDeleteObject;
73static jmethodID method_endDeleteObject;
74static jmethodID method_beginMoveObject;
75static jmethodID method_endMoveObject;
76static jmethodID method_beginCopyObject;
77static jmethodID method_endCopyObject;
Mike Lockwood9a2046f2010-08-03 15:30:09 -040078static jmethodID method_getObjectReferences;
79static jmethodID method_setObjectReferences;
Mike Lockwood2837eef2010-08-31 16:25:12 -040080
Mike Lockwoodd21eac92010-07-03 00:44:05 -040081static jfieldID field_context;
82
Jerry Zhangf9c5c252017-08-16 18:07:51 -070083// MtpPropertyList methods
84static jmethodID method_getCode;
85static jmethodID method_getCount;
86static jmethodID method_getObjectHandles;
87static jmethodID method_getPropertyCodes;
88static jmethodID method_getDataTypes;
89static jmethodID method_getLongValues;
90static jmethodID method_getStringValues;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -040091
92
Jerry Zhangf9c5c252017-08-16 18:07:51 -070093IMtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
94 return (IMtpDatabase *)env->GetLongField(database, field_context);
Mike Lockwoodd21eac92010-07-03 00:44:05 -040095}
96
97// ----------------------------------------------------------------------------
98
Jerry Zhangf9c5c252017-08-16 18:07:51 -070099class MtpDatabase : public IMtpDatabase {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400100private:
101 jobject mDatabase;
102 jintArray mIntBuffer;
103 jlongArray mLongBuffer;
104 jcharArray mStringBuffer;
105
106public:
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700107 MtpDatabase(JNIEnv *env, jobject client);
108 virtual ~MtpDatabase();
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400109 void cleanup(JNIEnv *env);
110
Mike Lockwoodd815f792010-07-12 08:49:01 -0400111 virtual MtpObjectHandle beginSendObject(const char* path,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400112 MtpObjectFormat format,
113 MtpObjectHandle parent,
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700114 MtpStorageID storage);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400115
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700116 virtual void endSendObject(MtpObjectHandle handle, bool succeeded);
117
118 virtual void rescanFile(const char* path,
Mike Lockwoodd815f792010-07-12 08:49:01 -0400119 MtpObjectHandle handle,
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700120 MtpObjectFormat format);
kyle_tsob4aa69f2017-11-22 20:11:27 +0800121
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400122 virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
123 MtpObjectFormat format,
124 MtpObjectHandle parent);
125
Mike Lockwood7a047c82010-08-02 10:52:20 -0400126 virtual int getNumObjects(MtpStorageID storageID,
127 MtpObjectFormat format,
128 MtpObjectHandle parent);
129
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400130 // callee should delete[] the results from these
131 // results can be NULL
132 virtual MtpObjectFormatList* getSupportedPlaybackFormats();
133 virtual MtpObjectFormatList* getSupportedCaptureFormats();
134 virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format);
135 virtual MtpDevicePropertyList* getSupportedDeviceProperties();
136
Mike Lockwood828d19d2010-08-10 15:20:35 -0400137 virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400138 MtpObjectProperty property,
139 MtpDataPacket& packet);
140
Mike Lockwood828d19d2010-08-10 15:20:35 -0400141 virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle handle,
142 MtpObjectProperty property,
143 MtpDataPacket& packet);
144
145 virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty property,
146 MtpDataPacket& packet);
147
148 virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty property,
149 MtpDataPacket& packet);
150
151 virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty property);
152
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400153 virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle handle,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500154 uint32_t format, uint32_t property,
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400155 int groupCode, int depth,
156 MtpDataPacket& packet);
157
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400158 virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
Mike Lockwood9df53fae2011-04-21 17:05:55 -0700159 MtpObjectInfo& info);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400160
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700161 virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
162
Mike Lockwood59c777a2010-08-02 10:37:41 -0400163 virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
Mike Lockwood365e03e2010-12-08 16:08:01 -0800164 MtpString& outFilePath,
165 int64_t& outFileLength,
166 MtpObjectFormat& outFormat);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700167 virtual MtpResponseCode beginDeleteObject(MtpObjectHandle handle);
168 virtual void endDeleteObject(MtpObjectHandle handle, bool succeeded);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400169
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400170 bool getObjectPropertyInfo(MtpObjectProperty property, int& type);
171 bool getDevicePropertyInfo(MtpDeviceProperty property, int& type);
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400172
173 virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle);
174
175 virtual MtpResponseCode setObjectReferences(MtpObjectHandle handle,
176 MtpObjectHandleList* references);
Mike Lockwood828d19d2010-08-10 15:20:35 -0400177
178 virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty property,
179 MtpObjectFormat format);
180
181 virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property);
Mike Lockwood2837eef2010-08-31 16:25:12 -0400182
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700183 virtual MtpResponseCode beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
184 MtpStorageID newStorage);
Jerry Zhang952558d2017-09-26 17:49:52 -0700185
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700186 virtual void endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
187 MtpStorageID oldStorage, MtpStorageID newStorage,
188 MtpObjectHandle handle, bool succeeded);
Mike Lockwood2837eef2010-08-31 16:25:12 -0400189
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700190 virtual MtpResponseCode beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
191 MtpStorageID newStorage);
192 virtual void endCopyObject(MtpObjectHandle handle, bool succeeded);
193
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400194};
195
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400196// ----------------------------------------------------------------------------
197
198static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
199 if (env->ExceptionCheck()) {
Steve Block3762c312012-01-06 19:20:56 +0000200 ALOGE("An exception was thrown by callback '%s'.", methodName);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400201 LOGE_EX(env);
202 env->ExceptionClear();
203 }
204}
205
206// ----------------------------------------------------------------------------
207
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700208MtpDatabase::MtpDatabase(JNIEnv *env, jobject client)
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400209 : mDatabase(env->NewGlobalRef(client)),
210 mIntBuffer(NULL),
211 mLongBuffer(NULL),
212 mStringBuffer(NULL)
213{
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400214 // create buffers for out arguments
215 // we don't need to be thread-safe so this is OK
Elliott Hughes15dd15f2011-04-08 17:42:34 -0700216 jintArray intArray = env->NewIntArray(3);
217 if (!intArray) {
218 return; // Already threw.
219 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400220 mIntBuffer = (jintArray)env->NewGlobalRef(intArray);
Elliott Hughes15dd15f2011-04-08 17:42:34 -0700221 jlongArray longArray = env->NewLongArray(2);
222 if (!longArray) {
223 return; // Already threw.
224 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400225 mLongBuffer = (jlongArray)env->NewGlobalRef(longArray);
Mike Lockwood63ffd782014-09-24 10:55:19 -0700226 // Needs to be long enough to hold a file path for getObjectFilePath()
227 jcharArray charArray = env->NewCharArray(PATH_MAX + 1);
Elliott Hughes15dd15f2011-04-08 17:42:34 -0700228 if (!charArray) {
229 return; // Already threw.
230 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400231 mStringBuffer = (jcharArray)env->NewGlobalRef(charArray);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400232}
233
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700234void MtpDatabase::cleanup(JNIEnv *env) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400235 env->DeleteGlobalRef(mDatabase);
236 env->DeleteGlobalRef(mIntBuffer);
237 env->DeleteGlobalRef(mLongBuffer);
238 env->DeleteGlobalRef(mStringBuffer);
239}
240
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700241MtpDatabase::~MtpDatabase() {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400242}
243
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700244MtpObjectHandle MtpDatabase::beginSendObject(const char* path,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900245 MtpObjectFormat format,
246 MtpObjectHandle parent,
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700247 MtpStorageID storage) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400248 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood88394712010-09-27 10:01:00 -0400249 jstring pathStr = env->NewStringUTF(path);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400250 MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700251 pathStr, (jint)format, (jint)parent, (jint)storage);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400252
Mike Lockwood88394712010-09-27 10:01:00 -0400253 if (pathStr)
254 env->DeleteLocalRef(pathStr);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400255 checkAndClearExceptionFromCallback(env, __FUNCTION__);
256 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400257}
258
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700259void MtpDatabase::endSendObject(MtpObjectHandle handle, bool succeeded) {
260 JNIEnv* env = AndroidRuntime::getJNIEnv();
261 env->CallVoidMethod(mDatabase, method_endSendObject, (jint)handle, (jboolean)succeeded);
262
263 checkAndClearExceptionFromCallback(env, __FUNCTION__);
264}
265
266void MtpDatabase::rescanFile(const char* path, MtpObjectHandle handle,
267 MtpObjectFormat format) {
Mike Lockwoodd815f792010-07-12 08:49:01 -0400268 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood88394712010-09-27 10:01:00 -0400269 jstring pathStr = env->NewStringUTF(path);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700270 env->CallVoidMethod(mDatabase, method_rescanFile, pathStr,
271 (jint)handle, (jint)format);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400272
Mike Lockwood88394712010-09-27 10:01:00 -0400273 if (pathStr)
274 env->DeleteLocalRef(pathStr);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400275 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd815f792010-07-12 08:49:01 -0400276}
277
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700278MtpObjectHandleList* MtpDatabase::getObjectList(MtpStorageID storageID,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900279 MtpObjectFormat format,
280 MtpObjectHandle parent) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400281 JNIEnv* env = AndroidRuntime::getJNIEnv();
282 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList,
283 (jint)storageID, (jint)format, (jint)parent);
284 if (!array)
285 return NULL;
286 MtpObjectHandleList* list = new MtpObjectHandleList();
287 jint* handles = env->GetIntArrayElements(array, 0);
288 jsize length = env->GetArrayLength(array);
Mike Lockwood7a047c82010-08-02 10:52:20 -0400289 for (int i = 0; i < length; i++)
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400290 list->push(handles[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400291 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400292 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400293
294 checkAndClearExceptionFromCallback(env, __FUNCTION__);
295 return list;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400296}
297
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700298int MtpDatabase::getNumObjects(MtpStorageID storageID,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900299 MtpObjectFormat format,
300 MtpObjectHandle parent) {
Mike Lockwood7a047c82010-08-02 10:52:20 -0400301 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400302 int result = env->CallIntMethod(mDatabase, method_getNumObjects,
Mike Lockwood7a047c82010-08-02 10:52:20 -0400303 (jint)storageID, (jint)format, (jint)parent);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400304
305 checkAndClearExceptionFromCallback(env, __FUNCTION__);
306 return result;
Mike Lockwood7a047c82010-08-02 10:52:20 -0400307}
308
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700309MtpObjectFormatList* MtpDatabase::getSupportedPlaybackFormats() {
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400310 JNIEnv* env = AndroidRuntime::getJNIEnv();
311 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
312 method_getSupportedPlaybackFormats);
313 if (!array)
314 return NULL;
315 MtpObjectFormatList* list = new MtpObjectFormatList();
316 jint* formats = env->GetIntArrayElements(array, 0);
317 jsize length = env->GetArrayLength(array);
318 for (int i = 0; i < length; i++)
319 list->push(formats[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400320 env->ReleaseIntArrayElements(array, formats, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400321 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400322
323 checkAndClearExceptionFromCallback(env, __FUNCTION__);
324 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400325}
326
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700327MtpObjectFormatList* MtpDatabase::getSupportedCaptureFormats() {
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400328 JNIEnv* env = AndroidRuntime::getJNIEnv();
329 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
330 method_getSupportedCaptureFormats);
331 if (!array)
332 return NULL;
333 MtpObjectFormatList* list = new MtpObjectFormatList();
334 jint* formats = env->GetIntArrayElements(array, 0);
335 jsize length = env->GetArrayLength(array);
336 for (int i = 0; i < length; i++)
337 list->push(formats[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400338 env->ReleaseIntArrayElements(array, formats, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400339 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400340
341 checkAndClearExceptionFromCallback(env, __FUNCTION__);
342 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400343}
344
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700345MtpObjectPropertyList* MtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400346 JNIEnv* env = AndroidRuntime::getJNIEnv();
347 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
348 method_getSupportedObjectProperties, (jint)format);
349 if (!array)
350 return NULL;
351 MtpObjectPropertyList* list = new MtpObjectPropertyList();
352 jint* properties = env->GetIntArrayElements(array, 0);
353 jsize length = env->GetArrayLength(array);
354 for (int i = 0; i < length; i++)
355 list->push(properties[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400356 env->ReleaseIntArrayElements(array, properties, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400357 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400358
359 checkAndClearExceptionFromCallback(env, __FUNCTION__);
360 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400361}
362
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700363MtpDevicePropertyList* MtpDatabase::getSupportedDeviceProperties() {
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400364 JNIEnv* env = AndroidRuntime::getJNIEnv();
365 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
366 method_getSupportedDeviceProperties);
367 if (!array)
368 return NULL;
369 MtpDevicePropertyList* list = new MtpDevicePropertyList();
370 jint* properties = env->GetIntArrayElements(array, 0);
371 jsize length = env->GetArrayLength(array);
372 for (int i = 0; i < length; i++)
373 list->push(properties[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400374 env->ReleaseIntArrayElements(array, properties, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400375 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400376
377 checkAndClearExceptionFromCallback(env, __FUNCTION__);
378 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400379}
380
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700381MtpResponseCode MtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900382 MtpObjectProperty property,
383 MtpDataPacket& packet) {
384 static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
385 "Casting MtpObjectHandle to jint loses a value");
386 static_assert(sizeof(jint) >= sizeof(MtpObjectProperty),
387 "Casting MtpObjectProperty to jint loses a value");
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400388 JNIEnv* env = AndroidRuntime::getJNIEnv();
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900389 jobject list = env->CallObjectMethod(
390 mDatabase,
391 method_getObjectPropertyList,
392 static_cast<jint>(handle),
393 0,
394 static_cast<jint>(property),
395 0,
396 0);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700397 MtpResponseCode result = env->CallIntMethod(list, method_getCode);
398 jint count = env->CallIntMethod(list, method_getCount);
399 if (count != 1)
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400400 result = MTP_RESPONSE_GENERAL_ERROR;
401
402 if (result == MTP_RESPONSE_OK) {
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700403 jintArray objectHandlesArray = (jintArray)env->CallObjectMethod(list, method_getObjectHandles);
404 jintArray propertyCodesArray = (jintArray)env->CallObjectMethod(list, method_getPropertyCodes);
405 jintArray dataTypesArray = (jintArray)env->CallObjectMethod(list, method_getDataTypes);
406 jlongArray longValuesArray = (jlongArray)env->CallObjectMethod(list, method_getLongValues);
407 jobjectArray stringValuesArray = (jobjectArray)env->CallObjectMethod(list, method_getStringValues);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400408
409 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
410 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
411 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700412 jlong* longValues = env->GetLongArrayElements(longValuesArray, 0);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400413
414 int type = dataTypes[0];
415 jlong longValue = (longValues ? longValues[0] : 0);
416
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400417 switch (type) {
418 case MTP_TYPE_INT8:
419 packet.putInt8(longValue);
420 break;
421 case MTP_TYPE_UINT8:
422 packet.putUInt8(longValue);
423 break;
424 case MTP_TYPE_INT16:
425 packet.putInt16(longValue);
426 break;
427 case MTP_TYPE_UINT16:
428 packet.putUInt16(longValue);
429 break;
430 case MTP_TYPE_INT32:
431 packet.putInt32(longValue);
432 break;
433 case MTP_TYPE_UINT32:
434 packet.putUInt32(longValue);
435 break;
436 case MTP_TYPE_INT64:
437 packet.putInt64(longValue);
438 break;
439 case MTP_TYPE_UINT64:
440 packet.putUInt64(longValue);
441 break;
442 case MTP_TYPE_INT128:
443 packet.putInt128(longValue);
444 break;
445 case MTP_TYPE_UINT128:
Wanwu Peng8937f1a2016-03-02 18:16:46 +0800446 packet.putUInt128(longValue);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400447 break;
448 case MTP_TYPE_STR:
449 {
450 jstring stringValue = (jstring)env->GetObjectArrayElement(stringValuesArray, 0);
Martin Blumenstingl17a24c52014-05-31 15:50:38 +0200451 const char* str = (stringValue ? env->GetStringUTFChars(stringValue, NULL) : NULL);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400452 if (stringValue) {
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400453 packet.putString(str);
454 env->ReleaseStringUTFChars(stringValue, str);
455 } else {
456 packet.putEmptyString();
457 }
Martin Blumenstingl17a24c52014-05-31 15:50:38 +0200458 env->DeleteLocalRef(stringValue);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400459 break;
460 }
461 default:
Steve Block3762c312012-01-06 19:20:56 +0000462 ALOGE("unsupported type in getObjectPropertyValue\n");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400463 result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
464 }
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400465 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
466 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
467 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700468 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400469
470 env->DeleteLocalRef(objectHandlesArray);
471 env->DeleteLocalRef(propertyCodesArray);
472 env->DeleteLocalRef(dataTypesArray);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700473 env->DeleteLocalRef(longValuesArray);
474 env->DeleteLocalRef(stringValuesArray);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400475 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400476
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400477 env->DeleteLocalRef(list);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400478 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400479 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400480}
481
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800482static bool readLongValue(int type, MtpDataPacket& packet, jlong& longValue) {
483 switch (type) {
484 case MTP_TYPE_INT8: {
485 int8_t temp;
486 if (!packet.getInt8(temp)) return false;
487 longValue = temp;
488 break;
489 }
490 case MTP_TYPE_UINT8: {
491 uint8_t temp;
492 if (!packet.getUInt8(temp)) return false;
493 longValue = temp;
494 break;
495 }
496 case MTP_TYPE_INT16: {
497 int16_t temp;
498 if (!packet.getInt16(temp)) return false;
499 longValue = temp;
500 break;
501 }
502 case MTP_TYPE_UINT16: {
503 uint16_t temp;
504 if (!packet.getUInt16(temp)) return false;
505 longValue = temp;
506 break;
507 }
508 case MTP_TYPE_INT32: {
509 int32_t temp;
510 if (!packet.getInt32(temp)) return false;
511 longValue = temp;
512 break;
513 }
514 case MTP_TYPE_UINT32: {
515 uint32_t temp;
516 if (!packet.getUInt32(temp)) return false;
517 longValue = temp;
518 break;
519 }
520 case MTP_TYPE_INT64: {
521 int64_t temp;
522 if (!packet.getInt64(temp)) return false;
523 longValue = temp;
524 break;
525 }
526 case MTP_TYPE_UINT64: {
527 uint64_t temp;
528 if (!packet.getUInt64(temp)) return false;
529 longValue = temp;
530 break;
531 }
532 default:
533 ALOGE("unsupported type in readLongValue");
534 return false;
535 }
536 return true;
537}
538
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700539MtpResponseCode MtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900540 MtpObjectProperty property,
541 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400542 int type;
543
544 if (!getObjectPropertyInfo(property, type))
545 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
546
547 JNIEnv* env = AndroidRuntime::getJNIEnv();
548 jlong longValue = 0;
549 jstring stringValue = NULL;
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800550 MtpResponseCode result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400551
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800552 if (type == MTP_TYPE_STR) {
553 MtpStringBuffer buffer;
554 if (!packet.getString(buffer)) goto fail;
555 stringValue = env->NewStringUTF((const char *)buffer);
556 } else {
557 if (!readLongValue(type, packet, longValue)) goto fail;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400558 }
559
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800560 result = env->CallIntMethod(mDatabase, method_setObjectProperty,
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400561 (jint)handle, (jint)property, longValue, stringValue);
Mike Lockwood88394712010-09-27 10:01:00 -0400562 if (stringValue)
563 env->DeleteLocalRef(stringValue);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400564
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800565fail:
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400566 checkAndClearExceptionFromCallback(env, __FUNCTION__);
567 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400568}
569
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700570MtpResponseCode MtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900571 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400572 JNIEnv* env = AndroidRuntime::getJNIEnv();
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700573 int type;
Mike Lockwood56c85242014-03-07 13:29:08 -0800574
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700575 if (!getDevicePropertyInfo(property, type))
576 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
Mike Lockwood56c85242014-03-07 13:29:08 -0800577
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700578 jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
579 (jint)property, mLongBuffer, mStringBuffer);
580 if (result != MTP_RESPONSE_OK) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400581 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700582 return result;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400583 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700584
585 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
586 jlong longValue = longValues[0];
587 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
588
589 switch (type) {
590 case MTP_TYPE_INT8:
591 packet.putInt8(longValue);
592 break;
593 case MTP_TYPE_UINT8:
594 packet.putUInt8(longValue);
595 break;
596 case MTP_TYPE_INT16:
597 packet.putInt16(longValue);
598 break;
599 case MTP_TYPE_UINT16:
600 packet.putUInt16(longValue);
601 break;
602 case MTP_TYPE_INT32:
603 packet.putInt32(longValue);
604 break;
605 case MTP_TYPE_UINT32:
606 packet.putUInt32(longValue);
607 break;
608 case MTP_TYPE_INT64:
609 packet.putInt64(longValue);
610 break;
611 case MTP_TYPE_UINT64:
612 packet.putUInt64(longValue);
613 break;
614 case MTP_TYPE_INT128:
615 packet.putInt128(longValue);
616 break;
617 case MTP_TYPE_UINT128:
618 packet.putInt128(longValue);
619 break;
620 case MTP_TYPE_STR:
621 {
622 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
623 packet.putString(str);
624 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
625 break;
626 }
627 default:
628 ALOGE("unsupported type in getDevicePropertyValue\n");
629 return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
630 }
631
632 checkAndClearExceptionFromCallback(env, __FUNCTION__);
633 return MTP_RESPONSE_OK;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400634}
635
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700636MtpResponseCode MtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900637 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400638 int type;
639
640 if (!getDevicePropertyInfo(property, type))
641 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
642
643 JNIEnv* env = AndroidRuntime::getJNIEnv();
644 jlong longValue = 0;
645 jstring stringValue = NULL;
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800646 MtpResponseCode result = MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400647
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800648 if (type == MTP_TYPE_STR) {
649 MtpStringBuffer buffer;
650 if (!packet.getString(buffer)) goto fail;
651 stringValue = env->NewStringUTF((const char *)buffer);
652 } else {
653 if (!readLongValue(type, packet, longValue)) goto fail;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400654 }
655
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800656 result = env->CallIntMethod(mDatabase, method_setDeviceProperty,
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400657 (jint)property, longValue, stringValue);
Mike Lockwood88394712010-09-27 10:01:00 -0400658 if (stringValue)
659 env->DeleteLocalRef(stringValue);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400660
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800661fail:
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400662 checkAndClearExceptionFromCallback(env, __FUNCTION__);
663 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400664}
665
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700666MtpResponseCode MtpDatabase::resetDeviceProperty(MtpDeviceProperty /*property*/) {
Mike Lockwood828d19d2010-08-10 15:20:35 -0400667 return -1;
668}
669
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700670MtpResponseCode MtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900671 uint32_t format, uint32_t property,
672 int groupCode, int depth,
673 MtpDataPacket& packet) {
674 static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
675 "Casting MtpObjectHandle to jint loses a value");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400676 JNIEnv* env = AndroidRuntime::getJNIEnv();
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900677 jobject list = env->CallObjectMethod(
678 mDatabase,
679 method_getObjectPropertyList,
680 static_cast<jint>(handle),
681 static_cast<jint>(format),
682 static_cast<jint>(property),
683 static_cast<jint>(groupCode),
684 static_cast<jint>(depth));
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500685 checkAndClearExceptionFromCallback(env, __FUNCTION__);
686 if (!list)
687 return MTP_RESPONSE_GENERAL_ERROR;
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700688 int count = env->CallIntMethod(list, method_getCount);
689 MtpResponseCode result = env->CallIntMethod(list, method_getCode);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400690
691 packet.putUInt32(count);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400692 if (count > 0) {
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700693 jintArray objectHandlesArray = (jintArray)env->CallObjectMethod(list, method_getObjectHandles);
694 jintArray propertyCodesArray = (jintArray)env->CallObjectMethod(list, method_getPropertyCodes);
695 jintArray dataTypesArray = (jintArray)env->CallObjectMethod(list, method_getDataTypes);
696 jlongArray longValuesArray = (jlongArray)env->CallObjectMethod(list, method_getLongValues);
697 jobjectArray stringValuesArray = (jobjectArray)env->CallObjectMethod(list, method_getStringValues);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400698
699 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
700 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
701 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
702 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
703
704 for (int i = 0; i < count; i++) {
705 packet.putUInt32(objectHandles[i]);
706 packet.putUInt16(propertyCodes[i]);
707 int type = dataTypes[i];
708 packet.putUInt16(type);
709
710 switch (type) {
711 case MTP_TYPE_INT8:
712 packet.putInt8(longValues[i]);
713 break;
714 case MTP_TYPE_UINT8:
715 packet.putUInt8(longValues[i]);
716 break;
717 case MTP_TYPE_INT16:
718 packet.putInt16(longValues[i]);
719 break;
720 case MTP_TYPE_UINT16:
721 packet.putUInt16(longValues[i]);
722 break;
723 case MTP_TYPE_INT32:
724 packet.putInt32(longValues[i]);
725 break;
726 case MTP_TYPE_UINT32:
727 packet.putUInt32(longValues[i]);
728 break;
729 case MTP_TYPE_INT64:
730 packet.putInt64(longValues[i]);
731 break;
732 case MTP_TYPE_UINT64:
733 packet.putUInt64(longValues[i]);
734 break;
735 case MTP_TYPE_INT128:
736 packet.putInt128(longValues[i]);
737 break;
738 case MTP_TYPE_UINT128:
739 packet.putUInt128(longValues[i]);
740 break;
741 case MTP_TYPE_STR: {
742 jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i);
Mike Lockwood2711e492010-12-11 11:24:37 -0800743 const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400744 if (valueStr) {
745 packet.putString(valueStr);
746 env->ReleaseStringUTFChars(value, valueStr);
747 } else {
748 packet.putEmptyString();
749 }
750 env->DeleteLocalRef(value);
751 break;
752 }
753 default:
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700754 ALOGE("bad or unsupported data type in MtpDatabase::getObjectPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400755 break;
756 }
757 }
758
759 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
760 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
761 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700762 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400763
764 env->DeleteLocalRef(objectHandlesArray);
765 env->DeleteLocalRef(propertyCodesArray);
766 env->DeleteLocalRef(dataTypesArray);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700767 env->DeleteLocalRef(longValuesArray);
768 env->DeleteLocalRef(stringValuesArray);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400769 }
770
771 env->DeleteLocalRef(list);
772 checkAndClearExceptionFromCallback(env, __FUNCTION__);
773 return result;
774}
775
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800776static void foreachentry(ExifEntry *entry, void* /* user */) {
Marco Nelissen3cd393c2014-01-10 10:39:27 -0800777 char buf[1024];
778 ALOGI("entry %x, format %d, size %d: %s",
779 entry->tag, entry->format, entry->size, exif_entry_get_value(entry, buf, sizeof(buf)));
780}
781
782static void foreachcontent(ExifContent *content, void *user) {
783 ALOGI("content %d", exif_content_get_ifd(content));
784 exif_content_foreach_entry(content, foreachentry, user);
785}
786
787static long getLongFromExifEntry(ExifEntry *e) {
788 ExifByteOrder o = exif_data_get_byte_order(e->parent->parent);
789 return exif_get_long(e->data, o);
790}
791
Chong Zhang63f81922018-03-14 18:57:05 -0700792static ExifData *getExifFromExtractor(const char *path) {
793 std::unique_ptr<uint8_t[]> exifBuf;
794 ExifData *exifdata = NULL;
795
796 FILE *fp = fopen (path, "rb");
797 if (!fp) {
798 ALOGE("failed to open file");
799 return NULL;
800 }
801
802 sp<NuMediaExtractor> extractor = new NuMediaExtractor();
803 fseek(fp, 0L, SEEK_END);
804 if (extractor->setDataSource(fileno(fp), 0, ftell(fp)) != OK) {
805 ALOGE("failed to setDataSource");
806 fclose(fp);
807 return NULL;
808 }
809
810 off64_t offset;
811 size_t size;
812 if (extractor->getExifOffsetSize(&offset, &size) != OK) {
813 fclose(fp);
814 return NULL;
815 }
816
817 exifBuf.reset(new uint8_t[size]);
818 fseek(fp, offset, SEEK_SET);
819 if (fread(exifBuf.get(), 1, size, fp) == size) {
820 exifdata = exif_data_new_from_data(exifBuf.get(), size);
821 }
822
823 fclose(fp);
824 return exifdata;
825}
826
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700827MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900828 MtpObjectInfo& info) {
Mike Lockwoodf6f16612012-09-12 15:50:59 -0700829 MtpString path;
830 int64_t length;
831 MtpObjectFormat format;
832
833 MtpResponseCode result = getObjectFilePath(handle, path, length, format);
834 if (result != MTP_RESPONSE_OK) {
835 return result;
836 }
837 info.mCompressedSize = (length > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)length);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400838
839 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwoodf6f16612012-09-12 15:50:59 -0700840 if (!env->CallBooleanMethod(mDatabase, method_getObjectInfo,
841 (jint)handle, mIntBuffer, mStringBuffer, mLongBuffer)) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400842 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodf6f16612012-09-12 15:50:59 -0700843 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400844
845 jint* intValues = env->GetIntArrayElements(mIntBuffer, 0);
Mike Lockwood9df53fae2011-04-21 17:05:55 -0700846 info.mStorageID = intValues[0];
847 info.mFormat = intValues[1];
848 info.mParent = intValues[2];
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400849 env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
850
851 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
Mike Lockwood1341f1e2013-04-01 10:52:47 -0700852 info.mDateCreated = longValues[0];
853 info.mDateModified = longValues[1];
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400854 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
855
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800856 if ((false)) {
857 info.mAssociationType = (format == MTP_FORMAT_ASSOCIATION ?
858 MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
859 MTP_ASSOCIATION_TYPE_UNDEFINED);
860 }
Mike Lockwood9df53fae2011-04-21 17:05:55 -0700861 info.mAssociationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400862
863 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
Dan Albert66987492014-11-20 11:41:21 -0800864 MtpString temp(reinterpret_cast<char16_t*>(str));
Mike Lockwood9df53fae2011-04-21 17:05:55 -0700865 info.mName = strdup((const char *)temp);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400866 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
867
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700868 // read EXIF data for thumbnail information
Jaesung Chung8409c062016-01-19 10:48:30 +0900869 switch (info.mFormat) {
870 case MTP_FORMAT_EXIF_JPEG:
Chong Zhang6e18cce2017-08-16 11:57:02 -0700871 case MTP_FORMAT_HEIF:
Jaesung Chung8409c062016-01-19 10:48:30 +0900872 case MTP_FORMAT_JFIF: {
Chong Zhang63f81922018-03-14 18:57:05 -0700873 ExifData *exifdata;
874 if (info.mFormat == MTP_FORMAT_HEIF) {
875 exifdata = getExifFromExtractor(path);
876 } else {
877 exifdata = exif_data_new_from_file(path);
878 }
Jaesung Chung8409c062016-01-19 10:48:30 +0900879 if (exifdata) {
880 if ((false)) {
881 exif_data_foreach_content(exifdata, foreachcontent, NULL);
882 }
Marco Nelissen3cd393c2014-01-10 10:39:27 -0800883
Jaesung Chung8409c062016-01-19 10:48:30 +0900884 ExifEntry *w = exif_content_get_entry(
885 exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_X_DIMENSION);
886 ExifEntry *h = exif_content_get_entry(
887 exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_Y_DIMENSION);
888 info.mThumbCompressedSize = exifdata->data ? exifdata->size : 0;
889 info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
890 info.mImagePixWidth = w ? getLongFromExifEntry(w) : 0;
891 info.mImagePixHeight = h ? getLongFromExifEntry(h) : 0;
892 exif_data_unref(exifdata);
893 }
894 break;
895 }
896
897 // Except DNG, all supported RAW image formats are not defined in PTP 1.2 specification.
898 // Most of RAW image formats are based on TIFF or TIFF/EP. To render Fuji's RAF format,
899 // it checks MTP_FORMAT_DEFINED case since it's designed as a custom format.
900 case MTP_FORMAT_DNG:
901 case MTP_FORMAT_TIFF:
902 case MTP_FORMAT_TIFF_EP:
903 case MTP_FORMAT_DEFINED: {
904 std::unique_ptr<FileStream> stream(new FileStream(path));
905 piex::PreviewImageData image_data;
906 if (!GetExifFromRawImage(stream.get(), path, image_data)) {
907 // Couldn't parse EXIF data from a image file via piex.
908 break;
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800909 }
Marco Nelissen3cd393c2014-01-10 10:39:27 -0800910
Jaesung Chungfd3446e2016-04-06 21:42:39 +0900911 info.mThumbCompressedSize = image_data.thumbnail.length;
Marco Nelissen3cd393c2014-01-10 10:39:27 -0800912 info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
Jaesung Chung8409c062016-01-19 10:48:30 +0900913 info.mImagePixWidth = image_data.full_width;
914 info.mImagePixHeight = image_data.full_height;
915
916 break;
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700917 }
918 }
919
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400920 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400921 return MTP_RESPONSE_OK;
922}
923
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700924void* MtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700925 MtpString path;
926 int64_t length;
927 MtpObjectFormat format;
928 void* result = NULL;
929 outThumbSize = 0;
930
Jaesung Chung8409c062016-01-19 10:48:30 +0900931 if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK) {
932 switch (format) {
933 case MTP_FORMAT_EXIF_JPEG:
Chong Zhang6e18cce2017-08-16 11:57:02 -0700934 case MTP_FORMAT_HEIF:
Jaesung Chung8409c062016-01-19 10:48:30 +0900935 case MTP_FORMAT_JFIF: {
Chong Zhang63f81922018-03-14 18:57:05 -0700936 ExifData *exifdata;
937 if (format == MTP_FORMAT_HEIF) {
938 exifdata = getExifFromExtractor(path);
939 } else {
940 exifdata = exif_data_new_from_file(path);
941 }
Jaesung Chung8409c062016-01-19 10:48:30 +0900942 if (exifdata) {
943 if (exifdata->data) {
944 result = malloc(exifdata->size);
945 if (result) {
946 memcpy(result, exifdata->data, exifdata->size);
947 outThumbSize = exifdata->size;
948 }
949 }
950 exif_data_unref(exifdata);
Marco Nelissen3cd393c2014-01-10 10:39:27 -0800951 }
Jaesung Chung8409c062016-01-19 10:48:30 +0900952 break;
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700953 }
Jaesung Chung8409c062016-01-19 10:48:30 +0900954
955 // See the above comment on getObjectInfo() method.
956 case MTP_FORMAT_DNG:
957 case MTP_FORMAT_TIFF:
958 case MTP_FORMAT_TIFF_EP:
959 case MTP_FORMAT_DEFINED: {
960 std::unique_ptr<FileStream> stream(new FileStream(path));
961 piex::PreviewImageData image_data;
962 if (!GetExifFromRawImage(stream.get(), path, image_data)) {
963 // Couldn't parse EXIF data from a image file via piex.
964 break;
965 }
966
Jaesung Chung742e89f2016-04-13 14:13:10 +0900967 if (image_data.thumbnail.length == 0
Insun Kang82c2ce12016-04-19 17:56:10 +0900968 || image_data.thumbnail.format != ::piex::Image::kJpegCompressed) {
Jaesung Chung742e89f2016-04-13 14:13:10 +0900969 // No thumbnail or non jpeg thumbnail.
Jaesung Chung8409c062016-01-19 10:48:30 +0900970 break;
971 }
972
Jaesung Chungfd3446e2016-04-06 21:42:39 +0900973 result = malloc(image_data.thumbnail.length);
Jaesung Chung8409c062016-01-19 10:48:30 +0900974 if (result) {
975 piex::Error err = stream.get()->GetData(
Jaesung Chungfd3446e2016-04-06 21:42:39 +0900976 image_data.thumbnail.offset,
977 image_data.thumbnail.length,
Jaesung Chung8409c062016-01-19 10:48:30 +0900978 (std::uint8_t *)result);
979 if (err == piex::Error::kOk) {
Jaesung Chungfd3446e2016-04-06 21:42:39 +0900980 outThumbSize = image_data.thumbnail.length;
Jaesung Chung8409c062016-01-19 10:48:30 +0900981 } else {
982 free(result);
Chong Zhange6b98532017-10-24 16:07:18 -0700983 result = NULL;
Jaesung Chung8409c062016-01-19 10:48:30 +0900984 }
985 }
986 break;
987 }
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700988 }
989 }
990
991 return result;
992}
993
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700994MtpResponseCode MtpDatabase::getObjectFilePath(MtpObjectHandle handle,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900995 MtpString& outFilePath,
996 int64_t& outFileLength,
997 MtpObjectFormat& outFormat) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400998 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood59c777a2010-08-02 10:37:41 -0400999 jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath,
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001000 (jint)handle, mStringBuffer, mLongBuffer);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001001 if (result != MTP_RESPONSE_OK) {
1002 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -04001003 return result;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001004 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001005
1006 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
Dan Albert66987492014-11-20 11:41:21 -08001007 outFilePath.setTo(reinterpret_cast<char16_t*>(str),
1008 strlen16(reinterpret_cast<char16_t*>(str)));
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001009 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
1010
1011 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
Mike Lockwood365e03e2010-12-08 16:08:01 -08001012 outFileLength = longValues[0];
1013 outFormat = longValues[1];
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001014 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
Elliott Hughes15dd15f2011-04-08 17:42:34 -07001015
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001016 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -04001017 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001018}
1019
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001020MtpResponseCode MtpDatabase::beginDeleteObject(MtpObjectHandle handle) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001021 JNIEnv* env = AndroidRuntime::getJNIEnv();
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001022 MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginDeleteObject, (jint)handle);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001023
1024 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1025 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001026}
1027
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001028void MtpDatabase::endDeleteObject(MtpObjectHandle handle, bool succeeded) {
Jerry Zhang952558d2017-09-26 17:49:52 -07001029 JNIEnv* env = AndroidRuntime::getJNIEnv();
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001030 env->CallVoidMethod(mDatabase, method_endDeleteObject, (jint)handle, (jboolean) succeeded);
Jerry Zhang952558d2017-09-26 17:49:52 -07001031
1032 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001033}
1034
1035MtpResponseCode MtpDatabase::beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
1036 MtpStorageID newStorage) {
1037 JNIEnv* env = AndroidRuntime::getJNIEnv();
1038 MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginMoveObject,
1039 (jint)handle, (jint)newParent, (jint) newStorage);
1040
1041 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Jerry Zhang952558d2017-09-26 17:49:52 -07001042 return result;
1043}
1044
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001045void MtpDatabase::endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
1046 MtpStorageID oldStorage, MtpStorageID newStorage,
1047 MtpObjectHandle handle, bool succeeded) {
1048 JNIEnv* env = AndroidRuntime::getJNIEnv();
1049 env->CallVoidMethod(mDatabase, method_endMoveObject,
1050 (jint)oldParent, (jint) newParent, (jint) oldStorage, (jint) newStorage,
1051 (jint) handle, (jboolean) succeeded);
1052
1053 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1054}
1055
1056MtpResponseCode MtpDatabase::beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
1057 MtpStorageID newStorage) {
1058 JNIEnv* env = AndroidRuntime::getJNIEnv();
1059 MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginCopyObject,
1060 (jint)handle, (jint)newParent, (jint) newStorage);
1061
1062 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1063 return result;
1064}
1065
1066void MtpDatabase::endCopyObject(MtpObjectHandle handle, bool succeeded) {
1067 JNIEnv* env = AndroidRuntime::getJNIEnv();
1068 env->CallVoidMethod(mDatabase, method_endCopyObject, (jint)handle, (jboolean)succeeded);
1069
1070 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1071}
1072
1073
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001074struct PropertyTableEntry {
1075 MtpObjectProperty property;
1076 int type;
1077};
1078
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001079static const PropertyTableEntry kObjectPropertyTable[] = {
Mike Lockwoodd3bfecb2010-09-23 23:04:28 -04001080 { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 },
1081 { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 },
1082 { MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16 },
1083 { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 },
1084 { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR },
1085 { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR },
1086 { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 },
1087 { MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128 },
1088 { MTP_PROPERTY_NAME, MTP_TYPE_STR },
Mike Lockwoodae078f72010-09-26 12:35:51 -04001089 { MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR },
1090 { MTP_PROPERTY_DATE_ADDED, MTP_TYPE_STR },
1091 { MTP_PROPERTY_ARTIST, MTP_TYPE_STR },
1092 { MTP_PROPERTY_ALBUM_NAME, MTP_TYPE_STR },
1093 { MTP_PROPERTY_ALBUM_ARTIST, MTP_TYPE_STR },
1094 { MTP_PROPERTY_TRACK, MTP_TYPE_UINT16 },
1095 { MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_TYPE_STR },
1096 { MTP_PROPERTY_GENRE, MTP_TYPE_STR },
1097 { MTP_PROPERTY_COMPOSER, MTP_TYPE_STR },
1098 { MTP_PROPERTY_DURATION, MTP_TYPE_UINT32 },
1099 { MTP_PROPERTY_DESCRIPTION, MTP_TYPE_STR },
Mike Lockwood71827742015-01-23 10:50:08 -08001100 { MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_TYPE_UINT32 },
1101 { MTP_PROPERTY_BITRATE_TYPE, MTP_TYPE_UINT16 },
1102 { MTP_PROPERTY_AUDIO_BITRATE, MTP_TYPE_UINT32 },
1103 { MTP_PROPERTY_NUMBER_OF_CHANNELS,MTP_TYPE_UINT16 },
1104 { MTP_PROPERTY_SAMPLE_RATE, MTP_TYPE_UINT32 },
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001105};
1106
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001107static const PropertyTableEntry kDevicePropertyTable[] = {
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001108 { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_STR },
1109 { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR },
1110 { MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR },
Mike Lockwood56c85242014-03-07 13:29:08 -08001111 { MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT8 },
Jerry Zhang13bb2f42016-12-14 15:39:29 -08001112 { MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE, MTP_TYPE_UINT32 },
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001113};
1114
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001115bool MtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001116 int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
1117 const PropertyTableEntry* entry = kObjectPropertyTable;
1118 for (int i = 0; i < count; i++, entry++) {
1119 if (entry->property == property) {
1120 type = entry->type;
1121 return true;
1122 }
1123 }
1124 return false;
1125}
1126
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001127bool MtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001128 int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
1129 const PropertyTableEntry* entry = kDevicePropertyTable;
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001130 for (int i = 0; i < count; i++, entry++) {
1131 if (entry->property == property) {
1132 type = entry->type;
1133 return true;
1134 }
1135 }
1136 return false;
1137}
1138
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001139MtpObjectHandleList* MtpDatabase::getObjectReferences(MtpObjectHandle handle) {
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001140 JNIEnv* env = AndroidRuntime::getJNIEnv();
1141 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectReferences,
1142 (jint)handle);
1143 if (!array)
1144 return NULL;
1145 MtpObjectHandleList* list = new MtpObjectHandleList();
1146 jint* handles = env->GetIntArrayElements(array, 0);
1147 jsize length = env->GetArrayLength(array);
1148 for (int i = 0; i < length; i++)
1149 list->push(handles[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001150 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood88394712010-09-27 10:01:00 -04001151 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001152
1153 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1154 return list;
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001155}
1156
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001157MtpResponseCode MtpDatabase::setObjectReferences(MtpObjectHandle handle,
Daichi Hirono486ad2e2016-02-29 17:28:47 +09001158 MtpObjectHandleList* references) {
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001159 JNIEnv* env = AndroidRuntime::getJNIEnv();
1160 int count = references->size();
1161 jintArray array = env->NewIntArray(count);
1162 if (!array) {
Steve Block3762c312012-01-06 19:20:56 +00001163 ALOGE("out of memory in setObjectReferences");
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001164 return false;
1165 }
1166 jint* handles = env->GetIntArrayElements(array, 0);
1167 for (int i = 0; i < count; i++)
1168 handles[i] = (*references)[i];
1169 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001170 MtpResponseCode result = env->CallIntMethod(mDatabase, method_setObjectReferences,
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001171 (jint)handle, array);
Mike Lockwood88394712010-09-27 10:01:00 -04001172 env->DeleteLocalRef(array);
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001173
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001174 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1175 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001176}
1177
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001178MtpProperty* MtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
Daichi Hirono486ad2e2016-02-29 17:28:47 +09001179 MtpObjectFormat format) {
Mike Lockwood92b53bc2014-03-13 14:51:29 -07001180 static const int channelEnum[] = {
1181 1, // mono
1182 2, // stereo
1183 3, // 2.1
1184 4, // 3
1185 5, // 3.1
1186 6, // 4
1187 7, // 4.1
1188 8, // 5
1189 9, // 5.1
1190 };
1191 static const int bitrateEnum[] = {
1192 1, // fixed rate
1193 2, // variable rate
1194 };
1195
Mike Lockwood828d19d2010-08-10 15:20:35 -04001196 MtpProperty* result = NULL;
1197 switch (property) {
1198 case MTP_PROPERTY_OBJECT_FORMAT:
Mike Lockwood9b5e9c42010-12-07 18:53:50 -08001199 // use format as default value
1200 result = new MtpProperty(property, MTP_TYPE_UINT16, false, format);
1201 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -04001202 case MTP_PROPERTY_PROTECTION_STATUS:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001203 case MTP_PROPERTY_TRACK:
Mike Lockwood828d19d2010-08-10 15:20:35 -04001204 result = new MtpProperty(property, MTP_TYPE_UINT16);
1205 break;
1206 case MTP_PROPERTY_STORAGE_ID:
1207 case MTP_PROPERTY_PARENT_OBJECT:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001208 case MTP_PROPERTY_DURATION:
Mike Lockwood92b53bc2014-03-13 14:51:29 -07001209 case MTP_PROPERTY_AUDIO_WAVE_CODEC:
Mike Lockwood828d19d2010-08-10 15:20:35 -04001210 result = new MtpProperty(property, MTP_TYPE_UINT32);
1211 break;
1212 case MTP_PROPERTY_OBJECT_SIZE:
1213 result = new MtpProperty(property, MTP_TYPE_UINT64);
1214 break;
1215 case MTP_PROPERTY_PERSISTENT_UID:
1216 result = new MtpProperty(property, MTP_TYPE_UINT128);
1217 break;
Mike Lockwoodd3bfecb2010-09-23 23:04:28 -04001218 case MTP_PROPERTY_NAME:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001219 case MTP_PROPERTY_DISPLAY_NAME:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001220 case MTP_PROPERTY_ARTIST:
1221 case MTP_PROPERTY_ALBUM_NAME:
1222 case MTP_PROPERTY_ALBUM_ARTIST:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001223 case MTP_PROPERTY_GENRE:
1224 case MTP_PROPERTY_COMPOSER:
1225 case MTP_PROPERTY_DESCRIPTION:
Mike Lockwood828d19d2010-08-10 15:20:35 -04001226 result = new MtpProperty(property, MTP_TYPE_STR);
1227 break;
Mike Lockwood5b19af02010-11-23 18:38:55 -05001228 case MTP_PROPERTY_DATE_MODIFIED:
1229 case MTP_PROPERTY_DATE_ADDED:
1230 case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
1231 result = new MtpProperty(property, MTP_TYPE_STR);
1232 result->setFormDateTime();
1233 break;
Mike Lockwood5ebac832010-10-12 11:33:47 -04001234 case MTP_PROPERTY_OBJECT_FILE_NAME:
Mike Lockwood6a6a3af2010-10-12 14:19:51 -04001235 // We allow renaming files and folders
1236 result = new MtpProperty(property, MTP_TYPE_STR, true);
Mike Lockwood5ebac832010-10-12 11:33:47 -04001237 break;
Mike Lockwood92b53bc2014-03-13 14:51:29 -07001238 case MTP_PROPERTY_BITRATE_TYPE:
1239 result = new MtpProperty(property, MTP_TYPE_UINT16);
1240 result->setFormEnum(bitrateEnum, sizeof(bitrateEnum)/sizeof(bitrateEnum[0]));
1241 break;
1242 case MTP_PROPERTY_AUDIO_BITRATE:
1243 result = new MtpProperty(property, MTP_TYPE_UINT32);
1244 result->setFormRange(1, 1536000, 1);
1245 break;
1246 case MTP_PROPERTY_NUMBER_OF_CHANNELS:
1247 result = new MtpProperty(property, MTP_TYPE_UINT16);
1248 result->setFormEnum(channelEnum, sizeof(channelEnum)/sizeof(channelEnum[0]));
1249 break;
1250 case MTP_PROPERTY_SAMPLE_RATE:
1251 result = new MtpProperty(property, MTP_TYPE_UINT32);
1252 result->setFormRange(8000, 48000, 1);
1253 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -04001254 }
1255
1256 return result;
1257}
1258
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001259MtpProperty* MtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001260 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001261 MtpProperty* result = NULL;
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001262 bool writable = false;
1263
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001264 // get current value
1265 jint ret = env->CallIntMethod(mDatabase, method_getDeviceProperty,
1266 (jint)property, mLongBuffer, mStringBuffer);
1267 if (ret == MTP_RESPONSE_OK) {
1268 switch (property) {
1269 case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
1270 case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
1271 writable = true;
1272 // fall through
1273 case MTP_DEVICE_PROPERTY_IMAGE_SIZE:
1274 {
1275 result = new MtpProperty(property, MTP_TYPE_STR, writable);
Mike Lockwooda2a21282010-09-25 21:21:05 -04001276 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
1277 result->setCurrentValue(str);
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001278 // for read-only properties it is safe to assume current value is default value
1279 if (!writable)
1280 result->setDefaultValue(str);
Mike Lockwooda2a21282010-09-25 21:21:05 -04001281 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001282 break;
Mike Lockwooda2a21282010-09-25 21:21:05 -04001283 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001284 case MTP_DEVICE_PROPERTY_BATTERY_LEVEL:
1285 {
1286 result = new MtpProperty(property, MTP_TYPE_UINT8);
1287 jlong* arr = env->GetLongArrayElements(mLongBuffer, 0);
1288 result->setFormRange(0, arr[1], 1);
1289 result->mCurrentValue.u.u8 = (uint8_t) arr[0];
1290 env->ReleaseLongArrayElements(mLongBuffer, arr, 0);
1291 break;
1292 }
1293 case MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE:
1294 {
1295 jlong* arr = env->GetLongArrayElements(mLongBuffer, 0);
1296 result = new MtpProperty(property, MTP_TYPE_UINT32);
1297 result->mCurrentValue.u.u32 = (uint32_t) arr[0];
1298 env->ReleaseLongArrayElements(mLongBuffer, arr, 0);
1299 break;
1300 }
1301 default:
1302 ALOGE("Unrecognized property %x", property);
Mike Lockwood56c85242014-03-07 13:29:08 -08001303 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001304 } else {
1305 ALOGE("unable to read device property, response: %04X", ret);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001306 }
1307
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001308 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001309 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -04001310}
1311
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001312// ----------------------------------------------------------------------------
1313
1314static void
Mike Lockwood0cd01362010-12-30 11:54:33 -05001315android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001316{
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001317 MtpDatabase* database = new MtpDatabase(env, thiz);
Ashok Bhate2e59322013-12-17 19:04:19 +00001318 env->SetLongField(thiz, field_context, (jlong)database);
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001319 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1320}
1321
1322static void
Mike Lockwood0cd01362010-12-30 11:54:33 -05001323android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001324{
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001325 MtpDatabase* database = (MtpDatabase *)env->GetLongField(thiz, field_context);
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001326 database->cleanup(env);
1327 delete database;
Ashok Bhate2e59322013-12-17 19:04:19 +00001328 env->SetLongField(thiz, field_context, 0);
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001329 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1330}
1331
Mike Lockwood31599912010-11-15 13:43:30 -05001332static jstring
Mark Salyzynaeb75fc2014-03-20 12:09:01 -07001333android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject /*thiz*/, jlong seconds)
Mike Lockwood31599912010-11-15 13:43:30 -05001334{
Mike Lockwood31599912010-11-15 13:43:30 -05001335 char date[20];
1336 formatDateTime(seconds, date, sizeof(date));
1337 return env->NewStringUTF(date);
Mike Lockwood31599912010-11-15 13:43:30 -05001338}
1339
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001340// ----------------------------------------------------------------------------
1341
Daniel Micay76f6a862015-09-19 17:31:01 -04001342static const JNINativeMethod gMtpDatabaseMethods[] = {
Mike Lockwood0cd01362010-12-30 11:54:33 -05001343 {"native_setup", "()V", (void *)android_mtp_MtpDatabase_setup},
1344 {"native_finalize", "()V", (void *)android_mtp_MtpDatabase_finalize},
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001345};
1346
Daniel Micay76f6a862015-09-19 17:31:01 -04001347static const JNINativeMethod gMtpPropertyGroupMethods[] = {
Mike Lockwood31599912010-11-15 13:43:30 -05001348 {"format_date_time", "(J)Ljava/lang/String;",
Mike Lockwood0cd01362010-12-30 11:54:33 -05001349 (void *)android_mtp_MtpPropertyGroup_format_date_time},
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001350};
1351
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001352#define GET_METHOD_ID(name, jclass, signature) \
1353 method_##name = env->GetMethodID(jclass, #name, signature); \
1354 if (method_##name == NULL) { \
1355 ALOGE("Can't find " #name); \
1356 return -1; \
1357 } \
1358
Mike Lockwood0cd01362010-12-30 11:54:33 -05001359int register_android_mtp_MtpDatabase(JNIEnv *env)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001360{
1361 jclass clazz;
1362
Mike Lockwood0cd01362010-12-30 11:54:33 -05001363 clazz = env->FindClass("android/mtp/MtpDatabase");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001364 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +00001365 ALOGE("Can't find android/mtp/MtpDatabase");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001366 return -1;
1367 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001368 GET_METHOD_ID(beginSendObject, clazz, "(Ljava/lang/String;III)I");
1369 GET_METHOD_ID(endSendObject, clazz, "(IZ)V");
1370 GET_METHOD_ID(rescanFile, clazz, "(Ljava/lang/String;II)V");
1371 GET_METHOD_ID(getObjectList, clazz, "(III)[I");
1372 GET_METHOD_ID(getNumObjects, clazz, "(III)I");
1373 GET_METHOD_ID(getSupportedPlaybackFormats, clazz, "()[I");
1374 GET_METHOD_ID(getSupportedCaptureFormats, clazz, "()[I");
1375 GET_METHOD_ID(getSupportedObjectProperties, clazz, "(I)[I");
1376 GET_METHOD_ID(getSupportedDeviceProperties, clazz, "()[I");
1377 GET_METHOD_ID(setObjectProperty, clazz, "(IIJLjava/lang/String;)I");
1378 GET_METHOD_ID(getDeviceProperty, clazz, "(I[J[C)I");
1379 GET_METHOD_ID(setDeviceProperty, clazz, "(IJLjava/lang/String;)I");
1380 GET_METHOD_ID(getObjectPropertyList, clazz, "(IIIII)Landroid/mtp/MtpPropertyList;");
1381 GET_METHOD_ID(getObjectInfo, clazz, "(I[I[C[J)Z");
1382 GET_METHOD_ID(getObjectFilePath, clazz, "(I[C[J)I");
1383 GET_METHOD_ID(beginDeleteObject, clazz, "(I)I");
1384 GET_METHOD_ID(endDeleteObject, clazz, "(IZ)V");
1385 GET_METHOD_ID(beginMoveObject, clazz, "(III)I");
1386 GET_METHOD_ID(endMoveObject, clazz, "(IIIIIZ)V");
1387 GET_METHOD_ID(beginCopyObject, clazz, "(III)I");
1388 GET_METHOD_ID(endCopyObject, clazz, "(IZ)V");
1389 GET_METHOD_ID(getObjectReferences, clazz, "(I)[I");
1390 GET_METHOD_ID(setObjectReferences, clazz, "(I[I)I");
Mike Lockwood2837eef2010-08-31 16:25:12 -04001391
Ashok Bhate2e59322013-12-17 19:04:19 +00001392 field_context = env->GetFieldID(clazz, "mNativeContext", "J");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001393 if (field_context == NULL) {
Steve Block3762c312012-01-06 19:20:56 +00001394 ALOGE("Can't find MtpDatabase.mNativeContext");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001395 return -1;
1396 }
1397
Mike Lockwood0cd01362010-12-30 11:54:33 -05001398 clazz = env->FindClass("android/mtp/MtpPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001399 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +00001400 ALOGE("Can't find android/mtp/MtpPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001401 return -1;
1402 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001403 GET_METHOD_ID(getCode, clazz, "()I");
1404 GET_METHOD_ID(getCount, clazz, "()I");
1405 GET_METHOD_ID(getObjectHandles, clazz, "()[I");
1406 GET_METHOD_ID(getPropertyCodes, clazz, "()[I");
1407 GET_METHOD_ID(getDataTypes, clazz, "()[I");
1408 GET_METHOD_ID(getLongValues, clazz, "()[J");
1409 GET_METHOD_ID(getStringValues, clazz, "()[Ljava/lang/String;");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001410
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001411 if (AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -05001412 "android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods)))
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001413 return -1;
1414
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001415 return AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -05001416 "android/mtp/MtpPropertyGroup", gMtpPropertyGroupMethods, NELEM(gMtpPropertyGroupMethods));
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001417}