blob: 1f89d86947a153a79ebe6995c0ea5ef1d43dcc54 [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"
Jerry Zhangd9f30052018-03-27 15:29:09 -070019#include "utils/String8.h"
Mike Lockwoodd21eac92010-07-03 00:44:05 -040020
Jooyung Hancb1e8962019-02-21 14:18:11 +090021#include "android_media_Streams.h"
Jaesung Chung8409c062016-01-19 10:48:30 +090022#include "mtp.h"
Jerry Zhangf9c5c252017-08-16 18:07:51 -070023#include "IMtpDatabase.h"
Mike Lockwoodd21eac92010-07-03 00:44:05 -040024#include "MtpDataPacket.h"
Mike Lockwood9df53fae2011-04-21 17:05:55 -070025#include "MtpObjectInfo.h"
Mike Lockwood828d19d2010-08-10 15:20:35 -040026#include "MtpProperty.h"
Mike Lockwood59e3f0d2010-09-02 14:57:30 -040027#include "MtpStringBuffer.h"
Mike Lockwoodd21eac92010-07-03 00:44:05 -040028#include "MtpUtils.h"
Jaesung Chung8409c062016-01-19 10:48:30 +090029
30#include "src/piex_types.h"
31#include "src/piex.h"
Mike Lockwoodd21eac92010-07-03 00:44:05 -040032
Mike Lockwoodc89f2222011-04-24 18:40:17 -070033extern "C" {
Marco Nelissen3cd393c2014-01-10 10:39:27 -080034#include "libexif/exif-content.h"
35#include "libexif/exif-data.h"
36#include "libexif/exif-tag.h"
37#include "libexif/exif-utils.h"
Mike Lockwoodc89f2222011-04-24 18:40:17 -070038}
39
Jaesung Chung8409c062016-01-19 10:48:30 +090040#include <android_runtime/AndroidRuntime.h>
41#include <android_runtime/Log.h>
42#include <jni.h>
Chong Zhang63f81922018-03-14 18:57:05 -070043#include <media/stagefright/NuMediaExtractor.h>
Steven Moreland2279b252017-07-19 09:50:45 -070044#include <nativehelper/JNIHelp.h>
Jaesung Chung8409c062016-01-19 10:48:30 +090045#include <nativehelper/ScopedLocalRef.h>
46
47#include <assert.h>
48#include <fcntl.h>
49#include <inttypes.h>
50#include <limits.h>
51#include <stdio.h>
52#include <unistd.h>
53
Mike Lockwoodd21eac92010-07-03 00:44:05 -040054using namespace android;
55
56// ----------------------------------------------------------------------------
57
Mike Lockwoodd815f792010-07-12 08:49:01 -040058static jmethodID method_beginSendObject;
59static jmethodID method_endSendObject;
Jerry Zhangf9c5c252017-08-16 18:07:51 -070060static jmethodID method_rescanFile;
Mike Lockwoodd21eac92010-07-03 00:44:05 -040061static jmethodID method_getObjectList;
Mike Lockwood7a047c82010-08-02 10:52:20 -040062static jmethodID method_getNumObjects;
Mike Lockwood4b322ce2010-08-10 07:37:50 -040063static jmethodID method_getSupportedPlaybackFormats;
64static jmethodID method_getSupportedCaptureFormats;
65static jmethodID method_getSupportedObjectProperties;
66static jmethodID method_getSupportedDeviceProperties;
Mike Lockwood828d19d2010-08-10 15:20:35 -040067static jmethodID method_setObjectProperty;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -040068static jmethodID method_getDeviceProperty;
69static jmethodID method_setDeviceProperty;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -040070static jmethodID method_getObjectPropertyList;
Mike Lockwoodd21eac92010-07-03 00:44:05 -040071static jmethodID method_getObjectInfo;
72static jmethodID method_getObjectFilePath;
Jerry Zhangf9c5c252017-08-16 18:07:51 -070073static jmethodID method_beginDeleteObject;
74static jmethodID method_endDeleteObject;
75static jmethodID method_beginMoveObject;
76static jmethodID method_endMoveObject;
77static jmethodID method_beginCopyObject;
78static jmethodID method_endCopyObject;
Mike Lockwood9a2046f2010-08-03 15:30:09 -040079static jmethodID method_getObjectReferences;
80static jmethodID method_setObjectReferences;
Mike Lockwood2837eef2010-08-31 16:25:12 -040081
Mike Lockwoodd21eac92010-07-03 00:44:05 -040082static jfieldID field_context;
83
Jerry Zhangf9c5c252017-08-16 18:07:51 -070084// MtpPropertyList methods
85static jmethodID method_getCode;
86static jmethodID method_getCount;
87static jmethodID method_getObjectHandles;
88static jmethodID method_getPropertyCodes;
89static jmethodID method_getDataTypes;
90static jmethodID method_getLongValues;
91static jmethodID method_getStringValues;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -040092
93
Jerry Zhangf9c5c252017-08-16 18:07:51 -070094IMtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
95 return (IMtpDatabase *)env->GetLongField(database, field_context);
Mike Lockwoodd21eac92010-07-03 00:44:05 -040096}
97
98// ----------------------------------------------------------------------------
99
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700100class MtpDatabase : public IMtpDatabase {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400101private:
102 jobject mDatabase;
103 jintArray mIntBuffer;
104 jlongArray mLongBuffer;
105 jcharArray mStringBuffer;
106
107public:
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700108 MtpDatabase(JNIEnv *env, jobject client);
109 virtual ~MtpDatabase();
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400110 void cleanup(JNIEnv *env);
111
Mike Lockwoodd815f792010-07-12 08:49:01 -0400112 virtual MtpObjectHandle beginSendObject(const char* path,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400113 MtpObjectFormat format,
114 MtpObjectHandle parent,
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700115 MtpStorageID storage);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400116
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700117 virtual void endSendObject(MtpObjectHandle handle, bool succeeded);
118
119 virtual void rescanFile(const char* path,
Mike Lockwoodd815f792010-07-12 08:49:01 -0400120 MtpObjectHandle handle,
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700121 MtpObjectFormat format);
kyle_tsob4aa69f2017-11-22 20:11:27 +0800122
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400123 virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
124 MtpObjectFormat format,
125 MtpObjectHandle parent);
126
Mike Lockwood7a047c82010-08-02 10:52:20 -0400127 virtual int getNumObjects(MtpStorageID storageID,
128 MtpObjectFormat format,
129 MtpObjectHandle parent);
130
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400131 // callee should delete[] the results from these
132 // results can be NULL
133 virtual MtpObjectFormatList* getSupportedPlaybackFormats();
134 virtual MtpObjectFormatList* getSupportedCaptureFormats();
135 virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format);
136 virtual MtpDevicePropertyList* getSupportedDeviceProperties();
137
Mike Lockwood828d19d2010-08-10 15:20:35 -0400138 virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400139 MtpObjectProperty property,
140 MtpDataPacket& packet);
141
Mike Lockwood828d19d2010-08-10 15:20:35 -0400142 virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle handle,
143 MtpObjectProperty property,
144 MtpDataPacket& packet);
145
146 virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty property,
147 MtpDataPacket& packet);
148
149 virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty property,
150 MtpDataPacket& packet);
151
152 virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty property);
153
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400154 virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle handle,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500155 uint32_t format, uint32_t property,
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400156 int groupCode, int depth,
157 MtpDataPacket& packet);
158
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400159 virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
Mike Lockwood9df53fae2011-04-21 17:05:55 -0700160 MtpObjectInfo& info);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400161
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700162 virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
163
Mike Lockwood59c777a2010-08-02 10:37:41 -0400164 virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
Jerry Zhangd9f30052018-03-27 15:29:09 -0700165 MtpStringBuffer& outFilePath,
Mike Lockwood365e03e2010-12-08 16:08:01 -0800166 int64_t& outFileLength,
167 MtpObjectFormat& outFormat);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700168 virtual MtpResponseCode beginDeleteObject(MtpObjectHandle handle);
169 virtual void endDeleteObject(MtpObjectHandle handle, bool succeeded);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400170
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400171 bool getObjectPropertyInfo(MtpObjectProperty property, int& type);
172 bool getDevicePropertyInfo(MtpDeviceProperty property, int& type);
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400173
174 virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle);
175
176 virtual MtpResponseCode setObjectReferences(MtpObjectHandle handle,
177 MtpObjectHandleList* references);
Mike Lockwood828d19d2010-08-10 15:20:35 -0400178
179 virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty property,
180 MtpObjectFormat format);
181
182 virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property);
Mike Lockwood2837eef2010-08-31 16:25:12 -0400183
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700184 virtual MtpResponseCode beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
185 MtpStorageID newStorage);
Jerry Zhang952558d2017-09-26 17:49:52 -0700186
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700187 virtual void endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
188 MtpStorageID oldStorage, MtpStorageID newStorage,
189 MtpObjectHandle handle, bool succeeded);
Mike Lockwood2837eef2010-08-31 16:25:12 -0400190
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700191 virtual MtpResponseCode beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
192 MtpStorageID newStorage);
193 virtual void endCopyObject(MtpObjectHandle handle, bool succeeded);
194
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400195};
196
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400197// ----------------------------------------------------------------------------
198
199static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
200 if (env->ExceptionCheck()) {
Steve Block3762c312012-01-06 19:20:56 +0000201 ALOGE("An exception was thrown by callback '%s'.", methodName);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400202 LOGE_EX(env);
203 env->ExceptionClear();
204 }
205}
206
207// ----------------------------------------------------------------------------
208
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700209MtpDatabase::MtpDatabase(JNIEnv *env, jobject client)
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400210 : mDatabase(env->NewGlobalRef(client)),
211 mIntBuffer(NULL),
212 mLongBuffer(NULL),
213 mStringBuffer(NULL)
214{
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400215 // create buffers for out arguments
216 // we don't need to be thread-safe so this is OK
Elliott Hughes15dd15f2011-04-08 17:42:34 -0700217 jintArray intArray = env->NewIntArray(3);
218 if (!intArray) {
219 return; // Already threw.
220 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400221 mIntBuffer = (jintArray)env->NewGlobalRef(intArray);
Elliott Hughes15dd15f2011-04-08 17:42:34 -0700222 jlongArray longArray = env->NewLongArray(2);
223 if (!longArray) {
224 return; // Already threw.
225 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400226 mLongBuffer = (jlongArray)env->NewGlobalRef(longArray);
Mike Lockwood63ffd782014-09-24 10:55:19 -0700227 // Needs to be long enough to hold a file path for getObjectFilePath()
228 jcharArray charArray = env->NewCharArray(PATH_MAX + 1);
Elliott Hughes15dd15f2011-04-08 17:42:34 -0700229 if (!charArray) {
230 return; // Already threw.
231 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400232 mStringBuffer = (jcharArray)env->NewGlobalRef(charArray);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400233}
234
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700235void MtpDatabase::cleanup(JNIEnv *env) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400236 env->DeleteGlobalRef(mDatabase);
237 env->DeleteGlobalRef(mIntBuffer);
238 env->DeleteGlobalRef(mLongBuffer);
239 env->DeleteGlobalRef(mStringBuffer);
240}
241
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700242MtpDatabase::~MtpDatabase() {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400243}
244
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700245MtpObjectHandle MtpDatabase::beginSendObject(const char* path,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900246 MtpObjectFormat format,
247 MtpObjectHandle parent,
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700248 MtpStorageID storage) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400249 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood88394712010-09-27 10:01:00 -0400250 jstring pathStr = env->NewStringUTF(path);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400251 MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700252 pathStr, (jint)format, (jint)parent, (jint)storage);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400253
Mike Lockwood88394712010-09-27 10:01:00 -0400254 if (pathStr)
255 env->DeleteLocalRef(pathStr);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400256 checkAndClearExceptionFromCallback(env, __FUNCTION__);
257 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400258}
259
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700260void MtpDatabase::endSendObject(MtpObjectHandle handle, bool succeeded) {
261 JNIEnv* env = AndroidRuntime::getJNIEnv();
262 env->CallVoidMethod(mDatabase, method_endSendObject, (jint)handle, (jboolean)succeeded);
263
264 checkAndClearExceptionFromCallback(env, __FUNCTION__);
265}
266
267void MtpDatabase::rescanFile(const char* path, MtpObjectHandle handle,
268 MtpObjectFormat format) {
Mike Lockwoodd815f792010-07-12 08:49:01 -0400269 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood88394712010-09-27 10:01:00 -0400270 jstring pathStr = env->NewStringUTF(path);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700271 env->CallVoidMethod(mDatabase, method_rescanFile, pathStr,
272 (jint)handle, (jint)format);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400273
Mike Lockwood88394712010-09-27 10:01:00 -0400274 if (pathStr)
275 env->DeleteLocalRef(pathStr);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400276 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd815f792010-07-12 08:49:01 -0400277}
278
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700279MtpObjectHandleList* MtpDatabase::getObjectList(MtpStorageID storageID,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900280 MtpObjectFormat format,
281 MtpObjectHandle parent) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400282 JNIEnv* env = AndroidRuntime::getJNIEnv();
283 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList,
284 (jint)storageID, (jint)format, (jint)parent);
285 if (!array)
286 return NULL;
287 MtpObjectHandleList* list = new MtpObjectHandleList();
288 jint* handles = env->GetIntArrayElements(array, 0);
289 jsize length = env->GetArrayLength(array);
Mike Lockwood7a047c82010-08-02 10:52:20 -0400290 for (int i = 0; i < length; i++)
Jerry Zhangd9f30052018-03-27 15:29:09 -0700291 list->push_back(handles[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400292 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400293 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400294
295 checkAndClearExceptionFromCallback(env, __FUNCTION__);
296 return list;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400297}
298
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700299int MtpDatabase::getNumObjects(MtpStorageID storageID,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900300 MtpObjectFormat format,
301 MtpObjectHandle parent) {
Mike Lockwood7a047c82010-08-02 10:52:20 -0400302 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400303 int result = env->CallIntMethod(mDatabase, method_getNumObjects,
Mike Lockwood7a047c82010-08-02 10:52:20 -0400304 (jint)storageID, (jint)format, (jint)parent);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400305
306 checkAndClearExceptionFromCallback(env, __FUNCTION__);
307 return result;
Mike Lockwood7a047c82010-08-02 10:52:20 -0400308}
309
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700310MtpObjectFormatList* MtpDatabase::getSupportedPlaybackFormats() {
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400311 JNIEnv* env = AndroidRuntime::getJNIEnv();
312 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
313 method_getSupportedPlaybackFormats);
314 if (!array)
315 return NULL;
316 MtpObjectFormatList* list = new MtpObjectFormatList();
317 jint* formats = env->GetIntArrayElements(array, 0);
318 jsize length = env->GetArrayLength(array);
319 for (int i = 0; i < length; i++)
Jerry Zhangd9f30052018-03-27 15:29:09 -0700320 list->push_back(formats[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400321 env->ReleaseIntArrayElements(array, formats, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400322 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400323
324 checkAndClearExceptionFromCallback(env, __FUNCTION__);
325 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400326}
327
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700328MtpObjectFormatList* MtpDatabase::getSupportedCaptureFormats() {
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400329 JNIEnv* env = AndroidRuntime::getJNIEnv();
330 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
331 method_getSupportedCaptureFormats);
332 if (!array)
333 return NULL;
334 MtpObjectFormatList* list = new MtpObjectFormatList();
335 jint* formats = env->GetIntArrayElements(array, 0);
336 jsize length = env->GetArrayLength(array);
337 for (int i = 0; i < length; i++)
Jerry Zhangd9f30052018-03-27 15:29:09 -0700338 list->push_back(formats[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400339 env->ReleaseIntArrayElements(array, formats, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400340 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400341
342 checkAndClearExceptionFromCallback(env, __FUNCTION__);
343 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400344}
345
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700346MtpObjectPropertyList* MtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400347 JNIEnv* env = AndroidRuntime::getJNIEnv();
348 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
349 method_getSupportedObjectProperties, (jint)format);
350 if (!array)
351 return NULL;
352 MtpObjectPropertyList* list = new MtpObjectPropertyList();
353 jint* properties = env->GetIntArrayElements(array, 0);
354 jsize length = env->GetArrayLength(array);
355 for (int i = 0; i < length; i++)
Jerry Zhangd9f30052018-03-27 15:29:09 -0700356 list->push_back(properties[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400357 env->ReleaseIntArrayElements(array, properties, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400358 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400359
360 checkAndClearExceptionFromCallback(env, __FUNCTION__);
361 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400362}
363
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700364MtpDevicePropertyList* MtpDatabase::getSupportedDeviceProperties() {
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400365 JNIEnv* env = AndroidRuntime::getJNIEnv();
366 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
367 method_getSupportedDeviceProperties);
368 if (!array)
369 return NULL;
370 MtpDevicePropertyList* list = new MtpDevicePropertyList();
371 jint* properties = env->GetIntArrayElements(array, 0);
372 jsize length = env->GetArrayLength(array);
373 for (int i = 0; i < length; i++)
Jerry Zhangd9f30052018-03-27 15:29:09 -0700374 list->push_back(properties[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400375 env->ReleaseIntArrayElements(array, properties, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400376 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400377
378 checkAndClearExceptionFromCallback(env, __FUNCTION__);
379 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400380}
381
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700382MtpResponseCode MtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900383 MtpObjectProperty property,
384 MtpDataPacket& packet) {
385 static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
386 "Casting MtpObjectHandle to jint loses a value");
387 static_assert(sizeof(jint) >= sizeof(MtpObjectProperty),
388 "Casting MtpObjectProperty to jint loses a value");
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400389 JNIEnv* env = AndroidRuntime::getJNIEnv();
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900390 jobject list = env->CallObjectMethod(
391 mDatabase,
392 method_getObjectPropertyList,
393 static_cast<jint>(handle),
394 0,
395 static_cast<jint>(property),
396 0,
397 0);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700398 MtpResponseCode result = env->CallIntMethod(list, method_getCode);
399 jint count = env->CallIntMethod(list, method_getCount);
400 if (count != 1)
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400401 result = MTP_RESPONSE_GENERAL_ERROR;
402
403 if (result == MTP_RESPONSE_OK) {
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700404 jintArray objectHandlesArray = (jintArray)env->CallObjectMethod(list, method_getObjectHandles);
405 jintArray propertyCodesArray = (jintArray)env->CallObjectMethod(list, method_getPropertyCodes);
406 jintArray dataTypesArray = (jintArray)env->CallObjectMethod(list, method_getDataTypes);
407 jlongArray longValuesArray = (jlongArray)env->CallObjectMethod(list, method_getLongValues);
408 jobjectArray stringValuesArray = (jobjectArray)env->CallObjectMethod(list, method_getStringValues);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400409
410 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
411 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
412 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700413 jlong* longValues = env->GetLongArrayElements(longValuesArray, 0);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400414
415 int type = dataTypes[0];
416 jlong longValue = (longValues ? longValues[0] : 0);
417
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400418 switch (type) {
419 case MTP_TYPE_INT8:
420 packet.putInt8(longValue);
421 break;
422 case MTP_TYPE_UINT8:
423 packet.putUInt8(longValue);
424 break;
425 case MTP_TYPE_INT16:
426 packet.putInt16(longValue);
427 break;
428 case MTP_TYPE_UINT16:
429 packet.putUInt16(longValue);
430 break;
431 case MTP_TYPE_INT32:
432 packet.putInt32(longValue);
433 break;
434 case MTP_TYPE_UINT32:
435 packet.putUInt32(longValue);
436 break;
437 case MTP_TYPE_INT64:
438 packet.putInt64(longValue);
439 break;
440 case MTP_TYPE_UINT64:
441 packet.putUInt64(longValue);
442 break;
443 case MTP_TYPE_INT128:
444 packet.putInt128(longValue);
445 break;
446 case MTP_TYPE_UINT128:
Wanwu Peng8937f1a2016-03-02 18:16:46 +0800447 packet.putUInt128(longValue);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400448 break;
449 case MTP_TYPE_STR:
450 {
451 jstring stringValue = (jstring)env->GetObjectArrayElement(stringValuesArray, 0);
Martin Blumenstingl17a24c52014-05-31 15:50:38 +0200452 const char* str = (stringValue ? env->GetStringUTFChars(stringValue, NULL) : NULL);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400453 if (stringValue) {
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400454 packet.putString(str);
455 env->ReleaseStringUTFChars(stringValue, str);
456 } else {
457 packet.putEmptyString();
458 }
Martin Blumenstingl17a24c52014-05-31 15:50:38 +0200459 env->DeleteLocalRef(stringValue);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400460 break;
461 }
462 default:
Steve Block3762c312012-01-06 19:20:56 +0000463 ALOGE("unsupported type in getObjectPropertyValue\n");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400464 result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
465 }
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400466 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
467 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
468 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700469 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400470
471 env->DeleteLocalRef(objectHandlesArray);
472 env->DeleteLocalRef(propertyCodesArray);
473 env->DeleteLocalRef(dataTypesArray);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700474 env->DeleteLocalRef(longValuesArray);
475 env->DeleteLocalRef(stringValuesArray);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400476 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400477
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400478 env->DeleteLocalRef(list);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400479 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400480 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400481}
482
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800483static bool readLongValue(int type, MtpDataPacket& packet, jlong& longValue) {
484 switch (type) {
485 case MTP_TYPE_INT8: {
486 int8_t temp;
487 if (!packet.getInt8(temp)) return false;
488 longValue = temp;
489 break;
490 }
491 case MTP_TYPE_UINT8: {
492 uint8_t temp;
493 if (!packet.getUInt8(temp)) return false;
494 longValue = temp;
495 break;
496 }
497 case MTP_TYPE_INT16: {
498 int16_t temp;
499 if (!packet.getInt16(temp)) return false;
500 longValue = temp;
501 break;
502 }
503 case MTP_TYPE_UINT16: {
504 uint16_t temp;
505 if (!packet.getUInt16(temp)) return false;
506 longValue = temp;
507 break;
508 }
509 case MTP_TYPE_INT32: {
510 int32_t temp;
511 if (!packet.getInt32(temp)) return false;
512 longValue = temp;
513 break;
514 }
515 case MTP_TYPE_UINT32: {
516 uint32_t temp;
517 if (!packet.getUInt32(temp)) return false;
518 longValue = temp;
519 break;
520 }
521 case MTP_TYPE_INT64: {
522 int64_t temp;
523 if (!packet.getInt64(temp)) return false;
524 longValue = temp;
525 break;
526 }
527 case MTP_TYPE_UINT64: {
528 uint64_t temp;
529 if (!packet.getUInt64(temp)) return false;
530 longValue = temp;
531 break;
532 }
533 default:
534 ALOGE("unsupported type in readLongValue");
535 return false;
536 }
537 return true;
538}
539
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700540MtpResponseCode MtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900541 MtpObjectProperty property,
542 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400543 int type;
544
545 if (!getObjectPropertyInfo(property, type))
546 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
547
548 JNIEnv* env = AndroidRuntime::getJNIEnv();
549 jlong longValue = 0;
550 jstring stringValue = NULL;
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800551 MtpResponseCode result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400552
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800553 if (type == MTP_TYPE_STR) {
554 MtpStringBuffer buffer;
555 if (!packet.getString(buffer)) goto fail;
556 stringValue = env->NewStringUTF((const char *)buffer);
557 } else {
558 if (!readLongValue(type, packet, longValue)) goto fail;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400559 }
560
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800561 result = env->CallIntMethod(mDatabase, method_setObjectProperty,
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400562 (jint)handle, (jint)property, longValue, stringValue);
Mike Lockwood88394712010-09-27 10:01:00 -0400563 if (stringValue)
564 env->DeleteLocalRef(stringValue);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400565
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800566fail:
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400567 checkAndClearExceptionFromCallback(env, __FUNCTION__);
568 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400569}
570
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700571MtpResponseCode MtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900572 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400573 JNIEnv* env = AndroidRuntime::getJNIEnv();
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700574 int type;
Mike Lockwood56c85242014-03-07 13:29:08 -0800575
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700576 if (!getDevicePropertyInfo(property, type))
577 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
Mike Lockwood56c85242014-03-07 13:29:08 -0800578
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700579 jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
580 (jint)property, mLongBuffer, mStringBuffer);
581 if (result != MTP_RESPONSE_OK) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400582 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700583 return result;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400584 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700585
586 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
587 jlong longValue = longValues[0];
588 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
589
590 switch (type) {
591 case MTP_TYPE_INT8:
592 packet.putInt8(longValue);
593 break;
594 case MTP_TYPE_UINT8:
595 packet.putUInt8(longValue);
596 break;
597 case MTP_TYPE_INT16:
598 packet.putInt16(longValue);
599 break;
600 case MTP_TYPE_UINT16:
601 packet.putUInt16(longValue);
602 break;
603 case MTP_TYPE_INT32:
604 packet.putInt32(longValue);
605 break;
606 case MTP_TYPE_UINT32:
607 packet.putUInt32(longValue);
608 break;
609 case MTP_TYPE_INT64:
610 packet.putInt64(longValue);
611 break;
612 case MTP_TYPE_UINT64:
613 packet.putUInt64(longValue);
614 break;
615 case MTP_TYPE_INT128:
616 packet.putInt128(longValue);
617 break;
618 case MTP_TYPE_UINT128:
619 packet.putInt128(longValue);
620 break;
621 case MTP_TYPE_STR:
622 {
623 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
624 packet.putString(str);
625 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
626 break;
627 }
628 default:
629 ALOGE("unsupported type in getDevicePropertyValue\n");
630 return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
631 }
632
633 checkAndClearExceptionFromCallback(env, __FUNCTION__);
634 return MTP_RESPONSE_OK;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400635}
636
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700637MtpResponseCode MtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900638 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400639 int type;
640
641 if (!getDevicePropertyInfo(property, type))
642 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
643
644 JNIEnv* env = AndroidRuntime::getJNIEnv();
645 jlong longValue = 0;
646 jstring stringValue = NULL;
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800647 MtpResponseCode result = MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400648
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800649 if (type == MTP_TYPE_STR) {
650 MtpStringBuffer buffer;
651 if (!packet.getString(buffer)) goto fail;
652 stringValue = env->NewStringUTF((const char *)buffer);
653 } else {
654 if (!readLongValue(type, packet, longValue)) goto fail;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400655 }
656
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800657 result = env->CallIntMethod(mDatabase, method_setDeviceProperty,
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400658 (jint)property, longValue, stringValue);
Mike Lockwood88394712010-09-27 10:01:00 -0400659 if (stringValue)
660 env->DeleteLocalRef(stringValue);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400661
Mike Lockwood9c803fa2014-11-13 09:40:42 -0800662fail:
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400663 checkAndClearExceptionFromCallback(env, __FUNCTION__);
664 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400665}
666
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700667MtpResponseCode MtpDatabase::resetDeviceProperty(MtpDeviceProperty /*property*/) {
Mike Lockwood828d19d2010-08-10 15:20:35 -0400668 return -1;
669}
670
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700671MtpResponseCode MtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900672 uint32_t format, uint32_t property,
673 int groupCode, int depth,
674 MtpDataPacket& packet) {
675 static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
676 "Casting MtpObjectHandle to jint loses a value");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400677 JNIEnv* env = AndroidRuntime::getJNIEnv();
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900678 jobject list = env->CallObjectMethod(
679 mDatabase,
680 method_getObjectPropertyList,
681 static_cast<jint>(handle),
682 static_cast<jint>(format),
683 static_cast<jint>(property),
684 static_cast<jint>(groupCode),
685 static_cast<jint>(depth));
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500686 checkAndClearExceptionFromCallback(env, __FUNCTION__);
687 if (!list)
688 return MTP_RESPONSE_GENERAL_ERROR;
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700689 int count = env->CallIntMethod(list, method_getCount);
690 MtpResponseCode result = env->CallIntMethod(list, method_getCode);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400691
692 packet.putUInt32(count);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400693 if (count > 0) {
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700694 jintArray objectHandlesArray = (jintArray)env->CallObjectMethod(list, method_getObjectHandles);
695 jintArray propertyCodesArray = (jintArray)env->CallObjectMethod(list, method_getPropertyCodes);
696 jintArray dataTypesArray = (jintArray)env->CallObjectMethod(list, method_getDataTypes);
697 jlongArray longValuesArray = (jlongArray)env->CallObjectMethod(list, method_getLongValues);
698 jobjectArray stringValuesArray = (jobjectArray)env->CallObjectMethod(list, method_getStringValues);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400699
700 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
701 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
702 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
703 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
704
705 for (int i = 0; i < count; i++) {
706 packet.putUInt32(objectHandles[i]);
707 packet.putUInt16(propertyCodes[i]);
708 int type = dataTypes[i];
709 packet.putUInt16(type);
710
George Burgess IVa8626ae2016-12-13 16:12:10 -0800711 if (type == MTP_TYPE_STR) {
712 jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i);
713 const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL);
714 if (valueStr) {
715 packet.putString(valueStr);
716 env->ReleaseStringUTFChars(value, valueStr);
717 } else {
718 packet.putEmptyString();
719 }
720 env->DeleteLocalRef(value);
721 continue;
722 }
723
724 if (!longValues) {
725 ALOGE("bad longValuesArray value in MyMtpDatabase::getObjectPropertyList");
726 continue;
727 }
728
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400729 switch (type) {
730 case MTP_TYPE_INT8:
731 packet.putInt8(longValues[i]);
732 break;
733 case MTP_TYPE_UINT8:
734 packet.putUInt8(longValues[i]);
735 break;
736 case MTP_TYPE_INT16:
737 packet.putInt16(longValues[i]);
738 break;
739 case MTP_TYPE_UINT16:
740 packet.putUInt16(longValues[i]);
741 break;
742 case MTP_TYPE_INT32:
743 packet.putInt32(longValues[i]);
744 break;
745 case MTP_TYPE_UINT32:
746 packet.putUInt32(longValues[i]);
747 break;
748 case MTP_TYPE_INT64:
749 packet.putInt64(longValues[i]);
750 break;
751 case MTP_TYPE_UINT64:
752 packet.putUInt64(longValues[i]);
753 break;
754 case MTP_TYPE_INT128:
755 packet.putInt128(longValues[i]);
756 break;
757 case MTP_TYPE_UINT128:
758 packet.putUInt128(longValues[i]);
759 break;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400760 default:
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700761 ALOGE("bad or unsupported data type in MtpDatabase::getObjectPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400762 break;
763 }
764 }
765
766 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
767 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
768 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700769 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400770
771 env->DeleteLocalRef(objectHandlesArray);
772 env->DeleteLocalRef(propertyCodesArray);
773 env->DeleteLocalRef(dataTypesArray);
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700774 env->DeleteLocalRef(longValuesArray);
775 env->DeleteLocalRef(stringValuesArray);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400776 }
777
778 env->DeleteLocalRef(list);
779 checkAndClearExceptionFromCallback(env, __FUNCTION__);
780 return result;
781}
782
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800783static void foreachentry(ExifEntry *entry, void* /* user */) {
Marco Nelissen3cd393c2014-01-10 10:39:27 -0800784 char buf[1024];
785 ALOGI("entry %x, format %d, size %d: %s",
786 entry->tag, entry->format, entry->size, exif_entry_get_value(entry, buf, sizeof(buf)));
787}
788
789static void foreachcontent(ExifContent *content, void *user) {
790 ALOGI("content %d", exif_content_get_ifd(content));
791 exif_content_foreach_entry(content, foreachentry, user);
792}
793
794static long getLongFromExifEntry(ExifEntry *e) {
795 ExifByteOrder o = exif_data_get_byte_order(e->parent->parent);
796 return exif_get_long(e->data, o);
797}
798
Chong Zhang63f81922018-03-14 18:57:05 -0700799static ExifData *getExifFromExtractor(const char *path) {
800 std::unique_ptr<uint8_t[]> exifBuf;
801 ExifData *exifdata = NULL;
802
803 FILE *fp = fopen (path, "rb");
804 if (!fp) {
805 ALOGE("failed to open file");
806 return NULL;
807 }
808
809 sp<NuMediaExtractor> extractor = new NuMediaExtractor();
810 fseek(fp, 0L, SEEK_END);
811 if (extractor->setDataSource(fileno(fp), 0, ftell(fp)) != OK) {
812 ALOGE("failed to setDataSource");
813 fclose(fp);
814 return NULL;
815 }
816
817 off64_t offset;
818 size_t size;
819 if (extractor->getExifOffsetSize(&offset, &size) != OK) {
820 fclose(fp);
821 return NULL;
822 }
823
824 exifBuf.reset(new uint8_t[size]);
825 fseek(fp, offset, SEEK_SET);
826 if (fread(exifBuf.get(), 1, size, fp) == size) {
827 exifdata = exif_data_new_from_data(exifBuf.get(), size);
828 }
829
830 fclose(fp);
831 return exifdata;
832}
833
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700834MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
Daichi Hirono486ad2e2016-02-29 17:28:47 +0900835 MtpObjectInfo& info) {
Jerry Zhangd9f30052018-03-27 15:29:09 -0700836 MtpStringBuffer path;
Mike Lockwoodf6f16612012-09-12 15:50:59 -0700837 int64_t length;
838 MtpObjectFormat format;
839
840 MtpResponseCode result = getObjectFilePath(handle, path, length, format);
841 if (result != MTP_RESPONSE_OK) {
842 return result;
843 }
844 info.mCompressedSize = (length > 0xFFFFFFFFLL ? 0xFFFFFFFF : (uint32_t)length);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400845
846 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwoodf6f16612012-09-12 15:50:59 -0700847 if (!env->CallBooleanMethod(mDatabase, method_getObjectInfo,
848 (jint)handle, mIntBuffer, mStringBuffer, mLongBuffer)) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400849 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
Mike Lockwoodf6f16612012-09-12 15:50:59 -0700850 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400851
852 jint* intValues = env->GetIntArrayElements(mIntBuffer, 0);
Mike Lockwood9df53fae2011-04-21 17:05:55 -0700853 info.mStorageID = intValues[0];
854 info.mFormat = intValues[1];
855 info.mParent = intValues[2];
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400856 env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
857
858 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
Mike Lockwood1341f1e2013-04-01 10:52:47 -0700859 info.mDateCreated = longValues[0];
860 info.mDateModified = longValues[1];
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400861 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
862
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800863 if ((false)) {
864 info.mAssociationType = (format == MTP_FORMAT_ASSOCIATION ?
865 MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
866 MTP_ASSOCIATION_TYPE_UNDEFINED);
867 }
Mike Lockwood9df53fae2011-04-21 17:05:55 -0700868 info.mAssociationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400869
870 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
Jerry Zhangd9f30052018-03-27 15:29:09 -0700871 MtpStringBuffer temp(str);
872 info.mName = strdup(temp);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400873 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
874
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700875 // read EXIF data for thumbnail information
Jaesung Chung8409c062016-01-19 10:48:30 +0900876 switch (info.mFormat) {
877 case MTP_FORMAT_EXIF_JPEG:
Chong Zhang6e18cce2017-08-16 11:57:02 -0700878 case MTP_FORMAT_HEIF:
Jaesung Chung8409c062016-01-19 10:48:30 +0900879 case MTP_FORMAT_JFIF: {
Chong Zhang63f81922018-03-14 18:57:05 -0700880 ExifData *exifdata;
881 if (info.mFormat == MTP_FORMAT_HEIF) {
882 exifdata = getExifFromExtractor(path);
883 } else {
884 exifdata = exif_data_new_from_file(path);
885 }
Jaesung Chung8409c062016-01-19 10:48:30 +0900886 if (exifdata) {
887 if ((false)) {
888 exif_data_foreach_content(exifdata, foreachcontent, NULL);
889 }
Marco Nelissen3cd393c2014-01-10 10:39:27 -0800890
Jaesung Chung8409c062016-01-19 10:48:30 +0900891 ExifEntry *w = exif_content_get_entry(
892 exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_X_DIMENSION);
893 ExifEntry *h = exif_content_get_entry(
894 exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_Y_DIMENSION);
895 info.mThumbCompressedSize = exifdata->data ? exifdata->size : 0;
896 info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
897 info.mImagePixWidth = w ? getLongFromExifEntry(w) : 0;
898 info.mImagePixHeight = h ? getLongFromExifEntry(h) : 0;
899 exif_data_unref(exifdata);
900 }
901 break;
902 }
903
904 // Except DNG, all supported RAW image formats are not defined in PTP 1.2 specification.
905 // Most of RAW image formats are based on TIFF or TIFF/EP. To render Fuji's RAF format,
906 // it checks MTP_FORMAT_DEFINED case since it's designed as a custom format.
907 case MTP_FORMAT_DNG:
908 case MTP_FORMAT_TIFF:
909 case MTP_FORMAT_TIFF_EP:
910 case MTP_FORMAT_DEFINED: {
Jerry Zhangd9f30052018-03-27 15:29:09 -0700911 String8 temp(path);
912 std::unique_ptr<FileStream> stream(new FileStream(temp));
Jaesung Chung8409c062016-01-19 10:48:30 +0900913 piex::PreviewImageData image_data;
Jerry Zhangd9f30052018-03-27 15:29:09 -0700914 if (!GetExifFromRawImage(stream.get(), temp, image_data)) {
Jaesung Chung8409c062016-01-19 10:48:30 +0900915 // Couldn't parse EXIF data from a image file via piex.
916 break;
Andreas Gampe5a15d0d2014-11-10 18:19:40 -0800917 }
Marco Nelissen3cd393c2014-01-10 10:39:27 -0800918
Jaesung Chungfd3446e2016-04-06 21:42:39 +0900919 info.mThumbCompressedSize = image_data.thumbnail.length;
Marco Nelissen3cd393c2014-01-10 10:39:27 -0800920 info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
Jaesung Chung8409c062016-01-19 10:48:30 +0900921 info.mImagePixWidth = image_data.full_width;
922 info.mImagePixHeight = image_data.full_height;
923
924 break;
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700925 }
926 }
927
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400928 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400929 return MTP_RESPONSE_OK;
930}
931
Jerry Zhangf9c5c252017-08-16 18:07:51 -0700932void* MtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
Jerry Zhangd9f30052018-03-27 15:29:09 -0700933 MtpStringBuffer path;
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700934 int64_t length;
935 MtpObjectFormat format;
936 void* result = NULL;
937 outThumbSize = 0;
938
Jaesung Chung8409c062016-01-19 10:48:30 +0900939 if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK) {
940 switch (format) {
941 case MTP_FORMAT_EXIF_JPEG:
Chong Zhang6e18cce2017-08-16 11:57:02 -0700942 case MTP_FORMAT_HEIF:
Jaesung Chung8409c062016-01-19 10:48:30 +0900943 case MTP_FORMAT_JFIF: {
Chong Zhang63f81922018-03-14 18:57:05 -0700944 ExifData *exifdata;
945 if (format == MTP_FORMAT_HEIF) {
946 exifdata = getExifFromExtractor(path);
947 } else {
948 exifdata = exif_data_new_from_file(path);
949 }
Jaesung Chung8409c062016-01-19 10:48:30 +0900950 if (exifdata) {
951 if (exifdata->data) {
952 result = malloc(exifdata->size);
953 if (result) {
954 memcpy(result, exifdata->data, exifdata->size);
955 outThumbSize = exifdata->size;
956 }
957 }
958 exif_data_unref(exifdata);
Marco Nelissen3cd393c2014-01-10 10:39:27 -0800959 }
Jaesung Chung8409c062016-01-19 10:48:30 +0900960 break;
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700961 }
Jaesung Chung8409c062016-01-19 10:48:30 +0900962
963 // See the above comment on getObjectInfo() method.
964 case MTP_FORMAT_DNG:
965 case MTP_FORMAT_TIFF:
966 case MTP_FORMAT_TIFF_EP:
967 case MTP_FORMAT_DEFINED: {
Jerry Zhangd9f30052018-03-27 15:29:09 -0700968 String8 temp(path);
969 std::unique_ptr<FileStream> stream(new FileStream(temp));
Jaesung Chung8409c062016-01-19 10:48:30 +0900970 piex::PreviewImageData image_data;
Jerry Zhangd9f30052018-03-27 15:29:09 -0700971 if (!GetExifFromRawImage(stream.get(), temp, image_data)) {
Jaesung Chung8409c062016-01-19 10:48:30 +0900972 // Couldn't parse EXIF data from a image file via piex.
973 break;
974 }
975
Jaesung Chung742e89f2016-04-13 14:13:10 +0900976 if (image_data.thumbnail.length == 0
Insun Kang82c2ce12016-04-19 17:56:10 +0900977 || image_data.thumbnail.format != ::piex::Image::kJpegCompressed) {
Jaesung Chung742e89f2016-04-13 14:13:10 +0900978 // No thumbnail or non jpeg thumbnail.
Jaesung Chung8409c062016-01-19 10:48:30 +0900979 break;
980 }
981
Jaesung Chungfd3446e2016-04-06 21:42:39 +0900982 result = malloc(image_data.thumbnail.length);
Jaesung Chung8409c062016-01-19 10:48:30 +0900983 if (result) {
984 piex::Error err = stream.get()->GetData(
Jaesung Chungfd3446e2016-04-06 21:42:39 +0900985 image_data.thumbnail.offset,
986 image_data.thumbnail.length,
Jaesung Chung8409c062016-01-19 10:48:30 +0900987 (std::uint8_t *)result);
988 if (err == piex::Error::kOk) {
Jaesung Chungfd3446e2016-04-06 21:42:39 +0900989 outThumbSize = image_data.thumbnail.length;
Jaesung Chung8409c062016-01-19 10:48:30 +0900990 } else {
991 free(result);
Chong Zhange6b98532017-10-24 16:07:18 -0700992 result = NULL;
Jaesung Chung8409c062016-01-19 10:48:30 +0900993 }
994 }
995 break;
996 }
Mike Lockwoodc89f2222011-04-24 18:40:17 -0700997 }
998 }
999
1000 return result;
1001}
1002
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001003MtpResponseCode MtpDatabase::getObjectFilePath(MtpObjectHandle handle,
Jerry Zhangd9f30052018-03-27 15:29:09 -07001004 MtpStringBuffer& outFilePath,
Daichi Hirono486ad2e2016-02-29 17:28:47 +09001005 int64_t& outFileLength,
1006 MtpObjectFormat& outFormat) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001007 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood59c777a2010-08-02 10:37:41 -04001008 jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath,
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001009 (jint)handle, mStringBuffer, mLongBuffer);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001010 if (result != MTP_RESPONSE_OK) {
1011 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -04001012 return result;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001013 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001014
1015 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
Jerry Zhangd9f30052018-03-27 15:29:09 -07001016 outFilePath.set(str);
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001017 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
1018
1019 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
Mike Lockwood365e03e2010-12-08 16:08:01 -08001020 outFileLength = longValues[0];
1021 outFormat = longValues[1];
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001022 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
Elliott Hughes15dd15f2011-04-08 17:42:34 -07001023
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001024 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -04001025 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001026}
1027
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001028MtpResponseCode MtpDatabase::beginDeleteObject(MtpObjectHandle handle) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001029 JNIEnv* env = AndroidRuntime::getJNIEnv();
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001030 MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginDeleteObject, (jint)handle);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001031
1032 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1033 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001034}
1035
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001036void MtpDatabase::endDeleteObject(MtpObjectHandle handle, bool succeeded) {
Jerry Zhang952558d2017-09-26 17:49:52 -07001037 JNIEnv* env = AndroidRuntime::getJNIEnv();
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001038 env->CallVoidMethod(mDatabase, method_endDeleteObject, (jint)handle, (jboolean) succeeded);
Jerry Zhang952558d2017-09-26 17:49:52 -07001039
1040 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001041}
1042
1043MtpResponseCode MtpDatabase::beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
1044 MtpStorageID newStorage) {
1045 JNIEnv* env = AndroidRuntime::getJNIEnv();
1046 MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginMoveObject,
1047 (jint)handle, (jint)newParent, (jint) newStorage);
1048
1049 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Jerry Zhang952558d2017-09-26 17:49:52 -07001050 return result;
1051}
1052
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001053void MtpDatabase::endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
1054 MtpStorageID oldStorage, MtpStorageID newStorage,
1055 MtpObjectHandle handle, bool succeeded) {
1056 JNIEnv* env = AndroidRuntime::getJNIEnv();
1057 env->CallVoidMethod(mDatabase, method_endMoveObject,
1058 (jint)oldParent, (jint) newParent, (jint) oldStorage, (jint) newStorage,
1059 (jint) handle, (jboolean) succeeded);
1060
1061 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1062}
1063
1064MtpResponseCode MtpDatabase::beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
1065 MtpStorageID newStorage) {
1066 JNIEnv* env = AndroidRuntime::getJNIEnv();
1067 MtpResponseCode result = env->CallIntMethod(mDatabase, method_beginCopyObject,
1068 (jint)handle, (jint)newParent, (jint) newStorage);
1069
1070 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1071 return result;
1072}
1073
1074void MtpDatabase::endCopyObject(MtpObjectHandle handle, bool succeeded) {
1075 JNIEnv* env = AndroidRuntime::getJNIEnv();
1076 env->CallVoidMethod(mDatabase, method_endCopyObject, (jint)handle, (jboolean)succeeded);
1077
1078 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1079}
1080
1081
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001082struct PropertyTableEntry {
1083 MtpObjectProperty property;
1084 int type;
1085};
1086
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001087static const PropertyTableEntry kObjectPropertyTable[] = {
Mike Lockwoodd3bfecb2010-09-23 23:04:28 -04001088 { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 },
1089 { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 },
1090 { MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16 },
1091 { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 },
1092 { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR },
1093 { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR },
1094 { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 },
1095 { MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128 },
1096 { MTP_PROPERTY_NAME, MTP_TYPE_STR },
Mike Lockwoodae078f72010-09-26 12:35:51 -04001097 { MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR },
1098 { MTP_PROPERTY_DATE_ADDED, MTP_TYPE_STR },
1099 { MTP_PROPERTY_ARTIST, MTP_TYPE_STR },
1100 { MTP_PROPERTY_ALBUM_NAME, MTP_TYPE_STR },
1101 { MTP_PROPERTY_ALBUM_ARTIST, MTP_TYPE_STR },
1102 { MTP_PROPERTY_TRACK, MTP_TYPE_UINT16 },
1103 { MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_TYPE_STR },
1104 { MTP_PROPERTY_GENRE, MTP_TYPE_STR },
1105 { MTP_PROPERTY_COMPOSER, MTP_TYPE_STR },
1106 { MTP_PROPERTY_DURATION, MTP_TYPE_UINT32 },
1107 { MTP_PROPERTY_DESCRIPTION, MTP_TYPE_STR },
Mike Lockwood71827742015-01-23 10:50:08 -08001108 { MTP_PROPERTY_AUDIO_WAVE_CODEC, MTP_TYPE_UINT32 },
1109 { MTP_PROPERTY_BITRATE_TYPE, MTP_TYPE_UINT16 },
1110 { MTP_PROPERTY_AUDIO_BITRATE, MTP_TYPE_UINT32 },
1111 { MTP_PROPERTY_NUMBER_OF_CHANNELS,MTP_TYPE_UINT16 },
1112 { MTP_PROPERTY_SAMPLE_RATE, MTP_TYPE_UINT32 },
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001113};
1114
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001115static const PropertyTableEntry kDevicePropertyTable[] = {
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001116 { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_STR },
1117 { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR },
1118 { MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR },
Mike Lockwood56c85242014-03-07 13:29:08 -08001119 { MTP_DEVICE_PROPERTY_BATTERY_LEVEL, MTP_TYPE_UINT8 },
Jerry Zhang13bb2f42016-12-14 15:39:29 -08001120 { MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE, MTP_TYPE_UINT32 },
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001121};
1122
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001123bool MtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001124 int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
1125 const PropertyTableEntry* entry = kObjectPropertyTable;
1126 for (int i = 0; i < count; i++, entry++) {
1127 if (entry->property == property) {
1128 type = entry->type;
1129 return true;
1130 }
1131 }
1132 return false;
1133}
1134
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001135bool MtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001136 int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
1137 const PropertyTableEntry* entry = kDevicePropertyTable;
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001138 for (int i = 0; i < count; i++, entry++) {
1139 if (entry->property == property) {
1140 type = entry->type;
1141 return true;
1142 }
1143 }
1144 return false;
1145}
1146
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001147MtpObjectHandleList* MtpDatabase::getObjectReferences(MtpObjectHandle handle) {
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001148 JNIEnv* env = AndroidRuntime::getJNIEnv();
1149 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectReferences,
1150 (jint)handle);
1151 if (!array)
1152 return NULL;
1153 MtpObjectHandleList* list = new MtpObjectHandleList();
1154 jint* handles = env->GetIntArrayElements(array, 0);
1155 jsize length = env->GetArrayLength(array);
1156 for (int i = 0; i < length; i++)
Jerry Zhangd9f30052018-03-27 15:29:09 -07001157 list->push_back(handles[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001158 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood88394712010-09-27 10:01:00 -04001159 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001160
1161 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1162 return list;
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001163}
1164
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001165MtpResponseCode MtpDatabase::setObjectReferences(MtpObjectHandle handle,
Daichi Hirono486ad2e2016-02-29 17:28:47 +09001166 MtpObjectHandleList* references) {
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001167 JNIEnv* env = AndroidRuntime::getJNIEnv();
1168 int count = references->size();
1169 jintArray array = env->NewIntArray(count);
1170 if (!array) {
Steve Block3762c312012-01-06 19:20:56 +00001171 ALOGE("out of memory in setObjectReferences");
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001172 return false;
1173 }
1174 jint* handles = env->GetIntArrayElements(array, 0);
1175 for (int i = 0; i < count; i++)
1176 handles[i] = (*references)[i];
1177 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001178 MtpResponseCode result = env->CallIntMethod(mDatabase, method_setObjectReferences,
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001179 (jint)handle, array);
Mike Lockwood88394712010-09-27 10:01:00 -04001180 env->DeleteLocalRef(array);
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001181
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -04001182 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1183 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001184}
1185
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001186MtpProperty* MtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
Daichi Hirono486ad2e2016-02-29 17:28:47 +09001187 MtpObjectFormat format) {
Mike Lockwood92b53bc2014-03-13 14:51:29 -07001188 static const int channelEnum[] = {
1189 1, // mono
1190 2, // stereo
1191 3, // 2.1
1192 4, // 3
1193 5, // 3.1
1194 6, // 4
1195 7, // 4.1
1196 8, // 5
1197 9, // 5.1
1198 };
1199 static const int bitrateEnum[] = {
1200 1, // fixed rate
1201 2, // variable rate
1202 };
1203
Mike Lockwood828d19d2010-08-10 15:20:35 -04001204 MtpProperty* result = NULL;
1205 switch (property) {
1206 case MTP_PROPERTY_OBJECT_FORMAT:
Mike Lockwood9b5e9c42010-12-07 18:53:50 -08001207 // use format as default value
1208 result = new MtpProperty(property, MTP_TYPE_UINT16, false, format);
1209 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -04001210 case MTP_PROPERTY_PROTECTION_STATUS:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001211 case MTP_PROPERTY_TRACK:
Mike Lockwood828d19d2010-08-10 15:20:35 -04001212 result = new MtpProperty(property, MTP_TYPE_UINT16);
1213 break;
1214 case MTP_PROPERTY_STORAGE_ID:
1215 case MTP_PROPERTY_PARENT_OBJECT:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001216 case MTP_PROPERTY_DURATION:
Mike Lockwood92b53bc2014-03-13 14:51:29 -07001217 case MTP_PROPERTY_AUDIO_WAVE_CODEC:
Mike Lockwood828d19d2010-08-10 15:20:35 -04001218 result = new MtpProperty(property, MTP_TYPE_UINT32);
1219 break;
1220 case MTP_PROPERTY_OBJECT_SIZE:
1221 result = new MtpProperty(property, MTP_TYPE_UINT64);
1222 break;
1223 case MTP_PROPERTY_PERSISTENT_UID:
1224 result = new MtpProperty(property, MTP_TYPE_UINT128);
1225 break;
Mike Lockwoodd3bfecb2010-09-23 23:04:28 -04001226 case MTP_PROPERTY_NAME:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001227 case MTP_PROPERTY_DISPLAY_NAME:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001228 case MTP_PROPERTY_ARTIST:
1229 case MTP_PROPERTY_ALBUM_NAME:
1230 case MTP_PROPERTY_ALBUM_ARTIST:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001231 case MTP_PROPERTY_GENRE:
1232 case MTP_PROPERTY_COMPOSER:
1233 case MTP_PROPERTY_DESCRIPTION:
Mike Lockwood828d19d2010-08-10 15:20:35 -04001234 result = new MtpProperty(property, MTP_TYPE_STR);
1235 break;
Mike Lockwood5b19af02010-11-23 18:38:55 -05001236 case MTP_PROPERTY_DATE_MODIFIED:
1237 case MTP_PROPERTY_DATE_ADDED:
1238 case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
1239 result = new MtpProperty(property, MTP_TYPE_STR);
1240 result->setFormDateTime();
1241 break;
Mike Lockwood5ebac832010-10-12 11:33:47 -04001242 case MTP_PROPERTY_OBJECT_FILE_NAME:
Mike Lockwood6a6a3af2010-10-12 14:19:51 -04001243 // We allow renaming files and folders
1244 result = new MtpProperty(property, MTP_TYPE_STR, true);
Mike Lockwood5ebac832010-10-12 11:33:47 -04001245 break;
Mike Lockwood92b53bc2014-03-13 14:51:29 -07001246 case MTP_PROPERTY_BITRATE_TYPE:
1247 result = new MtpProperty(property, MTP_TYPE_UINT16);
1248 result->setFormEnum(bitrateEnum, sizeof(bitrateEnum)/sizeof(bitrateEnum[0]));
1249 break;
1250 case MTP_PROPERTY_AUDIO_BITRATE:
1251 result = new MtpProperty(property, MTP_TYPE_UINT32);
1252 result->setFormRange(1, 1536000, 1);
1253 break;
1254 case MTP_PROPERTY_NUMBER_OF_CHANNELS:
1255 result = new MtpProperty(property, MTP_TYPE_UINT16);
1256 result->setFormEnum(channelEnum, sizeof(channelEnum)/sizeof(channelEnum[0]));
1257 break;
1258 case MTP_PROPERTY_SAMPLE_RATE:
1259 result = new MtpProperty(property, MTP_TYPE_UINT32);
1260 result->setFormRange(8000, 48000, 1);
1261 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -04001262 }
1263
1264 return result;
1265}
1266
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001267MtpProperty* MtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001268 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001269 MtpProperty* result = NULL;
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001270 bool writable = false;
1271
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001272 // get current value
1273 jint ret = env->CallIntMethod(mDatabase, method_getDeviceProperty,
1274 (jint)property, mLongBuffer, mStringBuffer);
1275 if (ret == MTP_RESPONSE_OK) {
1276 switch (property) {
1277 case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
1278 case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
1279 writable = true;
1280 // fall through
Ray Essick67004bc2018-11-01 13:57:11 -07001281 FALLTHROUGH_INTENDED;
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001282 case MTP_DEVICE_PROPERTY_IMAGE_SIZE:
1283 {
1284 result = new MtpProperty(property, MTP_TYPE_STR, writable);
Mike Lockwooda2a21282010-09-25 21:21:05 -04001285 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
1286 result->setCurrentValue(str);
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001287 // for read-only properties it is safe to assume current value is default value
1288 if (!writable)
1289 result->setDefaultValue(str);
Mike Lockwooda2a21282010-09-25 21:21:05 -04001290 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001291 break;
Mike Lockwooda2a21282010-09-25 21:21:05 -04001292 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001293 case MTP_DEVICE_PROPERTY_BATTERY_LEVEL:
1294 {
1295 result = new MtpProperty(property, MTP_TYPE_UINT8);
1296 jlong* arr = env->GetLongArrayElements(mLongBuffer, 0);
1297 result->setFormRange(0, arr[1], 1);
1298 result->mCurrentValue.u.u8 = (uint8_t) arr[0];
1299 env->ReleaseLongArrayElements(mLongBuffer, arr, 0);
1300 break;
1301 }
1302 case MTP_DEVICE_PROPERTY_PERCEIVED_DEVICE_TYPE:
1303 {
1304 jlong* arr = env->GetLongArrayElements(mLongBuffer, 0);
1305 result = new MtpProperty(property, MTP_TYPE_UINT32);
1306 result->mCurrentValue.u.u32 = (uint32_t) arr[0];
1307 env->ReleaseLongArrayElements(mLongBuffer, arr, 0);
1308 break;
1309 }
1310 default:
1311 ALOGE("Unrecognized property %x", property);
Mike Lockwood56c85242014-03-07 13:29:08 -08001312 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001313 } else {
1314 ALOGE("unable to read device property, response: %04X", ret);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001315 }
1316
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001317 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001318 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -04001319}
1320
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001321// ----------------------------------------------------------------------------
1322
1323static void
Mike Lockwood0cd01362010-12-30 11:54:33 -05001324android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001325{
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001326 MtpDatabase* database = new MtpDatabase(env, thiz);
Ashok Bhate2e59322013-12-17 19:04:19 +00001327 env->SetLongField(thiz, field_context, (jlong)database);
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001328 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1329}
1330
1331static void
Mike Lockwood0cd01362010-12-30 11:54:33 -05001332android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001333{
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001334 MtpDatabase* database = (MtpDatabase *)env->GetLongField(thiz, field_context);
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001335 database->cleanup(env);
1336 delete database;
Ashok Bhate2e59322013-12-17 19:04:19 +00001337 env->SetLongField(thiz, field_context, 0);
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001338 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1339}
1340
Mike Lockwood31599912010-11-15 13:43:30 -05001341static jstring
Mark Salyzynaeb75fc2014-03-20 12:09:01 -07001342android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject /*thiz*/, jlong seconds)
Mike Lockwood31599912010-11-15 13:43:30 -05001343{
Mike Lockwood31599912010-11-15 13:43:30 -05001344 char date[20];
1345 formatDateTime(seconds, date, sizeof(date));
1346 return env->NewStringUTF(date);
Mike Lockwood31599912010-11-15 13:43:30 -05001347}
1348
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001349// ----------------------------------------------------------------------------
1350
Daniel Micay76f6a862015-09-19 17:31:01 -04001351static const JNINativeMethod gMtpDatabaseMethods[] = {
Mike Lockwood0cd01362010-12-30 11:54:33 -05001352 {"native_setup", "()V", (void *)android_mtp_MtpDatabase_setup},
1353 {"native_finalize", "()V", (void *)android_mtp_MtpDatabase_finalize},
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001354};
1355
Daniel Micay76f6a862015-09-19 17:31:01 -04001356static const JNINativeMethod gMtpPropertyGroupMethods[] = {
Mike Lockwood31599912010-11-15 13:43:30 -05001357 {"format_date_time", "(J)Ljava/lang/String;",
Mike Lockwood0cd01362010-12-30 11:54:33 -05001358 (void *)android_mtp_MtpPropertyGroup_format_date_time},
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001359};
1360
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001361#define GET_METHOD_ID(name, jclass, signature) \
1362 method_##name = env->GetMethodID(jclass, #name, signature); \
1363 if (method_##name == NULL) { \
1364 ALOGE("Can't find " #name); \
1365 return -1; \
1366 } \
1367
Mike Lockwood0cd01362010-12-30 11:54:33 -05001368int register_android_mtp_MtpDatabase(JNIEnv *env)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001369{
1370 jclass clazz;
1371
Mike Lockwood0cd01362010-12-30 11:54:33 -05001372 clazz = env->FindClass("android/mtp/MtpDatabase");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001373 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +00001374 ALOGE("Can't find android/mtp/MtpDatabase");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001375 return -1;
1376 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001377 GET_METHOD_ID(beginSendObject, clazz, "(Ljava/lang/String;III)I");
1378 GET_METHOD_ID(endSendObject, clazz, "(IZ)V");
1379 GET_METHOD_ID(rescanFile, clazz, "(Ljava/lang/String;II)V");
1380 GET_METHOD_ID(getObjectList, clazz, "(III)[I");
1381 GET_METHOD_ID(getNumObjects, clazz, "(III)I");
1382 GET_METHOD_ID(getSupportedPlaybackFormats, clazz, "()[I");
1383 GET_METHOD_ID(getSupportedCaptureFormats, clazz, "()[I");
1384 GET_METHOD_ID(getSupportedObjectProperties, clazz, "(I)[I");
1385 GET_METHOD_ID(getSupportedDeviceProperties, clazz, "()[I");
1386 GET_METHOD_ID(setObjectProperty, clazz, "(IIJLjava/lang/String;)I");
1387 GET_METHOD_ID(getDeviceProperty, clazz, "(I[J[C)I");
1388 GET_METHOD_ID(setDeviceProperty, clazz, "(IJLjava/lang/String;)I");
1389 GET_METHOD_ID(getObjectPropertyList, clazz, "(IIIII)Landroid/mtp/MtpPropertyList;");
1390 GET_METHOD_ID(getObjectInfo, clazz, "(I[I[C[J)Z");
1391 GET_METHOD_ID(getObjectFilePath, clazz, "(I[C[J)I");
1392 GET_METHOD_ID(beginDeleteObject, clazz, "(I)I");
1393 GET_METHOD_ID(endDeleteObject, clazz, "(IZ)V");
1394 GET_METHOD_ID(beginMoveObject, clazz, "(III)I");
1395 GET_METHOD_ID(endMoveObject, clazz, "(IIIIIZ)V");
1396 GET_METHOD_ID(beginCopyObject, clazz, "(III)I");
1397 GET_METHOD_ID(endCopyObject, clazz, "(IZ)V");
1398 GET_METHOD_ID(getObjectReferences, clazz, "(I)[I");
1399 GET_METHOD_ID(setObjectReferences, clazz, "(I[I)I");
Mike Lockwood2837eef2010-08-31 16:25:12 -04001400
Ashok Bhate2e59322013-12-17 19:04:19 +00001401 field_context = env->GetFieldID(clazz, "mNativeContext", "J");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001402 if (field_context == NULL) {
Steve Block3762c312012-01-06 19:20:56 +00001403 ALOGE("Can't find MtpDatabase.mNativeContext");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001404 return -1;
1405 }
1406
Mike Lockwood0cd01362010-12-30 11:54:33 -05001407 clazz = env->FindClass("android/mtp/MtpPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001408 if (clazz == NULL) {
Steve Block3762c312012-01-06 19:20:56 +00001409 ALOGE("Can't find android/mtp/MtpPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001410 return -1;
1411 }
Jerry Zhangf9c5c252017-08-16 18:07:51 -07001412 GET_METHOD_ID(getCode, clazz, "()I");
1413 GET_METHOD_ID(getCount, clazz, "()I");
1414 GET_METHOD_ID(getObjectHandles, clazz, "()[I");
1415 GET_METHOD_ID(getPropertyCodes, clazz, "()[I");
1416 GET_METHOD_ID(getDataTypes, clazz, "()[I");
1417 GET_METHOD_ID(getLongValues, clazz, "()[J");
1418 GET_METHOD_ID(getStringValues, clazz, "()[Ljava/lang/String;");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001419
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001420 if (AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -05001421 "android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods)))
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001422 return -1;
1423
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001424 return AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -05001425 "android/mtp/MtpPropertyGroup", gMtpPropertyGroupMethods, NELEM(gMtpPropertyGroupMethods));
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001426}