blob: 2f88fd135a82eec0e726b6963afd9b1ce9e6b930 [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 Lockwood828d19d2010-08-10 15:20:35 -040032#include "MtpProperty.h"
Mike Lockwood59e3f0d2010-09-02 14:57:30 -040033#include "MtpStringBuffer.h"
Mike Lockwoodd21eac92010-07-03 00:44:05 -040034#include "MtpUtils.h"
35#include "mtp.h"
36
37using namespace android;
38
39// ----------------------------------------------------------------------------
40
Mike Lockwoodd815f792010-07-12 08:49:01 -040041static jmethodID method_beginSendObject;
42static jmethodID method_endSendObject;
Mike Lockwoodd21eac92010-07-03 00:44:05 -040043static jmethodID method_getObjectList;
Mike Lockwood7a047c82010-08-02 10:52:20 -040044static jmethodID method_getNumObjects;
Mike Lockwood4b322ce2010-08-10 07:37:50 -040045static jmethodID method_getSupportedPlaybackFormats;
46static jmethodID method_getSupportedCaptureFormats;
47static jmethodID method_getSupportedObjectProperties;
48static jmethodID method_getSupportedDeviceProperties;
Mike Lockwood828d19d2010-08-10 15:20:35 -040049static jmethodID method_setObjectProperty;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -040050static jmethodID method_getDeviceProperty;
51static jmethodID method_setDeviceProperty;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -040052static jmethodID method_getObjectPropertyList;
Mike Lockwoodd21eac92010-07-03 00:44:05 -040053static jmethodID method_getObjectInfo;
54static jmethodID method_getObjectFilePath;
55static jmethodID method_deleteFile;
Mike Lockwood9a2046f2010-08-03 15:30:09 -040056static jmethodID method_getObjectReferences;
57static jmethodID method_setObjectReferences;
Mike Lockwood2837eef2010-08-31 16:25:12 -040058static jmethodID method_sessionStarted;
59static jmethodID method_sessionEnded;
60
Mike Lockwoodd21eac92010-07-03 00:44:05 -040061static jfieldID field_context;
62
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -040063// MtpPropertyList fields
64static jfieldID field_mCount;
65static jfieldID field_mResult;
66static jfieldID field_mObjectHandles;
67static jfieldID field_mPropertyCodes;
68static jfieldID field_mDataTypes;
69static jfieldID field_mLongValues;
70static jfieldID field_mStringValues;
71
72
Mike Lockwoodd21eac92010-07-03 00:44:05 -040073MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
74 return (MtpDatabase *)env->GetIntField(database, field_context);
75}
76
Mike Lockwoodff164a72010-07-15 15:01:17 -040077#ifdef HAVE_ANDROID_OS
Mike Lockwoodd21eac92010-07-03 00:44:05 -040078// ----------------------------------------------------------------------------
79
80class MyMtpDatabase : public MtpDatabase {
81private:
82 jobject mDatabase;
83 jintArray mIntBuffer;
84 jlongArray mLongBuffer;
85 jcharArray mStringBuffer;
86
87public:
88 MyMtpDatabase(JNIEnv *env, jobject client);
89 virtual ~MyMtpDatabase();
90 void cleanup(JNIEnv *env);
91
Mike Lockwoodd815f792010-07-12 08:49:01 -040092 virtual MtpObjectHandle beginSendObject(const char* path,
Mike Lockwoodd21eac92010-07-03 00:44:05 -040093 MtpObjectFormat format,
94 MtpObjectHandle parent,
95 MtpStorageID storage,
96 uint64_t size,
97 time_t modified);
98
Mike Lockwoodd815f792010-07-12 08:49:01 -040099 virtual void endSendObject(const char* path,
100 MtpObjectHandle handle,
101 MtpObjectFormat format,
102 bool succeeded);
103
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400104 virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
105 MtpObjectFormat format,
106 MtpObjectHandle parent);
107
Mike Lockwood7a047c82010-08-02 10:52:20 -0400108 virtual int getNumObjects(MtpStorageID storageID,
109 MtpObjectFormat format,
110 MtpObjectHandle parent);
111
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400112 // callee should delete[] the results from these
113 // results can be NULL
114 virtual MtpObjectFormatList* getSupportedPlaybackFormats();
115 virtual MtpObjectFormatList* getSupportedCaptureFormats();
116 virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format);
117 virtual MtpDevicePropertyList* getSupportedDeviceProperties();
118
Mike Lockwood828d19d2010-08-10 15:20:35 -0400119 virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400120 MtpObjectProperty property,
121 MtpDataPacket& packet);
122
Mike Lockwood828d19d2010-08-10 15:20:35 -0400123 virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle handle,
124 MtpObjectProperty property,
125 MtpDataPacket& packet);
126
127 virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty property,
128 MtpDataPacket& packet);
129
130 virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty property,
131 MtpDataPacket& packet);
132
133 virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty property);
134
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400135 virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle handle,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500136 uint32_t format, uint32_t property,
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400137 int groupCode, int depth,
138 MtpDataPacket& packet);
139
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400140 virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
141 MtpDataPacket& packet);
142
Mike Lockwood59c777a2010-08-02 10:37:41 -0400143 virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
Mike Lockwood365e03e2010-12-08 16:08:01 -0800144 MtpString& outFilePath,
145 int64_t& outFileLength,
146 MtpObjectFormat& outFormat);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400147 virtual MtpResponseCode deleteFile(MtpObjectHandle handle);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400148
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400149 bool getObjectPropertyInfo(MtpObjectProperty property, int& type);
150 bool getDevicePropertyInfo(MtpDeviceProperty property, int& type);
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400151
152 virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle);
153
154 virtual MtpResponseCode setObjectReferences(MtpObjectHandle handle,
155 MtpObjectHandleList* references);
Mike Lockwood828d19d2010-08-10 15:20:35 -0400156
157 virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty property,
158 MtpObjectFormat format);
159
160 virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property);
Mike Lockwood2837eef2010-08-31 16:25:12 -0400161
162 virtual void sessionStarted();
163
164 virtual void sessionEnded();
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400165};
166
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400167// ----------------------------------------------------------------------------
168
169static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
170 if (env->ExceptionCheck()) {
171 LOGE("An exception was thrown by callback '%s'.", methodName);
172 LOGE_EX(env);
173 env->ExceptionClear();
174 }
175}
176
177// ----------------------------------------------------------------------------
178
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400179MyMtpDatabase::MyMtpDatabase(JNIEnv *env, jobject client)
180 : mDatabase(env->NewGlobalRef(client)),
181 mIntBuffer(NULL),
182 mLongBuffer(NULL),
183 mStringBuffer(NULL)
184{
185 jintArray intArray;
186 jlongArray longArray;
187 jcharArray charArray;
188
189 // create buffers for out arguments
190 // we don't need to be thread-safe so this is OK
191 intArray = env->NewIntArray(3);
192 if (!intArray)
193 goto out_of_memory;
194 mIntBuffer = (jintArray)env->NewGlobalRef(intArray);
195 longArray = env->NewLongArray(2);
196 if (!longArray)
197 goto out_of_memory;
198 mLongBuffer = (jlongArray)env->NewGlobalRef(longArray);
199 charArray = env->NewCharArray(256);
200 if (!charArray)
201 goto out_of_memory;
202 mStringBuffer = (jcharArray)env->NewGlobalRef(charArray);
203 return;
204
205out_of_memory:
206 env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), NULL);
207}
208
209void MyMtpDatabase::cleanup(JNIEnv *env) {
210 env->DeleteGlobalRef(mDatabase);
211 env->DeleteGlobalRef(mIntBuffer);
212 env->DeleteGlobalRef(mLongBuffer);
213 env->DeleteGlobalRef(mStringBuffer);
214}
215
216MyMtpDatabase::~MyMtpDatabase() {
217}
218
Mike Lockwoodd815f792010-07-12 08:49:01 -0400219MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400220 MtpObjectFormat format,
221 MtpObjectHandle parent,
222 MtpStorageID storage,
223 uint64_t size,
224 time_t modified) {
225 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood88394712010-09-27 10:01:00 -0400226 jstring pathStr = env->NewStringUTF(path);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400227 MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
Mike Lockwood88394712010-09-27 10:01:00 -0400228 pathStr, (jint)format, (jint)parent, (jint)storage,
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400229 (jlong)size, (jlong)modified);
230
Mike Lockwood88394712010-09-27 10:01:00 -0400231 if (pathStr)
232 env->DeleteLocalRef(pathStr);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400233 checkAndClearExceptionFromCallback(env, __FUNCTION__);
234 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400235}
236
Mike Lockwoodd815f792010-07-12 08:49:01 -0400237void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
Mike Lockwood7a0bd172011-01-18 11:06:19 -0800238 MtpObjectFormat format, bool succeeded) {
Mike Lockwoodd815f792010-07-12 08:49:01 -0400239 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood88394712010-09-27 10:01:00 -0400240 jstring pathStr = env->NewStringUTF(path);
241 env->CallVoidMethod(mDatabase, method_endSendObject, pathStr,
Mike Lockwood7a0bd172011-01-18 11:06:19 -0800242 (jint)handle, (jint)format, (jboolean)succeeded);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400243
Mike Lockwood88394712010-09-27 10:01:00 -0400244 if (pathStr)
245 env->DeleteLocalRef(pathStr);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400246 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd815f792010-07-12 08:49:01 -0400247}
248
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400249MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
250 MtpObjectFormat format,
251 MtpObjectHandle parent) {
252 JNIEnv* env = AndroidRuntime::getJNIEnv();
253 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList,
254 (jint)storageID, (jint)format, (jint)parent);
255 if (!array)
256 return NULL;
257 MtpObjectHandleList* list = new MtpObjectHandleList();
258 jint* handles = env->GetIntArrayElements(array, 0);
259 jsize length = env->GetArrayLength(array);
Mike Lockwood7a047c82010-08-02 10:52:20 -0400260 for (int i = 0; i < length; i++)
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400261 list->push(handles[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400262 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400263 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400264
265 checkAndClearExceptionFromCallback(env, __FUNCTION__);
266 return list;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400267}
268
Mike Lockwood7a047c82010-08-02 10:52:20 -0400269int MyMtpDatabase::getNumObjects(MtpStorageID storageID,
270 MtpObjectFormat format,
271 MtpObjectHandle parent) {
272 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400273 int result = env->CallIntMethod(mDatabase, method_getNumObjects,
Mike Lockwood7a047c82010-08-02 10:52:20 -0400274 (jint)storageID, (jint)format, (jint)parent);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400275
276 checkAndClearExceptionFromCallback(env, __FUNCTION__);
277 return result;
Mike Lockwood7a047c82010-08-02 10:52:20 -0400278}
279
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400280MtpObjectFormatList* MyMtpDatabase::getSupportedPlaybackFormats() {
281 JNIEnv* env = AndroidRuntime::getJNIEnv();
282 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
283 method_getSupportedPlaybackFormats);
284 if (!array)
285 return NULL;
286 MtpObjectFormatList* list = new MtpObjectFormatList();
287 jint* formats = env->GetIntArrayElements(array, 0);
288 jsize length = env->GetArrayLength(array);
289 for (int i = 0; i < length; i++)
290 list->push(formats[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400291 env->ReleaseIntArrayElements(array, formats, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400292 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400293
294 checkAndClearExceptionFromCallback(env, __FUNCTION__);
295 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400296}
297
298MtpObjectFormatList* MyMtpDatabase::getSupportedCaptureFormats() {
299 JNIEnv* env = AndroidRuntime::getJNIEnv();
300 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
301 method_getSupportedCaptureFormats);
302 if (!array)
303 return NULL;
304 MtpObjectFormatList* list = new MtpObjectFormatList();
305 jint* formats = env->GetIntArrayElements(array, 0);
306 jsize length = env->GetArrayLength(array);
307 for (int i = 0; i < length; i++)
308 list->push(formats[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400309 env->ReleaseIntArrayElements(array, formats, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400310 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400311
312 checkAndClearExceptionFromCallback(env, __FUNCTION__);
313 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400314}
315
316MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
317 JNIEnv* env = AndroidRuntime::getJNIEnv();
318 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
319 method_getSupportedObjectProperties, (jint)format);
320 if (!array)
321 return NULL;
322 MtpObjectPropertyList* list = new MtpObjectPropertyList();
323 jint* properties = env->GetIntArrayElements(array, 0);
324 jsize length = env->GetArrayLength(array);
325 for (int i = 0; i < length; i++)
326 list->push(properties[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400327 env->ReleaseIntArrayElements(array, properties, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400328 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400329
330 checkAndClearExceptionFromCallback(env, __FUNCTION__);
331 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400332}
333
334MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() {
335 JNIEnv* env = AndroidRuntime::getJNIEnv();
336 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
337 method_getSupportedDeviceProperties);
338 if (!array)
339 return NULL;
340 MtpDevicePropertyList* list = new MtpDevicePropertyList();
341 jint* properties = env->GetIntArrayElements(array, 0);
342 jsize length = env->GetArrayLength(array);
343 for (int i = 0; i < length; i++)
344 list->push(properties[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400345 env->ReleaseIntArrayElements(array, properties, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400346 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400347
348 checkAndClearExceptionFromCallback(env, __FUNCTION__);
349 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400350}
351
Mike Lockwood828d19d2010-08-10 15:20:35 -0400352MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400353 MtpObjectProperty property,
354 MtpDataPacket& packet) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400355 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400356 jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500357 (jlong)handle, 0, (jlong)property, 0, 0);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400358 MtpResponseCode result = env->GetIntField(list, field_mResult);
359 int count = env->GetIntField(list, field_mCount);
360 if (result == MTP_RESPONSE_OK && count != 1)
361 result = MTP_RESPONSE_GENERAL_ERROR;
362
363 if (result == MTP_RESPONSE_OK) {
364 jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
365 jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
366 jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
367 jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
368 jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
369
370 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
371 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
372 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
373 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
374
375 int type = dataTypes[0];
376 jlong longValue = (longValues ? longValues[0] : 0);
377
378 // special case date properties, which are strings to MTP
379 // but stored internally as a uint64
380 if (property == MTP_PROPERTY_DATE_MODIFIED || property == MTP_PROPERTY_DATE_ADDED) {
381 char date[20];
382 formatDateTime(longValue, date, sizeof(date));
383 packet.putString(date);
384 goto out;
385 }
386 // release date is stored internally as just the year
387 if (property == MTP_PROPERTY_ORIGINAL_RELEASE_DATE) {
388 char date[20];
389 snprintf(date, sizeof(date), "%04lld0101T000000", longValue);
390 packet.putString(date);
391 goto out;
392 }
393
394 switch (type) {
395 case MTP_TYPE_INT8:
396 packet.putInt8(longValue);
397 break;
398 case MTP_TYPE_UINT8:
399 packet.putUInt8(longValue);
400 break;
401 case MTP_TYPE_INT16:
402 packet.putInt16(longValue);
403 break;
404 case MTP_TYPE_UINT16:
405 packet.putUInt16(longValue);
406 break;
407 case MTP_TYPE_INT32:
408 packet.putInt32(longValue);
409 break;
410 case MTP_TYPE_UINT32:
411 packet.putUInt32(longValue);
412 break;
413 case MTP_TYPE_INT64:
414 packet.putInt64(longValue);
415 break;
416 case MTP_TYPE_UINT64:
417 packet.putUInt64(longValue);
418 break;
419 case MTP_TYPE_INT128:
420 packet.putInt128(longValue);
421 break;
422 case MTP_TYPE_UINT128:
423 packet.putInt128(longValue);
424 break;
425 case MTP_TYPE_STR:
426 {
427 jstring stringValue = (jstring)env->GetObjectArrayElement(stringValuesArray, 0);
428 if (stringValue) {
429 const char* str = env->GetStringUTFChars(stringValue, NULL);
James Dong39774722011-04-06 11:57:48 -0700430 if (str == NULL) {
431 return MTP_RESPONSE_GENERAL_ERROR;
432 }
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400433 packet.putString(str);
434 env->ReleaseStringUTFChars(stringValue, str);
435 } else {
436 packet.putEmptyString();
437 }
438 break;
439 }
440 default:
441 LOGE("unsupported type in getObjectPropertyValue\n");
442 result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
443 }
444out:
445 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
446 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
447 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
448 if (longValues)
449 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
450
451 env->DeleteLocalRef(objectHandlesArray);
452 env->DeleteLocalRef(propertyCodesArray);
453 env->DeleteLocalRef(dataTypesArray);
454 if (longValuesArray)
455 env->DeleteLocalRef(longValuesArray);
456 if (stringValuesArray)
457 env->DeleteLocalRef(stringValuesArray);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400458 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400459
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400460 env->DeleteLocalRef(list);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400461 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400462 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400463}
464
Mike Lockwood828d19d2010-08-10 15:20:35 -0400465MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
466 MtpObjectProperty property,
467 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400468 int type;
469
470 if (!getObjectPropertyInfo(property, type))
471 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
472
473 JNIEnv* env = AndroidRuntime::getJNIEnv();
474 jlong longValue = 0;
475 jstring stringValue = NULL;
476
477 switch (type) {
478 case MTP_TYPE_INT8:
479 longValue = packet.getInt8();
480 break;
481 case MTP_TYPE_UINT8:
482 longValue = packet.getUInt8();
483 break;
484 case MTP_TYPE_INT16:
485 longValue = packet.getInt16();
486 break;
487 case MTP_TYPE_UINT16:
488 longValue = packet.getUInt16();
489 break;
490 case MTP_TYPE_INT32:
491 longValue = packet.getInt32();
492 break;
493 case MTP_TYPE_UINT32:
494 longValue = packet.getUInt32();
495 break;
496 case MTP_TYPE_INT64:
497 longValue = packet.getInt64();
498 break;
499 case MTP_TYPE_UINT64:
500 longValue = packet.getUInt64();
501 break;
502 case MTP_TYPE_STR:
503 {
504 MtpStringBuffer buffer;
505 packet.getString(buffer);
506 stringValue = env->NewStringUTF((const char *)buffer);
507 break;
508 }
509 default:
510 LOGE("unsupported type in getObjectPropertyValue\n");
511 return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
512 }
513
514 jint result = env->CallIntMethod(mDatabase, method_setObjectProperty,
515 (jint)handle, (jint)property, longValue, stringValue);
Mike Lockwood88394712010-09-27 10:01:00 -0400516 if (stringValue)
517 env->DeleteLocalRef(stringValue);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400518
519 checkAndClearExceptionFromCallback(env, __FUNCTION__);
520 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400521}
522
523MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
524 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400525 int type;
526
527 if (!getDevicePropertyInfo(property, type))
528 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
529
530 JNIEnv* env = AndroidRuntime::getJNIEnv();
531 jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
532 (jint)property, mLongBuffer, mStringBuffer);
533 if (result != MTP_RESPONSE_OK) {
534 checkAndClearExceptionFromCallback(env, __FUNCTION__);
535 return result;
536 }
537
538 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
539 jlong longValue = longValues[0];
540 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
541
542 switch (type) {
543 case MTP_TYPE_INT8:
544 packet.putInt8(longValue);
545 break;
546 case MTP_TYPE_UINT8:
547 packet.putUInt8(longValue);
548 break;
549 case MTP_TYPE_INT16:
550 packet.putInt16(longValue);
551 break;
552 case MTP_TYPE_UINT16:
553 packet.putUInt16(longValue);
554 break;
555 case MTP_TYPE_INT32:
556 packet.putInt32(longValue);
557 break;
558 case MTP_TYPE_UINT32:
559 packet.putUInt32(longValue);
560 break;
561 case MTP_TYPE_INT64:
562 packet.putInt64(longValue);
563 break;
564 case MTP_TYPE_UINT64:
565 packet.putUInt64(longValue);
566 break;
567 case MTP_TYPE_INT128:
568 packet.putInt128(longValue);
569 break;
570 case MTP_TYPE_UINT128:
571 packet.putInt128(longValue);
572 break;
573 case MTP_TYPE_STR:
574 {
575 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
576 packet.putString(str);
577 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
578 break;
579 }
580 default:
581 LOGE("unsupported type in getDevicePropertyValue\n");
582 return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
583 }
584
585 checkAndClearExceptionFromCallback(env, __FUNCTION__);
586 return MTP_RESPONSE_OK;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400587}
588
589MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
590 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400591 int type;
592
593 if (!getDevicePropertyInfo(property, type))
594 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
595
596 JNIEnv* env = AndroidRuntime::getJNIEnv();
597 jlong longValue = 0;
598 jstring stringValue = NULL;
599
600 switch (type) {
601 case MTP_TYPE_INT8:
602 longValue = packet.getInt8();
603 break;
604 case MTP_TYPE_UINT8:
605 longValue = packet.getUInt8();
606 break;
607 case MTP_TYPE_INT16:
608 longValue = packet.getInt16();
609 break;
610 case MTP_TYPE_UINT16:
611 longValue = packet.getUInt16();
612 break;
613 case MTP_TYPE_INT32:
614 longValue = packet.getInt32();
615 break;
616 case MTP_TYPE_UINT32:
617 longValue = packet.getUInt32();
618 break;
619 case MTP_TYPE_INT64:
620 longValue = packet.getInt64();
621 break;
622 case MTP_TYPE_UINT64:
623 longValue = packet.getUInt64();
624 break;
625 case MTP_TYPE_STR:
626 {
627 MtpStringBuffer buffer;
628 packet.getString(buffer);
629 stringValue = env->NewStringUTF((const char *)buffer);
630 break;
631 }
632 default:
633 LOGE("unsupported type in setDevicePropertyValue\n");
634 return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
635 }
636
637 jint result = env->CallIntMethod(mDatabase, method_setDeviceProperty,
638 (jint)property, longValue, stringValue);
Mike Lockwood88394712010-09-27 10:01:00 -0400639 if (stringValue)
640 env->DeleteLocalRef(stringValue);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400641
642 checkAndClearExceptionFromCallback(env, __FUNCTION__);
643 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400644}
645
646MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty property) {
647 return -1;
648}
649
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400650MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500651 uint32_t format, uint32_t property,
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400652 int groupCode, int depth,
653 MtpDataPacket& packet) {
654 JNIEnv* env = AndroidRuntime::getJNIEnv();
655 jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500656 (jlong)handle, (jint)format, (jlong)property, (jint)groupCode, (jint)depth);
657 checkAndClearExceptionFromCallback(env, __FUNCTION__);
658 if (!list)
659 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400660 int count = env->GetIntField(list, field_mCount);
661 MtpResponseCode result = env->GetIntField(list, field_mResult);
662
663 packet.putUInt32(count);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400664 if (count > 0) {
665 jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
666 jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
667 jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
668 jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
669 jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
670
671 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
672 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
673 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
674 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
675
676 for (int i = 0; i < count; i++) {
677 packet.putUInt32(objectHandles[i]);
678 packet.putUInt16(propertyCodes[i]);
679 int type = dataTypes[i];
680 packet.putUInt16(type);
681
682 switch (type) {
683 case MTP_TYPE_INT8:
684 packet.putInt8(longValues[i]);
685 break;
686 case MTP_TYPE_UINT8:
687 packet.putUInt8(longValues[i]);
688 break;
689 case MTP_TYPE_INT16:
690 packet.putInt16(longValues[i]);
691 break;
692 case MTP_TYPE_UINT16:
693 packet.putUInt16(longValues[i]);
694 break;
695 case MTP_TYPE_INT32:
696 packet.putInt32(longValues[i]);
697 break;
698 case MTP_TYPE_UINT32:
699 packet.putUInt32(longValues[i]);
700 break;
701 case MTP_TYPE_INT64:
702 packet.putInt64(longValues[i]);
703 break;
704 case MTP_TYPE_UINT64:
705 packet.putUInt64(longValues[i]);
706 break;
707 case MTP_TYPE_INT128:
708 packet.putInt128(longValues[i]);
709 break;
710 case MTP_TYPE_UINT128:
711 packet.putUInt128(longValues[i]);
712 break;
713 case MTP_TYPE_STR: {
714 jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i);
Mike Lockwood2711e492010-12-11 11:24:37 -0800715 const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400716 if (valueStr) {
717 packet.putString(valueStr);
718 env->ReleaseStringUTFChars(value, valueStr);
719 } else {
720 packet.putEmptyString();
721 }
722 env->DeleteLocalRef(value);
723 break;
724 }
725 default:
726 LOGE("bad or unsupported data type in MyMtpDatabase::getObjectPropertyList");
727 break;
728 }
729 }
730
731 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
732 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
733 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
734 if (longValues)
735 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
736
737 env->DeleteLocalRef(objectHandlesArray);
738 env->DeleteLocalRef(propertyCodesArray);
739 env->DeleteLocalRef(dataTypesArray);
740 if (longValuesArray)
741 env->DeleteLocalRef(longValuesArray);
742 if (stringValuesArray)
743 env->DeleteLocalRef(stringValuesArray);
744 }
745
746 env->DeleteLocalRef(list);
747 checkAndClearExceptionFromCallback(env, __FUNCTION__);
748 return result;
749}
750
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400751MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
752 MtpDataPacket& packet) {
753 char date[20];
754
755 JNIEnv* env = AndroidRuntime::getJNIEnv();
756 jboolean result = env->CallBooleanMethod(mDatabase, method_getObjectInfo,
757 (jint)handle, mIntBuffer, mStringBuffer, mLongBuffer);
758 if (!result)
759 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
760
761 jint* intValues = env->GetIntArrayElements(mIntBuffer, 0);
762 MtpStorageID storageID = intValues[0];
763 MtpObjectFormat format = intValues[1];
764 MtpObjectHandle parent = intValues[2];
765 env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
766
767 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
768 uint64_t size = longValues[0];
769 uint64_t modified = longValues[1];
770 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
771
Mike Lockwood828d19d2010-08-10 15:20:35 -0400772// int associationType = (format == MTP_FORMAT_ASSOCIATION ?
773// MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
774// MTP_ASSOCIATION_TYPE_UNDEFINED);
775 int associationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400776
777 packet.putUInt32(storageID);
778 packet.putUInt16(format);
779 packet.putUInt16(0); // protection status
780 packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
781 packet.putUInt16(0); // thumb format
782 packet.putUInt32(0); // thumb compressed size
783 packet.putUInt32(0); // thumb pix width
784 packet.putUInt32(0); // thumb pix height
785 packet.putUInt32(0); // image pix width
786 packet.putUInt32(0); // image pix height
787 packet.putUInt32(0); // image bit depth
788 packet.putUInt32(parent);
789 packet.putUInt16(associationType);
790 packet.putUInt32(0); // association desc
791 packet.putUInt32(0); // sequence number
792
793 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
794 packet.putString(str); // file name
795 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
796
797 packet.putEmptyString();
798 formatDateTime(modified, date, sizeof(date));
799 packet.putString(date); // date modified
800 packet.putEmptyString(); // keywords
801
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400802 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400803 return MTP_RESPONSE_OK;
804}
805
Mike Lockwood59c777a2010-08-02 10:37:41 -0400806MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
Mike Lockwood365e03e2010-12-08 16:08:01 -0800807 MtpString& outFilePath,
808 int64_t& outFileLength,
809 MtpObjectFormat& outFormat) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400810 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood59c777a2010-08-02 10:37:41 -0400811 jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400812 (jint)handle, mStringBuffer, mLongBuffer);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400813 if (result != MTP_RESPONSE_OK) {
814 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400815 return result;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400816 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400817
818 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
Mike Lockwood365e03e2010-12-08 16:08:01 -0800819 outFilePath.setTo(str, strlen16(str));
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400820 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
821
822 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
Mike Lockwood365e03e2010-12-08 16:08:01 -0800823 outFileLength = longValues[0];
824 outFormat = longValues[1];
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400825 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
826
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400827 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400828 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400829}
830
Mike Lockwood59c777a2010-08-02 10:37:41 -0400831MtpResponseCode MyMtpDatabase::deleteFile(MtpObjectHandle handle) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400832 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400833 MtpResponseCode result = env->CallIntMethod(mDatabase, method_deleteFile, (jint)handle);
834
835 checkAndClearExceptionFromCallback(env, __FUNCTION__);
836 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400837}
838
839struct PropertyTableEntry {
840 MtpObjectProperty property;
841 int type;
842};
843
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400844static const PropertyTableEntry kObjectPropertyTable[] = {
Mike Lockwoodd3bfecb2010-09-23 23:04:28 -0400845 { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 },
846 { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 },
847 { MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16 },
848 { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 },
849 { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR },
850 { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR },
851 { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 },
852 { MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128 },
853 { MTP_PROPERTY_NAME, MTP_TYPE_STR },
Mike Lockwoodae078f72010-09-26 12:35:51 -0400854 { MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR },
855 { MTP_PROPERTY_DATE_ADDED, MTP_TYPE_STR },
856 { MTP_PROPERTY_ARTIST, MTP_TYPE_STR },
857 { MTP_PROPERTY_ALBUM_NAME, MTP_TYPE_STR },
858 { MTP_PROPERTY_ALBUM_ARTIST, MTP_TYPE_STR },
859 { MTP_PROPERTY_TRACK, MTP_TYPE_UINT16 },
860 { MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_TYPE_STR },
861 { MTP_PROPERTY_GENRE, MTP_TYPE_STR },
862 { MTP_PROPERTY_COMPOSER, MTP_TYPE_STR },
863 { MTP_PROPERTY_DURATION, MTP_TYPE_UINT32 },
864 { MTP_PROPERTY_DESCRIPTION, MTP_TYPE_STR },
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400865};
866
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400867static const PropertyTableEntry kDevicePropertyTable[] = {
Mike Lockwoodea93fa12010-12-07 10:41:35 -0800868 { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_STR },
869 { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR },
870 { MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR },
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400871};
872
873bool MyMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
874 int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
875 const PropertyTableEntry* entry = kObjectPropertyTable;
876 for (int i = 0; i < count; i++, entry++) {
877 if (entry->property == property) {
878 type = entry->type;
879 return true;
880 }
881 }
882 return false;
883}
884
885bool MyMtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
886 int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
887 const PropertyTableEntry* entry = kDevicePropertyTable;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400888 for (int i = 0; i < count; i++, entry++) {
889 if (entry->property == property) {
890 type = entry->type;
891 return true;
892 }
893 }
894 return false;
895}
896
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400897MtpObjectHandleList* MyMtpDatabase::getObjectReferences(MtpObjectHandle handle) {
898 JNIEnv* env = AndroidRuntime::getJNIEnv();
899 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectReferences,
900 (jint)handle);
901 if (!array)
902 return NULL;
903 MtpObjectHandleList* list = new MtpObjectHandleList();
904 jint* handles = env->GetIntArrayElements(array, 0);
905 jsize length = env->GetArrayLength(array);
906 for (int i = 0; i < length; i++)
907 list->push(handles[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400908 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400909 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400910
911 checkAndClearExceptionFromCallback(env, __FUNCTION__);
912 return list;
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400913}
914
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400915MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
916 MtpObjectHandleList* references) {
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400917 JNIEnv* env = AndroidRuntime::getJNIEnv();
918 int count = references->size();
919 jintArray array = env->NewIntArray(count);
920 if (!array) {
921 LOGE("out of memory in setObjectReferences");
922 return false;
923 }
924 jint* handles = env->GetIntArrayElements(array, 0);
925 for (int i = 0; i < count; i++)
926 handles[i] = (*references)[i];
927 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400928 MtpResponseCode result = env->CallIntMethod(mDatabase, method_setObjectReferences,
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400929 (jint)handle, array);
Mike Lockwood88394712010-09-27 10:01:00 -0400930 env->DeleteLocalRef(array);
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400931
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400932 checkAndClearExceptionFromCallback(env, __FUNCTION__);
933 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400934}
935
Mike Lockwood828d19d2010-08-10 15:20:35 -0400936MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
937 MtpObjectFormat format) {
938 MtpProperty* result = NULL;
939 switch (property) {
940 case MTP_PROPERTY_OBJECT_FORMAT:
Mike Lockwood9b5e9c42010-12-07 18:53:50 -0800941 // use format as default value
942 result = new MtpProperty(property, MTP_TYPE_UINT16, false, format);
943 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400944 case MTP_PROPERTY_PROTECTION_STATUS:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400945 case MTP_PROPERTY_TRACK:
Mike Lockwood828d19d2010-08-10 15:20:35 -0400946 result = new MtpProperty(property, MTP_TYPE_UINT16);
947 break;
948 case MTP_PROPERTY_STORAGE_ID:
949 case MTP_PROPERTY_PARENT_OBJECT:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400950 case MTP_PROPERTY_DURATION:
Mike Lockwood828d19d2010-08-10 15:20:35 -0400951 result = new MtpProperty(property, MTP_TYPE_UINT32);
952 break;
953 case MTP_PROPERTY_OBJECT_SIZE:
954 result = new MtpProperty(property, MTP_TYPE_UINT64);
955 break;
956 case MTP_PROPERTY_PERSISTENT_UID:
957 result = new MtpProperty(property, MTP_TYPE_UINT128);
958 break;
Mike Lockwoodd3bfecb2010-09-23 23:04:28 -0400959 case MTP_PROPERTY_NAME:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400960 case MTP_PROPERTY_DISPLAY_NAME:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400961 case MTP_PROPERTY_ARTIST:
962 case MTP_PROPERTY_ALBUM_NAME:
963 case MTP_PROPERTY_ALBUM_ARTIST:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400964 case MTP_PROPERTY_GENRE:
965 case MTP_PROPERTY_COMPOSER:
966 case MTP_PROPERTY_DESCRIPTION:
Mike Lockwood828d19d2010-08-10 15:20:35 -0400967 result = new MtpProperty(property, MTP_TYPE_STR);
968 break;
Mike Lockwood5b19af02010-11-23 18:38:55 -0500969 case MTP_PROPERTY_DATE_MODIFIED:
970 case MTP_PROPERTY_DATE_ADDED:
971 case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
972 result = new MtpProperty(property, MTP_TYPE_STR);
973 result->setFormDateTime();
974 break;
Mike Lockwood5ebac832010-10-12 11:33:47 -0400975 case MTP_PROPERTY_OBJECT_FILE_NAME:
Mike Lockwood6a6a3af2010-10-12 14:19:51 -0400976 // We allow renaming files and folders
977 result = new MtpProperty(property, MTP_TYPE_STR, true);
Mike Lockwood5ebac832010-10-12 11:33:47 -0400978 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400979 }
980
981 return result;
982}
983
984MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
Mike Lockwoodea93fa12010-12-07 10:41:35 -0800985 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400986 MtpProperty* result = NULL;
Mike Lockwoodea93fa12010-12-07 10:41:35 -0800987 bool writable = false;
988
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400989 switch (property) {
990 case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
991 case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
Mike Lockwoodea93fa12010-12-07 10:41:35 -0800992 writable = true;
993 // fall through
994 case MTP_DEVICE_PROPERTY_IMAGE_SIZE:
995 result = new MtpProperty(property, MTP_TYPE_STR, writable);
Mike Lockwooda2a21282010-09-25 21:21:05 -0400996
Mike Lockwoodea93fa12010-12-07 10:41:35 -0800997 // get current value
Mike Lockwooda2a21282010-09-25 21:21:05 -0400998 jint ret = env->CallIntMethod(mDatabase, method_getDeviceProperty,
999 (jint)property, mLongBuffer, mStringBuffer);
1000 if (ret == MTP_RESPONSE_OK) {
1001 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
1002 result->setCurrentValue(str);
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001003 // for read-only properties it is safe to assume current value is default value
1004 if (!writable)
1005 result->setDefaultValue(str);
Mike Lockwooda2a21282010-09-25 21:21:05 -04001006 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
1007 } else {
1008 LOGE("unable to read device property, response: %04X", ret);
1009 }
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001010 break;
1011 }
1012
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001013 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001014 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -04001015}
1016
Mike Lockwood2837eef2010-08-31 16:25:12 -04001017void MyMtpDatabase::sessionStarted() {
1018 JNIEnv* env = AndroidRuntime::getJNIEnv();
1019 env->CallVoidMethod(mDatabase, method_sessionStarted);
1020 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1021}
1022
1023void MyMtpDatabase::sessionEnded() {
1024 JNIEnv* env = AndroidRuntime::getJNIEnv();
1025 env->CallVoidMethod(mDatabase, method_sessionEnded);
1026 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1027}
1028
Mike Lockwoodff164a72010-07-15 15:01:17 -04001029#endif // HAVE_ANDROID_OS
1030
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001031// ----------------------------------------------------------------------------
1032
1033static void
Mike Lockwood0cd01362010-12-30 11:54:33 -05001034android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001035{
Mike Lockwoodff164a72010-07-15 15:01:17 -04001036#ifdef HAVE_ANDROID_OS
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001037 MyMtpDatabase* database = new MyMtpDatabase(env, thiz);
1038 env->SetIntField(thiz, field_context, (int)database);
1039 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodff164a72010-07-15 15:01:17 -04001040#endif
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001041}
1042
1043static void
Mike Lockwood0cd01362010-12-30 11:54:33 -05001044android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001045{
Mike Lockwoodff164a72010-07-15 15:01:17 -04001046#ifdef HAVE_ANDROID_OS
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001047 MyMtpDatabase* database = (MyMtpDatabase *)env->GetIntField(thiz, field_context);
1048 database->cleanup(env);
1049 delete database;
1050 env->SetIntField(thiz, field_context, 0);
1051 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodff164a72010-07-15 15:01:17 -04001052#endif
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001053}
1054
Mike Lockwood31599912010-11-15 13:43:30 -05001055static jstring
Mike Lockwood0cd01362010-12-30 11:54:33 -05001056android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject thiz, jlong seconds)
Mike Lockwood31599912010-11-15 13:43:30 -05001057{
1058#ifdef HAVE_ANDROID_OS
1059 char date[20];
1060 formatDateTime(seconds, date, sizeof(date));
1061 return env->NewStringUTF(date);
1062#else
1063 return NULL;
1064#endif
1065}
1066
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001067// ----------------------------------------------------------------------------
1068
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001069static JNINativeMethod gMtpDatabaseMethods[] = {
Mike Lockwood0cd01362010-12-30 11:54:33 -05001070 {"native_setup", "()V", (void *)android_mtp_MtpDatabase_setup},
1071 {"native_finalize", "()V", (void *)android_mtp_MtpDatabase_finalize},
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001072};
1073
1074static JNINativeMethod gMtpPropertyGroupMethods[] = {
Mike Lockwood31599912010-11-15 13:43:30 -05001075 {"format_date_time", "(J)Ljava/lang/String;",
Mike Lockwood0cd01362010-12-30 11:54:33 -05001076 (void *)android_mtp_MtpPropertyGroup_format_date_time},
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001077};
1078
Mike Lockwood0cd01362010-12-30 11:54:33 -05001079static const char* const kClassPathName = "android/mtp/MtpDatabase";
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001080
Mike Lockwood0cd01362010-12-30 11:54:33 -05001081int register_android_mtp_MtpDatabase(JNIEnv *env)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001082{
1083 jclass clazz;
1084
Mike Lockwood0cd01362010-12-30 11:54:33 -05001085 clazz = env->FindClass("android/mtp/MtpDatabase");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001086 if (clazz == NULL) {
Mike Lockwood0cd01362010-12-30 11:54:33 -05001087 LOGE("Can't find android/mtp/MtpDatabase");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001088 return -1;
1089 }
Mike Lockwoodd815f792010-07-12 08:49:01 -04001090 method_beginSendObject = env->GetMethodID(clazz, "beginSendObject", "(Ljava/lang/String;IIIJJ)I");
1091 if (method_beginSendObject == NULL) {
1092 LOGE("Can't find beginSendObject");
1093 return -1;
1094 }
Mike Lockwood7a0bd172011-01-18 11:06:19 -08001095 method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIZ)V");
Mike Lockwoodd815f792010-07-12 08:49:01 -04001096 if (method_endSendObject == NULL) {
1097 LOGE("Can't find endSendObject");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001098 return -1;
1099 }
1100 method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I");
1101 if (method_getObjectList == NULL) {
1102 LOGE("Can't find getObjectList");
1103 return -1;
1104 }
Mike Lockwood7a047c82010-08-02 10:52:20 -04001105 method_getNumObjects = env->GetMethodID(clazz, "getNumObjects", "(III)I");
1106 if (method_getNumObjects == NULL) {
1107 LOGE("Can't find getNumObjects");
1108 return -1;
1109 }
Mike Lockwood4b322ce2010-08-10 07:37:50 -04001110 method_getSupportedPlaybackFormats = env->GetMethodID(clazz, "getSupportedPlaybackFormats", "()[I");
1111 if (method_getSupportedPlaybackFormats == NULL) {
1112 LOGE("Can't find getSupportedPlaybackFormats");
1113 return -1;
1114 }
1115 method_getSupportedCaptureFormats = env->GetMethodID(clazz, "getSupportedCaptureFormats", "()[I");
1116 if (method_getSupportedCaptureFormats == NULL) {
1117 LOGE("Can't find getSupportedCaptureFormats");
1118 return -1;
1119 }
1120 method_getSupportedObjectProperties = env->GetMethodID(clazz, "getSupportedObjectProperties", "(I)[I");
1121 if (method_getSupportedObjectProperties == NULL) {
1122 LOGE("Can't find getSupportedObjectProperties");
1123 return -1;
1124 }
1125 method_getSupportedDeviceProperties = env->GetMethodID(clazz, "getSupportedDeviceProperties", "()[I");
1126 if (method_getSupportedDeviceProperties == NULL) {
1127 LOGE("Can't find getSupportedDeviceProperties");
1128 return -1;
1129 }
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001130 method_setObjectProperty = env->GetMethodID(clazz, "setObjectProperty", "(IIJLjava/lang/String;)I");
1131 if (method_setObjectProperty == NULL) {
1132 LOGE("Can't find setObjectProperty");
1133 return -1;
1134 }
1135 method_getDeviceProperty = env->GetMethodID(clazz, "getDeviceProperty", "(I[J[C)I");
1136 if (method_getDeviceProperty == NULL) {
1137 LOGE("Can't find getDeviceProperty");
1138 return -1;
1139 }
1140 method_setDeviceProperty = env->GetMethodID(clazz, "setDeviceProperty", "(IJLjava/lang/String;)I");
1141 if (method_setDeviceProperty == NULL) {
1142 LOGE("Can't find setDeviceProperty");
1143 return -1;
1144 }
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001145 method_getObjectPropertyList = env->GetMethodID(clazz, "getObjectPropertyList",
Mike Lockwood0cd01362010-12-30 11:54:33 -05001146 "(JIJII)Landroid/mtp/MtpPropertyList;");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001147 if (method_getObjectPropertyList == NULL) {
1148 LOGE("Can't find getObjectPropertyList");
1149 return -1;
1150 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001151 method_getObjectInfo = env->GetMethodID(clazz, "getObjectInfo", "(I[I[C[J)Z");
1152 if (method_getObjectInfo == NULL) {
1153 LOGE("Can't find getObjectInfo");
1154 return -1;
1155 }
Mike Lockwood59c777a2010-08-02 10:37:41 -04001156 method_getObjectFilePath = env->GetMethodID(clazz, "getObjectFilePath", "(I[C[J)I");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001157 if (method_getObjectFilePath == NULL) {
1158 LOGE("Can't find getObjectFilePath");
1159 return -1;
1160 }
Mike Lockwood59c777a2010-08-02 10:37:41 -04001161 method_deleteFile = env->GetMethodID(clazz, "deleteFile", "(I)I");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001162 if (method_deleteFile == NULL) {
1163 LOGE("Can't find deleteFile");
1164 return -1;
1165 }
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001166 method_getObjectReferences = env->GetMethodID(clazz, "getObjectReferences", "(I)[I");
1167 if (method_getObjectReferences == NULL) {
1168 LOGE("Can't find getObjectReferences");
1169 return -1;
1170 }
1171 method_setObjectReferences = env->GetMethodID(clazz, "setObjectReferences", "(I[I)I");
1172 if (method_setObjectReferences == NULL) {
1173 LOGE("Can't find setObjectReferences");
1174 return -1;
1175 }
Mike Lockwood2837eef2010-08-31 16:25:12 -04001176 method_sessionStarted = env->GetMethodID(clazz, "sessionStarted", "()V");
1177 if (method_sessionStarted == NULL) {
1178 LOGE("Can't find sessionStarted");
1179 return -1;
1180 }
1181 method_sessionEnded = env->GetMethodID(clazz, "sessionEnded", "()V");
1182 if (method_sessionEnded == NULL) {
1183 LOGE("Can't find sessionEnded");
1184 return -1;
1185 }
1186
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001187 field_context = env->GetFieldID(clazz, "mNativeContext", "I");
1188 if (field_context == NULL) {
1189 LOGE("Can't find MtpDatabase.mNativeContext");
1190 return -1;
1191 }
1192
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001193 // now set up fields for MtpPropertyList class
Mike Lockwood0cd01362010-12-30 11:54:33 -05001194 clazz = env->FindClass("android/mtp/MtpPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001195 if (clazz == NULL) {
Mike Lockwood0cd01362010-12-30 11:54:33 -05001196 LOGE("Can't find android/mtp/MtpPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001197 return -1;
1198 }
1199 field_mCount = env->GetFieldID(clazz, "mCount", "I");
1200 if (field_mCount == NULL) {
1201 LOGE("Can't find MtpPropertyList.mCount");
1202 return -1;
1203 }
1204 field_mResult = env->GetFieldID(clazz, "mResult", "I");
1205 if (field_mResult == NULL) {
1206 LOGE("Can't find MtpPropertyList.mResult");
1207 return -1;
1208 }
1209 field_mObjectHandles = env->GetFieldID(clazz, "mObjectHandles", "[I");
1210 if (field_mObjectHandles == NULL) {
1211 LOGE("Can't find MtpPropertyList.mObjectHandles");
1212 return -1;
1213 }
1214 field_mPropertyCodes = env->GetFieldID(clazz, "mPropertyCodes", "[I");
1215 if (field_mPropertyCodes == NULL) {
1216 LOGE("Can't find MtpPropertyList.mPropertyCodes");
1217 return -1;
1218 }
1219 field_mDataTypes = env->GetFieldID(clazz, "mDataTypes", "[I");
1220 if (field_mDataTypes == NULL) {
1221 LOGE("Can't find MtpPropertyList.mDataTypes");
1222 return -1;
1223 }
1224 field_mLongValues = env->GetFieldID(clazz, "mLongValues", "[J");
1225 if (field_mLongValues == NULL) {
1226 LOGE("Can't find MtpPropertyList.mLongValues");
1227 return -1;
1228 }
1229 field_mStringValues = env->GetFieldID(clazz, "mStringValues", "[Ljava/lang/String;");
1230 if (field_mStringValues == NULL) {
1231 LOGE("Can't find MtpPropertyList.mStringValues");
1232 return -1;
1233 }
1234
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001235 if (AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -05001236 "android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods)))
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001237 return -1;
1238
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001239 return AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -05001240 "android/mtp/MtpPropertyGroup", gMtpPropertyGroupMethods, NELEM(gMtpPropertyGroupMethods));
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001241}