Browse Source

Merge pull request #27010 from BastiaanOlij/restructure_android_glue

Restructuring android glue code to make it easier to extend
Rémi Verschelde 6 years ago
parent
commit
a9a4936518

+ 3 - 1
platform/android/SCsub

@@ -16,8 +16,10 @@ android_files = [
     'dir_access_jandroid.cpp',
     'thread_jandroid.cpp',
     'audio_driver_jandroid.cpp',
-    'java_glue.cpp',
+    'java_godot_lib_jni.cpp',
     'java_class_wrapper.cpp',
+    'java_godot_wrapper.cpp',
+    'java_godot_io_wrapper.cpp',
 #    'power_android.cpp'
 ]
 

+ 1 - 1
platform/android/audio_driver_jandroid.h

@@ -33,7 +33,7 @@
 
 #include "servers/audio_server.h"
 
-#include "java_glue.h"
+#include "java_godot_lib_jni.h"
 
 class AudioDriverAndroid : public AudioDriver {
 

+ 1 - 1
platform/android/dir_access_jandroid.h

@@ -32,7 +32,7 @@
 #define DIR_ACCESS_JANDROID_H
 
 #include "core/os/dir_access.h"
-#include "java_glue.h"
+#include "java_godot_lib_jni.h"
 #include <stdio.h>
 
 class DirAccessJAndroid : public DirAccess {

+ 1 - 1
platform/android/file_access_jandroid.h

@@ -32,7 +32,7 @@
 #define FILE_ACCESS_JANDROID_H
 
 #include "core/os/file_access.h"
-#include "java_glue.h"
+#include "java_godot_lib_jni.h"
 class FileAccessJAndroid : public FileAccess {
 
 	static jobject io;

+ 3 - 0
platform/android/java/src/org/godotengine/godot/Godot.java

@@ -606,6 +606,9 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
 		for (int i = 0; i < singleton_count; i++) {
 			singletons[i].onMainDestroy();
 		}
+
+		GodotLib.ondestroy(this);
+
 		super.onDestroy();
 	}
 

+ 1 - 0
platform/android/java/src/org/godotengine/godot/GodotLib.java

@@ -46,6 +46,7 @@ public class GodotLib {
      */
 
 	public static native void initialize(Godot p_instance, Object p_asset_manager, boolean use_apk_expansion);
+	public static native void ondestroy(Godot p_instance);
 	public static native void setup(String[] p_cmdline);
 	public static native void resize(int width, int height);
 	public static native void newcontext(boolean p_32_bits);

+ 207 - 0
platform/android/java_godot_io_wrapper.cpp

@@ -0,0 +1,207 @@
+/*************************************************************************/
+/*  java_godot_io_wrapper.cpp                                            */
+/*************************************************************************/
+/*                       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.                */
+/*************************************************************************/
+
+#include "java_godot_io_wrapper.h"
+#include "core/error_list.h"
+
+// JNIEnv is only valid within the thread it belongs to, in a multi threading environment
+// we can't cache it.
+// For GodotIO we call all access methods from our thread and we thus get a valid JNIEnv
+// from ThreadAndroid.
+
+GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instance) {
+	godot_io_instance = p_env->NewGlobalRef(p_godot_io_instance);
+	if (godot_io_instance) {
+		cls = p_env->GetObjectClass(godot_io_instance);
+		if (cls) {
+			cls = (jclass)p_env->NewGlobalRef(cls);
+		} else {
+			// this is a pretty serious fail.. bail... pointers will stay 0
+			return;
+		}
+
+		_open_URI = p_env->GetMethodID(cls, "openURI", "(Ljava/lang/String;)I");
+		_get_data_dir = p_env->GetMethodID(cls, "getDataDir", "()Ljava/lang/String;");
+		_get_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;");
+		_get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
+		_get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
+		_get_unique_ID = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;");
+		_show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;)V");
+		_hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V");
+		_set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V");
+		_get_system_dir = p_env->GetMethodID(cls, "getSystemDir", "(I)Ljava/lang/String;");
+		_play_video = p_env->GetMethodID(cls, "playVideo", "(Ljava/lang/String;)V");
+		_is_video_playing = p_env->GetMethodID(cls, "isVideoPlaying", "()Z");
+		_pause_video = p_env->GetMethodID(cls, "pauseVideo", "()V");
+		_stop_video = p_env->GetMethodID(cls, "stopVideo", "()V");
+	}
+}
+
+GodotIOJavaWrapper::~GodotIOJavaWrapper() {
+	// nothing to do here for now
+}
+
+jobject GodotIOJavaWrapper::get_instance() {
+	return godot_io_instance;
+}
+
+Error GodotIOJavaWrapper::open_uri(const String &p_uri) {
+	if (_open_URI) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jstring jStr = env->NewStringUTF(p_uri.utf8().get_data());
+		return env->CallIntMethod(godot_io_instance, _open_URI, jStr) ? ERR_CANT_OPEN : OK;
+	} else {
+		return ERR_UNAVAILABLE;
+	}
+}
+
+String GodotIOJavaWrapper::get_user_data_dir() {
+	if (_get_data_dir) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_data_dir);
+		return jstring_to_string(s, env);
+	} else {
+		return String();
+	}
+}
+
+String GodotIOJavaWrapper::get_locale() {
+	if (_get_locale) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_locale);
+		return jstring_to_string(s, env);
+	} else {
+		return String();
+	}
+}
+
+String GodotIOJavaWrapper::get_model() {
+	if (_get_model) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_model);
+		return jstring_to_string(s, env);
+	} else {
+		return String();
+	}
+}
+
+int GodotIOJavaWrapper::get_screen_dpi() {
+	if (_get_screen_DPI) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		return env->CallIntMethod(godot_io_instance, _get_screen_DPI);
+	} else {
+		return 160;
+	}
+}
+
+String GodotIOJavaWrapper::get_unique_id() {
+	if (_get_unique_ID) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_unique_ID);
+		return jstring_to_string(s, env);
+	} else {
+		return String();
+	}
+}
+
+bool GodotIOJavaWrapper::has_vk() {
+	return (_show_keyboard != 0) && (_hide_keyboard != 0);
+}
+
+void GodotIOJavaWrapper::show_vk(const String &p_existing) {
+	if (_show_keyboard) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
+		env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr);
+	}
+}
+
+void GodotIOJavaWrapper::hide_vk() {
+	if (_hide_keyboard) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		env->CallVoidMethod(godot_io_instance, _hide_keyboard);
+	}
+}
+
+void GodotIOJavaWrapper::set_screen_orientation(int p_orient) {
+	if (_set_screen_orientation) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		env->CallVoidMethod(godot_io_instance, _set_screen_orientation, p_orient);
+	}
+}
+
+String GodotIOJavaWrapper::get_system_dir(int p_dir) {
+	if (_get_system_dir) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_system_dir, p_dir);
+		return jstring_to_string(s, env);
+	} else {
+		return String(".");
+	}
+}
+
+void GodotIOJavaWrapper::play_video(const String &p_path) {
+	// Why is this not here?!?!
+}
+
+bool GodotIOJavaWrapper::is_video_playing() {
+	if (_is_video_playing) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		return env->CallBooleanMethod(godot_io_instance, _is_video_playing);
+	} else {
+		return false;
+	}
+}
+
+void GodotIOJavaWrapper::pause_video() {
+	if (_pause_video) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		env->CallVoidMethod(godot_io_instance, _pause_video);
+	}
+}
+
+void GodotIOJavaWrapper::stop_video() {
+	if (_stop_video) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		env->CallVoidMethod(godot_io_instance, _stop_video);
+	}
+}
+
+// volatile because it can be changed from non-main thread and we need to
+// ensure the change is immediately visible to other threads.
+static volatile int virtual_keyboard_height;
+
+int GodotIOJavaWrapper::get_vk_height() {
+	return virtual_keyboard_height;
+}
+
+void GodotIOJavaWrapper::set_vk_height(int p_height) {
+	virtual_keyboard_height = p_height;
+}

