blob: 67740bcb6f14f394362ab43fc63fe53f6611a182 [file] [log] [blame]
Mike Lockwood755fd612010-05-25 19:08:48 -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 "MtpClientJNI"
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>
Mike Lockwood755fd612010-05-25 19:08:48 -040025
26#include "jni.h"
27#include "JNIHelp.h"
28#include "android_runtime/AndroidRuntime.h"
29
30#include "MtpClient.h"
31#include "MtpDevice.h"
Mike Lockwoodbc4cb0b2010-07-26 20:40:45 -040032#include "MtpObjectInfo.h"
Mike Lockwood755fd612010-05-25 19:08:48 -040033
Mike Lockwood81ea83d2010-06-30 17:49:41 -040034using namespace android;
Mike Lockwood755fd612010-05-25 19:08:48 -040035
36// ----------------------------------------------------------------------------
37
38static jmethodID method_deviceAdded;
39static jmethodID method_deviceRemoved;
40static jfieldID field_context;
41
Mike Lockwoodbc4cb0b2010-07-26 20:40:45 -040042static struct file_descriptor_offsets_t
43{
44 jclass mClass;
45 jmethodID mConstructor;
46 jfieldID mDescriptor;
47} gFileDescriptorOffsets;
48
49static struct parcel_file_descriptor_offsets_t
50{
51 jclass mClass;
52 jmethodID mConstructor;
53} gParcelFileDescriptorOffsets;
54
Mike Lockwoodff164a72010-07-15 15:01:17 -040055#ifdef HAVE_ANDROID_OS
56
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -040057static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
58 if (env->ExceptionCheck()) {
59 LOGE("An exception was thrown by callback '%s'.", methodName);
60 LOGE_EX(env);
61 env->ExceptionClear();
62 }
63}
64
Mike Lockwood755fd612010-05-25 19:08:48 -040065class MyClient : public MtpClient {
66private:
Mike Lockwood755fd612010-05-25 19:08:48 -040067 virtual void deviceAdded(MtpDevice *device);
68 virtual void deviceRemoved(MtpDevice *device);
69
Mike Lockwood755fd612010-05-25 19:08:48 -040070 jobject mClient;
Mike Lockwood755fd612010-05-25 19:08:48 -040071 MtpDevice* mEventDevice;
72
73public:
74 MyClient(JNIEnv *env, jobject client);
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -040075 void cleanup(JNIEnv *env);
Mike Lockwood755fd612010-05-25 19:08:48 -040076};
77
78MtpClient* get_client_from_object(JNIEnv* env, jobject javaClient)
79{
80 return (MtpClient*)env->GetIntField(javaClient, field_context);
81}
82
83
84MyClient::MyClient(JNIEnv *env, jobject client)
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -040085 : mClient(env->NewGlobalRef(client))
Mike Lockwood755fd612010-05-25 19:08:48 -040086{
87}
88
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -040089void MyClient::cleanup(JNIEnv *env) {
90 env->DeleteGlobalRef(mClient);
Mike Lockwood755fd612010-05-25 19:08:48 -040091}
92
Mike Lockwood755fd612010-05-25 19:08:48 -040093void MyClient::deviceAdded(MtpDevice *device) {
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -040094 JNIEnv* env = AndroidRuntime::getJNIEnv();
Mike Lockwood755fd612010-05-25 19:08:48 -040095 const char* name = device->getDeviceName();
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -040096 LOGD("MyClient::deviceAdded %s\n", name);
Mike Lockwood755fd612010-05-25 19:08:48 -040097
98 env->CallVoidMethod(mClient, method_deviceAdded, device->getID());
99
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -0400100 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood755fd612010-05-25 19:08:48 -0400101}
102
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -0400103void MyClient::deviceRemoved(MtpDevice *device) {
104 JNIEnv* env = AndroidRuntime::getJNIEnv();
105 const char* name = device->getDeviceName();
106 LOGD("MyClient::deviceRemoved %s\n", name);
Mike Lockwood755fd612010-05-25 19:08:48 -0400107
108 env->CallVoidMethod(mClient, method_deviceRemoved, device->getID());
109
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -0400110 checkAndClearExceptionFromCallback(env, __FUNCTION__);
Mike Lockwood755fd612010-05-25 19:08:48 -0400111}
112
Mike Lockwoodff164a72010-07-15 15:01:17 -0400113#endif // HAVE_ANDROID_OS
114
Mike Lockwood755fd612010-05-25 19:08:48 -0400115// ----------------------------------------------------------------------------
116
Mike Lockwood755fd612010-05-25 19:08:48 -0400117static void
118android_media_MtpClient_setup(JNIEnv *env, jobject thiz)
119{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400120#ifdef HAVE_ANDROID_OS
Mike Lockwood755fd612010-05-25 19:08:48 -0400121 LOGD("setup\n");
122 MyClient* client = new MyClient(env, thiz);
123 client->start();
124 env->SetIntField(thiz, field_context, (int)client);
Mike Lockwoodff164a72010-07-15 15:01:17 -0400125#endif
Mike Lockwood755fd612010-05-25 19:08:48 -0400126}
127
128static void
129android_media_MtpClient_finalize(JNIEnv *env, jobject thiz)
130{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400131#ifdef HAVE_ANDROID_OS
Mike Lockwood755fd612010-05-25 19:08:48 -0400132 LOGD("finalize\n");
133 MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -0400134 client->cleanup(env);
Mike Lockwood755fd612010-05-25 19:08:48 -0400135 delete client;
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -0400136 env->SetIntField(thiz, field_context, 0);
Mike Lockwoodff164a72010-07-15 15:01:17 -0400137#endif
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -0400138}
139
140static jboolean
141android_media_MtpClient_start(JNIEnv *env, jobject thiz)
142{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400143#ifdef HAVE_ANDROID_OS
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -0400144 LOGD("start\n");
145 MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
146 return client->start();
Mike Lockwoodff164a72010-07-15 15:01:17 -0400147#else
148 return false;
149#endif
Mike Lockwood755fd612010-05-25 19:08:48 -0400150}
151
152static void
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -0400153android_media_MtpClient_stop(JNIEnv *env, jobject thiz)
Mike Lockwood755fd612010-05-25 19:08:48 -0400154{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400155#ifdef HAVE_ANDROID_OS
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -0400156 LOGD("stop\n");
Mike Lockwood755fd612010-05-25 19:08:48 -0400157 MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -0400158 client->stop();
Mike Lockwoodff164a72010-07-15 15:01:17 -0400159#endif
Mike Lockwood755fd612010-05-25 19:08:48 -0400160}
161
Mike Lockwoode0a89f62010-06-11 16:34:52 -0400162static jboolean
163android_media_MtpClient_delete_object(JNIEnv *env, jobject thiz,
164 jint device_id, jint object_id)
165{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400166#ifdef HAVE_ANDROID_OS
Mike Lockwoode0a89f62010-06-11 16:34:52 -0400167 MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
168 MtpDevice* device = client->getDevice(device_id);
169 if (device)
170 return device->deleteObject(object_id);
171 else
Mike Lockwoodff164a72010-07-15 15:01:17 -0400172 #endif
Mike Lockwoode0a89f62010-06-11 16:34:52 -0400173 return NULL;
174}
175
176static jint
177android_media_MtpClient_get_parent(JNIEnv *env, jobject thiz,
178 jint device_id, jint object_id)
179{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400180#ifdef HAVE_ANDROID_OS
Mike Lockwoode0a89f62010-06-11 16:34:52 -0400181 MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
182 MtpDevice* device = client->getDevice(device_id);
183 if (device)
184 return device->getParent(object_id);
185 else
Mike Lockwoodff164a72010-07-15 15:01:17 -0400186#endif
Mike Lockwoode0a89f62010-06-11 16:34:52 -0400187 return -1;
188}
189
190static jint
191android_media_MtpClient_get_storage_id(JNIEnv *env, jobject thiz,
192 jint device_id, jint object_id)
193{
Mike Lockwoodff164a72010-07-15 15:01:17 -0400194 #ifdef HAVE_ANDROID_OS
Mike Lockwoode0a89f62010-06-11 16:34:52 -0400195 MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
196 MtpDevice* device = client->getDevice(device_id);
197 if (device)
198 return device->getStorageID(object_id);
199 else
Mike Lockwoodff164a72010-07-15 15:01:17 -0400200#endif
Mike Lockwoode0a89f62010-06-11 16:34:52 -0400201 return -1;
202}
203
Mike Lockwoodbc4cb0b2010-07-26 20:40:45 -0400204static jobject
205android_media_MtpClient_open_file(JNIEnv *env, jobject thiz,
206 jint device_id, jint object_id)
207{
208#ifdef HAVE_ANDROID_OS
209 MyClient *client = (MyClient *)env->GetIntField(thiz, field_context);
210 MtpDevice* device = client->getDevice(device_id);
211 if (!device)
212 return NULL;
213
214 MtpObjectInfo* info = device->getObjectInfo(object_id);
215 if (!info)
216 return NULL;
217 int object_size = info->mCompressedSize;
218 delete info;
219 int fd = device->readObject(object_id, object_size);
220 if (fd < 0)
221 return NULL;
222
223 jobject fileDescriptor = env->NewObject(gFileDescriptorOffsets.mClass,
224 gFileDescriptorOffsets.mConstructor);
225 if (fileDescriptor != NULL) {
226 env->SetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor, fd);
227 } else {
228 return NULL;
229 }
230 return env->NewObject(gParcelFileDescriptorOffsets.mClass,
231 gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
232#endif
233 return NULL;
234}
235
Mike Lockwood755fd612010-05-25 19:08:48 -0400236// ----------------------------------------------------------------------------
237
238static JNINativeMethod gMethods[] = {
239 {"native_setup", "()V", (void *)android_media_MtpClient_setup},
240 {"native_finalize", "()V", (void *)android_media_MtpClient_finalize},
Mike Lockwoodd0e1a9f2010-07-01 11:32:08 -0400241 {"native_start", "()Z", (void *)android_media_MtpClient_start},
242 {"native_stop", "()V", (void *)android_media_MtpClient_stop},
Mike Lockwoode0a89f62010-06-11 16:34:52 -0400243 {"native_delete_object", "(II)Z", (void *)android_media_MtpClient_delete_object},
244 {"native_get_parent", "(II)I", (void *)android_media_MtpClient_get_parent},
245 {"native_get_storage_id", "(II)I", (void *)android_media_MtpClient_get_storage_id},
Mike Lockwoodbc4cb0b2010-07-26 20:40:45 -0400246 {"native_open_file", "(II)Landroid/os/ParcelFileDescriptor;",
247 (void *)android_media_MtpClient_open_file},
Mike Lockwood755fd612010-05-25 19:08:48 -0400248};
249
250static const char* const kClassPathName = "android/media/MtpClient";
251
252int register_android_media_MtpClient(JNIEnv *env)
253{
254 jclass clazz;
255
256 LOGD("register_android_media_MtpClient\n");
257
258 clazz = env->FindClass("android/media/MtpClient");
259 if (clazz == NULL) {
260 LOGE("Can't find android/media/MtpClient");
261 return -1;
262 }
263 method_deviceAdded = env->GetMethodID(clazz, "deviceAdded", "(I)V");
264 if (method_deviceAdded == NULL) {
265 LOGE("Can't find deviceAdded");
266 return -1;
267 }
268 method_deviceRemoved = env->GetMethodID(clazz, "deviceRemoved", "(I)V");
269 if (method_deviceRemoved == NULL) {
270 LOGE("Can't find deviceRemoved");
271 return -1;
272 }
273 field_context = env->GetFieldID(clazz, "mNativeContext", "I");
274 if (field_context == NULL) {
275 LOGE("Can't find MtpClient.mNativeContext");
276 return -1;
277 }
278
Mike Lockwoodbc4cb0b2010-07-26 20:40:45 -0400279 clazz = env->FindClass("java/io/FileDescriptor");
280 LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
281 gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
282 gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
283 gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
284 LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
285 "Unable to find descriptor field in java.io.FileDescriptor");
286
287 clazz = env->FindClass("android/os/ParcelFileDescriptor");
288 LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
289 gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
290 gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
291 LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
292 "Unable to find constructor for android.os.ParcelFileDescriptor");
293
Mike Lockwood755fd612010-05-25 19:08:48 -0400294 return AndroidRuntime::registerNativeMethods(env,
295 "android/media/MtpClient", gMethods, NELEM(gMethods));
296}