1 /*****************************************************************************
2 * specific.c: stubs for Android OS-specific initialization
3 *****************************************************************************
4 * Copyright © 2016 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
28 #include <vlc_common.h>
29 #include <vlc_network.h>
31 #include "../libvlc.h"
32 #include "config/configuration.h"
37 static JavaVM
*s_jvm
= NULL
;
38 #define GENERIC_DIR_COUNT (VLC_VIDEOS_DIR - VLC_DESKTOP_DIR + 1)
39 static char *ppsz_generic_names
[GENERIC_DIR_COUNT
] = {};
43 jmethodID getExternalStoragePublicDirectory
;
46 jmethodID getAbsolutePath
;
50 jmethodID getProperty
;
52 } fields
= { .Environment
.clazz
= NULL
};
55 get_java_string(JNIEnv
*env
, jclass clazz
, const char *psz_name
)
57 jfieldID id
= (*env
)->GetStaticFieldID(env
, clazz
, psz_name
,
58 "Ljava/lang/String;");
59 if ((*env
)->ExceptionCheck(env
))
61 (*env
)->ExceptionClear(env
);
65 jstring jstr
= (*env
)->GetStaticObjectField(env
, clazz
, id
);
67 const char *psz_str
= (*env
)->GetStringUTFChars(env
, jstr
, 0);
71 char *psz_strdup
= strdup(psz_str
);
73 (*env
)->ReleaseStringUTFChars(env
, jstr
, psz_str
);
74 (*env
)->DeleteLocalRef(env
, jstr
);
80 JNI_OnUnload(JavaVM
* vm
, void* reserved
)
84 for (size_t i
= 0; i
< GENERIC_DIR_COUNT
; ++i
)
85 free(ppsz_generic_names
[i
]);
88 if ((*vm
)->GetEnv(vm
, (void**) &env
, JNI_VERSION_1_2
) != JNI_OK
)
91 if (fields
.Environment
.clazz
)
92 (*env
)->DeleteGlobalRef(env
, fields
.Environment
.clazz
);
94 if (fields
.System
.clazz
)
95 (*env
)->DeleteGlobalRef(env
, fields
.System
.clazz
);
98 /* This function is called when the libvlcore dynamic library is loaded via the
99 * java.lang.System.loadLibrary method. Therefore, s_jvm will be already set
100 * when libvlc_InternalInit is called. */
102 JNI_OnLoad(JavaVM
*vm
, void *reserved
)
107 if ((*vm
)->GetEnv(vm
, (void**) &env
, JNI_VERSION_1_2
) != JNI_OK
)
110 jclass clazz
= (*env
)->FindClass(env
, "android/os/Environment");
111 if ((*env
)->ExceptionCheck(env
))
114 static const char *ppsz_env_names
[GENERIC_DIR_COUNT
] = {
115 NULL
, /* VLC_DESKTOP_DIR */
116 "DIRECTORY_DOWNLOADS", /* VLC_DOWNLOAD_DIR */
117 NULL
, /* VLC_TEMPLATES_DIR */
118 NULL
, /* VLC_PUBLICSHARE_DIR */
119 "DIRECTORY_DOCUMENTS", /* VLC_DOCUMENTS_DIR */
120 "DIRECTORY_MUSIC", /* VLC_MUSIC_DIR */
121 "DIRECTORY_PICTURES", /* VLC_PICTURES_DIR */
122 "DIRECTORY_MOVIES", /* VLC_VIDEOS_DIR */
124 for (size_t i
= 0; i
< GENERIC_DIR_COUNT
; ++i
)
126 if (ppsz_env_names
[i
] != NULL
)
127 ppsz_generic_names
[i
] = get_java_string(env
, clazz
,
131 fields
.Environment
.clazz
= (*env
)->NewGlobalRef(env
, clazz
);
132 fields
.Environment
.getExternalStoragePublicDirectory
=
133 (*env
)->GetStaticMethodID(env
, clazz
,
134 "getExternalStoragePublicDirectory",
135 "(Ljava/lang/String;)Ljava/io/File;");
136 if ((*env
)->ExceptionCheck(env
))
138 (*env
)->DeleteLocalRef(env
, clazz
);
140 clazz
= (*env
)->FindClass(env
, "java/io/File");
141 fields
.File
.getAbsolutePath
=
142 (*env
)->GetMethodID(env
, clazz
, "getAbsolutePath",
143 "()Ljava/lang/String;");
144 if ((*env
)->ExceptionCheck(env
))
146 (*env
)->DeleteLocalRef(env
, clazz
);
148 clazz
= (*env
)->FindClass(env
, "java/lang/System");
149 if ((*env
)->ExceptionCheck(env
))
151 fields
.System
.clazz
= (*env
)->NewGlobalRef(env
, clazz
);
152 fields
.System
.getProperty
=
153 (*env
)->GetStaticMethodID(env
, clazz
, "getProperty",
154 "(Ljava/lang/String;)Ljava/lang/String;");
155 (*env
)->DeleteLocalRef(env
, clazz
);
157 return JNI_VERSION_1_2
;
161 (*env
)->DeleteLocalRef(env
, clazz
);
162 JNI_OnUnload(vm
, reserved
);
172 system_Configure(libvlc_int_t
*p_libvlc
, int i_argc
, const char *const pp_argv
[])
174 (void)i_argc
; (void)pp_argv
;
175 assert(s_jvm
!= NULL
);
176 var_Create(p_libvlc
, "android-jvm", VLC_VAR_ADDRESS
);
177 var_SetAddress(p_libvlc
, "android-jvm", s_jvm
);
180 static char *config_GetHomeDir(const char *psz_dir
, const char *psz_default_dir
)
182 char *psz_home
= getenv("HOME");
183 if (psz_home
== NULL
)
187 return strdup(psz_home
);
190 if (asprintf(&psz_fullpath
, "%s/%s", psz_home
, psz_dir
) == -1)
192 if (vlc_mkdir(psz_fullpath
, 0700) == -1 && errno
!= EEXIST
)
200 return psz_default_dir
!= NULL
? strdup(psz_default_dir
) : NULL
;
203 static JNIEnv
*get_env(bool *p_detach
)
206 if ((*s_jvm
)->GetEnv(s_jvm
, (void **)&env
, JNI_VERSION_1_2
) != JNI_OK
)
208 /* attach the thread to the Java VM */
209 JavaVMAttachArgs args
;
211 args
.version
= JNI_VERSION_1_2
;
212 args
.name
= "config_GetGenericDir";
215 if ((*s_jvm
)->AttachCurrentThread(s_jvm
, &env
, &args
) != JNI_OK
)
224 static void release_env(bool b_detach
)
227 (*s_jvm
)->DetachCurrentThread(s_jvm
);
230 static char *config_GetGenericDir(const char *psz_name
)
234 char *psz_ret
= NULL
;
236 env
= get_env(&b_detach
);
240 jstring jname
= (*env
)->NewStringUTF(env
, psz_name
);
241 if ((*env
)->ExceptionCheck(env
))
243 (*env
)->ExceptionClear(env
);
249 jobject jfile
= (*env
)->CallStaticObjectMethod(env
,
250 fields
.Environment
.clazz
,
251 fields
.Environment
.getExternalStoragePublicDirectory
,
253 (*env
)->DeleteLocalRef(env
, jname
);
257 jstring jpath
= (*env
)->CallObjectMethod(env
, jfile
,
258 fields
.File
.getAbsolutePath
);
259 (*env
)->DeleteLocalRef(env
, jfile
);
261 const char *psz_path
= (*env
)->GetStringUTFChars(env
, jpath
, 0);
262 if (psz_path
== NULL
)
264 psz_ret
= strdup(psz_path
);
265 (*env
)->ReleaseStringUTFChars(env
, jpath
, psz_path
);
266 (*env
)->DeleteLocalRef(env
, jpath
);
269 release_env(b_detach
);
273 char *config_GetUserDir (vlc_userdir_t type
)
277 case VLC_USERDATA_DIR
:
278 return config_GetHomeDir(".share",
279 "/sdcard/Android/data/org.videolan.vlc");
281 return config_GetHomeDir(".cache",
282 "/sdcard/Android/data/org.videolan.vlc/cache");
284 return config_GetHomeDir(NULL
, NULL
);
286 return config_GetHomeDir(".config", NULL
);
288 case VLC_DESKTOP_DIR
:
289 case VLC_DOWNLOAD_DIR
:
290 case VLC_TEMPLATES_DIR
:
291 case VLC_PUBLICSHARE_DIR
:
292 case VLC_DOCUMENTS_DIR
:
294 case VLC_PICTURES_DIR
:
297 assert(type
>= VLC_DESKTOP_DIR
&& type
<= VLC_VIDEOS_DIR
);
298 const char *psz_name
= ppsz_generic_names
[type
- VLC_DESKTOP_DIR
];
299 if (psz_name
!= NULL
)
300 return config_GetGenericDir(psz_name
);
306 char *config_GetSysPath(vlc_sysdir_t type
, const char *filename
)
312 case VLC_SYSDATA_DIR
:
313 dir
= strdup("/system/usr/share");
316 dir
= config_GetLibDir();
322 if (filename
== NULL
|| dir
== NULL
)
326 if (unlikely(asprintf(&path
, "%s/%s", dir
, filename
) == -1))
333 * Determines the network proxy server to use (if any).
335 * This function fetch the Android proxy using the System.getProperty() method
336 * with "http.proxyHost" and "http.proxyPort" keys. This is working only for
337 * Android 4.0 and after.
339 * @param url absolute URL for which to get the proxy server (unused)
340 * @return proxy URL, NULL if no proxy or error
342 char *vlc_getProxyUrl(const char *url
)
347 char *psz_ret
= NULL
;
348 const char *psz_host
= NULL
, *psz_port
= NULL
;
349 jstring jhost
= NULL
, jport
= NULL
;
351 env
= get_env(&b_detach
);
355 /* Fetch "http.proxyHost" property */
356 jstring jkey
= (*env
)->NewStringUTF(env
, "http.proxyHost");
357 if ((*env
)->ExceptionCheck(env
))
359 (*env
)->ExceptionClear(env
);
365 jhost
= (*env
)->CallStaticObjectMethod(env
, fields
.System
.clazz
,
366 fields
.System
.getProperty
, jkey
);
367 (*env
)->DeleteLocalRef(env
, jkey
);
371 psz_host
= (*env
)->GetStringUTFChars(env
, jhost
, 0);
372 /* Ensure the property is valid */
373 if (psz_host
== NULL
|| psz_host
[0] == '\0')
376 /* Fetch "http.proxyPort" property (only if "http.proxyHost" is valid) */
377 jkey
= (*env
)->NewStringUTF(env
, "http.proxyPort");
378 if ((*env
)->ExceptionCheck(env
))
380 (*env
)->ExceptionClear(env
);
386 jport
= (*env
)->CallStaticObjectMethod(env
, fields
.System
.clazz
,
387 fields
.System
.getProperty
, jkey
);
388 (*env
)->DeleteLocalRef(env
, jkey
);
390 /* Ensure the property is valid */
393 psz_port
= (*env
)->GetStringUTFChars(env
, jport
, 0);
394 if (psz_port
!= NULL
&& (psz_port
[0] == '\0' || psz_port
[0] == '0'))
396 (*env
)->ReleaseStringUTFChars(env
, jport
, psz_port
);
401 /* Concat "http://" "http.proxyHost" and "http.proxyPort" */
402 if (asprintf(&psz_ret
, "http://%s%s%s",
404 psz_port
!= NULL
? ":" : "",
405 psz_port
!= NULL
? psz_port
: "") == -1)
409 if (psz_host
!= NULL
)
410 (*env
)->ReleaseStringUTFChars(env
, jhost
, psz_host
);
412 (*env
)->DeleteLocalRef(env
, jhost
);
413 if (psz_port
!= NULL
)
414 (*env
)->ReleaseStringUTFChars(env
, jport
, psz_port
);
416 (*env
)->DeleteLocalRef(env
, jport
);
417 release_env(b_detach
);