+ 88 - 0
platform/android/java_godot_io_wrapper.h

@@ -0,0 +1,88 @@
+/*************************************************************************/
+/*  java_godot_io_wrapper.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.                */
+/*************************************************************************/
+
+// note, swapped java and godot around in the file name so all the java
+// wrappers are together
+
+#ifndef JAVA_GODOT_IO_WRAPPER_H
+#define JAVA_GODOT_IO_WRAPPER_H
+
+#include <android/log.h>
+#include <jni.h>
+
+#include "string_android.h"
+
+// Class that makes functions in java/src/org/godotengine/godot/GodotIO.java callable from C++
+class GodotIOJavaWrapper {
+private:
+	jobject godot_io_instance;
+	jclass cls;
+
+	jmethodID _open_URI = 0;
+	jmethodID _get_data_dir = 0;
+	jmethodID _get_locale = 0;
+	jmethodID _get_model = 0;
+	jmethodID _get_screen_DPI = 0;
+	jmethodID _get_unique_ID = 0;
+	jmethodID _show_keyboard = 0;
+	jmethodID _hide_keyboard = 0;
+	jmethodID _set_screen_orientation = 0;
+	jmethodID _get_system_dir = 0;
+	jmethodID _play_video = 0;
+	jmethodID _is_video_playing = 0;
+	jmethodID _pause_video = 0;
+	jmethodID _stop_video = 0;
+
+public:
+	GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instance);
+	~GodotIOJavaWrapper();
+
+	jobject get_instance();
+
+	Error open_uri(const String &p_uri);
+	String get_user_data_dir();
+	String get_locale();
+	String get_model();
+	int get_screen_dpi();
+	String get_unique_id();
+	bool has_vk();
+	void show_vk(const String &p_existing);
+	void hide_vk();
+	int get_vk_height();
+	void set_vk_height(int p_height);
+	void set_screen_orientation(int p_orient);
+	String get_system_dir(int p_dir);
+	void play_video(const String &p_path);
+	bool is_video_playing();
+	void pause_video();
+	void stop_video();
+};
+
+#endif /* !JAVA_GODOT_IO_WRAPPER_H */

+ 43 - 234
platform/android/java_glue.cpp → platform/android/java_godot_lib_jni.cpp

@@ -1,5 +1,5 @@
 /*************************************************************************/
-/*  java_glue.cpp                                                        */
+/*  java_godot_lib_jni.cpp                                               */
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
@@ -28,7 +28,10 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#include "java_glue.h"
+#include "java_godot_lib_jni.h"
+#include "java_godot_io_wrapper.h"
+#include "java_godot_wrapper.h"
+
 #include "android/asset_manager_jni.h"
 #include "audio_driver_jandroid.h"
 #include "core/engine.h"
@@ -47,6 +50,8 @@
 
 static JavaClassWrapper *java_class_wrapper = NULL;
 static OS_Android *os_android = NULL;
