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 *****************************************************************************/
27 #include <vlc_common.h>
28 #include <vlc_network.h>
30 #include "../libvlc.h"
31 #include "config/configuration.h"
36 static JavaVM
*s_jvm
= NULL
;
37 #define GENERIC_DIR_COUNT (VLC_VIDEOS_DIR - VLC_DESKTOP_DIR + 1)
38 static char *ppsz_generic_names
[GENERIC_DIR_COUNT
] = {};
42 jmethodID getExternalStoragePublicDirectory
;
45 jmethodID getAbsolutePath
;
49 jmethodID getProperty
;
51 } fields
= { .Environment
.clazz
= NULL
};
54 get_java_string(JNIEnv
*env
, jclass clazz
, const char *psz_name
)
56 jfieldID id
= (*env
)->GetStaticFieldID(env
, clazz
, psz_name
,
57 "Ljava/lang/String;");
58 if ((*env
)->ExceptionCheck(env
))
60 (*env
)->ExceptionClear(env
);
64 jstring jstr
= (*env
)->GetStaticObjectField(env
, clazz
, id
);
66 const char *psz_str
= (*env
)->GetStringUTFChars(env
, jstr
, 0);
70 char *psz_strdup
= strdup(psz_str
);
72 (*env
)->ReleaseStringUTFChars(env
, jstr
, psz_str
);
73 (*env
)->DeleteLocalRef(env
, jstr
);
79 JNI_OnUnload(JavaVM
* vm
, void* reserved
)
83 for (size_t i
= 0; i
< GENERIC_DIR_COUNT
; ++i
)
84 free(ppsz_generic_names
[i
]);
87 if ((*vm
)->GetEnv(vm
, (void**) &env
, JNI_VERSION_1_2
) != JNI_OK
)
90 if (fields
.Environment
.clazz
)
91 (*env
)->DeleteGlobalRef(env
, fields
.Environment
.clazz
);
93 if (fields
.System
.clazz
)
94 (*env
)->DeleteGlobalRef(env
, fields
.System
.clazz
);
97 /* This function is called when the libvlcore dynamic library is loaded via the
98 * java.lang.System.loadLibrary method. Therefore, s_jvm will be already set
99 * when libvlc_InternalInit is called. */
101 JNI_OnLoad(JavaVM
*vm
, void *reserved
)
106 if ((*vm
)->GetEnv(vm
, (void**) &env
, JNI_VERSION_1_2
) != JNI_OK
)
109 jclass clazz
= (*env
)->FindClass(env
, "android/os/Environment");
110 if ((*env
)->ExceptionCheck(env
))
113 static const char *ppsz_env_names
[GENERIC_DIR_COUNT
] = {
114 NULL
, /* VLC_DESKTOP_DIR */
115 "DIRECTORY_DOWNLOADS", /* VLC_DOWNLOAD_DIR */
116 NULL
, /* VLC_TEMPLATES_DIR */
117 NULL
, /* VLC_PUBLICSHARE_DIR */
118 "DIRECTORY_DOCUMENTS", /* VLC_DOCUMENTS_DIR */
119 "DIRECTORY_MUSIC", /* VLC_MUSIC_DIR */
120 "DIRECTORY_PICTURES", /* VLC_PICTURES_DIR */
121 "DIRECTORY_MOVIES", /* VLC_VIDEOS_DIR */
123 for (size_t i
= 0; i
< GENERIC_DIR_COUNT
; ++i
)
125 if (ppsz_env_names
[i
] != NULL
)
126 ppsz_generic_names
[i
] = get_java_string(env
, clazz
,
130 fields
.Environment
.clazz
= (*env
)->NewGlobalRef(env
, clazz
);
131 fields
.Environment
.getExternalStoragePublicDirectory
=
132 (*env
)->GetStaticMethodID(env
, clazz
,
133 "getExternalStoragePublicDirectory",
134 "(Ljava/lang/String;)Ljava/io/File;");
135 if ((*env
)->ExceptionCheck(env
))
137 (*env
)->DeleteLocalRef(env
, clazz
);
139 clazz
= (*env
)->FindClass(env
, "java/io/File");
140 fields
.File
.getAbsolutePath
=
141 (*env
)->GetMethodID(env
, clazz
, "getAbsolutePath",
142 "()Ljava/lang/String;");
143 if ((*env
)->ExceptionCheck(env
))
145 (*env
)->DeleteLocalRef(env
, clazz
);
147 clazz
= (*env
)->FindClass(env
, "java/lang/System");
148 if ((*env
)->ExceptionCheck(env
))
150 fields
.System
.clazz
= (*env
)->NewGlobalRef(env
, clazz
);
151 fields
.System
.getProperty
=
152 (*env
)->GetStaticMethodID(env
, clazz
, "getProperty",
153 "(Ljava/lang/String;)Ljava/lang/String;");
154 (*env
)->DeleteLocalRef(env
, clazz
);
156 return JNI_VERSION_1_2
;
160 (*env
)->DeleteLocalRef(env
, clazz
);
161 JNI_OnUnload(vm
, reserved
);
171 system_Configure(libvlc_int_t
*p_libvlc
, int i_argc
, const char *const pp_argv
[])
173 (void)i_argc
; (void)pp_argv
;
174 assert(s_jvm
!= NULL
);
175 var_Create(p_libvlc
, "android-jvm", VLC_VAR_ADDRESS
);
176 var_SetAddress(p_libvlc
, "android-jvm", s_jvm
);
179 static char *config_GetHomeDir(const char *psz_dir
, const char *psz_default_dir
)
181 char *psz_home
= getenv("HOME");
182 if (psz_home
== NULL
)
186 return strdup(psz_home
);
189 if (asprintf(&psz_fullpath
, "%s/%s", psz_home
, psz_dir
) == -1)
191 if (vlc_mkdir(psz_fullpath
, 0700) == -1 && errno
!= EEXIST
)
199 return psz_default_dir
!= NULL
? strdup(psz_default_dir
) : NULL
;
202 static JNIEnv
*get_env(bool *p_detach
)
205 if ((*s_jvm
)->GetEnv(s_jvm
, (void **)&env
, JNI_VERSION_1_2
) != JNI_OK
)
207 /* attach the thread to the Java VM */
208 JavaVMAttachArgs args
;
210 args
.version
= JNI_VERSION_1_2
;
211 args
.name
= "config_GetGenericDir";
214 if ((*s_jvm
)->AttachCurrentThread(s_jvm
, &env
, &args
) != JNI_OK
)
223 static void release_env(bool b_detach
)
226 (*s_jvm
)->DetachCurrentThread(s_jvm
);
229 static char *config_GetGenericDir(const char *psz_name
)
233 char *psz_ret
= NULL
;
235 env
= get_env(&b_detach
);
239 jstring jname
= (*env
)->NewStringUTF(env
, psz_name
);
240 if ((*env
)->ExceptionCheck(env
))
242 (*env
)->ExceptionClear(env
);
248 jobject jfile
= (*env
)->CallStaticObjectMethod(env
,
249 fields
.Environment
.clazz
,
250 fields
.Environment
.getExternalStoragePublicDirectory
,
252 (*env
)->DeleteLocalRef(env
, jname
);
256 jstring jpath
= (*env
)->CallObjectMethod(env
, jfile
,
257 fields
.File
.getAbsolutePath
);
258 (*env
)->DeleteLocalRef(env
, jfile
);
260 const char *psz_path
= (*env
)->GetStringUTFChars(env
, jpath
, 0);
261 if (psz_path
== NULL
)
263 psz_ret
= strdup(psz_path
);
264 (*env
)->ReleaseStringUTFChars(env
, jpath
, psz_path
);
265 (*env
)->DeleteLocalRef(env
, jpath
);
268 release_env(b_detach
);
272 char *config_GetUserDir (vlc_userdir_t type
)
276 case VLC_USERDATA_DIR
:
277 return config_GetHomeDir(".share",
278 "/sdcard/Android/data/org.videolan.vlc");
280 return config_GetHomeDir(".cache",
281 "/sdcard/Android/data/org.videolan.vlc/cache");
283 return config_GetHomeDir(NULL
, NULL
);
285 return config_GetHomeDir(".config", NULL
);
287 case VLC_DESKTOP_DIR
:
288 case VLC_DOWNLOAD_DIR
:
289 case VLC_TEMPLATES_DIR
:
290 case VLC_PUBLICSHARE_DIR
:
291 case VLC_DOCUMENTS_DIR
:
293 case VLC_PICTURES_DIR
:
296 assert(type
>= VLC_DESKTOP_DIR
&& type
<= VLC_VIDEOS_DIR
);
297 const char *psz_name
= ppsz_generic_names
[type
- VLC_DESKTOP_DIR
];
298 if (psz_name
!= NULL
)
299 return config_GetGenericDir(psz_name
);
305 char *config_GetSysPath(vlc_sysdir_t type
, const char *filename
)
311 case VLC_SYSDATA_DIR
:
312 dir
= strdup("/system/usr/share");
315 dir
= config_GetLibDir();
321 if (filename
== NULL
|| dir
== NULL
)
325 if (unlikely(asprintf(&path
, "%s/%s", dir
, filename
) == -1))
332 * Determines the network proxy server to use (if any).
334 * This function fetch the Android proxy using the System.getProperty() method
335 * with "http.proxyHost" and "http.proxyPort" keys. This is working only for
336 * Android 4.0 and after.
338 * @param url absolute URL for which to get the proxy server (unused)
339 * @return proxy URL, NULL if no proxy or error
341 char *vlc_getProxyUrl(const char *url
)
346 char *psz_ret
= NULL
;
347 const char *psz_host
= NULL
, *psz_port
= NULL
;
348 jstring jhost
= NULL
, jport
= NULL
;
350 env
= get_env(&b_detach
);
354 /* Fetch "http.proxyHost" property */
355 jstring jkey
= (*env
)->NewStringUTF(env
, "http.proxyHost");
356 if ((*env
)->ExceptionCheck(env
))
358 (*env
)->ExceptionClear(env
);
364 jhost
= (*env
)->CallStaticObjectMethod(env
, fields
.System
.clazz
,
365 fields
.System
.getProperty
, jkey
);
366 (*env
)->DeleteLocalRef(env
, jkey
);
370 psz_host
= (*env
)->GetStringUTFChars(env
, jhost
, 0);
371 /* Ensure the property is valid */
372 if (psz_host
== NULL
|| psz_host
[0] == '\0')
375 /* Fetch "http.proxyPort" property (only if "http.proxyHost" is valid) */
376 jkey
= (*env
)->NewStringUTF(env
, "http.proxyPort");
377 if ((*env
)->ExceptionCheck(env
))
379 (*env
)->ExceptionClear(env
);
385 jport
= (*env
)->CallStaticObjectMethod(env
, fields
.System
.clazz
,
386 fields
.System
.getProperty
, jkey
);
387 (*env
)->DeleteLocalRef(env
, jkey
);
389 /* Ensure the property is valid */
392 psz_port
= (*env
)->GetStringUTFChars(env
, jport
, 0);
393 if (psz_port
!= NULL
&& (psz_port
[0] == '\0' || psz_port
[0] == '0'))
395 (*env
)->ReleaseStringUTFChars(env
, jport
, psz_port
);
400 /* Concat "http://" "http.proxyHost" and "http.proxyPort" */
401 if (asprintf(&psz_ret
, "http://%s%s%s",
403 psz_port
!= NULL
? ":" : "",
404 psz_port
!= NULL
? psz_port
: "") == -1)
408 if (psz_host
!= NULL
)
409 (*env
)->ReleaseStringUTFChars(env
, jhost
, psz_host
);
411 (*env
)->DeleteLocalRef(env
, jhost
);
412 if (psz_port
!= NULL
)
413 (*env
)->ReleaseStringUTFChars(env
, jport
, psz_port
);
415 (*env
)->DeleteLocalRef(env
, jport
);
416 release_env(b_detach
);