summaryrefslogtreecommitdiffstats
path: root/platform/android/java_godot_lib_jni.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/java_godot_lib_jni.cpp')
-rw-r--r--platform/android/java_godot_lib_jni.cpp172
1 files changed, 96 insertions, 76 deletions
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index d971727269..422c05e5ce 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 */
@@ -43,12 +43,14 @@
#include "dir_access_jandroid.h"
#include "display_server_android.h"
#include "file_access_android.h"
+#include "file_access_filesystem_jandroid.h"
#include "jni_utils.h"
#include "main/main.h"
#include "net_socket_android.h"
#include "os_android.h"
#include "string_android.h"
#include "thread_jandroid.h"
+#include "tts_android.h"
#include <android/input.h>
#include <unistd.h>
@@ -61,7 +63,6 @@ static AndroidInputHandler *input_handler = nullptr;
static GodotJavaWrapper *godot_java = nullptr;
static GodotIOJavaWrapper *godot_io_java = nullptr;
-static bool initialized = false;
static SafeNumeric<int> step; // Shared between UI and render threads
static Size2 new_size;
@@ -78,15 +79,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHei
}
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject activity, jobject godot_instance, jobject p_asset_manager, jboolean p_use_apk_expansion) {
- initialized = true;
-
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject p_activity, jobject p_godot_instance, jobject p_asset_manager, jobject p_godot_io, jobject p_net_utils, jobject p_directory_access_handler, jobject p_file_access_handler, jboolean p_use_apk_expansion, jobject p_godot_tts) {
JavaVM *jvm;
env->GetJavaVM(&jvm);
// create our wrapper classes
- godot_java = new GodotJavaWrapper(env, activity, godot_instance);
- godot_io_java = new GodotIOJavaWrapper(env, godot_java->get_member_object("io", "Lorg/godotengine/godot/GodotIO;", env));
+ godot_java = new GodotJavaWrapper(env, p_activity, p_godot_instance);
+ godot_io_java = new GodotIOJavaWrapper(env, p_godot_io);
init_thread_jandroid(jvm, env);
@@ -94,19 +93,21 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
FileAccessAndroid::asset_manager = AAssetManager_fromJava(env, amgr);
- DirAccessJAndroid::setup(godot_io_java->get_instance());
- NetSocketAndroid::setup(godot_java->get_member_object("netUtils", "Lorg/godotengine/godot/utils/GodotNetUtils;", env));
+ DirAccessJAndroid::setup(p_directory_access_handler);
+ FileAccessFilesystemJAndroid::setup(p_file_access_handler);
+ NetSocketAndroid::setup(p_net_utils);
+ TTS_Android::setup(p_godot_tts);
os_android = new OS_Android(godot_java, godot_io_java, p_use_apk_expansion);
- char wd[500];
- getcwd(wd, 500);
-
godot_java->on_video_init(env);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz) {
// lets cleanup
+ if (java_class_wrapper) {
+ memdelete(java_class_wrapper);
+ }
if (godot_io_java) {
delete godot_io_java;
}
@@ -117,6 +118,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env
delete input_handler;
}
if (os_android) {
+ os_android->main_loop_end();
delete os_android;
}
}
@@ -138,7 +140,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc
for (int i = 0; i < cmdlen; i++) {
jstring string = (jstring)env->GetObjectArrayElement(p_cmdline, i);
- const char *rawString = env->GetStringUTFChars(string, 0);
+ const char *rawString = env->GetStringUTFChars(string, nullptr);
cmdline[i] = rawString;
j_cmdline[i] = string;
@@ -146,7 +148,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc
}
}
- Error err = Main::setup("apk", cmdlen, (char **)cmdline, false);
+ Error err = Main::setup(OS_Android::ANDROID_EXEC_PATH, cmdlen, (char **)cmdline, false);
if (cmdline) {
if (j_cmdline) {
for (int i = 0; i < cmdlen; ++i) {
@@ -157,6 +159,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jc
memfree(cmdline);
}
+ // Note: --help and --version return ERR_HELP, but this should be translated to 0 if exit codes are propagated.
if (err != OK) {
return; // should exit instead and print the error
}
@@ -182,11 +185,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, j
}
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface, jboolean p_32_bits) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jobject p_surface) {
if (os_android) {
if (step.get() == 0) {
// During startup
- os_android->set_context_is_16_bits(!p_32_bits);
if (p_surface) {
ANativeWindow *native_window = ANativeWindow_fromSurface(env, p_surface);
os_android->set_native_window(native_window);
@@ -201,17 +203,23 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz) {
- if (step.get() == 0)
+ if (step.get() == 0) {
return;
+ }
if (DisplayServerAndroid *dsa = Object::cast_to<DisplayServerAndroid>(DisplayServer::get_singleton())) {
dsa->send_window_event(DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST);
}
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz) {
- if (step.get() == -1)
- return;
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ttsCallback(JNIEnv *env, jclass clazz, jint event, jint id, jint pos) {
+ TTS_Android::_java_utterance_callback(event, id, pos);
+}
+
+JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz) {
+ if (step.get() == -1) {
+ return true;
+ }
if (step.get() == 0) {
// Since Godot is initialized on the UI thread, main_thread_id was set to that thread's id,
@@ -219,12 +227,12 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl
Main::setup2(Thread::get_caller_id());
input_handler = new AndroidInputHandler();
step.increment();
- return;
+ return true;
}
if (step.get() == 1) {
if (!Main::start()) {
- return; // should exit instead and print the error
+ return true; // should exit instead and print the error
}
godot_java->on_godot_setup_completed(env);
@@ -238,14 +246,18 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jcl
DisplayServerAndroid::get_singleton()->process_magnetometer(magnetometer);
DisplayServerAndroid::get_singleton()->process_gyroscope(gyroscope);
- if (os_android->main_loop_iterate()) {
+ bool should_swap_buffers = false;
+ if (os_android->main_loop_iterate(&should_swap_buffers)) {
godot_java->force_quit(env);
}
+
+ return should_swap_buffers;
}
void touch_preprocessing(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
Vector<AndroidInputHandler::TouchPos> points;
for (int i = 0; i < pointer_count; i++) {
@@ -280,32 +292,27 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNI
// Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
input_handler->process_hover(p_type, Point2(p_x, p_y));
}
// Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
input_handler->process_double_tap(p_button_mask, Point2(p_x, p_y));
}
// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y) {
- if (step.get() <= 0)
- return;
-
- input_handler->process_scroll(Point2(p_x, p_y));
-}
-
-// Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
AndroidInputHandler::JoypadEvent jevent;
jevent.device = p_device;
@@ -318,8 +325,9 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env
// Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
AndroidInputHandler::JoypadEvent jevent;
jevent.device = p_device;
@@ -332,24 +340,27 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env,
// Called on the UI thread
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
AndroidInputHandler::JoypadEvent jevent;
jevent.device = p_device;
jevent.type = AndroidInputHandler::JOY_EVENT_HAT;
- int hat = 0;
+ HatMask hat = HatMask::CENTER;
if (p_hat_x != 0) {
- if (p_hat_x < 0)
- hat |= HatMask::HAT_MASK_LEFT;
- else
- hat |= HatMask::HAT_MASK_RIGHT;
+ if (p_hat_x < 0) {
+ hat |= HatMask::LEFT;
+ } else {
+ hat |= HatMask::RIGHT;
+ }
}
if (p_hat_y != 0) {
- if (p_hat_y < 0)
- hat |= HatMask::HAT_MASK_UP;
- else
- hat |= HatMask::HAT_MASK_DOWN;
+ if (p_hat_y < 0) {
+ hat |= HatMask::UP;
+ } else {
+ hat |= HatMask::DOWN;
+ }
}
jevent.hat = hat;
@@ -365,11 +376,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(
}
// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed) {
- if (step.get() <= 0)
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed) {
+ if (step.get() <= 0) {
return;
-
- input_handler->process_key_event(p_keycode, p_scancode, p_unicode_char, p_pressed);
+ }
+ input_handler->process_key_event(p_keycode, p_physical_keycode, p_unicode, p_pressed);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) {
@@ -389,15 +400,17 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jclass clazz) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
os_android->main_loop_focusin();
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, jclass clazz) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
os_android->main_loop_focusout();
}
@@ -410,7 +423,7 @@ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params) {
Object *obj = ObjectDB::get_instance(ObjectID(ID));
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
int res = env->PushLocalFrame(16);
ERR_FAIL_COND(res != 0);
@@ -421,26 +434,26 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *en
Variant *vlist = (Variant *)alloca(sizeof(Variant) * count);
Variant **vptr = (Variant **)alloca(sizeof(Variant *) * count);
for (int i = 0; i < count; i++) {
- jobject obj = env->GetObjectArrayElement(params, i);
+ jobject jobj = env->GetObjectArrayElement(params, i);
Variant v;
- if (obj)
- v = _jobject_to_variant(env, obj);
+ if (jobj) {
+ v = _jobject_to_variant(env, jobj);
+ }
memnew_placement(&vlist[i], Variant);
vlist[i] = v;
vptr[i] = &vlist[i];
- env->DeleteLocalRef(obj);
- };
+ env->DeleteLocalRef(jobj);
+ }
Callable::CallError err;
- obj->call(str_method, (const Variant **)vptr, count, err);
- // something
+ obj->callp(str_method, (const Variant **)vptr, count, err);
env->PopLocalFrame(nullptr);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params) {
Object *obj = ObjectDB::get_instance(ObjectID(ID));
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
int res = env->PushLocalFrame(16);
ERR_FAIL_COND(res != 0);
@@ -448,18 +461,21 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
String str_method = jstring_to_string(method, env);
int count = env->GetArrayLength(params);
- Variant args[VARIANT_ARG_MAX];
-
- for (int i = 0; i < MIN(count, VARIANT_ARG_MAX); i++) {
- jobject obj = env->GetObjectArrayElement(params, i);
- if (obj)
- args[i] = _jobject_to_variant(env, obj);
- env->DeleteLocalRef(obj);
- };
-
- static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8");
- obj->call_deferred(str_method, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
- // something
+
+ Variant *args = (Variant *)alloca(sizeof(Variant) * count);
+ const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * count);
+
+ for (int i = 0; i < count; i++) {
+ jobject jobj = env->GetObjectArrayElement(params, i);
+ if (jobj) {
+ args[i] = _jobject_to_variant(env, jobj);
+ }
+ env->DeleteLocalRef(jobj);
+ argptrs[i] = &args[i];
+ }
+
+ MessageQueue::get_singleton()->push_callp(obj, str_method, (const Variant **)argptrs, count);
+
env->PopLocalFrame(nullptr);
}
@@ -475,17 +491,21 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResu
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
+ // We force redraw to ensure we render at least once when resuming the app.
+ Main::force_redraw();
if (os_android->get_main_loop()) {
os_android->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_RESUMED);
}
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIEnv *env, jclass clazz) {
- if (step.get() <= 0)
+ if (step.get() <= 0) {
return;
+ }
if (os_android->get_main_loop()) {
os_android->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_PAUSED);