+static GodotJavaWrapper *godot_java = NULL;
+static GodotIOJavaWrapper *godot_io_java = NULL;
 
 struct jvalret {
 
@@ -588,181 +593,23 @@ TST tst;
 
 static bool initialized = false;
 static int step = 0;
+
 static Size2 new_size;
 static Vector3 accelerometer;
 static Vector3 gravity;
 static Vector3 magnetometer;
 static Vector3 gyroscope;
 static HashMap<String, JNISingleton *> jni_singletons;
-static jobject godot_io;
-
-typedef void (*GFXInitFunc)(void *ud, bool gl2);
-
-static jmethodID _on_video_init = 0;
-static jmethodID _restart = 0;
-static jobject _godot_instance;
-
-static jmethodID _openURI = 0;
-static jmethodID _getDataDir = 0;
-static jmethodID _getLocale = 0;
-static jmethodID _getClipboard = 0;
-static jmethodID _setClipboard = 0;
-static jmethodID _getModel = 0;
-static jmethodID _getScreenDPI = 0;
-static jmethodID _showKeyboard = 0;
-static jmethodID _hideKeyboard = 0;
-static jmethodID _setScreenOrientation = 0;
-static jmethodID _getUniqueID = 0;
-static jmethodID _getSystemDir = 0;
-static jmethodID _getGLESVersionCode = 0;
-static jmethodID _playVideo = 0;
-static jmethodID _isVideoPlaying = 0;
-static jmethodID _pauseVideo = 0;
-static jmethodID _stopVideo = 0;
-static jmethodID _setKeepScreenOn = 0;
-static jmethodID _alertDialog = 0;
-static jmethodID _requestPermission = 0;
-
-static void _gfx_init_func(void *ud, bool gl2) {
-}
-
-static int _open_uri(const String &p_uri) {
-
-	JNIEnv *env = ThreadAndroid::get_env();
-	jstring jStr = env->NewStringUTF(p_uri.utf8().get_data());
-	return env->CallIntMethod(godot_io, _openURI, jStr);
-}
-
-static String _get_user_data_dir() {
-
-	JNIEnv *env = ThreadAndroid::get_env();
-	jstring s = (jstring)env->CallObjectMethod(godot_io, _getDataDir);
-	return jstring_to_string(s, env);
-}
-
-static String _get_locale() {
-
-	JNIEnv *env = ThreadAndroid::get_env();
-	jstring s = (jstring)env->CallObjectMethod(godot_io, _getLocale);
-	return jstring_to_string(s, env);
-}
-
-static String _get_clipboard() {
-	JNIEnv *env = ThreadAndroid::get_env();
-	jstring s = (jstring)env->CallObjectMethod(_godot_instance, _getClipboard);
-	return jstring_to_string(s, env);
-}
-
-static void _set_clipboard(const String &p_text) {
-
-	JNIEnv *env = ThreadAndroid::get_env();
-	jstring jStr = env->NewStringUTF(p_text.utf8().get_data());
-	env->CallVoidMethod(_godot_instance, _setClipboard, jStr);
-}
-
-static String _get_model() {
-
-	JNIEnv *env = ThreadAndroid::get_env();
-	jstring s = (jstring)env->CallObjectMethod(godot_io, _getModel);
-	return jstring_to_string(s, env);
-}
-
-static int _get_screen_dpi() {
-
-	JNIEnv *env = ThreadAndroid::get_env();
-	return env->CallIntMethod(godot_io, _getScreenDPI);
-}
-
-static String _get_unique_id() {
-
-	JNIEnv *env = ThreadAndroid::get_env();
-	jstring s = (jstring)env->CallObjectMethod(godot_io, _getUniqueID);
-	return jstring_to_string(s, env);
-}
-
-static void _show_vk(const String &p_existing) {
-
-	JNIEnv *env = ThreadAndroid::get_env();
-	jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
-	env->CallVoidMethod(godot_io, _showKeyboard, jStr);
-}
-
-static void _set_screen_orient(int p_orient) {
-
-	JNIEnv *env = ThreadAndroid::get_env();
-	env->CallVoidMethod(godot_io, _setScreenOrientation, p_orient);
-}
-
-static String _get_system_dir(int p_dir) {
-
-	JNIEnv *env = ThreadAndroid::get_env();
-	jstring s = (jstring)env->CallObjectMethod(godot_io, _getSystemDir, p_dir);
-	return jstring_to_string(s, env);
-}
-
-static int _get_gles_version_code() {
-	JNIEnv *env = ThreadAndroid::get_env();
-	return env->CallIntMethod(_godot_instance, _getGLESVersionCode);
-}
-
-static void _hide_vk() {
-
-	JNIEnv *env = ThreadAndroid::get_env();
-	env->CallVoidMethod(godot_io, _hideKeyboard);
-}
 
 // virtual Error native_video_play(String p_path);
 // virtual bool native_video_is_playing();
 // virtual void native_video_pause();
 // virtual void native_video_stop();
 
-static void _play_video(const String &p_path) {
-}
-
-static bool _is_video_playing() {
-	JNIEnv *env = ThreadAndroid::get_env();
-	return env->CallBooleanMethod(godot_io, _isVideoPlaying);
-	//return false;
-}
-
-static void _pause_video() {
-	JNIEnv *env = ThreadAndroid::get_env();
-	env->CallVoidMethod(godot_io, _pauseVideo);
-}
-
-static void _stop_video() {
-	JNIEnv *env = ThreadAndroid::get_env();
-	env->CallVoidMethod(godot_io, _stopVideo);
-}
-
-static void _set_keep_screen_on(bool p_enabled) {
-	JNIEnv *env = ThreadAndroid::get_env();
-	env->CallVoidMethod(_godot_instance, _setKeepScreenOn, p_enabled);
-}
-
-static void _alert(const String &p_message, const String &p_title) {
-	JNIEnv *env = ThreadAndroid::get_env();
-	jstring jStrMessage = env->NewStringUTF(p_message.utf8().get_data());
-	jstring jStrTitle = env->NewStringUTF(p_title.utf8().get_data());
-	env->CallVoidMethod(_godot_instance, _alertDialog, jStrMessage, jStrTitle);
-}
-
-static bool _request_permission(const String &p_name) {
-	JNIEnv *env = ThreadAndroid::get_env();
-	jstring jStrName = env->NewStringUTF(p_name.utf8().get_data());
-	return env->CallBooleanMethod(_godot_instance, _requestPermission, jStrName);
-}
-
-// volatile because it can be changed from non-main thread and we need to
-// ensure the change is immediately visible to other threads.
-static volatile int virtual_keyboard_height;
-
-static int _get_vk_height() {
-	return virtual_keyboard_height;
-}
-
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height) {
-	virtual_keyboard_height = p_height;
+	if (godot_io_java) {
+		godot_io_java->set_vk_height(p_height);
+	}
 }
 
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jobject p_asset_manager, jboolean p_use_apk_expansion) {
@@ -772,70 +619,42 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
 	JavaVM *jvm;
 	env->GetJavaVM(&jvm);
 
-	_godot_instance = env->NewGlobalRef(activity);
-	//_godot_instance=activity;
-
-	{
-		//setup IO Object
-
-		jclass cls = env->FindClass("org/godotengine/godot/Godot");
-		if (cls) {
-
-			cls = (jclass)env->NewGlobalRef(cls);
-		}
-
-		jfieldID fid = env->GetStaticFieldID(cls, "io", "Lorg/godotengine/godot/GodotIO;");
-		jobject ob = env->GetStaticObjectField(cls, fid);
-		jobject gob = env->NewGlobalRef(ob);
-
-		godot_io = gob;
-
-		_on_video_init = env->GetMethodID(cls, "onVideoInit", "()V");
-		_restart = env->GetMethodID(cls, "restart", "()V");
-		_setKeepScreenOn = env->GetMethodID(cls, "setKeepScreenOn", "(Z)V");
-		_alertDialog = env->GetMethodID(cls, "alert", "(Ljava/lang/String;Ljava/lang/String;)V");
-		_getGLESVersionCode = env->GetMethodID(cls, "getGLESVersionCode", "()I");
-		_getClipboard = env->GetMethodID(cls, "getClipboard", "()Ljava/lang/String;");
-		_setClipboard = env->GetMethodID(cls, "setClipboard", "(Ljava/lang/String;)V");
-		_requestPermission = env->GetMethodID(cls, "requestPermission", "(Ljava/lang/String;)Z");
-
-		if (cls) {
-			jclass c = env->GetObjectClass(gob);
-			_openURI = env->GetMethodID(c, "openURI", "(Ljava/lang/String;)I");
-			_getDataDir = env->GetMethodID(c, "getDataDir", "()Ljava/lang/String;");
-			_getLocale = env->GetMethodID(c, "getLocale", "()Ljava/lang/String;");
-			_getModel = env->GetMethodID(c, "getModel", "()Ljava/lang/String;");
-			_getScreenDPI = env->GetMethodID(c, "getScreenDPI", "()I");
-			_getUniqueID = env->GetMethodID(c, "getUniqueID", "()Ljava/lang/String;");
-			_showKeyboard = env->GetMethodID(c, "showKeyboard", "(Ljava/lang/String;)V");
-			_hideKeyboard = env->GetMethodID(c, "hideKeyboard", "()V");
-			_setScreenOrientation = env->GetMethodID(c, "setScreenOrientation", "(I)V");
-			_getSystemDir = env->GetMethodID(c, "getSystemDir", "(I)Ljava/lang/String;");
-			_playVideo = env->GetMethodID(c, "playVideo", "(Ljava/lang/String;)V");
-			_isVideoPlaying = env->GetMethodID(c, "isVideoPlaying", "()Z");
-			_pauseVideo = env->GetMethodID(c, "pauseVideo", "()V");
-			_stopVideo = env->GetMethodID(c, "stopVideo", "()V");
-		}
+	// create our wrapper classes
+	godot_java = new GodotJavaWrapper(env, activity); // our activity is our godot instance is our activity..
+	godot_io_java = new GodotIOJavaWrapper(env, godot_java->get_member_object("io", "Lorg/godotengine/godot/GodotIO;", env));
 
-		ThreadAndroid::make_default(jvm);
+	ThreadAndroid::make_default(jvm);
 #ifdef USE_JAVA_FILE_ACCESS
-		FileAccessJAndroid::setup(gob);
+	FileAccessJAndroid::setup(godot_io_java->get_instance());
 #else
 
-		jobject amgr = env->NewGlobalRef(p_asset_manager);
+	jobject amgr = env->NewGlobalRef(p_asset_manager);
 
-		FileAccessAndroid::asset_manager = AAssetManager_fromJava(env, amgr);
+	FileAccessAndroid::asset_manager = AAssetManager_fromJava(env, amgr);
 #endif
-		DirAccessJAndroid::setup(gob);
-		AudioDriverAndroid::setup(gob);
-	}
 
-	os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_user_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _get_vk_height, _set_screen_orient, _get_unique_id, _get_system_dir, _get_gles_version_code, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, _set_clipboard, _get_clipboard, _request_permission, p_use_apk_expansion);
+	DirAccessJAndroid::setup(godot_io_java->get_instance());
+	AudioDriverAndroid::setup(godot_io_java->get_instance());
+
+	os_android = new OS_Android(godot_java, godot_io_java, p_use_apk_expansion);
 
 	char wd[500];
 	getcwd(wd, 500);
 
