blob: 8bbb997571d0fa12b088dc88185bd29d2df7377b [file] [log] [blame]
James Dongf3997522011-03-11 12:02:12 -08001/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002**
3** Copyright 2007, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
James Dongf3997522011-03-11 12:02:12 -080018//#define LOG_NDEBUG 0
19#define LOG_TAG "MediaScannerJNI"
20#include <utils/Log.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021#include <utils/threads.h>
James Dongf3997522011-03-11 12:02:12 -080022#include <media/mediascanner.h>
23#include <media/stagefright/StagefrightMediaScanner.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
25#include "jni.h"
26#include "JNIHelp.h"
27#include "android_runtime/AndroidRuntime.h"
28
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029using namespace android;
30
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031
32struct fields_t {
33 jfieldID context;
34};
35static fields_t fields;
36
James Dongf3997522011-03-11 12:02:12 -080037static const char* const kClassMediaScannerClient =
38 "android/media/MediaScannerClient";
39
40static const char* const kClassMediaScanner =
41 "android/media/MediaScanner";
42
43static const char* const kRunTimeException =
44 "java/lang/RuntimeException";
45
46static const char* const kIllegalArgumentException =
47 "java/lang/IllegalArgumentException";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048
49class MyMediaScannerClient : public MediaScannerClient
50{
51public:
52 MyMediaScannerClient(JNIEnv *env, jobject client)
53 : mEnv(env),
54 mClient(env->NewGlobalRef(client)),
55 mScanFileMethodID(0),
56 mHandleStringTagMethodID(0),
57 mSetMimeTypeMethodID(0)
58 {
James Dongf3997522011-03-11 12:02:12 -080059 LOGV("MyMediaScannerClient constructor");
60 jclass mediaScannerClientInterface =
61 env->FindClass(kClassMediaScannerClient);
62
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 if (mediaScannerClientInterface == NULL) {
James Dongf3997522011-03-11 12:02:12 -080064 LOGE("Class %s not found", kClassMediaScannerClient);
65 } else {
66 mScanFileMethodID = env->GetMethodID(
67 mediaScannerClientInterface,
68 "scanFile",
69 "(Ljava/lang/String;JJZ)V");
70
71 mHandleStringTagMethodID = env->GetMethodID(
72 mediaScannerClientInterface,
73 "handleStringTag",
74 "(Ljava/lang/String;Ljava/lang/String;)V");
75
76 mSetMimeTypeMethodID = env->GetMethodID(
77 mediaScannerClientInterface,
78 "setMimeType",
79 "(Ljava/lang/String;)V");
80
81 mAddNoMediaFolderMethodID = env->GetMethodID(
82 mediaScannerClientInterface,
83 "addNoMediaFolder",
84 "(Ljava/lang/String;)V");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 }
86 }
James Dongf3997522011-03-11 12:02:12 -080087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 virtual ~MyMediaScannerClient()
89 {
James Dongf3997522011-03-11 12:02:12 -080090 LOGV("MyMediaScannerClient destructor");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 mEnv->DeleteGlobalRef(mClient);
92 }
James Dongf3997522011-03-11 12:02:12 -080093
94 // Returns true if it succeeded, false if an exception occured
95 // in the Java code
Mike Lockwood076e05b2010-12-16 12:54:24 -080096 virtual bool scanFile(const char* path, long long lastModified,
97 long long fileSize, bool isDirectory)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 {
James Dongf3997522011-03-11 12:02:12 -080099 LOGV("scanFile: path(%s), time(%lld), size(%lld) and isDir(%d)",
100 path, lastModified, fileSize, isDirectory);
101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 jstring pathStr;
James Dongf3997522011-03-11 12:02:12 -0800103 if ((pathStr = mEnv->NewStringUTF(path)) == NULL) {
104 return false;
105 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
Mike Lockwood076e05b2010-12-16 12:54:24 -0800107 mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified,
108 fileSize, isDirectory);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109
110 mEnv->DeleteLocalRef(pathStr);
111 return (!mEnv->ExceptionCheck());
112 }
113
James Dongf3997522011-03-11 12:02:12 -0800114 // Returns true if it succeeded, false if an exception occured
115 // in the Java code
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 virtual bool handleStringTag(const char* name, const char* value)
117 {
James Dongf3997522011-03-11 12:02:12 -0800118 LOGV("handleStringTag: name(%s) and value(%s)", name, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 jstring nameStr, valueStr;
James Dongf3997522011-03-11 12:02:12 -0800120 if ((nameStr = mEnv->NewStringUTF(name)) == NULL) {
121 return false;
122 }
123 if ((valueStr = mEnv->NewStringUTF(value)) == NULL) {
124 return false;
125 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126
James Dongf3997522011-03-11 12:02:12 -0800127 mEnv->CallVoidMethod(
128 mClient, mHandleStringTagMethodID, nameStr, valueStr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
130 mEnv->DeleteLocalRef(nameStr);
131 mEnv->DeleteLocalRef(valueStr);
132 return (!mEnv->ExceptionCheck());
133 }
134
James Dongf3997522011-03-11 12:02:12 -0800135 // Returns true if it succeeded, false if an exception occured
136 // in the Java code
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 virtual bool setMimeType(const char* mimeType)
138 {
James Dongf3997522011-03-11 12:02:12 -0800139 LOGV("setMimeType: %s", mimeType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 jstring mimeTypeStr;
James Dongf3997522011-03-11 12:02:12 -0800141 if ((mimeTypeStr = mEnv->NewStringUTF(mimeType)) == NULL) {
142 return false;
143 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144
145 mEnv->CallVoidMethod(mClient, mSetMimeTypeMethodID, mimeTypeStr);
146
147 mEnv->DeleteLocalRef(mimeTypeStr);
148 return (!mEnv->ExceptionCheck());
149 }
150
James Dongf3997522011-03-11 12:02:12 -0800151 // Returns true if it succeeded, false if an exception occured
152 // in the Java code
Marco Nelissen8b046612009-09-03 10:49:55 -0700153 virtual bool addNoMediaFolder(const char* path)
154 {
James Dongf3997522011-03-11 12:02:12 -0800155 LOGV("addNoMediaFolder: path(%s)", path);
Marco Nelissen8b046612009-09-03 10:49:55 -0700156 jstring pathStr;
James Dongf3997522011-03-11 12:02:12 -0800157 if ((pathStr = mEnv->NewStringUTF(path)) == NULL) {
158 return false;
159 }
Marco Nelissen8b046612009-09-03 10:49:55 -0700160
161 mEnv->CallVoidMethod(mClient, mAddNoMediaFolderMethodID, pathStr);
162
163 mEnv->DeleteLocalRef(pathStr);
164 return (!mEnv->ExceptionCheck());
165 }
166
167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168private:
169 JNIEnv *mEnv;
170 jobject mClient;
James Dongf3997522011-03-11 12:02:12 -0800171 jmethodID mScanFileMethodID;
172 jmethodID mHandleStringTagMethodID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 jmethodID mSetMimeTypeMethodID;
Marco Nelissen8b046612009-09-03 10:49:55 -0700174 jmethodID mAddNoMediaFolderMethodID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175};
176
177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178static bool ExceptionCheck(void* env)
179{
James Dongf3997522011-03-11 12:02:12 -0800180 LOGV("ExceptionCheck");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 return ((JNIEnv *)env)->ExceptionCheck();
182}
183
184static void
James Dongf3997522011-03-11 12:02:12 -0800185android_media_MediaScanner_processDirectory(
186 JNIEnv *env, jobject thiz, jstring path, jobject client)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187{
James Dongf3997522011-03-11 12:02:12 -0800188 LOGV("processDirectory");
189 MediaScanner *mp =
190 (MediaScanner *)env->GetIntField(thiz, fields.context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191
192 if (path == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800193 jniThrowException(env, kIllegalArgumentException, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 return;
195 }
Mike Lockwoodc37255d2010-09-10 14:47:36 -0400196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 const char *pathStr = env->GetStringUTFChars(path, NULL);
198 if (pathStr == NULL) { // Out of memory
James Dongf3997522011-03-11 12:02:12 -0800199 jniThrowException(env, kRunTimeException, "Out of memory");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 return;
201 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202
203 MyMediaScannerClient myClient(env, client);
Mike Lockwoodc37255d2010-09-10 14:47:36 -0400204 mp->processDirectory(pathStr, myClient, ExceptionCheck, env);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 env->ReleaseStringUTFChars(path, pathStr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206}
207
208static void
James Dongf3997522011-03-11 12:02:12 -0800209android_media_MediaScanner_processFile(
210 JNIEnv *env, jobject thiz, jstring path,
211 jstring mimeType, jobject client)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212{
James Dongf3997522011-03-11 12:02:12 -0800213 LOGV("processFile");
214 MediaScanner *mp =
215 (MediaScanner *)env->GetIntField(thiz, fields.context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216
217 if (path == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800218 jniThrowException(env, kIllegalArgumentException, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 return;
220 }
James Dongf3997522011-03-11 12:02:12 -0800221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 const char *pathStr = env->GetStringUTFChars(path, NULL);
223 if (pathStr == NULL) { // Out of memory
James Dongf3997522011-03-11 12:02:12 -0800224 jniThrowException(env, kRunTimeException, "Out of memory");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 return;
226 }
James Dongf3997522011-03-11 12:02:12 -0800227
228 const char *mimeTypeStr =
229 (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 if (mimeType && mimeTypeStr == NULL) { // Out of memory
231 env->ReleaseStringUTFChars(path, pathStr);
James Dongf3997522011-03-11 12:02:12 -0800232 jniThrowException(env, kRunTimeException, "Out of memory");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 return;
234 }
235
236 MyMediaScannerClient myClient(env, client);
237 mp->processFile(pathStr, mimeTypeStr, myClient);
238 env->ReleaseStringUTFChars(path, pathStr);
239 if (mimeType) {
240 env->ReleaseStringUTFChars(mimeType, mimeTypeStr);
241 }
242}
243
244static void
James Dongf3997522011-03-11 12:02:12 -0800245android_media_MediaScanner_setLocale(
246 JNIEnv *env, jobject thiz, jstring locale)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247{
James Dongf3997522011-03-11 12:02:12 -0800248 LOGV("setLocale");
249 MediaScanner *mp =
250 (MediaScanner *)env->GetIntField(thiz, fields.context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251
252 if (locale == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800253 jniThrowException(env, kIllegalArgumentException, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 return;
255 }
256 const char *localeStr = env->GetStringUTFChars(locale, NULL);
257 if (localeStr == NULL) { // Out of memory
James Dongf3997522011-03-11 12:02:12 -0800258 jniThrowException(env, kRunTimeException, "Out of memory");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 return;
260 }
261 mp->setLocale(localeStr);
262
263 env->ReleaseStringUTFChars(locale, localeStr);
264}
265
266static jbyteArray
James Dongf3997522011-03-11 12:02:12 -0800267android_media_MediaScanner_extractAlbumArt(
268 JNIEnv *env, jobject thiz, jobject fileDescriptor)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269{
James Dongf3997522011-03-11 12:02:12 -0800270 LOGV("extractAlbumArt");
271 MediaScanner *mp =
272 (MediaScanner *)env->GetIntField(thiz, fields.context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273
274 if (fileDescriptor == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800275 jniThrowException(env, kIllegalArgumentException, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 return NULL;
277 }
278
279 int fd = getParcelFileDescriptorFD(env, fileDescriptor);
280 char* data = mp->extractAlbumArt(fd);
281 if (!data) {
282 return NULL;
283 }
284 long len = *((long*)data);
James Dongf3997522011-03-11 12:02:12 -0800285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 jbyteArray array = env->NewByteArray(len);
287 if (array != NULL) {
288 jbyte* bytes = env->GetByteArrayElements(array, NULL);
289 memcpy(bytes, data + 4, len);
290 env->ReleaseByteArrayElements(array, bytes, 0);
291 }
James Dongf3997522011-03-11 12:02:12 -0800292
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293done:
294 free(data);
295 // if NewByteArray() returned NULL, an out-of-memory
296 // exception will have been raised. I just want to
297 // return null in that case.
298 env->ExceptionClear();
299 return array;
300}
301
Marco Nelissen4935d052009-08-03 11:12:58 -0700302// This function gets a field ID, which in turn causes class initialization.
303// It is called from a static block in MediaScanner, which won't run until the
304// first time an instance of this class is used.
305static void
306android_media_MediaScanner_native_init(JNIEnv *env)
307{
James Dongf3997522011-03-11 12:02:12 -0800308 LOGV("native_init");
309 jclass clazz = env->FindClass(kClassMediaScanner);
Marco Nelissen4935d052009-08-03 11:12:58 -0700310 if (clazz == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800311 const char* err = "Can't find android/media/MediaScanner";
312 jniThrowException(env, kRunTimeException, err);
Marco Nelissen4935d052009-08-03 11:12:58 -0700313 return;
314 }
315
316 fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
317 if (fields.context == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800318 const char* err = "Can't find MediaScanner.mNativeContext";
319 jniThrowException(env, kRunTimeException, err);
Marco Nelissen4935d052009-08-03 11:12:58 -0700320 return;
321 }
322}
323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324static void
325android_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz)
326{
James Dongf3997522011-03-11 12:02:12 -0800327 LOGV("native_setup");
Andreas Huber8d65dd22010-06-23 16:40:57 -0700328 MediaScanner *mp = new StagefrightMediaScanner;
Andreas Huberbfb9fb12009-12-03 11:31:19 -0800329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 if (mp == NULL) {
James Dongf3997522011-03-11 12:02:12 -0800331 jniThrowException(env, kRunTimeException, "Out of memory");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 return;
333 }
334
335 env->SetIntField(thiz, fields.context, (int)mp);
336}
337
338static void
339android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz)
340{
James Dongf3997522011-03-11 12:02:12 -0800341 LOGV("native_finalize");
342 MediaScanner *mp =
343 (MediaScanner *)env->GetIntField(thiz, fields.context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344
James Dongf3997522011-03-11 12:02:12 -0800345 if (mp == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 return;
James Dongf3997522011-03-11 12:02:12 -0800347 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348
349 delete mp;
350}
351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352static JNINativeMethod gMethods[] = {
James Dongf3997522011-03-11 12:02:12 -0800353 {
354 "processDirectory",
355 "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
356 (void *)android_media_MediaScanner_processDirectory
357 },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358
James Dongf3997522011-03-11 12:02:12 -0800359 {
360 "processFile",
361 "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
362 (void *)android_media_MediaScanner_processFile
363 },
364
365 {
366 "setLocale",
367 "(Ljava/lang/String;)V",
368 (void *)android_media_MediaScanner_setLocale
369 },
370
371 {
372 "extractAlbumArt",
373 "(Ljava/io/FileDescriptor;)[B",
374 (void *)android_media_MediaScanner_extractAlbumArt
375 },
376
377 {
378 "native_init",
379 "()V",
380 (void *)android_media_MediaScanner_native_init
381 },
382
383 {
384 "native_setup",
385 "()V",
386 (void *)android_media_MediaScanner_native_setup
387 },
388
389 {
390 "native_finalize",
391 "()V",
392 (void *)android_media_MediaScanner_native_finalize
393 },
394};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395
Marco Nelissen4935d052009-08-03 11:12:58 -0700396// This function only registers the native methods, and is called from
397// JNI_OnLoad in android_media_MediaPlayer.cpp
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398int register_android_media_MediaScanner(JNIEnv *env)
399{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 return AndroidRuntime::registerNativeMethods(env,
James Dongf3997522011-03-11 12:02:12 -0800401 kClassMediaScanner, gMethods, NELEM(gMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402}
403
404