blob: b78af44db3613d16a3aca90b5811350aff85b1cc [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
20#include <stdio.h>
21#include <assert.h>
22#include <limits.h>
23#include <unistd.h>
24#include <fcntl.h>
25
26#include "jni.h"
27#include "JNIHelp.h"
28#include "android_runtime/AndroidRuntime.h"
29
30#include "MtpDatabase.h"
31#include "MtpDataPacket.h"
Mike Lockwoodfdb50e62011-04-21 17:05:55 -070032#include "MtpObjectInfo.h"
Mike Lockwood828d19d2010-08-10 15:20:35 -040033#include "MtpProperty.h"
Mike Lockwood59e3f0d2010-09-02 14:57:30 -040034#include "MtpStringBuffer.h"
Mike Lockwoodd21eac92010-07-03 00:44:05 -040035#include "MtpUtils.h"
36#include "mtp.h"
37
Mike Lockwooda792c802011-04-24 18:40:17 -070038extern "C" {
39#include "jhead.h"
40}
41
Mike Lockwoodd21eac92010-07-03 00:44:05 -040042using namespace android;
43
44// ----------------------------------------------------------------------------
45
Mike Lockwoodd815f792010-07-12 08:49:01 -040046static jmethodID method_beginSendObject;
47static jmethodID method_endSendObject;
Mike Lockwoodd21eac92010-07-03 00:44:05 -040048static jmethodID method_getObjectList;
Mike Lockwood7a047c82010-08-02 10:52:20 -040049static jmethodID method_getNumObjects;
Mike Lockwood4b322ce2010-08-10 07:37:50 -040050static jmethodID method_getSupportedPlaybackFormats;
51static jmethodID method_getSupportedCaptureFormats;
52static jmethodID method_getSupportedObjectProperties;
53static jmethodID method_getSupportedDeviceProperties;
Mike Lockwood828d19d2010-08-10 15:20:35 -040054static jmethodID method_setObjectProperty;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -040055static jmethodID method_getDeviceProperty;
56static jmethodID method_setDeviceProperty;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -040057static jmethodID method_getObjectPropertyList;
Mike Lockwoodd21eac92010-07-03 00:44:05 -040058static jmethodID method_getObjectInfo;
59static jmethodID method_getObjectFilePath;
60static jmethodID method_deleteFile;
Mike Lockwood9a2046f2010-08-03 15:30:09 -040061static jmethodID method_getObjectReferences;
62static jmethodID method_setObjectReferences;
Mike Lockwood2837eef2010-08-31 16:25:12 -040063static jmethodID method_sessionStarted;
64static jmethodID method_sessionEnded;
65
Mike Lockwoodd21eac92010-07-03 00:44:05 -040066static jfieldID field_context;
67
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -040068// MtpPropertyList fields
69static jfieldID field_mCount;
70static jfieldID field_mResult;
71static jfieldID field_mObjectHandles;
72static jfieldID field_mPropertyCodes;
73static jfieldID field_mDataTypes;
74static jfieldID field_mLongValues;
75static jfieldID field_mStringValues;
76
77
Mike Lockwoodd21eac92010-07-03 00:44:05 -040078MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
79 return (MtpDatabase *)env->GetIntField(database, field_context);
80}
81
Mike Lockwoodff164a72010-07-15 15:01:17 -040082#ifdef HAVE_ANDROID_OS
Mike Lockwoodd21eac92010-07-03 00:44:05 -040083// ----------------------------------------------------------------------------
84
85class MyMtpDatabase : public MtpDatabase {
86private:
87 jobject mDatabase;
88 jintArray mIntBuffer;
89 jlongArray mLongBuffer;
90 jcharArray mStringBuffer;
91
92public:
93 MyMtpDatabase(JNIEnv *env, jobject client);
94 virtual ~MyMtpDatabase();
95 void cleanup(JNIEnv *env);
96
Mike Lockwoodd815f792010-07-12 08:49:01 -040097 virtual MtpObjectHandle beginSendObject(const char* path,
Mike Lockwoodd21eac92010-07-03 00:44:05 -040098 MtpObjectFormat format,
99 MtpObjectHandle parent,
100 MtpStorageID storage,
101 uint64_t size,
102 time_t modified);
103
Mike Lockwoodd815f792010-07-12 08:49:01 -0400104 virtual void endSendObject(const char* path,
105 MtpObjectHandle handle,
106 MtpObjectFormat format,
107 bool succeeded);
108
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400109 virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
110 MtpObjectFormat format,
111 MtpObjectHandle parent);
112
Mike Lockwood7a047c82010-08-02 10:52:20 -0400113 virtual int getNumObjects(MtpStorageID storageID,
114 MtpObjectFormat format,
115 MtpObjectHandle parent);
116
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400117 // callee should delete[] the results from these
118 // results can be NULL
119 virtual MtpObjectFormatList* getSupportedPlaybackFormats();
120 virtual MtpObjectFormatList* getSupportedCaptureFormats();
121 virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format);
122 virtual MtpDevicePropertyList* getSupportedDeviceProperties();
123
Mike Lockwood828d19d2010-08-10 15:20:35 -0400124 virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400125 MtpObjectProperty property,
126 MtpDataPacket& packet);
127
Mike Lockwood828d19d2010-08-10 15:20:35 -0400128 virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle handle,
129 MtpObjectProperty property,
130 MtpDataPacket& packet);
131
132 virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty property,
133 MtpDataPacket& packet);
134
135 virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty property,
136 MtpDataPacket& packet);
137
138 virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty property);
139
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400140 virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle handle,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500141 uint32_t format, uint32_t property,
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400142 int groupCode, int depth,
143 MtpDataPacket& packet);
144
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400145 virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
Mike Lockwoodfdb50e62011-04-21 17:05:55 -0700146 MtpObjectInfo& info);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400147
Mike Lockwooda792c802011-04-24 18:40:17 -0700148 virtual void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
149
Mike Lockwood59c777a2010-08-02 10:37:41 -0400150 virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
Mike Lockwood365e03e2010-12-08 16:08:01 -0800151 MtpString& outFilePath,
152 int64_t& outFileLength,
153 MtpObjectFormat& outFormat);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400154 virtual MtpResponseCode deleteFile(MtpObjectHandle handle);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400155
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400156 bool getObjectPropertyInfo(MtpObjectProperty property, int& type);
157 bool getDevicePropertyInfo(MtpDeviceProperty property, int& type);
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400158
159 virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle);
160
161 virtual MtpResponseCode setObjectReferences(MtpObjectHandle handle,
162 MtpObjectHandleList* references);
Mike Lockwood828d19d2010-08-10 15:20:35 -0400163
164 virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty property,
165 MtpObjectFormat format);
166
167 virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property);
Mike Lockwood2837eef2010-08-31 16:25:12 -0400168
169 virtual void sessionStarted();
170
171 virtual void sessionEnded();
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400172};
173
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400174// ----------------------------------------------------------------------------
175
176static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
177 if (env->ExceptionCheck()) {
178 LOGE("An exception was thrown by callback '%s'.", methodName);
179 LOGE_EX(env);
180 env->ExceptionClear();
181 }
182}
183
184// ----------------------------------------------------------------------------
185
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400186MyMtpDatabase::MyMtpDatabase(JNIEnv *env, jobject client)
187 : mDatabase(env->NewGlobalRef(client)),
188 mIntBuffer(NULL),
189 mLongBuffer(NULL),
190 mStringBuffer(NULL)
191{
192 jintArray intArray;
193 jlongArray longArray;
194 jcharArray charArray;
195
196 // create buffers for out arguments
197 // we don't need to be thread-safe so this is OK
198 intArray = env->NewIntArray(3);
199 if (!intArray)
200 goto out_of_memory;
201 mIntBuffer = (jintArray)env->NewGlobalRef(intArray);
202 longArray = env->NewLongArray(2);
203 if (!longArray)
204 goto out_of_memory;
205 mLongBuffer = (jlongArray)env->NewGlobalRef(longArray);
206 charArray = env->NewCharArray(256);
207 if (!charArray)
208 goto out_of_memory;
209 mStringBuffer = (jcharArray)env->NewGlobalRef(charArray);
210 return;
211
212out_of_memory:
213 env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), NULL);
214}
215
216void MyMtpDatabase::cleanup(JNIEnv *env) {
217 env->DeleteGlobalRef(mDatabase);
218 env->DeleteGlobalRef(mIntBuffer);
219 env->DeleteGlobalRef(mLongBuffer);
220 env->DeleteGlobalRef(mStringBuffer);
221}
222
223MyMtpDatabase::~MyMtpDatabase() {
224}
225
Mike Lockwoodd815f792010-07-12 08:49:01 -0400226MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400227 MtpObjectFormat format,
228 MtpObjectHandle parent,
229 MtpStorageID storage,
230 uint64_t size,
231 time_t modified) {
232 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood88394712010-09-27 10:01:00 -0400233 jstring pathStr = env->NewStringUTF(path);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400234 MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
Mike Lockwood88394712010-09-27 10:01:00 -0400235 pathStr, (jint)format, (jint)parent, (jint)storage,
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400236 (jlong)size, (jlong)modified);
237
Mike Lockwood88394712010-09-27 10:01:00 -0400238 if (pathStr)
239 env->DeleteLocalRef(pathStr);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400240 checkAndClearExceptionFromCallback(env, __FUNCTION__);
241 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400242}
243
Mike Lockwoodd815f792010-07-12 08:49:01 -0400244void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
Mike Lockwood7a0bd172011-01-18 11:06:19 -0800245 MtpObjectFormat format, bool succeeded) {
Mike Lockwoodd815f792010-07-12 08:49:01 -0400246 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood88394712010-09-27 10:01:00 -0400247 jstring pathStr = env->NewStringUTF(path);
248 env->CallVoidMethod(mDatabase, method_endSendObject, pathStr,
Mike Lockwood7a0bd172011-01-18 11:06:19 -0800249 (jint)handle, (jint)format, (jboolean)succeeded);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400250
Mike Lockwood88394712010-09-27 10:01:00 -0400251 if (pathStr)
252 env->DeleteLocalRef(pathStr);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400253 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd815f792010-07-12 08:49:01 -0400254}
255
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400256MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
257 MtpObjectFormat format,
258 MtpObjectHandle parent) {
259 JNIEnv* env = AndroidRuntime::getJNIEnv();
260 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList,
261 (jint)storageID, (jint)format, (jint)parent);
262 if (!array)
263 return NULL;
264 MtpObjectHandleList* list = new MtpObjectHandleList();
265 jint* handles = env->GetIntArrayElements(array, 0);
266 jsize length = env->GetArrayLength(array);
Mike Lockwood7a047c82010-08-02 10:52:20 -0400267 for (int i = 0; i < length; i++)
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400268 list->push(handles[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400269 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400270 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400271
272 checkAndClearExceptionFromCallback(env, __FUNCTION__);
273 return list;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400274}
275
Mike Lockwood7a047c82010-08-02 10:52:20 -0400276int MyMtpDatabase::getNumObjects(MtpStorageID storageID,
277 MtpObjectFormat format,
278 MtpObjectHandle parent) {
279 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400280 int result = env->CallIntMethod(mDatabase, method_getNumObjects,
Mike Lockwood7a047c82010-08-02 10:52:20 -0400281 (jint)storageID, (jint)format, (jint)parent);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400282
283 checkAndClearExceptionFromCallback(env, __FUNCTION__);
284 return result;
Mike Lockwood7a047c82010-08-02 10:52:20 -0400285}
286
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400287MtpObjectFormatList* MyMtpDatabase::getSupportedPlaybackFormats() {
288 JNIEnv* env = AndroidRuntime::getJNIEnv();
289 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
290 method_getSupportedPlaybackFormats);
291 if (!array)
292 return NULL;
293 MtpObjectFormatList* list = new MtpObjectFormatList();
294 jint* formats = env->GetIntArrayElements(array, 0);
295 jsize length = env->GetArrayLength(array);
296 for (int i = 0; i < length; i++)
297 list->push(formats[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400298 env->ReleaseIntArrayElements(array, formats, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400299 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400300
301 checkAndClearExceptionFromCallback(env, __FUNCTION__);
302 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400303}
304
305MtpObjectFormatList* MyMtpDatabase::getSupportedCaptureFormats() {
306 JNIEnv* env = AndroidRuntime::getJNIEnv();
307 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
308 method_getSupportedCaptureFormats);
309 if (!array)
310 return NULL;
311 MtpObjectFormatList* list = new MtpObjectFormatList();
312 jint* formats = env->GetIntArrayElements(array, 0);
313 jsize length = env->GetArrayLength(array);
314 for (int i = 0; i < length; i++)
315 list->push(formats[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400316 env->ReleaseIntArrayElements(array, formats, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400317 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400318
319 checkAndClearExceptionFromCallback(env, __FUNCTION__);
320 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400321}
322
323MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
324 JNIEnv* env = AndroidRuntime::getJNIEnv();
325 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
326 method_getSupportedObjectProperties, (jint)format);
327 if (!array)
328 return NULL;
329 MtpObjectPropertyList* list = new MtpObjectPropertyList();
330 jint* properties = env->GetIntArrayElements(array, 0);
331 jsize length = env->GetArrayLength(array);
332 for (int i = 0; i < length; i++)
333 list->push(properties[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400334 env->ReleaseIntArrayElements(array, properties, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400335 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400336
337 checkAndClearExceptionFromCallback(env, __FUNCTION__);
338 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400339}
340
341MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() {
342 JNIEnv* env = AndroidRuntime::getJNIEnv();
343 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
344 method_getSupportedDeviceProperties);
345 if (!array)
346 return NULL;
347 MtpDevicePropertyList* list = new MtpDevicePropertyList();
348 jint* properties = env->GetIntArrayElements(array, 0);
349 jsize length = env->GetArrayLength(array);
350 for (int i = 0; i < length; i++)
351 list->push(properties[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400352 env->ReleaseIntArrayElements(array, properties, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400353 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400354
355 checkAndClearExceptionFromCallback(env, __FUNCTION__);
356 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400357}
358
Mike Lockwood828d19d2010-08-10 15:20:35 -0400359MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400360 MtpObjectProperty property,
361 MtpDataPacket& packet) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400362 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400363 jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500364 (jlong)handle, 0, (jlong)property, 0, 0);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400365 MtpResponseCode result = env->GetIntField(list, field_mResult);
366 int count = env->GetIntField(list, field_mCount);
367 if (result == MTP_RESPONSE_OK && count != 1)
368 result = MTP_RESPONSE_GENERAL_ERROR;
369
370 if (result == MTP_RESPONSE_OK) {
371 jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
372 jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
373 jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
374 jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
375 jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
376
377 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
378 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
379 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
380 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
381
382 int type = dataTypes[0];
383 jlong longValue = (longValues ? longValues[0] : 0);
384
385 // special case date properties, which are strings to MTP
386 // but stored internally as a uint64
387 if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) {
388 char date[20];
389 formatDateTime(longValue, date, sizeof(date));
390 packet.putString(date);
391 goto out;
392 }
393 // release date is stored internally as just the year
394 if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) {
395 char date[20];
396 snprintf(date, sizeof(date), "%04lld0101T000000", longValue);
397 packet.putString(date);
398 goto out;
399 }
400
401 switch (type) {
402 case MTP_TYPE_INT8:
403 packet.putInt8(longValue);
404 break;
405 case MTP_TYPE_UINT8:
406 packet.putUInt8(longValue);
407 break;
408 case MTP_TYPE_INT16:
409 packet.putInt16(longValue);
410 break;
411 case MTP_TYPE_UINT16:
412 packet.putUInt16(longValue);
413 break;
414 case MTP_TYPE_INT32:
415 packet.putInt32(longValue);
416 break;
417 case MTP_TYPE_UINT32:
418 packet.putUInt32(longValue);
419 break;
420 case MTP_TYPE_INT64:
421 packet.putInt64(longValue);
422 break;
423 case MTP_TYPE_UINT64:
424 packet.putUInt64(longValue);
425 break;
426 case MTP_TYPE_INT128:
427 packet.putInt128(longValue);
428 break;
429 case MTP_TYPE_UINT128:
430 packet.putInt128(longValue);
431 break;
432 case MTP_TYPE_STR:
433 {
434 jstring stringValue = (jstring)env->GetObjectArrayElement(stringValuesArray, 0);
435 if (stringValue) {
436 const char* str = env->GetStringUTFChars(stringValue, NULL);
437 packet.putString(str);
438 env->ReleaseStringUTFChars(stringValue, str);
439 } else {
440 packet.putEmptyString();
441 }
442 break;
443 }
444 default:
445 LOGE("unsupported type in getObjectPropertyValue\n");
446 result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
447 }
448out:
449 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
450 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
451 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
452 if (longValues)
453 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
454
455 env->DeleteLocalRef(objectHandlesArray);
456 env->DeleteLocalRef(propertyCodesArray);
457 env->DeleteLocalRef(dataTypesArray);
458 if (longValuesArray)
459 env->DeleteLocalRef(longValuesArray);
460 if (stringValuesArray)
461 env->DeleteLocalRef(stringValuesArray);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400462 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400463
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400464 env->DeleteLocalRef(list);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400465 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400466 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400467}
468
Mike Lockwood828d19d2010-08-10 15:20:35 -0400469MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
470 MtpObjectProperty property,
471 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400472 int type;
473
474 if (!getObjectPropertyInfo(property, type))
475 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
476
477 JNIEnv* env = AndroidRuntime::getJNIEnv();
478 jlong longValue = 0;
479 jstring stringValue = NULL;
480
481 switch (type) {
482 case MTP_TYPE_INT8:
483 longValue = packet.getInt8();
484 break;
485 case MTP_TYPE_UINT8:
486 longValue = packet.getUInt8();
487 break;
488 case MTP_TYPE_INT16:
489 longValue = packet.getInt16();
490 break;
491 case MTP_TYPE_UINT16:
492 longValue = packet.getUInt16();
493 break;
494 case MTP_TYPE_INT32:
495 longValue = packet.getInt32();
496 break;
497 case MTP_TYPE_UINT32:
498 longValue = packet.getUInt32();
499 break;
500 case MTP_TYPE_INT64:
501 longValue = packet.getInt64();
502 break;
503 case MTP_TYPE_UINT64:
504 longValue = packet.getUInt64();
505 break;
506 case MTP_TYPE_STR:
507 {
508 MtpStringBuffer buffer;
509 packet.getString(buffer);
510 stringValue = env->NewStringUTF((const char *)buffer);
511 break;
512 }
513 default:
514 LOGE("unsupported type in getObjectPropertyValue\n");
515 return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
516 }
517
518 jint result = env->CallIntMethod(mDatabase, method_setObjectProperty,
519 (jint)handle, (jint)property, longValue, stringValue);
Mike Lockwood88394712010-09-27 10:01:00 -0400520 if (stringValue)
521 env->DeleteLocalRef(stringValue);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400522
523 checkAndClearExceptionFromCallback(env, __FUNCTION__);
524 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400525}
526
527MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
528 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400529 int type;
530
531 if (!getDevicePropertyInfo(property, type))
532 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
533
534 JNIEnv* env = AndroidRuntime::getJNIEnv();
535 jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
536 (jint)property, mLongBuffer, mStringBuffer);
537 if (result != MTP_RESPONSE_OK) {
538 checkAndClearExceptionFromCallback(env, __FUNCTION__);
539 return result;
540 }
541
542 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
543 jlong longValue = longValues[0];
544 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
545
546 switch (type) {
547 case MTP_TYPE_INT8:
548 packet.putInt8(longValue);
549 break;
550 case MTP_TYPE_UINT8:
551 packet.putUInt8(longValue);
552 break;
553 case MTP_TYPE_INT16:
554 packet.putInt16(longValue);
555 break;
556 case MTP_TYPE_UINT16:
557 packet.putUInt16(longValue);
558 break;
559 case MTP_TYPE_INT32:
560 packet.putInt32(longValue);
561 break;
562 case MTP_TYPE_UINT32:
563 packet.putUInt32(longValue);
564 break;
565 case MTP_TYPE_INT64:
566 packet.putInt64(longValue);
567 break;
568 case MTP_TYPE_UINT64:
569 packet.putUInt64(longValue);
570 break;
571 case MTP_TYPE_INT128:
572 packet.putInt128(longValue);
573 break;
574 case MTP_TYPE_UINT128:
575 packet.putInt128(longValue);
576 break;
577 case MTP_TYPE_STR:
578 {
579 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
580 packet.putString(str);
581 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
582 break;
583 }
584 default:
585 LOGE("unsupported type in getDevicePropertyValue\n");
586 return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
587 }
588
589 checkAndClearExceptionFromCallback(env, __FUNCTION__);
590 return MTP_RESPONSE_OK;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400591}
592
593MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
594 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400595 int type;
596
597 if (!getDevicePropertyInfo(property, type))
598 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
599
600 JNIEnv* env = AndroidRuntime::getJNIEnv();
601 jlong longValue = 0;
602 jstring stringValue = NULL;
603
604 switch (type) {
605 case MTP_TYPE_INT8:
606 longValue = packet.getInt8();
607 break;
608 case MTP_TYPE_UINT8:
609 longValue = packet.getUInt8();
610 break;
611 case MTP_TYPE_INT16:
612 longValue = packet.getInt16();
613 break;
614 case MTP_TYPE_UINT16:
615 longValue = packet.getUInt16();
616 break;
617 case MTP_TYPE_INT32:
618 longValue = packet.getInt32();
619 break;
620 case MTP_TYPE_UINT32:
621 longValue = packet.getUInt32();
622 break;
623 case MTP_TYPE_INT64:
624 longValue = packet.getInt64();
625 break;
626 case MTP_TYPE_UINT64:
627 longValue = packet.getUInt64();
628 break;
629 case MTP_TYPE_STR:
630 {
631 MtpStringBuffer buffer;
632 packet.getString(buffer);
633 stringValue = env->NewStringUTF((const char *)buffer);
634 break;
635 }
636 default:
637 LOGE("unsupported type in setDevicePropertyValue\n");
638 return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
639 }
640
641 jint result = env->CallIntMethod(mDatabase, method_setDeviceProperty,
642 (jint)property, longValue, stringValue);
Mike Lockwood88394712010-09-27 10:01:00 -0400643 if (stringValue)
644 env->DeleteLocalRef(stringValue);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400645
646 checkAndClearExceptionFromCallback(env, __FUNCTION__);
647 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400648}
649
650MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty property) {
651 return -1;
652}
653
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400654MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500655 uint32_t format, uint32_t property,
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400656 int groupCode, int depth,
657 MtpDataPacket& packet) {
658 JNIEnv* env = AndroidRuntime::getJNIEnv();
659 jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500660 (jlong)handle, (jint)format, (jlong)property, (jint)groupCode, (jint)depth);
661 checkAndClearExceptionFromCallback(env, __FUNCTION__);
662 if (!list)
663 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400664 int count = env->GetIntField(list, field_mCount);
665 MtpResponseCode result = env->GetIntField(list, field_mResult);
666
667 packet.putUInt32(count);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400668 if (count > 0) {
669 jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
670 jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
671 jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
672 jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
673 jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
674
675 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
676 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
677 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
678 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
679
680 for (int i = 0; i < count; i++) {
681 packet.putUInt32(objectHandles[i]);
682 packet.putUInt16(propertyCodes[i]);
683 int type = dataTypes[i];
684 packet.putUInt16(type);
685
686 switch (type) {
687 case MTP_TYPE_INT8:
688 packet.putInt8(longValues[i]);
689 break;
690 case MTP_TYPE_UINT8:
691 packet.putUInt8(longValues[i]);
692 break;
693 case MTP_TYPE_INT16:
694 packet.putInt16(longValues[i]);
695 break;
696 case MTP_TYPE_UINT16:
697 packet.putUInt16(longValues[i]);
698 break;
699 case MTP_TYPE_INT32:
700 packet.putInt32(longValues[i]);
701 break;
702 case MTP_TYPE_UINT32:
703 packet.putUInt32(longValues[i]);
704 break;
705 case MTP_TYPE_INT64:
706 packet.putInt64(longValues[i]);
707 break;
708 case MTP_TYPE_UINT64:
709 packet.putUInt64(longValues[i]);
710 break;
711 case MTP_TYPE_INT128:
712 packet.putInt128(longValues[i]);
713 break;
714 case MTP_TYPE_UINT128:
715 packet.putUInt128(longValues[i]);
716 break;
717 case MTP_TYPE_STR: {
718 jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i);
Mike Lockwood2711e492010-12-11 11:24:37 -0800719 const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400720 if (valueStr) {
721 packet.putString(valueStr);
722 env->ReleaseStringUTFChars(value, valueStr);
723 } else {
724 packet.putEmptyString();
725 }
726 env->DeleteLocalRef(value);
727 break;
728 }
729 default:
730 LOGE("bad or unsupported data type in MyMtpDatabase::getObjectPropertyList");
731 break;
732 }
733 }
734
735 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
736 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
737 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
738 if (longValues)
739 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
740
741 env->DeleteLocalRef(objectHandlesArray);
742 env->DeleteLocalRef(propertyCodesArray);
743 env->DeleteLocalRef(dataTypesArray);
744 if (longValuesArray)
745 env->DeleteLocalRef(longValuesArray);
746 if (stringValuesArray)
747 env->DeleteLocalRef(stringValuesArray);
748 }
749
750 env->DeleteLocalRef(list);
751 checkAndClearExceptionFromCallback(env, __FUNCTION__);
752 return result;
753}
754
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400755MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
Mike Lockwoodfdb50e62011-04-21 17:05:55 -0700756 MtpObjectInfo& info) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400757 char date[20];
758
759 JNIEnv* env = AndroidRuntime::getJNIEnv();
760 jboolean result = env->CallBooleanMethod(mDatabase, method_getObjectInfo,
761 (jint)handle, mIntBuffer, mStringBuffer, mLongBuffer);
762 if (!result)
763 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
764
765 jint* intValues = env->GetIntArrayElements(mIntBuffer, 0);
Mike Lockwoodfdb50e62011-04-21 17:05:55 -0700766 info.mStorageID = intValues[0];
767 info.mFormat = intValues[1];
768 info.mParent = intValues[2];
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400769 env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
770
771 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
772 uint64_t size = longValues[0];
Mike Lockwoodfdb50e62011-04-21 17:05:55 -0700773 info.mCompressedSize = (size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size);
774 info.mDateModified = longValues[1];
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400775 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
776
Mike Lockwoodfdb50e62011-04-21 17:05:55 -0700777// info.mAssociationType = (format == MTP_FORMAT_ASSOCIATION ?
Mike Lockwood828d19d2010-08-10 15:20:35 -0400778// MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
779// MTP_ASSOCIATION_TYPE_UNDEFINED);
Mike Lockwoodfdb50e62011-04-21 17:05:55 -0700780 info.mAssociationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400781
782 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
Mike Lockwoodfdb50e62011-04-21 17:05:55 -0700783 MtpString temp(str);
784 info.mName = strdup((const char *)temp);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400785 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
786
Mike Lockwooda792c802011-04-24 18:40:17 -0700787 // read EXIF data for thumbnail information
788 if (info.mFormat == MTP_FORMAT_EXIF_JPEG || info.mFormat == MTP_FORMAT_JFIF) {
789 MtpString path;
790 int64_t length;
791 MtpObjectFormat format;
792 if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK) {
793 ResetJpgfile();
794 // Start with an empty image information structure.
795 memset(&ImageInfo, 0, sizeof(ImageInfo));
796 ImageInfo.FlashUsed = -1;
797 ImageInfo.MeteringMode = -1;
798 ImageInfo.Whitebalance = -1;
799 strncpy(ImageInfo.FileName, (const char *)path, PATH_MAX);
800 if (ReadJpegFile((const char*)path, READ_METADATA)) {
801 Section_t* section = FindSection(M_EXIF);
802 if (section) {
803 info.mThumbCompressedSize = ImageInfo.ThumbnailSize;
804 info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
805 info.mImagePixWidth = ImageInfo.Width;
806 info.mImagePixHeight = ImageInfo.Height;
807 }
808 }
809 DiscardData();
810 }
811 }
812
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400813 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400814 return MTP_RESPONSE_OK;
815}
816
Mike Lockwooda792c802011-04-24 18:40:17 -0700817void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
818 MtpString path;
819 int64_t length;
820 MtpObjectFormat format;
821 void* result = NULL;
822 outThumbSize = 0;
823
824 if (getObjectFilePath(handle, path, length, format) == MTP_RESPONSE_OK
825 && (format == MTP_FORMAT_EXIF_JPEG || format == MTP_FORMAT_JFIF)) {
826 ResetJpgfile();
827 // Start with an empty image information structure.
828 memset(&ImageInfo, 0, sizeof(ImageInfo));
829 ImageInfo.FlashUsed = -1;
830 ImageInfo.MeteringMode = -1;
831 ImageInfo.Whitebalance = -1;
832 strncpy(ImageInfo.FileName, (const char *)path, PATH_MAX);
833 if (ReadJpegFile((const char*)path, READ_METADATA)) {
834 Section_t* section = FindSection(M_EXIF);
835 if (section) {
836 outThumbSize = ImageInfo.ThumbnailSize;
837 result = malloc(outThumbSize);
838 if (result)
839 memcpy(result, section->Data + ImageInfo.ThumbnailOffset + 8, outThumbSize);
840 }
841 DiscardData();
842 }
843 }
844
845 return result;
846}
847
Mike Lockwood59c777a2010-08-02 10:37:41 -0400848MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
Mike Lockwood365e03e2010-12-08 16:08:01 -0800849 MtpString& outFilePath,
850 int64_t& outFileLength,
851 MtpObjectFormat& outFormat) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400852 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood59c777a2010-08-02 10:37:41 -0400853 jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400854 (jint)handle, mStringBuffer, mLongBuffer);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400855 if (result != MTP_RESPONSE_OK) {
856 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400857 return result;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400858 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400859
860 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
Mike Lockwood365e03e2010-12-08 16:08:01 -0800861 outFilePath.setTo(str, strlen16(str));
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400862 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
863
864 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
Mike Lockwood365e03e2010-12-08 16:08:01 -0800865 outFileLength = longValues[0];
866 outFormat = longValues[1];
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400867 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
868
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400869 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400870 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400871}
872
Mike Lockwood59c777a2010-08-02 10:37:41 -0400873MtpResponseCode MyMtpDatabase::deleteFile(MtpObjectHandle handle) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400874 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400875 MtpResponseCode result = env->CallIntMethod(mDatabase, method_deleteFile, (jint)handle);
876
877 checkAndClearExceptionFromCallback(env, __FUNCTION__);
878 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400879}
880
881struct PropertyTableEntry {
882 MtpObjectProperty property;
883 int type;
884};
885
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400886static const PropertyTableEntry kObjectPropertyTable[] = {
Mike Lockwoodd3bfecb2010-09-23 23:04:28 -0400887 { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 },
888 { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 },
889 { MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16 },
890 { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 },
891 { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR },
892 { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR },
893 { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 },
894 { MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128 },
895 { MTP_PROPERTY_NAME, MTP_TYPE_STR },
Mike Lockwoodae078f72010-09-26 12:35:51 -0400896 { MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR },
897 { MTP_PROPERTY_DATE_ADDED, MTP_TYPE_STR },
898 { MTP_PROPERTY_ARTIST, MTP_TYPE_STR },
899 { MTP_PROPERTY_ALBUM_NAME, MTP_TYPE_STR },
900 { MTP_PROPERTY_ALBUM_ARTIST, MTP_TYPE_STR },
901 { MTP_PROPERTY_TRACK, MTP_TYPE_UINT16 },
902 { MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_TYPE_STR },
903 { MTP_PROPERTY_GENRE, MTP_TYPE_STR },
904 { MTP_PROPERTY_COMPOSER, MTP_TYPE_STR },
905 { MTP_PROPERTY_DURATION, MTP_TYPE_UINT32 },
906 { MTP_PROPERTY_DESCRIPTION, MTP_TYPE_STR },
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400907};
908
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400909static const PropertyTableEntry kDevicePropertyTable[] = {
Mike Lockwoodea93fa12010-12-07 10:41:35 -0800910 { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_STR },
911 { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR },
912 { MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR },
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400913};
914
915bool MyMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
916 int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
917 const PropertyTableEntry* entry = kObjectPropertyTable;
918 for (int i = 0; i < count; i++, entry++) {
919 if (entry->property == property) {
920 type = entry->type;
921 return true;
922 }
923 }
924 return false;
925}
926
927bool MyMtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
928 int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
929 const PropertyTableEntry* entry = kDevicePropertyTable;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400930 for (int i = 0; i < count; i++, entry++) {
931 if (entry->property == property) {
932 type = entry->type;
933 return true;
934 }
935 }
936 return false;
937}
938
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400939MtpObjectHandleList* MyMtpDatabase::getObjectReferences(MtpObjectHandle handle) {
940 JNIEnv* env = AndroidRuntime::getJNIEnv();
941 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectReferences,
942 (jint)handle);
943 if (!array)
944 return NULL;
945 MtpObjectHandleList* list = new MtpObjectHandleList();
946 jint* handles = env->GetIntArrayElements(array, 0);
947 jsize length = env->GetArrayLength(array);
948 for (int i = 0; i < length; i++)
949 list->push(handles[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400950 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400951 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400952
953 checkAndClearExceptionFromCallback(env, __FUNCTION__);
954 return list;
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400955}
956
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400957MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
958 MtpObjectHandleList* references) {
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400959 JNIEnv* env = AndroidRuntime::getJNIEnv();
960 int count = references->size();
961 jintArray array = env->NewIntArray(count);
962 if (!array) {
963 LOGE("out of memory in setObjectReferences");
964 return false;
965 }
966 jint* handles = env->GetIntArrayElements(array, 0);
967 for (int i = 0; i < count; i++)
968 handles[i] = (*references)[i];
969 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400970 MtpResponseCode result = env->CallIntMethod(mDatabase, method_setObjectReferences,
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400971 (jint)handle, array);
Mike Lockwood88394712010-09-27 10:01:00 -0400972 env->DeleteLocalRef(array);
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400973
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400974 checkAndClearExceptionFromCallback(env, __FUNCTION__);
975 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400976}
977
Mike Lockwood828d19d2010-08-10 15:20:35 -0400978MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
979 MtpObjectFormat format) {
980 MtpProperty* result = NULL;
981 switch (property) {
982 case MTP_PROPERTY_OBJECT_FORMAT:
Mike Lockwood9b5e9c42010-12-07 18:53:50 -0800983 // use format as default value
984 result = new MtpProperty(property, MTP_TYPE_UINT16, false, format);
985 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400986 case MTP_PROPERTY_PROTECTION_STATUS:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400987 case MTP_PROPERTY_TRACK:
Mike Lockwood828d19d2010-08-10 15:20:35 -0400988 result = new MtpProperty(property, MTP_TYPE_UINT16);
989 break;
990 case MTP_PROPERTY_STORAGE_ID:
991 case MTP_PROPERTY_PARENT_OBJECT:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400992 case MTP_PROPERTY_DURATION:
Mike Lockwood828d19d2010-08-10 15:20:35 -0400993 result = new MtpProperty(property, MTP_TYPE_UINT32);
994 break;
995 case MTP_PROPERTY_OBJECT_SIZE:
996 result = new MtpProperty(property, MTP_TYPE_UINT64);
997 break;
998 case MTP_PROPERTY_PERSISTENT_UID:
999 result = new MtpProperty(property, MTP_TYPE_UINT128);
1000 break;
Mike Lockwoodd3bfecb2010-09-23 23:04:28 -04001001 case MTP_PROPERTY_NAME:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001002 case MTP_PROPERTY_DISPLAY_NAME:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001003 case MTP_PROPERTY_ARTIST:
1004 case MTP_PROPERTY_ALBUM_NAME:
1005 case MTP_PROPERTY_ALBUM_ARTIST:
Mike Lockwoodae078f72010-09-26 12:35:51 -04001006 case MTP_PROPERTY_GENRE:
1007 case MTP_PROPERTY_COMPOSER:
1008 case MTP_PROPERTY_DESCRIPTION:
Mike Lockwood828d19d2010-08-10 15:20:35 -04001009 result = new MtpProperty(property, MTP_TYPE_STR);
1010 break;
Mike Lockwood5b19af02010-11-23 18:38:55 -05001011 case MTP_PROPERTY_DATE_MODIFIED:
1012 case MTP_PROPERTY_DATE_ADDED:
1013 case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
1014 result = new MtpProperty(property, MTP_TYPE_STR);
1015 result->setFormDateTime();
1016 break;
Mike Lockwood5ebac832010-10-12 11:33:47 -04001017 case MTP_PROPERTY_OBJECT_FILE_NAME:
Mike Lockwood6a6a3af2010-10-12 14:19:51 -04001018 // We allow renaming files and folders
1019 result = new MtpProperty(property, MTP_TYPE_STR, true);
Mike Lockwood5ebac832010-10-12 11:33:47 -04001020 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -04001021 }
1022
1023 return result;
1024}
1025
1026MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001027 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001028 MtpProperty* result = NULL;
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001029 bool writable = false;
1030
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001031 switch (property) {
1032 case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
1033 case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001034 writable = true;
1035 // fall through
1036 case MTP_DEVICE_PROPERTY_IMAGE_SIZE:
1037 result = new MtpProperty(property, MTP_TYPE_STR, writable);
Mike Lockwooda2a21282010-09-25 21:21:05 -04001038
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001039 // get current value
Mike Lockwooda2a21282010-09-25 21:21:05 -04001040 jint ret = env->CallIntMethod(mDatabase, method_getDeviceProperty,
1041 (jint)property, mLongBuffer, mStringBuffer);
1042 if (ret == MTP_RESPONSE_OK) {
1043 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
1044 result->setCurrentValue(str);
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001045 // for read-only properties it is safe to assume current value is default value
1046 if (!writable)
1047 result->setDefaultValue(str);
Mike Lockwooda2a21282010-09-25 21:21:05 -04001048 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
1049 } else {
1050 LOGE("unable to read device property, response: %04X", ret);
1051 }
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001052 break;
1053 }
1054
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001055 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001056 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -04001057}
1058
Mike Lockwood2837eef2010-08-31 16:25:12 -04001059void MyMtpDatabase::sessionStarted() {
1060 JNIEnv* env = AndroidRuntime::getJNIEnv();
1061 env->CallVoidMethod(mDatabase, method_sessionStarted);
1062 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1063}
1064
1065void MyMtpDatabase::sessionEnded() {
1066 JNIEnv* env = AndroidRuntime::getJNIEnv();
1067 env->CallVoidMethod(mDatabase, method_sessionEnded);
1068 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1069}
1070
Mike Lockwoodff164a72010-07-15 15:01:17 -04001071#endif // HAVE_ANDROID_OS
1072
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001073// ----------------------------------------------------------------------------
1074
1075static void
Mike Lockwood0cd01362010-12-30 11:54:33 -05001076android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001077{
Mike Lockwoodff164a72010-07-15 15:01:17 -04001078#ifdef HAVE_ANDROID_OS
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001079 MyMtpDatabase* database = new MyMtpDatabase(env, thiz);
1080 env->SetIntField(thiz, field_context, (int)database);
1081 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodff164a72010-07-15 15:01:17 -04001082#endif
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001083}
1084
1085static void
Mike Lockwood0cd01362010-12-30 11:54:33 -05001086android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001087{
Mike Lockwoodff164a72010-07-15 15:01:17 -04001088#ifdef HAVE_ANDROID_OS
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001089 MyMtpDatabase* database = (MyMtpDatabase *)env->GetIntField(thiz, field_context);
1090 database->cleanup(env);
1091 delete database;
1092 env->SetIntField(thiz, field_context, 0);
1093 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodff164a72010-07-15 15:01:17 -04001094#endif
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001095}
1096
Mike Lockwood31599912010-11-15 13:43:30 -05001097static jstring
Mike Lockwood0cd01362010-12-30 11:54:33 -05001098android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject thiz, jlong seconds)
Mike Lockwood31599912010-11-15 13:43:30 -05001099{
1100#ifdef HAVE_ANDROID_OS
1101 char date[20];
1102 formatDateTime(seconds, date, sizeof(date));
1103 return env->NewStringUTF(date);
1104#else
1105 return NULL;
1106#endif
1107}
1108
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001109// ----------------------------------------------------------------------------
1110
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001111static JNINativeMethod gMtpDatabaseMethods[] = {
Mike Lockwood0cd01362010-12-30 11:54:33 -05001112 {"native_setup", "()V", (void *)android_mtp_MtpDatabase_setup},
1113 {"native_finalize", "()V", (void *)android_mtp_MtpDatabase_finalize},
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001114};
1115
1116static JNINativeMethod gMtpPropertyGroupMethods[] = {
Mike Lockwood31599912010-11-15 13:43:30 -05001117 {"format_date_time", "(J)Ljava/lang/String;",
Mike Lockwood0cd01362010-12-30 11:54:33 -05001118 (void *)android_mtp_MtpPropertyGroup_format_date_time},
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001119};
1120
Mike Lockwood0cd01362010-12-30 11:54:33 -05001121static const char* const kClassPathName = "android/mtp/MtpDatabase";
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001122
Mike Lockwood0cd01362010-12-30 11:54:33 -05001123int register_android_mtp_MtpDatabase(JNIEnv *env)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001124{
1125 jclass clazz;
1126
Mike Lockwood0cd01362010-12-30 11:54:33 -05001127 clazz = env->FindClass("android/mtp/MtpDatabase");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001128 if (clazz == NULL) {
Mike Lockwood0cd01362010-12-30 11:54:33 -05001129 LOGE("Can't find android/mtp/MtpDatabase");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001130 return -1;
1131 }
Mike Lockwoodd815f792010-07-12 08:49:01 -04001132 method_beginSendObject = env->GetMethodID(clazz, "beginSendObject", "(Ljava/lang/String;IIIJJ)I");
1133 if (method_beginSendObject == NULL) {
1134 LOGE("Can't find beginSendObject");
1135 return -1;
1136 }
Mike Lockwood7a0bd172011-01-18 11:06:19 -08001137 method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIZ)V");
Mike Lockwoodd815f792010-07-12 08:49:01 -04001138 if (method_endSendObject == NULL) {
1139 LOGE("Can't find endSendObject");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001140 return -1;
1141 }
1142 method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I");
1143 if (method_getObjectList == NULL) {
1144 LOGE("Can't find getObjectList");
1145 return -1;
1146 }
Mike Lockwood7a047c82010-08-02 10:52:20 -04001147 method_getNumObjects = env->GetMethodID(clazz, "getNumObjects", "(III)I");
1148 if (method_getNumObjects == NULL) {
1149 LOGE("Can't find getNumObjects");
1150 return -1;
1151 }
Mike Lockwood4b322ce2010-08-10 07:37:50 -04001152 method_getSupportedPlaybackFormats = env->GetMethodID(clazz, "getSupportedPlaybackFormats", "()[I");
1153 if (method_getSupportedPlaybackFormats == NULL) {
1154 LOGE("Can't find getSupportedPlaybackFormats");
1155 return -1;
1156 }
1157 method_getSupportedCaptureFormats = env->GetMethodID(clazz, "getSupportedCaptureFormats", "()[I");
1158 if (method_getSupportedCaptureFormats == NULL) {
1159 LOGE("Can't find getSupportedCaptureFormats");
1160 return -1;
1161 }
1162 method_getSupportedObjectProperties = env->GetMethodID(clazz, "getSupportedObjectProperties", "(I)[I");
1163 if (method_getSupportedObjectProperties == NULL) {
1164 LOGE("Can't find getSupportedObjectProperties");
1165 return -1;
1166 }
1167 method_getSupportedDeviceProperties = env->GetMethodID(clazz, "getSupportedDeviceProperties", "()[I");
1168 if (method_getSupportedDeviceProperties == NULL) {
1169 LOGE("Can't find getSupportedDeviceProperties");
1170 return -1;
1171 }
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001172 method_setObjectProperty = env->GetMethodID(clazz, "setObjectProperty", "(IIJLjava/lang/String;)I");
1173 if (method_setObjectProperty == NULL) {
1174 LOGE("Can't find setObjectProperty");
1175 return -1;
1176 }
1177 method_getDeviceProperty = env->GetMethodID(clazz, "getDeviceProperty", "(I[J[C)I");
1178 if (method_getDeviceProperty == NULL) {
1179 LOGE("Can't find getDeviceProperty");
1180 return -1;
1181 }
1182 method_setDeviceProperty = env->GetMethodID(clazz, "setDeviceProperty", "(IJLjava/lang/String;)I");
1183 if (method_setDeviceProperty == NULL) {
1184 LOGE("Can't find setDeviceProperty");
1185 return -1;
1186 }
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001187 method_getObjectPropertyList = env->GetMethodID(clazz, "getObjectPropertyList",
Mike Lockwood0cd01362010-12-30 11:54:33 -05001188 "(JIJII)Landroid/mtp/MtpPropertyList;");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001189 if (method_getObjectPropertyList == NULL) {
1190 LOGE("Can't find getObjectPropertyList");
1191 return -1;
1192 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001193 method_getObjectInfo = env->GetMethodID(clazz, "getObjectInfo", "(I[I[C[J)Z");
1194 if (method_getObjectInfo == NULL) {
1195 LOGE("Can't find getObjectInfo");
1196 return -1;
1197 }
Mike Lockwood59c777a2010-08-02 10:37:41 -04001198 method_getObjectFilePath = env->GetMethodID(clazz, "getObjectFilePath", "(I[C[J)I");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001199 if (method_getObjectFilePath == NULL) {
1200 LOGE("Can't find getObjectFilePath");
1201 return -1;
1202 }
Mike Lockwood59c777a2010-08-02 10:37:41 -04001203 method_deleteFile = env->GetMethodID(clazz, "deleteFile", "(I)I");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001204 if (method_deleteFile == NULL) {
1205 LOGE("Can't find deleteFile");
1206 return -1;
1207 }
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001208 method_getObjectReferences = env->GetMethodID(clazz, "getObjectReferences", "(I)[I");
1209 if (method_getObjectReferences == NULL) {
1210 LOGE("Can't find getObjectReferences");
1211 return -1;
1212 }
1213 method_setObjectReferences = env->GetMethodID(clazz, "setObjectReferences", "(I[I)I");
1214 if (method_setObjectReferences == NULL) {
1215 LOGE("Can't find setObjectReferences");
1216 return -1;
1217 }
Mike Lockwood2837eef2010-08-31 16:25:12 -04001218 method_sessionStarted = env->GetMethodID(clazz, "sessionStarted", "()V");
1219 if (method_sessionStarted == NULL) {
1220 LOGE("Can't find sessionStarted");
1221 return -1;
1222 }
1223 method_sessionEnded = env->GetMethodID(clazz, "sessionEnded", "()V");
1224 if (method_sessionEnded == NULL) {
1225 LOGE("Can't find sessionEnded");
1226 return -1;
1227 }
1228
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001229 field_context = env->GetFieldID(clazz, "mNativeContext", "I");
1230 if (field_context == NULL) {
1231 LOGE("Can't find MtpDatabase.mNativeContext");
1232 return -1;
1233 }
1234
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001235 // now set up fields for MtpPropertyList class
Mike Lockwood0cd01362010-12-30 11:54:33 -05001236 clazz = env->FindClass("android/mtp/MtpPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001237 if (clazz == NULL) {
Mike Lockwood0cd01362010-12-30 11:54:33 -05001238 LOGE("Can't find android/mtp/MtpPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001239 return -1;
1240 }
1241 field_mCount = env->GetFieldID(clazz, "mCount", "I");
1242 if (field_mCount == NULL) {
1243 LOGE("Can't find MtpPropertyList.mCount");
1244 return -1;
1245 }
1246 field_mResult = env->GetFieldID(clazz, "mResult", "I");
1247 if (field_mResult == NULL) {
1248 LOGE("Can't find MtpPropertyList.mResult");
1249 return -1;
1250 }
1251 field_mObjectHandles = env->GetFieldID(clazz, "mObjectHandles", "[I");
1252 if (field_mObjectHandles == NULL) {
1253 LOGE("Can't find MtpPropertyList.mObjectHandles");
1254 return -1;
1255 }
1256 field_mPropertyCodes = env->GetFieldID(clazz, "mPropertyCodes", "[I");
1257 if (field_mPropertyCodes == NULL) {
1258 LOGE("Can't find MtpPropertyList.mPropertyCodes");
1259 return -1;
1260 }
1261 field_mDataTypes = env->GetFieldID(clazz, "mDataTypes", "[I");
1262 if (field_mDataTypes == NULL) {
1263 LOGE("Can't find MtpPropertyList.mDataTypes");
1264 return -1;
1265 }
1266 field_mLongValues = env->GetFieldID(clazz, "mLongValues", "[J");
1267 if (field_mLongValues == NULL) {
1268 LOGE("Can't find MtpPropertyList.mLongValues");
1269 return -1;
1270 }
1271 field_mStringValues = env->GetFieldID(clazz, "mStringValues", "[Ljava/lang/String;");
1272 if (field_mStringValues == NULL) {
1273 LOGE("Can't find MtpPropertyList.mStringValues");
1274 return -1;
1275 }
1276
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001277 if (AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -05001278 "android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods)))
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001279 return -1;
1280
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001281 return AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -05001282 "android/mtp/MtpPropertyGroup", gMtpPropertyGroupMethods, NELEM(gMtpPropertyGroupMethods));
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001283}