-	env->CallVoidMethod(_godot_instance, _on_video_init);
+	godot_java->on_video_init(env);
+}
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env) {
+	// lets cleanup
+	if (godot_io_java) {
+		delete godot_io_java;
+	}
+	if (godot_java) {
+		delete godot_java;
+	}
+	if (os_android) {
+		delete os_android;
+	}
 }
 
 static void _initialize_java_modules() {
@@ -852,17 +671,12 @@ static void _initialize_java_modules() {
 	Vector<String> mods = modules.split(",", false);
 
 	if (mods.size()) {
+		jobject cls = godot_java->get_class_loader();
 
-		JNIEnv *env = ThreadAndroid::get_env();
-
-		jclass activityClass = env->FindClass("org/godotengine/godot/Godot");
-
-		jmethodID getClassLoader = env->GetMethodID(activityClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
-
-		jobject cls = env->CallObjectMethod(_godot_instance, getClassLoader);
+		// TODO create wrapper for class loader
 
+		JNIEnv *env = ThreadAndroid::get_env();
 		jclass classLoader = env->FindClass("java/lang/ClassLoader");
-
 		jmethodID findClass = env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
 
 		for (int i = 0; i < mods.size(); i++) {
@@ -886,7 +700,7 @@ static void _initialize_java_modules() {
 				ERR_EXPLAIN("Couldn't find proper initialize function 'public static Godot.SingletonBase Class::initialize(Activity p_activity)' initializer for singleton class: " + m);
 				ERR_CONTINUE(!initialize);
 			}
-			jobject obj = env->CallStaticObjectMethod(singletonClass, initialize, _godot_instance);
+			jobject obj = env->CallStaticObjectMethod(singletonClass, initialize, godot_java->get_activity());
 			env->NewGlobalRef(obj);
 		}
 	}
@@ -931,7 +745,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
 		return; //should exit instead and print the error
 	}
 
-	java_class_wrapper = memnew(JavaClassWrapper(_godot_instance));
+	java_class_wrapper = memnew(JavaClassWrapper(godot_java->get_activity()));
 	Engine::get_singleton()->add_singleton(Engine::Singleton("JavaClassWrapper", java_class_wrapper));
 	_initialize_java_modules();
 }
@@ -951,7 +765,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en
 		} else {
 			// GL context recreated because it was lost; restart app to let it reload everything
 			os_android->main_loop_end();
-			env->CallVoidMethod(_godot_instance, _restart);
+			godot_java->restart(env);
 			step = -1; // Ensure no further steps are attempted
 		}
 	}
