summaryrefslogtreecommitdiff
path: root/platform/android
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android')
-rw-r--r--platform/android/audio_driver_opensl.cpp104
-rw-r--r--platform/android/audio_driver_opensl.h15
-rw-r--r--platform/android/detect.py6
-rw-r--r--platform/android/dir_access_jandroid.cpp3
-rw-r--r--platform/android/export/export.cpp10
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotIO.java8
-rw-r--r--platform/android/java_class_wrapper.cpp11
-rw-r--r--platform/android/java_glue.cpp54
-rw-r--r--platform/android/os_android.cpp2
-rw-r--r--platform/android/string_android.h58
10 files changed, 226 insertions, 45 deletions
diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp
index e259380a63..0d62b242a8 100644
--- a/platform/android/audio_driver_opensl.cpp
+++ b/platform/android/audio_driver_opensl.cpp
@@ -211,6 +211,110 @@ void AudioDriverOpenSL::start() {
active = true;
}
+void AudioDriverOpenSL::_record_buffer_callback(SLAndroidSimpleBufferQueueItf queueItf) {
+
+ for (int i = 0; i < rec_buffer.size(); i++) {
+ int32_t sample = rec_buffer[i] << 16;
+ input_buffer_write(sample);
+ input_buffer_write(sample); // call twice to convert to Stereo
+ }
+
+ SLresult res = (*recordBufferQueueItf)->Enqueue(recordBufferQueueItf, rec_buffer.ptrw(), rec_buffer.size() * sizeof(int16_t));
+ ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
+}
+
+void AudioDriverOpenSL::_record_buffer_callbacks(SLAndroidSimpleBufferQueueItf queueItf, void *pContext) {
+
+ AudioDriverOpenSL *ad = (AudioDriverOpenSL *)pContext;
+
+ ad->_record_buffer_callback(queueItf);
+}
+
+Error AudioDriverOpenSL::capture_start() {
+
+ SLDataLocator_IODevice loc_dev = {
+ SL_DATALOCATOR_IODEVICE,
+ SL_IODEVICE_AUDIOINPUT,
+ SL_DEFAULTDEVICEID_AUDIOINPUT,
+ NULL
+ };
+ SLDataSource recSource = { &loc_dev, NULL };
+
+ SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
+ SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
+ 2
+ };
+ SLDataFormat_PCM format_pcm = {
+ SL_DATAFORMAT_PCM,
+ 1,
+ SL_SAMPLINGRATE_44_1,
+ SL_PCMSAMPLEFORMAT_FIXED_16,
+ SL_PCMSAMPLEFORMAT_FIXED_16,
+ SL_SPEAKER_FRONT_CENTER,
+ SL_BYTEORDER_LITTLEENDIAN
+ };
+ SLDataSink recSnk = { &loc_bq, &format_pcm };
+
+ const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
+ const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
+
+ SLresult res = (*EngineItf)->CreateAudioRecorder(EngineItf, &recorder, &recSource, &recSnk, 2, ids, req);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recorder)->Realize(recorder, SL_BOOLEAN_FALSE);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recorder)->GetInterface(recorder, SL_IID_RECORD, (void *)&recordItf);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, (void *)&recordBufferQueueItf);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recordBufferQueueItf)->RegisterCallback(recordBufferQueueItf, _record_buffer_callbacks, this);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ SLuint32 state;
+ res = (*recordItf)->GetRecordState(recordItf, &state);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ if (state != SL_RECORDSTATE_STOPPED) {
+ res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recordBufferQueueItf)->Clear(recordBufferQueueItf);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+ }
+
+ const int rec_buffer_frames = 2048;
+ rec_buffer.resize(rec_buffer_frames);
+ input_buffer_init(rec_buffer_frames);
+
+ res = (*recordBufferQueueItf)->Enqueue(recordBufferQueueItf, rec_buffer.ptrw(), rec_buffer.size() * sizeof(int16_t));
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ return OK;
+}
+
+Error AudioDriverOpenSL::capture_stop() {
+
+ SLuint32 state;
+ SLresult res = (*recordItf)->GetRecordState(recordItf, &state);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ if (state != SL_RECORDSTATE_STOPPED) {
+ res = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+
+ res = (*recordBufferQueueItf)->Clear(recordBufferQueueItf);
+ ERR_FAIL_COND_V(res != SL_RESULT_SUCCESS, ERR_CANT_OPEN);
+ }
+
+ return OK;
+}
+
int AudioDriverOpenSL::get_mix_rate() const {
return 44100;
diff --git a/platform/android/audio_driver_opensl.h b/platform/android/audio_driver_opensl.h
index 77e16e507a..9bd0d5e999 100644
--- a/platform/android/audio_driver_opensl.h
+++ b/platform/android/audio_driver_opensl.h
@@ -54,13 +54,18 @@ class AudioDriverOpenSL : public AudioDriver {
int32_t *mixdown_buffer;
int last_free;
+ Vector<int16_t> rec_buffer;
+
SLPlayItf playItf;
+ SLRecordItf recordItf;
SLObjectItf sl;
SLEngineItf EngineItf;
SLObjectItf OutputMix;
SLVolumeItf volumeItf;
SLObjectItf player;
+ SLObjectItf recorder;
SLAndroidSimpleBufferQueueItf bufferQueueItf;
+ SLAndroidSimpleBufferQueueItf recordBufferQueueItf;
SLDataSource audioSource;
SLDataFormat_PCM pcm;
SLDataSink audioSink;
@@ -76,6 +81,13 @@ class AudioDriverOpenSL : public AudioDriver {
SLAndroidSimpleBufferQueueItf queueItf,
void *pContext);
+ void _record_buffer_callback(
+ SLAndroidSimpleBufferQueueItf queueItf);
+
+ static void _record_buffer_callbacks(
+ SLAndroidSimpleBufferQueueItf queueItf,
+ void *pContext);
+
public:
void set_singleton();
@@ -91,6 +103,9 @@ public:
virtual void set_pause(bool p_pause);
+ virtual Error capture_start();
+ virtual Error capture_stop();
+
AudioDriverOpenSL();
};
diff --git a/platform/android/detect.py b/platform/android/detect.py
index aa48252435..80cda68a9e 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -298,12 +298,6 @@ def configure(env):
env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL'])
env.Append(LIBS=['OpenSLES', 'EGL', 'GLESv3', 'android', 'log', 'z', 'dl'])
- # TODO: Move that to opus module's config
- if 'module_opus_enabled' in env and env['module_opus_enabled']:
- if (env["android_arch"] == "armv6" or env["android_arch"] == "armv7"):
- env.Append(CFLAGS=["-DOPUS_ARM_OPT"])
- env.opus_fixed_point = "yes"
-
# Return NDK version string in source.properties (adapted from the Chromium project).
def get_ndk_version(path):
if path is None:
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index 4b3d93aaa7..8c464465ca 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -31,6 +31,7 @@
#include "dir_access_jandroid.h"
#include "core/print_string.h"
#include "file_access_jandroid.h"
+#include "string_android.h"
#include "thread_jandroid.h"
jobject DirAccessJAndroid::io = NULL;
@@ -69,7 +70,7 @@ String DirAccessJAndroid::get_next() {
if (!str)
return "";
- String ret = String::utf8(env->GetStringUTFChars((jstring)str, NULL));
+ String ret = jstring_to_string((jstring)str, env);
env->DeleteLocalRef((jobject)str);
return ret;
}
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index 60cc33e6bf..8d9d9c697e 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -301,10 +301,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
args.push_back(d.id);
args.push_back("shell");
args.push_back("getprop");
- int ec;
+ int ec2;
String dp;
- OS::get_singleton()->execute(adb, args, true, NULL, &dp, &ec);
+ OS::get_singleton()->execute(adb, args, true, NULL, &dp, &ec2);
Vector<String> props = dp.split("\n");
String vendor;
@@ -1453,6 +1453,12 @@ public:
err += TTR("Invalid package name:") + " " + pn_err + "\n";
}
+ String etc_error = test_etc2();
+ if (etc_error != String()) {
+ valid = false;
+ err += etc_error;
+ }
+
r_error = err;
return valid;
}
diff --git a/platform/android/java/src/org/godotengine/godot/GodotIO.java b/platform/android/java/src/org/godotengine/godot/GodotIO.java
index 8cee20e435..85bba8bb4c 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotIO.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotIO.java
@@ -516,14 +516,6 @@ public class GodotIO {
public void hideKeyboard() {
if (edit != null)
edit.hideKeyboard();
-
- InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
- View v = activity.getCurrentFocus();
- if (v != null) {
- inputMgr.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
- } else {
- inputMgr.hideSoftInputFromWindow(new View(activity).getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
- }
};
public void setScreenOrientation(int p_orientation) {
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index 4be1106967..2bed1f0892 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "java_class_wrapper.h"
+#include "string_android.h"
#include "thread_jandroid.h"
bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error, Variant &ret) {
@@ -553,7 +554,7 @@ void JavaClassWrapper::_bind_methods() {
bool JavaClassWrapper::_get_type_sig(JNIEnv *env, jobject obj, uint32_t &sig, String &strsig) {
jstring name2 = (jstring)env->CallObjectMethod(obj, Class_getName);
- String str_type = env->GetStringUTFChars(name2, NULL);
+ String str_type = jstring_to_string(name2, env);
env->DeleteLocalRef(name2);
uint32_t t = 0;
@@ -697,7 +698,7 @@ bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &va
} break;
case ARG_TYPE_STRING: {
- var = String::utf8(env->GetStringUTFChars((jstring)obj, NULL));
+ var = jstring_to_string((jstring)obj, env);
return true;
} break;
case ARG_TYPE_CLASS: {
@@ -1030,7 +1031,7 @@ bool JavaClass::_convert_object_to_variant(JNIEnv *env, jobject obj, Variant &va
if (!o)
ret.push_back(Variant());
else {
- String val = String::utf8(env->GetStringUTFChars((jstring)o, NULL));
+ String val = jstring_to_string((jstring)o, env);
ret.push_back(val);
}
env->DeleteLocalRef(o);
@@ -1075,7 +1076,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
ERR_CONTINUE(!obj);
jstring name = (jstring)env->CallObjectMethod(obj, getName);
- String str_method = env->GetStringUTFChars(name, NULL);
+ String str_method = jstring_to_string(name, env);
env->DeleteLocalRef(name);
Vector<String> params;
@@ -1204,7 +1205,7 @@ Ref<JavaClass> JavaClassWrapper::wrap(const String &p_class) {
ERR_CONTINUE(!obj);
jstring name = (jstring)env->CallObjectMethod(obj, Field_getName);
- String str_field = env->GetStringUTFChars(name, NULL);
+ String str_field = jstring_to_string(name, env);
env->DeleteLocalRef(name);
int mods = env->CallIntMethod(obj, Field_getModifiers);
if ((mods & 0x8) && (mods & 0x10) && (mods & 0x1)) { //static final public!
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index 885fb185a7..53c909da88 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_glue.cpp
@@ -41,6 +41,7 @@
#include "main/input_default.h"
#include "main/main.h"
#include "os_android.h"
+#include "string_android.h"
#include "thread_jandroid.h"
#include <unistd.h>
@@ -223,7 +224,7 @@ String _get_class_name(JNIEnv *env, jclass cls, bool *array) {
jboolean isarr = env->CallBooleanMethod(cls, isArray);
(*array) = isarr ? true : false;
}
- String name = env->GetStringUTFChars(clsName, NULL);
+ String name = jstring_to_string(clsName, env);
env->DeleteLocalRef(clsName);
return name;
@@ -241,7 +242,7 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
if (name == "java.lang.String") {
- return String::utf8(env->GetStringUTFChars((jstring)obj, NULL));
+ return jstring_to_string((jstring)obj, env);
};
if (name == "[Ljava.lang.String;") {
@@ -252,7 +253,7 @@ Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
for (int i = 0; i < stringCount; i++) {
jstring string = (jstring)env->GetObjectArrayElement(arr, i);
- sarr.push_back(String::utf8(env->GetStringUTFChars(string, NULL)));
+ sarr.push_back(jstring_to_string(string, env));
env->DeleteLocalRef(string);
}
@@ -487,7 +488,7 @@ public:
case Variant::STRING: {
jobject o = env->CallObjectMethodA(instance, E->get().method, v);
- ret = String::utf8(env->GetStringUTFChars((jstring)o, NULL));
+ ret = jstring_to_string((jstring)o, env);
env->DeleteLocalRef(o);
} break;
case Variant::POOL_STRING_ARRAY: {
@@ -634,20 +635,20 @@ static String _get_user_data_dir() {
JNIEnv *env = ThreadAndroid::get_env();
jstring s = (jstring)env->CallObjectMethod(godot_io, _getDataDir);
- return String(env->GetStringUTFChars(s, NULL));
+ return jstring_to_string(s, env);
}
static String _get_locale() {
JNIEnv *env = ThreadAndroid::get_env();
jstring s = (jstring)env->CallObjectMethod(godot_io, _getLocale);
- return String(env->GetStringUTFChars(s, NULL));
+ return jstring_to_string(s, env);
}
static String _get_clipboard() {
JNIEnv *env = ThreadAndroid::get_env();
jstring s = (jstring)env->CallObjectMethod(_godot_instance, _getClipboard);
- return String(env->GetStringUTFChars(s, NULL));
+ return jstring_to_string(s, env);
}
static void _set_clipboard(const String &p_text) {
@@ -661,7 +662,7 @@ static String _get_model() {
JNIEnv *env = ThreadAndroid::get_env();
jstring s = (jstring)env->CallObjectMethod(godot_io, _getModel);
- return String(env->GetStringUTFChars(s, NULL));
+ return jstring_to_string(s, env);
}
static int _get_screen_dpi() {
@@ -674,7 +675,7 @@ static String _get_unique_id() {
JNIEnv *env = ThreadAndroid::get_env();
jstring s = (jstring)env->CallObjectMethod(godot_io, _getUniqueID);
- return String(env->GetStringUTFChars(s, NULL));
+ return jstring_to_string(s, env);
}
static void _show_vk(const String &p_existing) {
@@ -694,7 +695,7 @@ static String _get_system_dir(int p_dir) {
JNIEnv *env = ThreadAndroid::get_env();
jstring s = (jstring)env->CallObjectMethod(godot_io, _getSystemDir, p_dir);
- return String(env->GetStringUTFChars(s, NULL));
+ return jstring_to_string(s, env);
}
static int _get_gles_version_code() {
@@ -891,12 +892,14 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
ThreadAndroid::setup_thread();
const char **cmdline = NULL;
+ jstring *j_cmdline = NULL;
int cmdlen = 0;
if (p_cmdline) {
cmdlen = env->GetArrayLength(p_cmdline);
if (cmdlen) {
- cmdline = (const char **)malloc((env->GetArrayLength(p_cmdline) + 1) * sizeof(const char *));
+ cmdline = (const char **)malloc((cmdlen + 1) * sizeof(const char *));
cmdline[cmdlen] = NULL;
+ j_cmdline = (jstring *)malloc(cmdlen * sizeof(jstring));
for (int i = 0; i < cmdlen; i++) {
@@ -904,12 +907,19 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
const char *rawString = env->GetStringUTFChars(string, 0);
cmdline[i] = rawString;
+ j_cmdline[i] = string;
}
}
}
Error err = Main::setup("apk", cmdlen, (char **)cmdline, false);
if (cmdline) {
+ if (j_cmdline) {
+ for (int i = 0; i < cmdlen; ++i) {
+ env->ReleaseStringUTFChars(j_cmdline[i], cmdline[i]);
+ }
+ free(j_cmdline);
+ }
free(cmdline);
}
@@ -1313,7 +1323,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jobject obj, jint p_device, jboolean p_connected, jstring p_name) {
if (os_android) {
- String name = env->GetStringUTFChars(p_name, NULL);
+ String name = jstring_to_string(p_name, env);
os_android->joy_connection_changed(p_device, p_connected, name);
}
}
@@ -1386,7 +1396,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jo
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv *env, jobject obj, jstring name, jobject p_object) {
- String singname = env->GetStringUTFChars(name, NULL);
+ String singname = jstring_to_string(name, env);
JNISingleton *s = memnew(JNISingleton);
s->set_instance(env->NewGlobalRef(p_object));
jni_singletons[singname] = s;
@@ -1463,21 +1473,21 @@ static const char *get_jni_sig(const String &p_type) {
JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jobject obj, jstring path) {
- String js = env->GetStringUTFChars(path, NULL);
+ String js = jstring_to_string(path, env);
return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data());
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args) {
- String singname = env->GetStringUTFChars(sname, NULL);
+ String singname = jstring_to_string(sname, env);
ERR_FAIL_COND(!jni_singletons.has(singname));
JNISingleton *s = jni_singletons.get(singname);
- String mname = env->GetStringUTFChars(name, NULL);
- String retval = env->GetStringUTFChars(ret, NULL);
+ String mname = jstring_to_string(name, env);
+ String retval = jstring_to_string(ret, env);
Vector<Variant::Type> types;
String cs = "(";
@@ -1486,9 +1496,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, j
for (int i = 0; i < stringCount; i++) {
jstring string = (jstring)env->GetObjectArrayElement(args, i);
- const char *rawString = env->GetStringUTFChars(string, 0);
- types.push_back(get_jni_type(String(rawString)));
- cs += get_jni_sig(String(rawString));
+ const String rawString = jstring_to_string(string, env);
+ types.push_back(get_jni_type(rawString));
+ cs += get_jni_sig(rawString);
}
cs += ")";
@@ -1511,7 +1521,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *en
int res = env->PushLocalFrame(16);
ERR_FAIL_COND(res != 0);
- String str_method = env->GetStringUTFChars(method, NULL);
+ String str_method = jstring_to_string(method, env);
int count = env->GetArrayLength(params);
Variant *vlist = (Variant *)alloca(sizeof(Variant) * count);
@@ -1543,7 +1553,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
int res = env->PushLocalFrame(16);
ERR_FAIL_COND(res != 0);
- String str_method = env->GetStringUTFChars(method, NULL);
+ String str_method = jstring_to_string(method, env);
int count = env->GetArrayLength(params);
Variant args[VARIANT_ARG_MAX];
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 3ba8468e0b..b86976843c 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -706,7 +706,7 @@ String OS_Android::get_joy_guid(int p_device) const {
}
bool OS_Android::_check_internal_feature_support(const String &p_feature) {
- if (p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2") {
+ if (p_feature == "mobile") {
//TODO support etc2 only if GLES3 driver is selected
return true;
}
diff --git a/platform/android/string_android.h b/platform/android/string_android.h
new file mode 100644
index 0000000000..fe627a3e0c
--- /dev/null
+++ b/platform/android/string_android.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* string_android.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef STRING_ANDROID_H
+#define STRING_ANDROID_H
+#include "core/ustring.h"
+#include "thread_jandroid.h"
+#include <jni.h>
+
+/**
+ * Converts JNI jstring to Godot String.
+ * @param source Source JNI string. If null an empty string is returned.
+ * @param env JNI environment instance. If null obtained by ThreadAndroid::get_env().
+ * @return Godot string instance.
+ */
+static inline String jstring_to_string(jstring source, JNIEnv *env = NULL) {
+ String result;
+ if (source) {
+ if (!env) {
+ env = ThreadAndroid::get_env();
+ }
+ const char *const source_utf8 = env->GetStringUTFChars(source, NULL);
+ if (source_utf8) {
+ result.parse_utf8(source_utf8);
+ env->ReleaseStringUTFChars(source, source_utf8);
+ }
+ }
+ return result;
+}
+
+#endif // STRING_ANDROID_H