vlc | branch: master | Thomas Guillem <[email protected]> | Wed Jul 13 15:19:14 2016 +0200| [fd6a25a7258d111e199596e6f3d313edf453ace1] | committer: Thomas Guillem
android: fix config_GetUserDir for generic dirs Call android.os.Environment.getExternalStoragePublicDirectory() from JNI to get the path to a valid directory. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=fd6a25a7258d111e199596e6f3d313edf453ace1 --- src/android/specific.c | 172 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 164 insertions(+), 8 deletions(-) diff --git a/src/android/specific.c b/src/android/specific.c index 959dc37..1337157 100644 --- a/src/android/specific.c +++ b/src/android/specific.c @@ -33,6 +33,56 @@ #include <jni.h> static JavaVM *s_jvm = NULL; +#define GENERIC_DIR_COUNT (VLC_VIDEOS_DIR - VLC_DESKTOP_DIR + 1) +static char *ppsz_generic_names[GENERIC_DIR_COUNT] = {}; +static struct { + struct { + jclass clazz; + jmethodID getExternalStoragePublicDirectory; + } Environment; + struct { + jmethodID getAbsolutePath; + } File; +} fields = { .Environment.clazz = NULL }; + +static char * +get_java_string(JNIEnv *env, jclass clazz, const char *psz_name) +{ + jfieldID id = (*env)->GetStaticFieldID(env, clazz, psz_name, + "Ljava/lang/String;"); + if ((*env)->ExceptionCheck(env)) + return NULL; + + jstring jstr = (*env)->GetStaticObjectField(env, clazz, id); + + const char *psz_str = (*env)->GetStringUTFChars(env, jstr, 0); + if (psz_str == NULL) + return NULL; + + char *psz_strdup = strdup(psz_str); + + (*env)->ReleaseStringUTFChars(env, jstr, psz_str); + (*env)->DeleteLocalRef(env, jstr); + + return psz_strdup; +} + +void +JNI_OnUnload(JavaVM* vm, void* reserved) +{ + (void) reserved; + + for (size_t i = 0; i < GENERIC_DIR_COUNT; ++i) + free(ppsz_generic_names[i]); + + if (fields.Environment.clazz) + { + JNIEnv* env = NULL; + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_2) != JNI_OK) + return; + (*env)->DeleteGlobalRef(env, fields.Environment.clazz); + } +} /* This function is called when the libvlcore dynamic library is loaded via the * java.lang.System.loadLibrary method. Therefore, s_jvm will be already set @@ -40,16 +90,61 @@ static JavaVM *s_jvm = NULL; jint JNI_OnLoad(JavaVM *vm, void *reserved) { - (void) reserved; s_jvm = vm; + JNIEnv* env = NULL; + + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_2) != JNI_OK) + return -1; + + jclass clazz = (*env)->FindClass(env, "android/os/Environment"); + if ((*env)->ExceptionCheck(env)) + return -1; + + static const char *ppsz_env_names[GENERIC_DIR_COUNT] = { + NULL, /* VLC_DESKTOP_DIR */ + "DIRECTORY_DOWNLOADS", /* VLC_DOWNLOAD_DIR */ + NULL, /* VLC_TEMPLATES_DIR */ + NULL, /* VLC_PUBLICSHARE_DIR */ + "DIRECTORY_DOCUMENTS", /* VLC_DOCUMENTS_DIR */ + "DIRECTORY_MUSIC", /* VLC_MUSIC_DIR */ + "DIRECTORY_PICTURES", /* VLC_PICTURES_DIR */ + "DIRECTORY_MOVIES", /* VLC_VIDEOS_DIR */ + }; + for (size_t i = 0; i < GENERIC_DIR_COUNT; ++i) + { + if (ppsz_env_names[i] != NULL) + { + ppsz_generic_names[i] = get_java_string(env, clazz, + ppsz_env_names[i]); + if (!ppsz_generic_names[i]) + goto error; + } + } + + fields.Environment.clazz = (*env)->NewGlobalRef(env, clazz); + fields.Environment.getExternalStoragePublicDirectory = + (*env)->GetStaticMethodID(env, clazz, + "getExternalStoragePublicDirectory", + "(Ljava/lang/String;)Ljava/io/File;"); + if ((*env)->ExceptionCheck(env)) + goto error; + (*env)->DeleteLocalRef(env, clazz); + + clazz = (*env)->FindClass(env, "java/io/File"); + fields.File.getAbsolutePath = + (*env)->GetMethodID(env, clazz, "getAbsolutePath", + "()Ljava/lang/String;"); + if ((*env)->ExceptionCheck(env)) + goto error; + (*env)->DeleteLocalRef(env, clazz); + return JNI_VERSION_1_2; -} -void -JNI_OnUnload(JavaVM* vm, void* reserved) -{ - (void) vm; - (void) reserved; +error: + if (clazz) + (*env)->DeleteLocalRef(env, clazz); + JNI_OnUnload(vm, reserved); + return -1; } void @@ -89,6 +184,62 @@ fallback: return psz_default_dir != NULL ? strdup(psz_default_dir) : NULL; } +static char *config_GetGenericDir(const char *psz_name) +{ + JNIEnv *env; + bool b_detach; + char *psz_ret = NULL; + + if ((*s_jvm)->GetEnv(s_jvm, (void **)&env, JNI_VERSION_1_2) != JNI_OK) + { + /* attach the thread to the Java VM */ + JavaVMAttachArgs args; + + args.version = JNI_VERSION_1_2; + args.name = "config_GetGenericDir"; + args.group = NULL; + + if ((*s_jvm)->AttachCurrentThread(s_jvm, &env, &args) != JNI_OK) + return NULL; + b_detach = true; + } + else + b_detach = false; + + jstring jname= (*env)->NewStringUTF(env, psz_name); + if ((*env)->ExceptionCheck(env)) + { + (*env)->ExceptionClear(env); + jname = NULL; + } + if (jname == NULL) + goto error; + + jobject jfile = (*env)->CallStaticObjectMethod(env, + fields.Environment.clazz, + fields.Environment.getExternalStoragePublicDirectory, + jname); + (*env)->DeleteLocalRef(env, jname); + if (jfile == NULL) + goto error; + + jstring jpath = (*env)->CallObjectMethod(env, jfile, + fields.File.getAbsolutePath); + (*env)->DeleteLocalRef(env, jfile); + + const char *psz_path = (*env)->GetStringUTFChars(env, jpath, 0); + if (psz_path == NULL) + goto error; + psz_ret = strdup(psz_path); + (*env)->ReleaseStringUTFChars(env, jpath, psz_path); + (*env)->DeleteLocalRef(env, jpath); + +error: + if (b_detach) + (*s_jvm)->DetachCurrentThread(s_jvm); + return psz_ret; +} + char *config_GetUserDir (vlc_userdir_t type) { switch (type) @@ -112,7 +263,12 @@ char *config_GetUserDir (vlc_userdir_t type) case VLC_MUSIC_DIR: case VLC_PICTURES_DIR: case VLC_VIDEOS_DIR: - return NULL; + { + assert(type >= VLC_DESKTOP_DIR && type <= VLC_VIDEOS_DIR); + const char *psz_name = ppsz_generic_names[type - VLC_DESKTOP_DIR]; + if (psz_name != NULL) + return config_GetGenericDir(psz_name); + } } return NULL; } _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