@@ -987,18 +801,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job
 	}
 
 	os_android->process_accelerometer(accelerometer);
-
 	os_android->process_gravity(gravity);
-
 	os_android->process_magnetometer(magnetometer);
-
 	os_android->process_gyroscope(gyroscope);
 
 	if (os_android->main_loop_iterate()) {
 
-		jclass cls = env->FindClass("org/godotengine/godot/Godot");
-		jmethodID _finish = env->GetMethodID(cls, "forceQuit", "()V");
-		env->CallVoidMethod(_godot_instance, _finish);
+		godot_java->force_quit(env);
 	}
 }
 

+ 7 - 4
platform/android/java_glue.h → platform/android/java_godot_lib_jni.h

@@ -1,5 +1,5 @@
 /*************************************************************************/
-/*  java_glue.h                                                          */
+/*  java_godot_lib_jni.h                                                 */
 /*************************************************************************/
 /*                       This file is part of:                           */
 /*                           GODOT ENGINE                                */
@@ -28,14 +28,17 @@
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
 
-#ifndef JAVA_GLUE_H
-#define JAVA_GLUE_H
+#ifndef JAVA_GODOT_LIB_JNI_H
+#define JAVA_GODOT_LIB_JNI_H
 
 #include <android/log.h>
 #include <jni.h>
 
+// These functions can be called from within JAVA and are the means by which our JAVA implementation calls back into our C++ code.
+// See java/src/org/godotengine/godot/GodotLib.java for the JAVA side of this (yes thats why we have the long names)
 extern "C" {
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jobject p_asset_manager, jboolean p_use_apk_expansion);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jobject obj, jobjectArray p_cmdline);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jobject obj, jint width, jint height);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits);
@@ -63,4 +66,4 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHei
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jobject p_obj, jstring p_permission, jboolean p_result);
 }
 
-#endif // JAVA_GLUE_H
+#endif /* !JAVA_GODOT_LIB_JNI_H */

+ 185 - 0
platform/android/java_godot_wrapper.cpp

@@ -0,0 +1,185 @@
+/*************************************************************************/
+/*  java_godot_wrapper.cpp                                               */
+/*************************************************************************/
+/*                       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.                */
+/*************************************************************************/
+
+#include "java_godot_wrapper.h"
+
+// JNIEnv is only valid within the thread it belongs to, in a multi threading environment
+// we can't cache it.
+// For Godot we call most access methods from our thread and we thus get a valid JNIEnv
+// from ThreadAndroid. For one or two we expect to pass the environment
+
+// TODO we could probably create a base class for this...
+
+GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) {
+	godot_instance = p_env->NewGlobalRef(p_godot_instance);
+
+	// get info about our Godot class so we can get pointers and stuff...
+	cls = p_env->FindClass("org/godotengine/godot/Godot");
+	if (cls) {
+		cls = (jclass)p_env->NewGlobalRef(cls);
+	} else {
+		// this is a pretty serious fail.. bail... pointers will stay 0
+		return;
+	}
+
+	// get some method pointers...
+	_on_video_init = p_env->GetMethodID(cls, "onVideoInit", "()V");
+	_restart = p_env->GetMethodID(cls, "restart", "()V");
+	_finish = p_env->GetMethodID(cls, "forceQuit", "()V");
+	_set_keep_screen_on = p_env->GetMethodID(cls, "setKeepScreenOn", "(Z)V");
+	_alert = p_env->GetMethodID(cls, "alert", "(Ljava/lang/String;Ljava/lang/String;)V");
+	_get_GLES_version_code = p_env->GetMethodID(cls, "getGLESVersionCode", "()I");
+	_get_clipboard = p_env->GetMethodID(cls, "getClipboard", "()Ljava/lang/String;");
+	_set_clipboard = p_env->GetMethodID(cls, "setClipboard", "(Ljava/lang/String;)V");
+	_request_permission = p_env->GetMethodID(cls, "requestPermission", "(Ljava/lang/String;)Z");
+}
+
+GodotJavaWrapper::~GodotJavaWrapper() {
+	// nothing to do here for now
+}
+
+jobject GodotJavaWrapper::get_activity() {
+	// our godot instance is our activity
+	return godot_instance;
+}
+
+jobject GodotJavaWrapper::get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env) {
+	if (cls) {
+		if (p_env == NULL)
+			p_env = ThreadAndroid::get_env();
+
+		jfieldID fid = p_env->GetStaticFieldID(cls, p_name, p_class);
+		return p_env->GetStaticObjectField(cls, fid);
+	} else {
+		return NULL;
+	}
+}
+
+jobject GodotJavaWrapper::get_class_loader() {
+	if (cls) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jmethodID getClassLoader = env->GetMethodID(cls, "getClassLoader", "()Ljava/lang/ClassLoader;");
+		return env->CallObjectMethod(godot_instance, getClassLoader);
+	} else {
+		return NULL;
+	}
+}
+
+void GodotJavaWrapper::gfx_init(bool gl2) {
+	// beats me what this once did, there was no code,
+	// but we're getting false if our GLES3 driver is initialised
+	// and true for our GLES2 driver
+	// Maybe we're supposed to communicate this back or store it?
+}
+
+void GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
+	if (_on_video_init)
+		if (p_env == NULL)
+			p_env = ThreadAndroid::get_env();
+
+	p_env->CallVoidMethod(godot_instance, _on_video_init);
+}
+
+void GodotJavaWrapper::restart(JNIEnv *p_env) {
+	if (_restart)
+		if (p_env == NULL)
+			p_env = ThreadAndroid::get_env();
+
+	p_env->CallVoidMethod(godot_instance, _restart);
+}
+
+void GodotJavaWrapper::force_quit(JNIEnv *p_env) {
+	if (_finish)
+		if (p_env == NULL)
+			p_env = ThreadAndroid::get_env();
+
+	p_env->CallVoidMethod(godot_instance, _finish);
+}
+
+void GodotJavaWrapper::set_keep_screen_on(bool p_enabled) {
+	if (_set_keep_screen_on) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		env->CallVoidMethod(godot_instance, _set_keep_screen_on, p_enabled);
+	}
+}
+
+void GodotJavaWrapper::alert(const String &p_message, const String &p_title) {
+	if (_alert) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jstring jStrMessage = env->NewStringUTF(p_message.utf8().get_data());
+		jstring jStrTitle = env->NewStringUTF(p_title.utf8().get_data());
+		env->CallVoidMethod(godot_instance, _alert, jStrMessage, jStrTitle);
+	}
+}
+
+int GodotJavaWrapper::get_gles_version_code() {
+	JNIEnv *env = ThreadAndroid::get_env();
+	if (_get_GLES_version_code) {
+		return env->CallIntMethod(godot_instance, _get_GLES_version_code);
+	}
+
+	return 0;
+}
+
+bool GodotJavaWrapper::has_get_clipboard() {
+	return _get_clipboard != 0;
+}
+
+String GodotJavaWrapper::get_clipboard() {
+	if (_get_clipboard) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jstring s = (jstring)env->CallObjectMethod(godot_instance, _get_clipboard);
+		return jstring_to_string(s, env);
+	} else {
+		return String();
+	}
+}
+
+bool GodotJavaWrapper::has_set_clipboard() {
+	return _set_clipboard != 0;
+}
+
+void GodotJavaWrapper::set_clipboard(const String &p_text) {
+	if (_set_clipboard) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jstring jStr = env->NewStringUTF(p_text.utf8().get_data());
+		env->CallVoidMethod(godot_instance, _set_clipboard, jStr);
+	}
+}
+
+bool GodotJavaWrapper::request_permission(const String &p_name) {
+	if (_request_permission) {
+		JNIEnv *env = ThreadAndroid::get_env();
+		jstring jStrName = env->NewStringUTF(p_name.utf8().get_data());
+		return env->CallBooleanMethod(godot_instance, _request_permission, jStrName);
+	} else {
+		return false;
+	}
+}

