blob: 17d39e3eb656127d6b126273b72aa2c7a0c61935 [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);
430 packet.putString(str);
431 env->ReleaseStringUTFChars(stringValue, str);
432 } else {
433 packet.putEmptyString();
434 }
435 break;
436 }
437 default:
438 LOGE("unsupported type in getObjectPropertyValue\n");
439 result = MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
440 }
441out:
442 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
443 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
444 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
445 if (longValues)
446 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
447
448 env->DeleteLocalRef(objectHandlesArray);
449 env->DeleteLocalRef(propertyCodesArray);
450 env->DeleteLocalRef(dataTypesArray);
451 if (longValuesArray)
452 env->DeleteLocalRef(longValuesArray);
453 if (stringValuesArray)
454 env->DeleteLocalRef(stringValuesArray);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400455 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400456
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400457 env->DeleteLocalRef(list);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400458 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400459 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400460}
461
Mike Lockwood828d19d2010-08-10 15:20:35 -0400462MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
463 MtpObjectProperty property,
464 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400465 int type;
466
467 if (!getObjectPropertyInfo(property, type))
468 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
469
470 JNIEnv* env = AndroidRuntime::getJNIEnv();
471 jlong longValue = 0;
472 jstring stringValue = NULL;
473
474 switch (type) {
475 case MTP_TYPE_INT8:
476 longValue = packet.getInt8();
477 break;
478 case MTP_TYPE_UINT8:
479 longValue = packet.getUInt8();
480 break;
481 case MTP_TYPE_INT16:
482 longValue = packet.getInt16();
483 break;
484 case MTP_TYPE_UINT16:
485 longValue = packet.getUInt16();
486 break;
487 case MTP_TYPE_INT32:
488 longValue = packet.getInt32();
489 break;
490 case MTP_TYPE_UINT32:
491 longValue = packet.getUInt32();
492 break;
493 case MTP_TYPE_INT64:
494 longValue = packet.getInt64();
495 break;
496 case MTP_TYPE_UINT64:
497 longValue = packet.getUInt64();
498 break;
499 case MTP_TYPE_STR:
500 {
501 MtpStringBuffer buffer;
502 packet.getString(buffer);
503 stringValue = env->NewStringUTF((const char *)buffer);
504 break;
505 }
506 default:
507 LOGE("unsupported type in getObjectPropertyValue\n");
508 return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
509 }
510
511 jint result = env->CallIntMethod(mDatabase, method_setObjectProperty,
512 (jint)handle, (jint)property, longValue, stringValue);
Mike Lockwood88394712010-09-27 10:01:00 -0400513 if (stringValue)
514 env->DeleteLocalRef(stringValue);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400515
516 checkAndClearExceptionFromCallback(env, __FUNCTION__);
517 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400518}
519
520MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
521 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400522 int type;
523
524 if (!getDevicePropertyInfo(property, type))
525 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
526
527 JNIEnv* env = AndroidRuntime::getJNIEnv();
528 jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
529 (jint)property, mLongBuffer, mStringBuffer);
530 if (result != MTP_RESPONSE_OK) {
531 checkAndClearExceptionFromCallback(env, __FUNCTION__);
532 return result;
533 }
534
535 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
536 jlong longValue = longValues[0];
537 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
538
539 switch (type) {
540 case MTP_TYPE_INT8:
541 packet.putInt8(longValue);
542 break;
543 case MTP_TYPE_UINT8:
544 packet.putUInt8(longValue);
545 break;
546 case MTP_TYPE_INT16:
547 packet.putInt16(longValue);
548 break;
549 case MTP_TYPE_UINT16:
550 packet.putUInt16(longValue);
551 break;
552 case MTP_TYPE_INT32:
553 packet.putInt32(longValue);
554 break;
555 case MTP_TYPE_UINT32:
556 packet.putUInt32(longValue);
557 break;
558 case MTP_TYPE_INT64:
559 packet.putInt64(longValue);
560 break;
561 case MTP_TYPE_UINT64:
562 packet.putUInt64(longValue);
563 break;
564 case MTP_TYPE_INT128:
565 packet.putInt128(longValue);
566 break;
567 case MTP_TYPE_UINT128:
568 packet.putInt128(longValue);
569 break;
570 case MTP_TYPE_STR:
571 {
572 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
573 packet.putString(str);
574 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
575 break;
576 }
577 default:
578 LOGE("unsupported type in getDevicePropertyValue\n");
579 return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
580 }
581
582 checkAndClearExceptionFromCallback(env, __FUNCTION__);
583 return MTP_RESPONSE_OK;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400584}
585
586MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
587 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400588 int type;
589
590 if (!getDevicePropertyInfo(property, type))
591 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
592
593 JNIEnv* env = AndroidRuntime::getJNIEnv();
594 jlong longValue = 0;
595 jstring stringValue = NULL;
596
597 switch (type) {
598 case MTP_TYPE_INT8:
599 longValue = packet.getInt8();
600 break;
601 case MTP_TYPE_UINT8:
602 longValue = packet.getUInt8();
603 break;
604 case MTP_TYPE_INT16:
605 longValue = packet.getInt16();
606 break;
607 case MTP_TYPE_UINT16:
608 longValue = packet.getUInt16();
609 break;
610 case MTP_TYPE_INT32:
611 longValue = packet.getInt32();
612 break;
613 case MTP_TYPE_UINT32:
614 longValue = packet.getUInt32();
615 break;
616 case MTP_TYPE_INT64:
617 longValue = packet.getInt64();
618 break;
619 case MTP_TYPE_UINT64:
620 longValue = packet.getUInt64();
621 break;
622 case MTP_TYPE_STR:
623 {
624 MtpStringBuffer buffer;
625 packet.getString(buffer);
626 stringValue = env->NewStringUTF((const char *)buffer);
627 break;
628 }
629 default:
630 LOGE("unsupported type in setDevicePropertyValue\n");
631 return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
632 }
633
634 jint result = env->CallIntMethod(mDatabase, method_setDeviceProperty,
635 (jint)property, longValue, stringValue);
Mike Lockwood88394712010-09-27 10:01:00 -0400636 if (stringValue)
637 env->DeleteLocalRef(stringValue);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400638
639 checkAndClearExceptionFromCallback(env, __FUNCTION__);
640 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400641}
642
643MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty property) {
644 return -1;
645}
646
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400647MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500648 uint32_t format, uint32_t property,
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400649 int groupCode, int depth,
650 MtpDataPacket& packet) {
651 JNIEnv* env = AndroidRuntime::getJNIEnv();
652 jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
Mike Lockwood7d7fb632010-12-01 18:46:23 -0500653 (jlong)handle, (jint)format, (jlong)property, (jint)groupCode, (jint)depth);
654 checkAndClearExceptionFromCallback(env, __FUNCTION__);
655 if (!list)
656 return MTP_RESPONSE_GENERAL_ERROR;
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400657 int count = env->GetIntField(list, field_mCount);
658 MtpResponseCode result = env->GetIntField(list, field_mResult);
659
660 packet.putUInt32(count);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400661 if (count > 0) {
662 jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
663 jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
664 jintArray dataTypesArray = (jintArray)env->GetObjectField(list, field_mDataTypes);
665 jlongArray longValuesArray = (jlongArray)env->GetObjectField(list, field_mLongValues);
666 jobjectArray stringValuesArray = (jobjectArray)env->GetObjectField(list, field_mStringValues);
667
668 jint* objectHandles = env->GetIntArrayElements(objectHandlesArray, 0);
669 jint* propertyCodes = env->GetIntArrayElements(propertyCodesArray, 0);
670 jint* dataTypes = env->GetIntArrayElements(dataTypesArray, 0);
671 jlong* longValues = (longValuesArray ? env->GetLongArrayElements(longValuesArray, 0) : NULL);
672
673 for (int i = 0; i < count; i++) {
674 packet.putUInt32(objectHandles[i]);
675 packet.putUInt16(propertyCodes[i]);
676 int type = dataTypes[i];
677 packet.putUInt16(type);
678
679 switch (type) {
680 case MTP_TYPE_INT8:
681 packet.putInt8(longValues[i]);
682 break;
683 case MTP_TYPE_UINT8:
684 packet.putUInt8(longValues[i]);
685 break;
686 case MTP_TYPE_INT16:
687 packet.putInt16(longValues[i]);
688 break;
689 case MTP_TYPE_UINT16:
690 packet.putUInt16(longValues[i]);
691 break;
692 case MTP_TYPE_INT32:
693 packet.putInt32(longValues[i]);
694 break;
695 case MTP_TYPE_UINT32:
696 packet.putUInt32(longValues[i]);
697 break;
698 case MTP_TYPE_INT64:
699 packet.putInt64(longValues[i]);
700 break;
701 case MTP_TYPE_UINT64:
702 packet.putUInt64(longValues[i]);
703 break;
704 case MTP_TYPE_INT128:
705 packet.putInt128(longValues[i]);
706 break;
707 case MTP_TYPE_UINT128:
708 packet.putUInt128(longValues[i]);
709 break;
710 case MTP_TYPE_STR: {
711 jstring value = (jstring)env->GetObjectArrayElement(stringValuesArray, i);
Mike Lockwood2711e492010-12-11 11:24:37 -0800712 const char *valueStr = (value ? env->GetStringUTFChars(value, NULL) : NULL);
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -0400713 if (valueStr) {
714 packet.putString(valueStr);
715 env->ReleaseStringUTFChars(value, valueStr);
716 } else {
717 packet.putEmptyString();
718 }
719 env->DeleteLocalRef(value);
720 break;
721 }
722 default:
723 LOGE("bad or unsupported data type in MyMtpDatabase::getObjectPropertyList");
724 break;
725 }
726 }
727
728 env->ReleaseIntArrayElements(objectHandlesArray, objectHandles, 0);
729 env->ReleaseIntArrayElements(propertyCodesArray, propertyCodes, 0);
730 env->ReleaseIntArrayElements(dataTypesArray, dataTypes, 0);
731 if (longValues)
732 env->ReleaseLongArrayElements(longValuesArray, longValues, 0);
733
734 env->DeleteLocalRef(objectHandlesArray);
735 env->DeleteLocalRef(propertyCodesArray);
736 env->DeleteLocalRef(dataTypesArray);
737 if (longValuesArray)
738 env->DeleteLocalRef(longValuesArray);
739 if (stringValuesArray)
740 env->DeleteLocalRef(stringValuesArray);
741 }
742
743 env->DeleteLocalRef(list);
744 checkAndClearExceptionFromCallback(env, __FUNCTION__);
745 return result;
746}
747
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400748MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
749 MtpDataPacket& packet) {
750 char date[20];
751
752 JNIEnv* env = AndroidRuntime::getJNIEnv();
753 jboolean result = env->CallBooleanMethod(mDatabase, method_getObjectInfo,
754 (jint)handle, mIntBuffer, mStringBuffer, mLongBuffer);
755 if (!result)
756 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
757
758 jint* intValues = env->GetIntArrayElements(mIntBuffer, 0);
759 MtpStorageID storageID = intValues[0];
760 MtpObjectFormat format = intValues[1];
761 MtpObjectHandle parent = intValues[2];
762 env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
763
764 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
765 uint64_t size = longValues[0];
766 uint64_t modified = longValues[1];
767 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
768
Mike Lockwood828d19d2010-08-10 15:20:35 -0400769// int associationType = (format == MTP_FORMAT_ASSOCIATION ?
770// MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
771// MTP_ASSOCIATION_TYPE_UNDEFINED);
772 int associationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400773
774 packet.putUInt32(storageID);
775 packet.putUInt16(format);
776 packet.putUInt16(0); // protection status
777 packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
778 packet.putUInt16(0); // thumb format
779 packet.putUInt32(0); // thumb compressed size
780 packet.putUInt32(0); // thumb pix width
781 packet.putUInt32(0); // thumb pix height
782 packet.putUInt32(0); // image pix width
783 packet.putUInt32(0); // image pix height
784 packet.putUInt32(0); // image bit depth
785 packet.putUInt32(parent);
786 packet.putUInt16(associationType);
787 packet.putUInt32(0); // association desc
788 packet.putUInt32(0); // sequence number
789
790 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
791 packet.putString(str); // file name
792 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
793
794 packet.putEmptyString();
795 formatDateTime(modified, date, sizeof(date));
796 packet.putString(date); // date modified
797 packet.putEmptyString(); // keywords
798
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400799 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400800 return MTP_RESPONSE_OK;
801}
802
Mike Lockwood59c777a2010-08-02 10:37:41 -0400803MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
Mike Lockwood365e03e2010-12-08 16:08:01 -0800804 MtpString& outFilePath,
805 int64_t& outFileLength,
806 MtpObjectFormat& outFormat) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400807 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood59c777a2010-08-02 10:37:41 -0400808 jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400809 (jint)handle, mStringBuffer, mLongBuffer);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400810 if (result != MTP_RESPONSE_OK) {
811 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400812 return result;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400813 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400814
815 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
Mike Lockwood365e03e2010-12-08 16:08:01 -0800816 outFilePath.setTo(str, strlen16(str));
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400817 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
818
819 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
Mike Lockwood365e03e2010-12-08 16:08:01 -0800820 outFileLength = longValues[0];
821 outFormat = longValues[1];
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400822 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
823
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400824 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400825 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400826}
827
Mike Lockwood59c777a2010-08-02 10:37:41 -0400828MtpResponseCode MyMtpDatabase::deleteFile(MtpObjectHandle handle) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400829 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400830 MtpResponseCode result = env->CallIntMethod(mDatabase, method_deleteFile, (jint)handle);
831
832 checkAndClearExceptionFromCallback(env, __FUNCTION__);
833 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400834}
835
836struct PropertyTableEntry {
837 MtpObjectProperty property;
838 int type;
839};
840
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400841static const PropertyTableEntry kObjectPropertyTable[] = {
Mike Lockwoodd3bfecb2010-09-23 23:04:28 -0400842 { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 },
843 { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 },
844 { MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16 },
845 { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 },
846 { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR },
847 { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR },
848 { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 },
849 { MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128 },
850 { MTP_PROPERTY_NAME, MTP_TYPE_STR },
Mike Lockwoodae078f72010-09-26 12:35:51 -0400851 { MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR },
852 { MTP_PROPERTY_DATE_ADDED, MTP_TYPE_STR },
853 { MTP_PROPERTY_ARTIST, MTP_TYPE_STR },
854 { MTP_PROPERTY_ALBUM_NAME, MTP_TYPE_STR },
855 { MTP_PROPERTY_ALBUM_ARTIST, MTP_TYPE_STR },
856 { MTP_PROPERTY_TRACK, MTP_TYPE_UINT16 },
857 { MTP_PROPERTY_ORIGINAL_RELEASE_DATE, MTP_TYPE_STR },
858 { MTP_PROPERTY_GENRE, MTP_TYPE_STR },
859 { MTP_PROPERTY_COMPOSER, MTP_TYPE_STR },
860 { MTP_PROPERTY_DURATION, MTP_TYPE_UINT32 },
861 { MTP_PROPERTY_DESCRIPTION, MTP_TYPE_STR },
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400862};
863
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400864static const PropertyTableEntry kDevicePropertyTable[] = {
Mike Lockwoodea93fa12010-12-07 10:41:35 -0800865 { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_STR },
866 { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR },
867 { MTP_DEVICE_PROPERTY_IMAGE_SIZE, MTP_TYPE_STR },
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400868};
869
870bool MyMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
871 int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
872 const PropertyTableEntry* entry = kObjectPropertyTable;
873 for (int i = 0; i < count; i++, entry++) {
874 if (entry->property == property) {
875 type = entry->type;
876 return true;
877 }
878 }
879 return false;
880}
881
882bool MyMtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
883 int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
884 const PropertyTableEntry* entry = kDevicePropertyTable;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400885 for (int i = 0; i < count; i++, entry++) {
886 if (entry->property == property) {
887 type = entry->type;
888 return true;
889 }
890 }
891 return false;
892}
893
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400894MtpObjectHandleList* MyMtpDatabase::getObjectReferences(MtpObjectHandle handle) {
895 JNIEnv* env = AndroidRuntime::getJNIEnv();
896 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectReferences,
897 (jint)handle);
898 if (!array)
899 return NULL;
900 MtpObjectHandleList* list = new MtpObjectHandleList();
901 jint* handles = env->GetIntArrayElements(array, 0);
902 jsize length = env->GetArrayLength(array);
903 for (int i = 0; i < length; i++)
904 list->push(handles[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400905 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood88394712010-09-27 10:01:00 -0400906 env->DeleteLocalRef(array);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400907
908 checkAndClearExceptionFromCallback(env, __FUNCTION__);
909 return list;
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400910}
911
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400912MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
913 MtpObjectHandleList* references) {
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400914 JNIEnv* env = AndroidRuntime::getJNIEnv();
915 int count = references->size();
916 jintArray array = env->NewIntArray(count);
917 if (!array) {
918 LOGE("out of memory in setObjectReferences");
919 return false;
920 }
921 jint* handles = env->GetIntArrayElements(array, 0);
922 for (int i = 0; i < count; i++)
923 handles[i] = (*references)[i];
924 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400925 MtpResponseCode result = env->CallIntMethod(mDatabase, method_setObjectReferences,
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400926 (jint)handle, array);
Mike Lockwood88394712010-09-27 10:01:00 -0400927 env->DeleteLocalRef(array);
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400928
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400929 checkAndClearExceptionFromCallback(env, __FUNCTION__);
930 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400931}
932
Mike Lockwood828d19d2010-08-10 15:20:35 -0400933MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
934 MtpObjectFormat format) {
935 MtpProperty* result = NULL;
936 switch (property) {
937 case MTP_PROPERTY_OBJECT_FORMAT:
Mike Lockwood9b5e9c42010-12-07 18:53:50 -0800938 // use format as default value
939 result = new MtpProperty(property, MTP_TYPE_UINT16, false, format);
940 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400941 case MTP_PROPERTY_PROTECTION_STATUS:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400942 case MTP_PROPERTY_TRACK:
Mike Lockwood828d19d2010-08-10 15:20:35 -0400943 result = new MtpProperty(property, MTP_TYPE_UINT16);
944 break;
945 case MTP_PROPERTY_STORAGE_ID:
946 case MTP_PROPERTY_PARENT_OBJECT:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400947 case MTP_PROPERTY_DURATION:
Mike Lockwood828d19d2010-08-10 15:20:35 -0400948 result = new MtpProperty(property, MTP_TYPE_UINT32);
949 break;
950 case MTP_PROPERTY_OBJECT_SIZE:
951 result = new MtpProperty(property, MTP_TYPE_UINT64);
952 break;
953 case MTP_PROPERTY_PERSISTENT_UID:
954 result = new MtpProperty(property, MTP_TYPE_UINT128);
955 break;
Mike Lockwoodd3bfecb2010-09-23 23:04:28 -0400956 case MTP_PROPERTY_NAME:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400957 case MTP_PROPERTY_DISPLAY_NAME:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400958 case MTP_PROPERTY_ARTIST:
959 case MTP_PROPERTY_ALBUM_NAME:
960 case MTP_PROPERTY_ALBUM_ARTIST:
Mike Lockwoodae078f72010-09-26 12:35:51 -0400961 case MTP_PROPERTY_GENRE:
962 case MTP_PROPERTY_COMPOSER:
963 case MTP_PROPERTY_DESCRIPTION:
Mike Lockwood828d19d2010-08-10 15:20:35 -0400964 result = new MtpProperty(property, MTP_TYPE_STR);
965 break;
Mike Lockwood5b19af02010-11-23 18:38:55 -0500966 case MTP_PROPERTY_DATE_MODIFIED:
967 case MTP_PROPERTY_DATE_ADDED:
968 case MTP_PROPERTY_ORIGINAL_RELEASE_DATE:
969 result = new MtpProperty(property, MTP_TYPE_STR);
970 result->setFormDateTime();
971 break;
Mike Lockwood5ebac832010-10-12 11:33:47 -0400972 case MTP_PROPERTY_OBJECT_FILE_NAME:
Mike Lockwood6a6a3af2010-10-12 14:19:51 -0400973 // We allow renaming files and folders
974 result = new MtpProperty(property, MTP_TYPE_STR, true);
Mike Lockwood5ebac832010-10-12 11:33:47 -0400975 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400976 }
977
978 return result;
979}
980
981MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
Mike Lockwoodea93fa12010-12-07 10:41:35 -0800982 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400983 MtpProperty* result = NULL;
Mike Lockwoodea93fa12010-12-07 10:41:35 -0800984 bool writable = false;
985
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400986 switch (property) {
987 case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
988 case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
Mike Lockwoodea93fa12010-12-07 10:41:35 -0800989 writable = true;
990 // fall through
991 case MTP_DEVICE_PROPERTY_IMAGE_SIZE:
992 result = new MtpProperty(property, MTP_TYPE_STR, writable);
Mike Lockwooda2a21282010-09-25 21:21:05 -0400993
Mike Lockwoodea93fa12010-12-07 10:41:35 -0800994 // get current value
Mike Lockwooda2a21282010-09-25 21:21:05 -0400995 jint ret = env->CallIntMethod(mDatabase, method_getDeviceProperty,
996 (jint)property, mLongBuffer, mStringBuffer);
997 if (ret == MTP_RESPONSE_OK) {
998 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
999 result->setCurrentValue(str);
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001000 // for read-only properties it is safe to assume current value is default value
1001 if (!writable)
1002 result->setDefaultValue(str);
Mike Lockwooda2a21282010-09-25 21:21:05 -04001003 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
1004 } else {
1005 LOGE("unable to read device property, response: %04X", ret);
1006 }
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001007 break;
1008 }
1009
Mike Lockwoodea93fa12010-12-07 10:41:35 -08001010 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001011 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -04001012}
1013
Mike Lockwood2837eef2010-08-31 16:25:12 -04001014void MyMtpDatabase::sessionStarted() {
1015 JNIEnv* env = AndroidRuntime::getJNIEnv();
1016 env->CallVoidMethod(mDatabase, method_sessionStarted);
1017 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1018}
1019
1020void MyMtpDatabase::sessionEnded() {
1021 JNIEnv* env = AndroidRuntime::getJNIEnv();
1022 env->CallVoidMethod(mDatabase, method_sessionEnded);
1023 checkAndClearExceptionFromCallback(env, __FUNCTION__);
1024}
1025
Mike Lockwoodff164a72010-07-15 15:01:17 -04001026#endif // HAVE_ANDROID_OS
1027
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001028// ----------------------------------------------------------------------------
1029
1030static void
Mike Lockwood0cd01362010-12-30 11:54:33 -05001031android_mtp_MtpDatabase_setup(JNIEnv *env, jobject thiz)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001032{
Mike Lockwoodff164a72010-07-15 15:01:17 -04001033#ifdef HAVE_ANDROID_OS
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001034 MyMtpDatabase* database = new MyMtpDatabase(env, thiz);
1035 env->SetIntField(thiz, field_context, (int)database);
1036 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodff164a72010-07-15 15:01:17 -04001037#endif
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001038}
1039
1040static void
Mike Lockwood0cd01362010-12-30 11:54:33 -05001041android_mtp_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001042{
Mike Lockwoodff164a72010-07-15 15:01:17 -04001043#ifdef HAVE_ANDROID_OS
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001044 MyMtpDatabase* database = (MyMtpDatabase *)env->GetIntField(thiz, field_context);
1045 database->cleanup(env);
1046 delete database;
1047 env->SetIntField(thiz, field_context, 0);
1048 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodff164a72010-07-15 15:01:17 -04001049#endif
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001050}
1051
Mike Lockwood31599912010-11-15 13:43:30 -05001052static jstring
Mike Lockwood0cd01362010-12-30 11:54:33 -05001053android_mtp_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject thiz, jlong seconds)
Mike Lockwood31599912010-11-15 13:43:30 -05001054{
1055#ifdef HAVE_ANDROID_OS
1056 char date[20];
1057 formatDateTime(seconds, date, sizeof(date));
1058 return env->NewStringUTF(date);
1059#else
1060 return NULL;
1061#endif
1062}
1063
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001064// ----------------------------------------------------------------------------
1065
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001066static JNINativeMethod gMtpDatabaseMethods[] = {
Mike Lockwood0cd01362010-12-30 11:54:33 -05001067 {"native_setup", "()V", (void *)android_mtp_MtpDatabase_setup},
1068 {"native_finalize", "()V", (void *)android_mtp_MtpDatabase_finalize},
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001069};
1070
1071static JNINativeMethod gMtpPropertyGroupMethods[] = {
Mike Lockwood31599912010-11-15 13:43:30 -05001072 {"format_date_time", "(J)Ljava/lang/String;",
Mike Lockwood0cd01362010-12-30 11:54:33 -05001073 (void *)android_mtp_MtpPropertyGroup_format_date_time},
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001074};
1075
Mike Lockwood0cd01362010-12-30 11:54:33 -05001076static const char* const kClassPathName = "android/mtp/MtpDatabase";
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001077
Mike Lockwood0cd01362010-12-30 11:54:33 -05001078int register_android_mtp_MtpDatabase(JNIEnv *env)
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001079{
1080 jclass clazz;
1081
Mike Lockwood0cd01362010-12-30 11:54:33 -05001082 clazz = env->FindClass("android/mtp/MtpDatabase");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001083 if (clazz == NULL) {
Mike Lockwood0cd01362010-12-30 11:54:33 -05001084 LOGE("Can't find android/mtp/MtpDatabase");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001085 return -1;
1086 }
Mike Lockwoodd815f792010-07-12 08:49:01 -04001087 method_beginSendObject = env->GetMethodID(clazz, "beginSendObject", "(Ljava/lang/String;IIIJJ)I");
1088 if (method_beginSendObject == NULL) {
1089 LOGE("Can't find beginSendObject");
1090 return -1;
1091 }
Mike Lockwood7a0bd172011-01-18 11:06:19 -08001092 method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIZ)V");
Mike Lockwoodd815f792010-07-12 08:49:01 -04001093 if (method_endSendObject == NULL) {
1094 LOGE("Can't find endSendObject");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001095 return -1;
1096 }
1097 method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I");
1098 if (method_getObjectList == NULL) {
1099 LOGE("Can't find getObjectList");
1100 return -1;
1101 }
Mike Lockwood7a047c82010-08-02 10:52:20 -04001102 method_getNumObjects = env->GetMethodID(clazz, "getNumObjects", "(III)I");
1103 if (method_getNumObjects == NULL) {
1104 LOGE("Can't find getNumObjects");
1105 return -1;
1106 }
Mike Lockwood4b322ce2010-08-10 07:37:50 -04001107 method_getSupportedPlaybackFormats = env->GetMethodID(clazz, "getSupportedPlaybackFormats", "()[I");
1108 if (method_getSupportedPlaybackFormats == NULL) {
1109 LOGE("Can't find getSupportedPlaybackFormats");
1110 return -1;
1111 }
1112 method_getSupportedCaptureFormats = env->GetMethodID(clazz, "getSupportedCaptureFormats", "()[I");
1113 if (method_getSupportedCaptureFormats == NULL) {
1114 LOGE("Can't find getSupportedCaptureFormats");
1115 return -1;
1116 }
1117 method_getSupportedObjectProperties = env->GetMethodID(clazz, "getSupportedObjectProperties", "(I)[I");
1118 if (method_getSupportedObjectProperties == NULL) {
1119 LOGE("Can't find getSupportedObjectProperties");
1120 return -1;
1121 }
1122 method_getSupportedDeviceProperties = env->GetMethodID(clazz, "getSupportedDeviceProperties", "()[I");
1123 if (method_getSupportedDeviceProperties == NULL) {
1124 LOGE("Can't find getSupportedDeviceProperties");
1125 return -1;
1126 }
Mike Lockwood59e3f0d2010-09-02 14:57:30 -04001127 method_setObjectProperty = env->GetMethodID(clazz, "setObjectProperty", "(IIJLjava/lang/String;)I");
1128 if (method_setObjectProperty == NULL) {
1129 LOGE("Can't find setObjectProperty");
1130 return -1;
1131 }
1132 method_getDeviceProperty = env->GetMethodID(clazz, "getDeviceProperty", "(I[J[C)I");
1133 if (method_getDeviceProperty == NULL) {
1134 LOGE("Can't find getDeviceProperty");
1135 return -1;
1136 }
1137 method_setDeviceProperty = env->GetMethodID(clazz, "setDeviceProperty", "(IJLjava/lang/String;)I");
1138 if (method_setDeviceProperty == NULL) {
1139 LOGE("Can't find setDeviceProperty");
1140 return -1;
1141 }
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001142 method_getObjectPropertyList = env->GetMethodID(clazz, "getObjectPropertyList",
Mike Lockwood0cd01362010-12-30 11:54:33 -05001143 "(JIJII)Landroid/mtp/MtpPropertyList;");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001144 if (method_getObjectPropertyList == NULL) {
1145 LOGE("Can't find getObjectPropertyList");
1146 return -1;
1147 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001148 method_getObjectInfo = env->GetMethodID(clazz, "getObjectInfo", "(I[I[C[J)Z");
1149 if (method_getObjectInfo == NULL) {
1150 LOGE("Can't find getObjectInfo");
1151 return -1;
1152 }
Mike Lockwood59c777a2010-08-02 10:37:41 -04001153 method_getObjectFilePath = env->GetMethodID(clazz, "getObjectFilePath", "(I[C[J)I");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001154 if (method_getObjectFilePath == NULL) {
1155 LOGE("Can't find getObjectFilePath");
1156 return -1;
1157 }
Mike Lockwood59c777a2010-08-02 10:37:41 -04001158 method_deleteFile = env->GetMethodID(clazz, "deleteFile", "(I)I");
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001159 if (method_deleteFile == NULL) {
1160 LOGE("Can't find deleteFile");
1161 return -1;
1162 }
Mike Lockwood9a2046f2010-08-03 15:30:09 -04001163 method_getObjectReferences = env->GetMethodID(clazz, "getObjectReferences", "(I)[I");
1164 if (method_getObjectReferences == NULL) {
1165 LOGE("Can't find getObjectReferences");
1166 return -1;
1167 }
1168 method_setObjectReferences = env->GetMethodID(clazz, "setObjectReferences", "(I[I)I");
1169 if (method_setObjectReferences == NULL) {
1170 LOGE("Can't find setObjectReferences");
1171 return -1;
1172 }
Mike Lockwood2837eef2010-08-31 16:25:12 -04001173 method_sessionStarted = env->GetMethodID(clazz, "sessionStarted", "()V");
1174 if (method_sessionStarted == NULL) {
1175 LOGE("Can't find sessionStarted");
1176 return -1;
1177 }
1178 method_sessionEnded = env->GetMethodID(clazz, "sessionEnded", "()V");
1179 if (method_sessionEnded == NULL) {
1180 LOGE("Can't find sessionEnded");
1181 return -1;
1182 }
1183
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001184 field_context = env->GetFieldID(clazz, "mNativeContext", "I");
1185 if (field_context == NULL) {
1186 LOGE("Can't find MtpDatabase.mNativeContext");
1187 return -1;
1188 }
1189
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001190 // now set up fields for MtpPropertyList class
Mike Lockwood0cd01362010-12-30 11:54:33 -05001191 clazz = env->FindClass("android/mtp/MtpPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001192 if (clazz == NULL) {
Mike Lockwood0cd01362010-12-30 11:54:33 -05001193 LOGE("Can't find android/mtp/MtpPropertyList");
Mike Lockwoode2ad6ec2010-10-14 18:03:25 -04001194 return -1;
1195 }
1196 field_mCount = env->GetFieldID(clazz, "mCount", "I");
1197 if (field_mCount == NULL) {
1198 LOGE("Can't find MtpPropertyList.mCount");
1199 return -1;
1200 }
1201 field_mResult = env->GetFieldID(clazz, "mResult", "I");
1202 if (field_mResult == NULL) {
1203 LOGE("Can't find MtpPropertyList.mResult");
1204 return -1;
1205 }
1206 field_mObjectHandles = env->GetFieldID(clazz, "mObjectHandles", "[I");
1207 if (field_mObjectHandles == NULL) {
1208 LOGE("Can't find MtpPropertyList.mObjectHandles");
1209 return -1;
1210 }
1211 field_mPropertyCodes = env->GetFieldID(clazz, "mPropertyCodes", "[I");
1212 if (field_mPropertyCodes == NULL) {
1213 LOGE("Can't find MtpPropertyList.mPropertyCodes");
1214 return -1;
1215 }
1216 field_mDataTypes = env->GetFieldID(clazz, "mDataTypes", "[I");
1217 if (field_mDataTypes == NULL) {
1218 LOGE("Can't find MtpPropertyList.mDataTypes");
1219 return -1;
1220 }
1221 field_mLongValues = env->GetFieldID(clazz, "mLongValues", "[J");
1222 if (field_mLongValues == NULL) {
1223 LOGE("Can't find MtpPropertyList.mLongValues");
1224 return -1;
1225 }
1226 field_mStringValues = env->GetFieldID(clazz, "mStringValues", "[Ljava/lang/String;");
1227 if (field_mStringValues == NULL) {
1228 LOGE("Can't find MtpPropertyList.mStringValues");
1229 return -1;
1230 }
1231
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001232 if (AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -05001233 "android/mtp/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods)))
Mike Lockwood7d7fb632010-12-01 18:46:23 -05001234 return -1;
1235
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001236 return AndroidRuntime::registerNativeMethods(env,
Mike Lockwood0cd01362010-12-30 11:54:33 -05001237 "android/mtp/MtpPropertyGroup", gMtpPropertyGroupMethods, NELEM(gMtpPropertyGroupMethods));
Mike Lockwoodd21eac92010-07-03 00:44:05 -04001238}