blob: 1842cb2aa980f7310cc9621bbd94ae0ec65c750a [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 Lockwoodd21eac92010-07-03 00:44:05 -040049static jmethodID method_getObjectProperty;
Mike Lockwood828d19d2010-08-10 15:20:35 -040050static jmethodID method_setObjectProperty;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -040051static jmethodID method_getDeviceProperty;
52static jmethodID method_setDeviceProperty;
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
63MtpDatabase* getMtpDatabase(JNIEnv *env, jobject database) {
64 return (MtpDatabase *)env->GetIntField(database, field_context);
65}
66
Mike Lockwoodff164a72010-07-15 15:01:17 -040067#ifdef HAVE_ANDROID_OS
Mike Lockwoodd21eac92010-07-03 00:44:05 -040068// ----------------------------------------------------------------------------
69
70class MyMtpDatabase : public MtpDatabase {
71private:
72 jobject mDatabase;
73 jintArray mIntBuffer;
74 jlongArray mLongBuffer;
75 jcharArray mStringBuffer;
76
77public:
78 MyMtpDatabase(JNIEnv *env, jobject client);
79 virtual ~MyMtpDatabase();
80 void cleanup(JNIEnv *env);
81
Mike Lockwoodd815f792010-07-12 08:49:01 -040082 virtual MtpObjectHandle beginSendObject(const char* path,
Mike Lockwoodd21eac92010-07-03 00:44:05 -040083 MtpObjectFormat format,
84 MtpObjectHandle parent,
85 MtpStorageID storage,
86 uint64_t size,
87 time_t modified);
88
Mike Lockwoodd815f792010-07-12 08:49:01 -040089 virtual void endSendObject(const char* path,
90 MtpObjectHandle handle,
91 MtpObjectFormat format,
92 bool succeeded);
93
Mike Lockwoodd21eac92010-07-03 00:44:05 -040094 virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
95 MtpObjectFormat format,
96 MtpObjectHandle parent);
97
Mike Lockwood7a047c82010-08-02 10:52:20 -040098 virtual int getNumObjects(MtpStorageID storageID,
99 MtpObjectFormat format,
100 MtpObjectHandle parent);
101
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400102 // callee should delete[] the results from these
103 // results can be NULL
104 virtual MtpObjectFormatList* getSupportedPlaybackFormats();
105 virtual MtpObjectFormatList* getSupportedCaptureFormats();
106 virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format);
107 virtual MtpDevicePropertyList* getSupportedDeviceProperties();
108
Mike Lockwood828d19d2010-08-10 15:20:35 -0400109 virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400110 MtpObjectProperty property,
111 MtpDataPacket& packet);
112
Mike Lockwood828d19d2010-08-10 15:20:35 -0400113 virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle handle,
114 MtpObjectProperty property,
115 MtpDataPacket& packet);
116
117 virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty property,
118 MtpDataPacket& packet);
119
120 virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty property,
121 MtpDataPacket& packet);
122
123 virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty property);
124
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400125 virtual MtpResponseCode getObjectInfo(MtpObjectHandle handle,
126 MtpDataPacket& packet);
127
Mike Lockwood59c777a2010-08-02 10:37:41 -0400128 virtual MtpResponseCode getObjectFilePath(MtpObjectHandle handle,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400129 MtpString& filePath,
130 int64_t& fileLength);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400131 virtual MtpResponseCode deleteFile(MtpObjectHandle handle);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400132
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400133 bool getObjectPropertyInfo(MtpObjectProperty property, int& type);
134 bool getDevicePropertyInfo(MtpDeviceProperty property, int& type);
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400135
136 virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle);
137
138 virtual MtpResponseCode setObjectReferences(MtpObjectHandle handle,
139 MtpObjectHandleList* references);
Mike Lockwood828d19d2010-08-10 15:20:35 -0400140
141 virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty property,
142 MtpObjectFormat format);
143
144 virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property);
Mike Lockwood2837eef2010-08-31 16:25:12 -0400145
146 virtual void sessionStarted();
147
148 virtual void sessionEnded();
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400149};
150
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400151// ----------------------------------------------------------------------------
152
153static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
154 if (env->ExceptionCheck()) {
155 LOGE("An exception was thrown by callback '%s'.", methodName);
156 LOGE_EX(env);
157 env->ExceptionClear();
158 }
159}
160
161// ----------------------------------------------------------------------------
162
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400163MyMtpDatabase::MyMtpDatabase(JNIEnv *env, jobject client)
164 : mDatabase(env->NewGlobalRef(client)),
165 mIntBuffer(NULL),
166 mLongBuffer(NULL),
167 mStringBuffer(NULL)
168{
169 jintArray intArray;
170 jlongArray longArray;
171 jcharArray charArray;
172
173 // create buffers for out arguments
174 // we don't need to be thread-safe so this is OK
175 intArray = env->NewIntArray(3);
176 if (!intArray)
177 goto out_of_memory;
178 mIntBuffer = (jintArray)env->NewGlobalRef(intArray);
179 longArray = env->NewLongArray(2);
180 if (!longArray)
181 goto out_of_memory;
182 mLongBuffer = (jlongArray)env->NewGlobalRef(longArray);
183 charArray = env->NewCharArray(256);
184 if (!charArray)
185 goto out_of_memory;
186 mStringBuffer = (jcharArray)env->NewGlobalRef(charArray);
187 return;
188
189out_of_memory:
190 env->ThrowNew(env->FindClass("java/lang/OutOfMemoryError"), NULL);
191}
192
193void MyMtpDatabase::cleanup(JNIEnv *env) {
194 env->DeleteGlobalRef(mDatabase);
195 env->DeleteGlobalRef(mIntBuffer);
196 env->DeleteGlobalRef(mLongBuffer);
197 env->DeleteGlobalRef(mStringBuffer);
198}
199
200MyMtpDatabase::~MyMtpDatabase() {
201}
202
Mike Lockwoodd815f792010-07-12 08:49:01 -0400203MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400204 MtpObjectFormat format,
205 MtpObjectHandle parent,
206 MtpStorageID storage,
207 uint64_t size,
208 time_t modified) {
209 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400210 MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
211 env->NewStringUTF(path), (jint)format, (jint)parent, (jint)storage,
212 (jlong)size, (jlong)modified);
213
214 checkAndClearExceptionFromCallback(env, __FUNCTION__);
215 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400216}
217
Mike Lockwoodd815f792010-07-12 08:49:01 -0400218void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
219 MtpObjectFormat format, bool succeeded) {
220 JNIEnv* env = AndroidRuntime::getJNIEnv();
221 env->CallVoidMethod(mDatabase, method_endSendObject, env->NewStringUTF(path),
222 (jint)handle, (jint)format, (jboolean)succeeded);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400223
224 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd815f792010-07-12 08:49:01 -0400225}
226
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400227MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
228 MtpObjectFormat format,
229 MtpObjectHandle parent) {
230 JNIEnv* env = AndroidRuntime::getJNIEnv();
231 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList,
232 (jint)storageID, (jint)format, (jint)parent);
233 if (!array)
234 return NULL;
235 MtpObjectHandleList* list = new MtpObjectHandleList();
236 jint* handles = env->GetIntArrayElements(array, 0);
237 jsize length = env->GetArrayLength(array);
Mike Lockwood7a047c82010-08-02 10:52:20 -0400238 for (int i = 0; i < length; i++)
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400239 list->push(handles[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400240 env->ReleaseIntArrayElements(array, handles, 0);
241
242 checkAndClearExceptionFromCallback(env, __FUNCTION__);
243 return list;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400244}
245
Mike Lockwood7a047c82010-08-02 10:52:20 -0400246int MyMtpDatabase::getNumObjects(MtpStorageID storageID,
247 MtpObjectFormat format,
248 MtpObjectHandle parent) {
249 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400250 int result = env->CallIntMethod(mDatabase, method_getNumObjects,
Mike Lockwood7a047c82010-08-02 10:52:20 -0400251 (jint)storageID, (jint)format, (jint)parent);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400252
253 checkAndClearExceptionFromCallback(env, __FUNCTION__);
254 return result;
Mike Lockwood7a047c82010-08-02 10:52:20 -0400255}
256
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400257MtpObjectFormatList* MyMtpDatabase::getSupportedPlaybackFormats() {
258 JNIEnv* env = AndroidRuntime::getJNIEnv();
259 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
260 method_getSupportedPlaybackFormats);
261 if (!array)
262 return NULL;
263 MtpObjectFormatList* list = new MtpObjectFormatList();
264 jint* formats = env->GetIntArrayElements(array, 0);
265 jsize length = env->GetArrayLength(array);
266 for (int i = 0; i < length; i++)
267 list->push(formats[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400268 env->ReleaseIntArrayElements(array, formats, 0);
269
270 checkAndClearExceptionFromCallback(env, __FUNCTION__);
271 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400272}
273
274MtpObjectFormatList* MyMtpDatabase::getSupportedCaptureFormats() {
275 JNIEnv* env = AndroidRuntime::getJNIEnv();
276 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
277 method_getSupportedCaptureFormats);
278 if (!array)
279 return NULL;
280 MtpObjectFormatList* list = new MtpObjectFormatList();
281 jint* formats = env->GetIntArrayElements(array, 0);
282 jsize length = env->GetArrayLength(array);
283 for (int i = 0; i < length; i++)
284 list->push(formats[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400285 env->ReleaseIntArrayElements(array, formats, 0);
286
287 checkAndClearExceptionFromCallback(env, __FUNCTION__);
288 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400289}
290
291MtpObjectPropertyList* MyMtpDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
292 JNIEnv* env = AndroidRuntime::getJNIEnv();
293 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
294 method_getSupportedObjectProperties, (jint)format);
295 if (!array)
296 return NULL;
297 MtpObjectPropertyList* list = new MtpObjectPropertyList();
298 jint* properties = env->GetIntArrayElements(array, 0);
299 jsize length = env->GetArrayLength(array);
300 for (int i = 0; i < length; i++)
301 list->push(properties[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400302 env->ReleaseIntArrayElements(array, properties, 0);
303
304 checkAndClearExceptionFromCallback(env, __FUNCTION__);
305 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400306}
307
308MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() {
309 JNIEnv* env = AndroidRuntime::getJNIEnv();
310 jintArray array = (jintArray)env->CallObjectMethod(mDatabase,
311 method_getSupportedDeviceProperties);
312 if (!array)
313 return NULL;
314 MtpDevicePropertyList* list = new MtpDevicePropertyList();
315 jint* properties = env->GetIntArrayElements(array, 0);
316 jsize length = env->GetArrayLength(array);
317 for (int i = 0; i < length; i++)
318 list->push(properties[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400319 env->ReleaseIntArrayElements(array, properties, 0);
320
321 checkAndClearExceptionFromCallback(env, __FUNCTION__);
322 return list;
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400323}
324
Mike Lockwood828d19d2010-08-10 15:20:35 -0400325MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400326 MtpObjectProperty property,
327 MtpDataPacket& packet) {
328 int type;
329
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400330 if (!getObjectPropertyInfo(property, type))
331 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400332
333 JNIEnv* env = AndroidRuntime::getJNIEnv();
334 jint result = env->CallIntMethod(mDatabase, method_getObjectProperty,
335 (jint)handle, (jint)property, mLongBuffer, mStringBuffer);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400336 if (result != MTP_RESPONSE_OK) {
337 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400338 return result;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400339 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400340
341 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
342 jlong longValue = longValues[0];
343 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
344
Mike Lockwood828d19d2010-08-10 15:20:35 -0400345 // special case MTP_PROPERTY_DATE_MODIFIED, which is a string to MTP
346 // but stored internally as a uint64
347 if (property == MTP_PROPERTY_DATE_MODIFIED) {
348 char date[20];
349 formatDateTime(longValue, date, sizeof(date));
350 packet.putString(date);
351 return MTP_RESPONSE_OK;
352 }
353
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400354 switch (type) {
355 case MTP_TYPE_INT8:
356 packet.putInt8(longValue);
357 break;
358 case MTP_TYPE_UINT8:
359 packet.putUInt8(longValue);
360 break;
361 case MTP_TYPE_INT16:
362 packet.putInt16(longValue);
363 break;
364 case MTP_TYPE_UINT16:
365 packet.putUInt16(longValue);
366 break;
367 case MTP_TYPE_INT32:
368 packet.putInt32(longValue);
369 break;
370 case MTP_TYPE_UINT32:
371 packet.putUInt32(longValue);
372 break;
373 case MTP_TYPE_INT64:
374 packet.putInt64(longValue);
375 break;
376 case MTP_TYPE_UINT64:
377 packet.putUInt64(longValue);
378 break;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400379 case MTP_TYPE_INT128:
380 packet.putInt128(longValue);
381 break;
382 case MTP_TYPE_UINT128:
383 packet.putInt128(longValue);
384 break;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400385 case MTP_TYPE_STR:
386 {
387 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
388 packet.putString(str);
389 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
390 break;
391 }
392 default:
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400393 LOGE("unsupported type in getObjectPropertyValue\n");
394 return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400395 }
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400396
397 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400398 return MTP_RESPONSE_OK;
399}
400
Mike Lockwood828d19d2010-08-10 15:20:35 -0400401MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
402 MtpObjectProperty property,
403 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400404 int type;
405
406 if (!getObjectPropertyInfo(property, type))
407 return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED;
408
409 JNIEnv* env = AndroidRuntime::getJNIEnv();
410 jlong longValue = 0;
411 jstring stringValue = NULL;
412
413 switch (type) {
414 case MTP_TYPE_INT8:
415 longValue = packet.getInt8();
416 break;
417 case MTP_TYPE_UINT8:
418 longValue = packet.getUInt8();
419 break;
420 case MTP_TYPE_INT16:
421 longValue = packet.getInt16();
422 break;
423 case MTP_TYPE_UINT16:
424 longValue = packet.getUInt16();
425 break;
426 case MTP_TYPE_INT32:
427 longValue = packet.getInt32();
428 break;
429 case MTP_TYPE_UINT32:
430 longValue = packet.getUInt32();
431 break;
432 case MTP_TYPE_INT64:
433 longValue = packet.getInt64();
434 break;
435 case MTP_TYPE_UINT64:
436 longValue = packet.getUInt64();
437 break;
438 case MTP_TYPE_STR:
439 {
440 MtpStringBuffer buffer;
441 packet.getString(buffer);
442 stringValue = env->NewStringUTF((const char *)buffer);
443 break;
444 }
445 default:
446 LOGE("unsupported type in getObjectPropertyValue\n");
447 return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
448 }
449
450 jint result = env->CallIntMethod(mDatabase, method_setObjectProperty,
451 (jint)handle, (jint)property, longValue, stringValue);
452
453 checkAndClearExceptionFromCallback(env, __FUNCTION__);
454 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400455}
456
457MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
458 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400459
460 int type;
461
462 if (!getDevicePropertyInfo(property, type))
463 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
464
465 JNIEnv* env = AndroidRuntime::getJNIEnv();
466 jint result = env->CallIntMethod(mDatabase, method_getDeviceProperty,
467 (jint)property, mLongBuffer, mStringBuffer);
468 if (result != MTP_RESPONSE_OK) {
469 checkAndClearExceptionFromCallback(env, __FUNCTION__);
470 return result;
471 }
472
473 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
474 jlong longValue = longValues[0];
475 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
476
477 switch (type) {
478 case MTP_TYPE_INT8:
479 packet.putInt8(longValue);
480 break;
481 case MTP_TYPE_UINT8:
482 packet.putUInt8(longValue);
483 break;
484 case MTP_TYPE_INT16:
485 packet.putInt16(longValue);
486 break;
487 case MTP_TYPE_UINT16:
488 packet.putUInt16(longValue);
489 break;
490 case MTP_TYPE_INT32:
491 packet.putInt32(longValue);
492 break;
493 case MTP_TYPE_UINT32:
494 packet.putUInt32(longValue);
495 break;
496 case MTP_TYPE_INT64:
497 packet.putInt64(longValue);
498 break;
499 case MTP_TYPE_UINT64:
500 packet.putUInt64(longValue);
501 break;
502 case MTP_TYPE_INT128:
503 packet.putInt128(longValue);
504 break;
505 case MTP_TYPE_UINT128:
506 packet.putInt128(longValue);
507 break;
508 case MTP_TYPE_STR:
509 {
510 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
511 packet.putString(str);
512 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
513 break;
514 }
515 default:
516 LOGE("unsupported type in getDevicePropertyValue\n");
517 return MTP_RESPONSE_INVALID_DEVICE_PROP_FORMAT;
518 }
519
520 checkAndClearExceptionFromCallback(env, __FUNCTION__);
521 return MTP_RESPONSE_OK;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400522}
523
524MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
525 MtpDataPacket& packet) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400526 int type;
527
528 if (!getDevicePropertyInfo(property, type))
529 return MTP_RESPONSE_DEVICE_PROP_NOT_SUPPORTED;
530
531 JNIEnv* env = AndroidRuntime::getJNIEnv();
532 jlong longValue = 0;
533 jstring stringValue = NULL;
534
535 switch (type) {
536 case MTP_TYPE_INT8:
537 longValue = packet.getInt8();
538 break;
539 case MTP_TYPE_UINT8:
540 longValue = packet.getUInt8();
541 break;
542 case MTP_TYPE_INT16:
543 longValue = packet.getInt16();
544 break;
545 case MTP_TYPE_UINT16:
546 longValue = packet.getUInt16();
547 break;
548 case MTP_TYPE_INT32:
549 longValue = packet.getInt32();
550 break;
551 case MTP_TYPE_UINT32:
552 longValue = packet.getUInt32();
553 break;
554 case MTP_TYPE_INT64:
555 longValue = packet.getInt64();
556 break;
557 case MTP_TYPE_UINT64:
558 longValue = packet.getUInt64();
559 break;
560 case MTP_TYPE_STR:
561 {
562 MtpStringBuffer buffer;
563 packet.getString(buffer);
564 stringValue = env->NewStringUTF((const char *)buffer);
565 break;
566 }
567 default:
568 LOGE("unsupported type in setDevicePropertyValue\n");
569 return MTP_RESPONSE_INVALID_OBJECT_PROP_FORMAT;
570 }
571
572 jint result = env->CallIntMethod(mDatabase, method_setDeviceProperty,
573 (jint)property, longValue, stringValue);
574
575 checkAndClearExceptionFromCallback(env, __FUNCTION__);
576 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400577}
578
579MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty property) {
580 return -1;
581}
582
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400583MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
584 MtpDataPacket& packet) {
585 char date[20];
586
587 JNIEnv* env = AndroidRuntime::getJNIEnv();
588 jboolean result = env->CallBooleanMethod(mDatabase, method_getObjectInfo,
589 (jint)handle, mIntBuffer, mStringBuffer, mLongBuffer);
590 if (!result)
591 return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
592
593 jint* intValues = env->GetIntArrayElements(mIntBuffer, 0);
594 MtpStorageID storageID = intValues[0];
595 MtpObjectFormat format = intValues[1];
596 MtpObjectHandle parent = intValues[2];
597 env->ReleaseIntArrayElements(mIntBuffer, intValues, 0);
598
599 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
600 uint64_t size = longValues[0];
601 uint64_t modified = longValues[1];
602 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
603
Mike Lockwood828d19d2010-08-10 15:20:35 -0400604// int associationType = (format == MTP_FORMAT_ASSOCIATION ?
605// MTP_ASSOCIATION_TYPE_GENERIC_FOLDER :
606// MTP_ASSOCIATION_TYPE_UNDEFINED);
607 int associationType = MTP_ASSOCIATION_TYPE_UNDEFINED;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400608
609 packet.putUInt32(storageID);
610 packet.putUInt16(format);
611 packet.putUInt16(0); // protection status
612 packet.putUInt32((size > 0xFFFFFFFFLL ? 0xFFFFFFFF : size));
613 packet.putUInt16(0); // thumb format
614 packet.putUInt32(0); // thumb compressed size
615 packet.putUInt32(0); // thumb pix width
616 packet.putUInt32(0); // thumb pix height
617 packet.putUInt32(0); // image pix width
618 packet.putUInt32(0); // image pix height
619 packet.putUInt32(0); // image bit depth
620 packet.putUInt32(parent);
621 packet.putUInt16(associationType);
622 packet.putUInt32(0); // association desc
623 packet.putUInt32(0); // sequence number
624
625 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
626 packet.putString(str); // file name
627 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
628
629 packet.putEmptyString();
630 formatDateTime(modified, date, sizeof(date));
631 packet.putString(date); // date modified
632 packet.putEmptyString(); // keywords
633
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400634 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400635 return MTP_RESPONSE_OK;
636}
637
Mike Lockwood59c777a2010-08-02 10:37:41 -0400638MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400639 MtpString& filePath,
640 int64_t& fileLength) {
641 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood59c777a2010-08-02 10:37:41 -0400642 jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath,
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400643 (jint)handle, mStringBuffer, mLongBuffer);
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400644 if (result != MTP_RESPONSE_OK) {
645 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400646 return result;
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400647 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400648
649 jchar* str = env->GetCharArrayElements(mStringBuffer, 0);
650 filePath.setTo(str, strlen16(str));
651 env->ReleaseCharArrayElements(mStringBuffer, str, 0);
652
653 jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
654 fileLength = longValues[0];
655 env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
656
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400657 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood59c777a2010-08-02 10:37:41 -0400658 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400659}
660
Mike Lockwood59c777a2010-08-02 10:37:41 -0400661MtpResponseCode MyMtpDatabase::deleteFile(MtpObjectHandle handle) {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400662 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400663 MtpResponseCode result = env->CallIntMethod(mDatabase, method_deleteFile, (jint)handle);
664
665 checkAndClearExceptionFromCallback(env, __FUNCTION__);
666 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400667}
668
669struct PropertyTableEntry {
670 MtpObjectProperty property;
671 int type;
672};
673
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400674static const PropertyTableEntry kObjectPropertyTable[] = {
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400675 { MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 },
676 { MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 },
Mike Lockwoodc642e8a2010-08-09 14:17:52 -0400677 { MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 },
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400678 { MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR },
679 { MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 },
680 { MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR },
681};
682
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400683static const PropertyTableEntry kDevicePropertyTable[] = {
684 { MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER, MTP_TYPE_STR },
685 { MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME, MTP_TYPE_STR },
686};
687
688bool MyMtpDatabase::getObjectPropertyInfo(MtpObjectProperty property, int& type) {
689 int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]);
690 const PropertyTableEntry* entry = kObjectPropertyTable;
691 for (int i = 0; i < count; i++, entry++) {
692 if (entry->property == property) {
693 type = entry->type;
694 return true;
695 }
696 }
697 return false;
698}
699
700bool MyMtpDatabase::getDevicePropertyInfo(MtpDeviceProperty property, int& type) {
701 int count = sizeof(kDevicePropertyTable) / sizeof(kDevicePropertyTable[0]);
702 const PropertyTableEntry* entry = kDevicePropertyTable;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400703 for (int i = 0; i < count; i++, entry++) {
704 if (entry->property == property) {
705 type = entry->type;
706 return true;
707 }
708 }
709 return false;
710}
711
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400712MtpObjectHandleList* MyMtpDatabase::getObjectReferences(MtpObjectHandle handle) {
713 JNIEnv* env = AndroidRuntime::getJNIEnv();
714 jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectReferences,
715 (jint)handle);
716 if (!array)
717 return NULL;
718 MtpObjectHandleList* list = new MtpObjectHandleList();
719 jint* handles = env->GetIntArrayElements(array, 0);
720 jsize length = env->GetArrayLength(array);
721 for (int i = 0; i < length; i++)
722 list->push(handles[i]);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400723 env->ReleaseIntArrayElements(array, handles, 0);
724
725 checkAndClearExceptionFromCallback(env, __FUNCTION__);
726 return list;
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400727}
728
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400729MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
730 MtpObjectHandleList* references) {
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400731 JNIEnv* env = AndroidRuntime::getJNIEnv();
732 int count = references->size();
733 jintArray array = env->NewIntArray(count);
734 if (!array) {
735 LOGE("out of memory in setObjectReferences");
736 return false;
737 }
738 jint* handles = env->GetIntArrayElements(array, 0);
739 for (int i = 0; i < count; i++)
740 handles[i] = (*references)[i];
741 env->ReleaseIntArrayElements(array, handles, 0);
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400742 MtpResponseCode result = env->CallIntMethod(mDatabase, method_setObjectReferences,
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400743 (jint)handle, array);
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400744
Mike Lockwood0a7fa0a2010-08-24 11:25:28 -0400745 checkAndClearExceptionFromCallback(env, __FUNCTION__);
746 return result;
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400747}
748
Mike Lockwood828d19d2010-08-10 15:20:35 -0400749MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
750 MtpObjectFormat format) {
751 MtpProperty* result = NULL;
752 switch (property) {
753 case MTP_PROPERTY_OBJECT_FORMAT:
754 case MTP_PROPERTY_PROTECTION_STATUS:
755 result = new MtpProperty(property, MTP_TYPE_UINT16);
756 break;
757 case MTP_PROPERTY_STORAGE_ID:
758 case MTP_PROPERTY_PARENT_OBJECT:
759 result = new MtpProperty(property, MTP_TYPE_UINT32);
760 break;
761 case MTP_PROPERTY_OBJECT_SIZE:
762 result = new MtpProperty(property, MTP_TYPE_UINT64);
763 break;
764 case MTP_PROPERTY_PERSISTENT_UID:
765 result = new MtpProperty(property, MTP_TYPE_UINT128);
766 break;
767 case MTP_PROPERTY_OBJECT_FILE_NAME:
768 case MTP_PROPERTY_DATE_MODIFIED:
769 result = new MtpProperty(property, MTP_TYPE_STR);
770 break;
771 }
772
773 return result;
774}
775
776MtpProperty* MyMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400777 MtpProperty* result = NULL;
778 switch (property) {
779 case MTP_DEVICE_PROPERTY_SYNCHRONIZATION_PARTNER:
780 case MTP_DEVICE_PROPERTY_DEVICE_FRIENDLY_NAME:
781 // writeable string properties
782 result = new MtpProperty(property, MTP_TYPE_STR, true);
783 break;
784 }
785
786 return result;
Mike Lockwood828d19d2010-08-10 15:20:35 -0400787}
788
Mike Lockwood2837eef2010-08-31 16:25:12 -0400789void MyMtpDatabase::sessionStarted() {
790 JNIEnv* env = AndroidRuntime::getJNIEnv();
791 env->CallVoidMethod(mDatabase, method_sessionStarted);
792 checkAndClearExceptionFromCallback(env, __FUNCTION__);
793}
794
795void MyMtpDatabase::sessionEnded() {
796 JNIEnv* env = AndroidRuntime::getJNIEnv();
797 env->CallVoidMethod(mDatabase, method_sessionEnded);
798 checkAndClearExceptionFromCallback(env, __FUNCTION__);
799}
800
Mike Lockwoodff164a72010-07-15 15:01:17 -0400801#endif // HAVE_ANDROID_OS
802
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400803// ----------------------------------------------------------------------------
804
805static void
806android_media_MtpDatabase_setup(JNIEnv *env, jobject thiz)
807{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400808#ifdef HAVE_ANDROID_OS
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400809 LOGD("setup\n");
810 MyMtpDatabase* database = new MyMtpDatabase(env, thiz);
811 env->SetIntField(thiz, field_context, (int)database);
812 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodff164a72010-07-15 15:01:17 -0400813#endif
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400814}
815
816static void
817android_media_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
818{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400819#ifdef HAVE_ANDROID_OS
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400820 LOGD("finalize\n");
821 MyMtpDatabase* database = (MyMtpDatabase *)env->GetIntField(thiz, field_context);
822 database->cleanup(env);
823 delete database;
824 env->SetIntField(thiz, field_context, 0);
825 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwoodff164a72010-07-15 15:01:17 -0400826#endif
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400827}
828
829// ----------------------------------------------------------------------------
830
831static JNINativeMethod gMethods[] = {
832 {"native_setup", "()V", (void *)android_media_MtpDatabase_setup},
833 {"native_finalize", "()V", (void *)android_media_MtpDatabase_finalize},
834};
835
836static const char* const kClassPathName = "android/media/MtpDatabase";
837
838int register_android_media_MtpDatabase(JNIEnv *env)
839{
840 jclass clazz;
841
842 LOGD("register_android_media_MtpDatabase\n");
843
844 clazz = env->FindClass("android/media/MtpDatabase");
845 if (clazz == NULL) {
846 LOGE("Can't find android/media/MtpDatabase");
847 return -1;
848 }
Mike Lockwoodd815f792010-07-12 08:49:01 -0400849 method_beginSendObject = env->GetMethodID(clazz, "beginSendObject", "(Ljava/lang/String;IIIJJ)I");
850 if (method_beginSendObject == NULL) {
851 LOGE("Can't find beginSendObject");
852 return -1;
853 }
854 method_endSendObject = env->GetMethodID(clazz, "endSendObject", "(Ljava/lang/String;IIZ)V");
855 if (method_endSendObject == NULL) {
856 LOGE("Can't find endSendObject");
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400857 return -1;
858 }
859 method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I");
860 if (method_getObjectList == NULL) {
861 LOGE("Can't find getObjectList");
862 return -1;
863 }
Mike Lockwood7a047c82010-08-02 10:52:20 -0400864 method_getNumObjects = env->GetMethodID(clazz, "getNumObjects", "(III)I");
865 if (method_getNumObjects == NULL) {
866 LOGE("Can't find getNumObjects");
867 return -1;
868 }
Mike Lockwood4b322ce2010-08-10 07:37:50 -0400869 method_getSupportedPlaybackFormats = env->GetMethodID(clazz, "getSupportedPlaybackFormats", "()[I");
870 if (method_getSupportedPlaybackFormats == NULL) {
871 LOGE("Can't find getSupportedPlaybackFormats");
872 return -1;
873 }
874 method_getSupportedCaptureFormats = env->GetMethodID(clazz, "getSupportedCaptureFormats", "()[I");
875 if (method_getSupportedCaptureFormats == NULL) {
876 LOGE("Can't find getSupportedCaptureFormats");
877 return -1;
878 }
879 method_getSupportedObjectProperties = env->GetMethodID(clazz, "getSupportedObjectProperties", "(I)[I");
880 if (method_getSupportedObjectProperties == NULL) {
881 LOGE("Can't find getSupportedObjectProperties");
882 return -1;
883 }
884 method_getSupportedDeviceProperties = env->GetMethodID(clazz, "getSupportedDeviceProperties", "()[I");
885 if (method_getSupportedDeviceProperties == NULL) {
886 LOGE("Can't find getSupportedDeviceProperties");
887 return -1;
888 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400889 method_getObjectProperty = env->GetMethodID(clazz, "getObjectProperty", "(II[J[C)I");
890 if (method_getObjectProperty == NULL) {
891 LOGE("Can't find getObjectProperty");
892 return -1;
893 }
Mike Lockwood59e3f0d2010-09-02 14:57:30 -0400894 method_setObjectProperty = env->GetMethodID(clazz, "setObjectProperty", "(IIJLjava/lang/String;)I");
895 if (method_setObjectProperty == NULL) {
896 LOGE("Can't find setObjectProperty");
897 return -1;
898 }
899 method_getDeviceProperty = env->GetMethodID(clazz, "getDeviceProperty", "(I[J[C)I");
900 if (method_getDeviceProperty == NULL) {
901 LOGE("Can't find getDeviceProperty");
902 return -1;
903 }
904 method_setDeviceProperty = env->GetMethodID(clazz, "setDeviceProperty", "(IJLjava/lang/String;)I");
905 if (method_setDeviceProperty == NULL) {
906 LOGE("Can't find setDeviceProperty");
907 return -1;
908 }
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400909 method_getObjectInfo = env->GetMethodID(clazz, "getObjectInfo", "(I[I[C[J)Z");
910 if (method_getObjectInfo == NULL) {
911 LOGE("Can't find getObjectInfo");
912 return -1;
913 }
Mike Lockwood59c777a2010-08-02 10:37:41 -0400914 method_getObjectFilePath = env->GetMethodID(clazz, "getObjectFilePath", "(I[C[J)I");
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400915 if (method_getObjectFilePath == NULL) {
916 LOGE("Can't find getObjectFilePath");
917 return -1;
918 }
Mike Lockwood59c777a2010-08-02 10:37:41 -0400919 method_deleteFile = env->GetMethodID(clazz, "deleteFile", "(I)I");
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400920 if (method_deleteFile == NULL) {
921 LOGE("Can't find deleteFile");
922 return -1;
923 }
Mike Lockwood9a2046f2010-08-03 15:30:09 -0400924 method_getObjectReferences = env->GetMethodID(clazz, "getObjectReferences", "(I)[I");
925 if (method_getObjectReferences == NULL) {
926 LOGE("Can't find getObjectReferences");
927 return -1;
928 }
929 method_setObjectReferences = env->GetMethodID(clazz, "setObjectReferences", "(I[I)I");
930 if (method_setObjectReferences == NULL) {
931 LOGE("Can't find setObjectReferences");
932 return -1;
933 }
Mike Lockwood2837eef2010-08-31 16:25:12 -0400934 method_sessionStarted = env->GetMethodID(clazz, "sessionStarted", "()V");
935 if (method_sessionStarted == NULL) {
936 LOGE("Can't find sessionStarted");
937 return -1;
938 }
939 method_sessionEnded = env->GetMethodID(clazz, "sessionEnded", "()V");
940 if (method_sessionEnded == NULL) {
941 LOGE("Can't find sessionEnded");
942 return -1;
943 }
944
Mike Lockwoodd21eac92010-07-03 00:44:05 -0400945 field_context = env->GetFieldID(clazz, "mNativeContext", "I");
946 if (field_context == NULL) {
947 LOGE("Can't find MtpDatabase.mNativeContext");
948 return -1;
949 }
950
951 return AndroidRuntime::registerNativeMethods(env,
952 "android/media/MtpDatabase", gMethods, NELEM(gMethods));
953}