+ 81 - 0
platform/android/java_godot_wrapper.h

@@ -0,0 +1,81 @@
+/*************************************************************************/
+/*  java_godot_wrapper.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.                */
+/*************************************************************************/
+
+// note, swapped java and godot around in the file name so all the java
+// wrappers are together
+
+#ifndef JAVA_GODOT_WRAPPER_H
+#define JAVA_GODOT_WRAPPER_H
+
+#include <android/log.h>
+#include <jni.h>
+
+#include "string_android.h"
+
+// Class that makes functions in java/src/org/godotengine/godot/Godot.java callable from C++
+class GodotJavaWrapper {
+private:
+	jobject godot_instance;
+	jclass cls;
+
+	jmethodID _on_video_init = 0;
+	jmethodID _restart = 0;
+	jmethodID _finish = 0;
+	jmethodID _set_keep_screen_on = 0;
+	jmethodID _alert = 0;
+	jmethodID _get_GLES_version_code = 0;
+	jmethodID _get_clipboard = 0;
+	jmethodID _set_clipboard = 0;
+	jmethodID _request_permission = 0;
+
+public:
+	GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance);
+	~GodotJavaWrapper();
+
+	jobject get_activity();
+	jobject get_member_object(const char *p_name, const char *p_class, JNIEnv *p_env = NULL);
+
+	jobject get_class_loader();
+
+	void gfx_init(bool gl2);
+	void on_video_init(JNIEnv *p_env = NULL);
+	void restart(JNIEnv *p_env = NULL);
+	void force_quit(JNIEnv *p_env = NULL);
+	void set_keep_screen_on(bool p_enabled);
+	void alert(const String &p_message, const String &p_title);
+	int get_gles_version_code();
+	bool has_get_clipboard();
+	String get_clipboard();
+	bool has_set_clipboard();
+	void set_clipboard(const String &p_text);
+	bool request_permission(const String &p_name);
+};
+
+#endif /* !JAVA_GODOT_WRAPPER_H */

+ 62 - 83
platform/android/os_android.cpp

@@ -46,6 +46,9 @@
 
 #include <dlfcn.h>
 
+#include "java_godot_io_wrapper.h"
+#include "java_godot_wrapper.h"
+
 class AndroidLogger : public Logger {
 public:
 	virtual void logv(const char *p_format, va_list p_list, bool p_err) {
@@ -118,15 +121,14 @@ int OS_Android::get_current_video_driver() const {
 
 Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
 
-	bool use_gl3 = get_gl_version_code_func() >= 0x00030000;
+	bool use_gl3 = godot_java->get_gles_version_code() >= 0x00030000;
 	use_gl3 = use_gl3 && (GLOBAL_GET("rendering/quality/driver/driver_name") == "GLES3");
 	bool gl_initialization_error = false;
 
 	while (true) {
 		if (use_gl3) {
 			if (RasterizerGLES3::is_viable() == OK) {
-				if (gfx_init_func)
-					gfx_init_func(gfx_init_ud, false);
+				godot_java->gfx_init(false);
 				RasterizerGLES3::register_config();
 				RasterizerGLES3::make_current();
 				break;
@@ -142,8 +144,7 @@ Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int
 			}
 		} else {
 			if (RasterizerGLES2::is_viable() == OK) {
-				if (gfx_init_func)
-					gfx_init_func(gfx_init_ud, true);
+				godot_java->gfx_init(true);
 				RasterizerGLES2::register_config();
 				RasterizerGLES2::make_current();
 				break;
@@ -195,17 +196,23 @@ void OS_Android::finalize() {
 	memdelete(input);
 }
 
+GodotJavaWrapper *OS_Android::get_godot_java() {
+	return godot_java;
+}
+
+GodotIOJavaWrapper *OS_Android::get_godot_io_java() {
+	return godot_io_java;
+}
+
 void OS_Android::alert(const String &p_alert, const String &p_title) {
 
 	//print("ALERT: %s\n", p_alert.utf8().get_data());
-	if (alert_func)
-		alert_func(p_alert, p_title);
+	godot_java->alert(p_alert, p_title);
 }
 
 bool OS_Android::request_permission(const String &p_name) {
-	if (request_permission_func)
-		return request_permission_func(p_name);
-	return false;
+
+	return godot_java->request_permission(p_name);
 }
 
 Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
@@ -262,9 +269,7 @@ void OS_Android::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen)
 void OS_Android::set_keep_screen_on(bool p_enabled) {
 	OS::set_keep_screen_on(p_enabled);
 
-	if (set_keep_screen_on_func) {
-		set_keep_screen_on_func(p_enabled);
-	}
+	godot_java->set_keep_screen_on(p_enabled);
 }
 
 Size2 OS_Android::get_window_size() const {
@@ -505,18 +510,16 @@ bool OS_Android::has_virtual_keyboard() const {
 }
 
 int OS_Android::get_virtual_keyboard_height() const {
-	if (get_virtual_keyboard_height_func) {
-		return get_virtual_keyboard_height_func();
-	}
+	return godot_io_java->get_vk_height();
 
-	ERR_PRINT("Cannot obtain virtual keyboard height.");
-	return 0;
+	// ERR_PRINT("Cannot obtain virtual keyboard height.");
+	// return 0;
 }
 
 void OS_Android::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect) {
 
-	if (show_virtual_keyboard_func) {
-		show_virtual_keyboard_func(p_existing_text);
+	if (godot_io_java->has_vk()) {
+		godot_io_java->show_vk(p_existing_text);
 	} else {
 
 		ERR_PRINT("Virtual keyboard not available");
@@ -525,9 +528,9 @@ void OS_Android::show_virtual_keyboard(const String &p_existing_text, const Rect
 
 void OS_Android::hide_virtual_keyboard() {
 
-	if (hide_virtual_keyboard_func) {
+	if (godot_io_java->has_vk()) {
 
-		hide_virtual_keyboard_func();
+		godot_io_java->hide_vk();
 	} else {
 
 		ERR_PRINT("Virtual keyboard not available");
@@ -556,9 +559,7 @@ void OS_Android::set_display_size(Size2 p_size) {
 
 Error OS_Android::shell_open(String p_uri) {
 
-	if (open_uri_func)
-		return open_uri_func(p_uri) ? ERR_CANT_OPEN : OK;
-	return ERR_UNAVAILABLE;
+	return godot_io_java->open_uri(p_uri);
 }
 
 String OS_Android::get_resource_dir() const {
@@ -568,23 +569,29 @@ String OS_Android::get_resource_dir() const {
 
 String OS_Android::get_locale() const {
 
-	if (get_locale_func)
-		return get_locale_func();
+	String locale = godot_io_java->get_locale();
+	if (locale != "") {
+		return locale;
+	}
+
 	return OS_Unix::get_locale();
 }
 
 void OS_Android::set_clipboard(const String &p_text) {
 
-	if (set_clipboard_func) {
-		set_clipboard_func(p_text);
+	// DO we really need the fallback to OS_Unix here?!
+	if (godot_java->has_set_clipboard()) {
+		godot_java->set_clipboard(p_text);
 	} else {
 		OS_Unix::set_clipboard(p_text);
 	}
 }
 
 String OS_Android::get_clipboard() const {
-	if (get_clipboard_func) {
-		return get_clipboard_func();
+
+	// DO we really need the fallback to OS_Unix here?!
+	if (godot_java->has_get_clipboard()) {
+		return godot_java->get_clipboard();
 	}
 
 	return OS_Unix::get_clipboard();
@@ -592,17 +599,16 @@ String OS_Android::get_clipboard() const {
 
 String OS_Android::get_model_name() const {
 
-	if (get_model_func)
-		return get_model_func();
+	String model = godot_io_java->get_model();
+	if (model != "")
+		return model;
+
 	return OS_Unix::get_model_name();
 }
 
 int OS_Android::get_screen_dpi(int p_screen) const {
 
-	if (get_screen_dpi_func) {
-		return get_screen_dpi_func();
-	}
-	return 160;
+	return godot_io_java->get_screen_dpi();
 }
 
 String OS_Android::get_user_data_dir() const {
@@ -610,8 +616,8 @@ String OS_Android::get_user_data_dir() const {
 	if (data_dir_cache != String())
 		return data_dir_cache;
 
-	if (get_user_data_dir_func) {
-		String data_dir = get_user_data_dir_func();
+	String data_dir = godot_io_java->get_user_data_dir();
+	if (data_dir != "") {
 
 		//store current dir
 		char real_current_dir_name[2048];
@@ -638,45 +644,43 @@ String OS_Android::get_user_data_dir() const {
 
 void OS_Android::set_screen_orientation(ScreenOrientation p_orientation) {
 
-	if (set_screen_orientation_func)
-		set_screen_orientation_func(p_orientation);
+	godot_io_java->set_screen_orientation(p_orientation);
 }
 
 String OS_Android::get_unique_id() const {
 
-	if (get_unique_id_func)
-		return get_unique_id_func();
+	String unique_id = godot_io_java->get_unique_id();
+	if (unique_id != "")
+		return unique_id;
+
 	return OS::get_unique_id();
 }
 
 Error OS_Android::native_video_play(String p_path, float p_volume, String p_audio_track, String p_subtitle_track) {
 	// FIXME: Add support for volume, audio and subtitle tracks
-	if (video_play_func)
-		video_play_func(p_path);
+
+	godot_io_java->play_video(p_path);
 	return OK;
 }
 
 bool OS_Android::native_video_is_playing() const {
-	if (video_is_playing_func)
-		return video_is_playing_func();
-	return false;
+
+	return godot_io_java->is_video_playing();
 }
 
 void OS_Android::native_video_pause() {
-	if (video_pause_func)
-		video_pause_func();
+
+	godot_io_java->pause_video();
 }
 
 String OS_Android::get_system_dir(SystemDir p_dir) const {
 
-	if (get_system_dir_func)
-		return get_system_dir_func(p_dir);
-	return String(".");
+	return godot_io_java->get_system_dir(p_dir);
 }
 
 void OS_Android::native_video_stop() {
-	if (video_stop_func)
-		video_stop_func();
+
+	godot_io_java->stop_video();
 }
 
 void OS_Android::set_context_is_16_bits(bool p_is_16) {
@@ -719,7 +723,7 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) {
 	return false;
 }
 
-OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetUserDataDirFunc p_get_user_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, GetGLVersionCodeFunc p_get_gl_version_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, SetClipboardFunc p_set_clipboard_func, GetClipboardFunc p_get_clipboard_func, RequestPermissionFunc p_request_permission, bool p_use_apk_expansion) {
+OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_godot_io_java, bool p_use_apk_expansion) {
 
 	use_apk_expansion = p_use_apk_expansion;
 	default_videomode.width = 800;
@@ -727,38 +731,13 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI
 	default_videomode.fullscreen = true;
 	default_videomode.resizable = false;
 
-	gfx_init_func = p_gfx_init_func;
-	gfx_init_ud = p_gfx_init_ud;
 	main_loop = NULL;
 	gl_extensions = NULL;
 	//rasterizer = NULL;
 	use_gl2 = false;
 
-	open_uri_func = p_open_uri_func;
-	get_user_data_dir_func = p_get_user_data_dir_func;
-	get_locale_func = p_get_locale_func;
-	get_model_func = p_get_model_func;
-	get_screen_dpi_func = p_get_screen_dpi_func;
-	get_unique_id_func = p_get_unique_id;
-	get_system_dir_func = p_get_sdir_func;
-	get_gl_version_code_func = p_get_gl_version_func;
-
-	video_play_func = p_video_play_func;
-	video_is_playing_func = p_video_is_playing_func;
-	video_pause_func = p_video_pause_func;
-	video_stop_func = p_video_stop_func;
-
-	show_virtual_keyboard_func = p_show_vk;
-	hide_virtual_keyboard_func = p_hide_vk;
-	get_virtual_keyboard_height_func = p_vk_height_func;
-
-	set_clipboard_func = p_set_clipboard_func;
-	get_clipboard_func = p_get_clipboard_func;
-
-	set_screen_orientation_func = p_screen_orient;
-	set_keep_screen_on_func = p_set_keep_screen_on_func;
-	alert_func = p_alert_func;
-	request_permission_func = p_request_permission;
+	godot_java = p_godot_java;
+	godot_io_java = p_godot_io_java;
 
 	Vector<Logger *> loggers;
 	loggers.push_back(memnew(AndroidLogger));

+ 10 - 51
platform/android/os_android.h

@@ -41,29 +41,8 @@
 #include "servers/audio_server.h"
 #include "servers/visual/rasterizer.h"
 
-typedef void (*GFXInitFunc)(void *ud, bool gl2);
-typedef int (*OpenURIFunc)(const String &);
-typedef String (*GetUserDataDirFunc)();
-typedef String (*GetLocaleFunc)();
-typedef void (*SetClipboardFunc)(const String &);
-typedef String (*GetClipboardFunc)();
-typedef String (*GetModelFunc)();
-typedef int (*GetScreenDPIFunc)();
-typedef String (*GetUniqueIDFunc)();
-typedef void (*ShowVirtualKeyboardFunc)(const String &);
-typedef void (*HideVirtualKeyboardFunc)();
-typedef void (*SetScreenOrientationFunc)(int);
-typedef String (*GetSystemDirFunc)(int);
-typedef int (*GetGLVersionCodeFunc)();
-
-typedef void (*VideoPlayFunc)(const String &);
-typedef bool (*VideoIsPlayingFunc)();
-typedef void (*VideoPauseFunc)();
-typedef void (*VideoStopFunc)();
-typedef void (*SetKeepScreenOnFunc)(bool p_enabled);
-typedef void (*AlertFunc)(const String &, const String &);
-typedef int (*VirtualKeyboardHeightFunc)();
-typedef bool (*RequestPermissionFunc)(const String &);
+class GodotJavaWrapper;
+class GodotIOJavaWrapper;
 
 class OS_Android : public OS_Unix {
 public:
@@ -91,9 +70,6 @@ public:
 private:
 	Vector<TouchPos> touch;
 
-	GFXInitFunc gfx_init_func;
-	void *gfx_init_ud;
-
 	bool use_gl2;
 	bool use_apk_expansion;
 
@@ -112,30 +88,11 @@ private:
 	VideoMode default_videomode;
 	MainLoop *main_loop;
 
-	OpenURIFunc open_uri_func;
-	GetUserDataDirFunc get_user_data_dir_func;
-	GetLocaleFunc get_locale_func;
-	SetClipboardFunc set_clipboard_func;
-	GetClipboardFunc get_clipboard_func;
-	GetModelFunc get_model_func;
-	GetScreenDPIFunc get_screen_dpi_func;
-	ShowVirtualKeyboardFunc show_virtual_keyboard_func;
-	HideVirtualKeyboardFunc hide_virtual_keyboard_func;
-	VirtualKeyboardHeightFunc get_virtual_keyboard_height_func;
-	SetScreenOrientationFunc set_screen_orientation_func;
-	GetUniqueIDFunc get_unique_id_func;
-	GetSystemDirFunc get_system_dir_func;
-	GetGLVersionCodeFunc get_gl_version_code_func;
-
-	VideoPlayFunc video_play_func;
-	VideoIsPlayingFunc video_is_playing_func;
-	VideoPauseFunc video_pause_func;
-	VideoStopFunc video_stop_func;
-	SetKeepScreenOnFunc set_keep_screen_on_func;
-	AlertFunc alert_func;
-	RequestPermissionFunc request_permission_func;
-
-	//PowerAndroid *power_manager;
+	GodotJavaWrapper *godot_java;
+	GodotIOJavaWrapper *godot_io_java;
+
+	//PowerAndroid *power_manager_func;
+
 	int video_driver_index;
 
 public:
@@ -159,6 +116,8 @@ public:
 	typedef int64_t ProcessID;
 
 	static OS *get_singleton();
+	GodotJavaWrapper *get_godot_java();
+	GodotIOJavaWrapper *get_godot_io_java();
 
 	virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
 	virtual bool request_permission(const String &p_name);
@@ -241,7 +200,7 @@ public:
 	void joy_connection_changed(int p_device, bool p_connected, String p_name);
 
 	virtual bool _check_internal_feature_support(const String &p_feature);
-	OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetUserDataDirFunc p_get_user_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, GetGLVersionCodeFunc p_get_gl_version_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, SetClipboardFunc p_set_clipboard, GetClipboardFunc p_get_clipboard, RequestPermissionFunc p_request_permission, bool p_use_apk_expansion);
+	OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_godot_io_java, bool p_use_apk_expansion);
 	~OS_Android();
 };