summaryrefslogtreecommitdiff
path: root/platform/android
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android')
-rw-r--r--platform/android/SCsub8
-rw-r--r--platform/android/android_keys_utils.cpp43
-rw-r--r--platform/android/android_keys_utils.h280
-rw-r--r--platform/android/api/api.cpp4
-rw-r--r--platform/android/api/java_class_wrapper.h30
-rw-r--r--platform/android/audio_driver_jandroid.cpp13
-rw-r--r--platform/android/audio_driver_jandroid.h2
-rw-r--r--platform/android/audio_driver_opensl.cpp18
-rw-r--r--platform/android/audio_driver_opensl.h2
-rw-r--r--platform/android/detect.py6
-rw-r--r--platform/android/dir_access_jandroid.cpp2
-rw-r--r--platform/android/dir_access_jandroid.h2
-rw-r--r--platform/android/export/export.cpp343
-rw-r--r--platform/android/java/app/AndroidManifest.xml26
-rw-r--r--platform/android/java/app/build.gradle69
-rw-r--r--platform/android/java/app/config.gradle72
-rw-r--r--platform/android/java/build.gradle101
-rw-r--r--platform/android/java/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--platform/android/java/lib/build.gradle5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java201
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java18
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java20
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotView.java3
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java6
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java24
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java256
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java199
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java1
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt99
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt136
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt230
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java15
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java15
-rw-r--r--platform/android/java/plugins/godotpayment/build.gradle31
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/AndroidManifest.xml11
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl (renamed from platform/android/java/lib/aidl/com/android/vending/billing/IInAppBillingService.aidl)0
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ConsumeTask.java (renamed from platform/android/java/lib/src/org/godotengine/godot/payments/ConsumeTask.java)2
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java (renamed from platform/android/java/lib/src/org/godotengine/godot/GodotPaymentV3.java)73
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/HandlePurchaseTask.java (renamed from platform/android/java/lib/src/org/godotengine/godot/payments/HandlePurchaseTask.java)2
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsCache.java (renamed from platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsCache.java)3
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsManager.java (renamed from platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsManager.java)84
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PurchaseTask.java (renamed from platform/android/java/lib/src/org/godotengine/godot/payments/PurchaseTask.java)2
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ReleaseAllConsumablesTask.java (renamed from platform/android/java/lib/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java)2
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ValidateTask.java (renamed from platform/android/java/lib/src/org/godotengine/godot/payments/ValidateTask.java)11
-rw-r--r--platform/android/java/settings.gradle1
-rw-r--r--platform/android/java_class_wrapper.cpp24
-rw-r--r--platform/android/java_godot_lib_jni.cpp1033
-rw-r--r--platform/android/java_godot_lib_jni.h58
-rw-r--r--platform/android/java_godot_wrapper.cpp17
-rw-r--r--platform/android/java_godot_wrapper.h3
-rw-r--r--platform/android/jni_utils.cpp434
-rw-r--r--platform/android/jni_utils.h242
-rw-r--r--platform/android/os_android.cpp68
-rw-r--r--platform/android/os_android.h3
-rw-r--r--platform/android/plugin/godot_plugin_jni.cpp115
-rw-r--r--platform/android/plugin/godot_plugin_jni.h43
-rw-r--r--platform/android/power_android.cpp255
-rw-r--r--platform/android/vulkan/vk_renderer_jni.cpp (renamed from platform/android/power_android.h)66
-rw-r--r--platform/android/vulkan/vk_renderer_jni.h46
60 files changed, 2754 insertions, 2128 deletions
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 3ff5b8278a..5ca5ce548c 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -1,8 +1,5 @@
#!/usr/bin/env python
-from detect import get_ndk_version
-from distutils.version import LooseVersion
-
Import('env')
android_files = [
@@ -18,7 +15,10 @@ android_files = [
'java_class_wrapper.cpp',
'java_godot_wrapper.cpp',
'java_godot_io_wrapper.cpp',
- #'power_android.cpp'
+ 'jni_utils.cpp',
+ 'android_keys_utils.cpp',
+ 'vulkan/vk_renderer_jni.cpp',
+ 'plugin/godot_plugin_jni.cpp'
]
env_android = env.Clone()
diff --git a/platform/android/android_keys_utils.cpp b/platform/android/android_keys_utils.cpp
new file mode 100644
index 0000000000..88874ba2c7
--- /dev/null
+++ b/platform/android/android_keys_utils.cpp
@@ -0,0 +1,43 @@
+/*************************************************************************/
+/* android_keys_utils.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "android_keys_utils.h"
+
+unsigned int android_get_keysym(unsigned int p_code) {
+ for (int i = 0; _ak_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
+
+ if (_ak_to_keycode[i].keycode == p_code) {
+
+ return _ak_to_keycode[i].keysym;
+ }
+ }
+
+ return KEY_UNKNOWN;
+}
diff --git a/platform/android/android_keys_utils.h b/platform/android/android_keys_utils.h
new file mode 100644
index 0000000000..f076688ac8
--- /dev/null
+++ b/platform/android/android_keys_utils.h
@@ -0,0 +1,280 @@
+/*************************************************************************/
+/* android_keys_utils.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 ANDROID_KEYS_UTILS_H
+#define ANDROID_KEYS_UTILS_H
+
+#include <core/os/keyboard.h>
+
+/*
+ * Android Key codes.
+ */
+enum {
+ AKEYCODE_UNKNOWN = 0,
+ AKEYCODE_SOFT_LEFT = 1,
+ AKEYCODE_SOFT_RIGHT = 2,
+ AKEYCODE_HOME = 3,
+ AKEYCODE_BACK = 4,
+ AKEYCODE_CALL = 5,
+ AKEYCODE_ENDCALL = 6,
+ AKEYCODE_0 = 7,
+ AKEYCODE_1 = 8,
+ AKEYCODE_2 = 9,
+ AKEYCODE_3 = 10,
+ AKEYCODE_4 = 11,
+ AKEYCODE_5 = 12,
+ AKEYCODE_6 = 13,
+ AKEYCODE_7 = 14,
+ AKEYCODE_8 = 15,
+ AKEYCODE_9 = 16,
+ AKEYCODE_STAR = 17,
+ AKEYCODE_POUND = 18,
+ AKEYCODE_DPAD_UP = 19,
+ AKEYCODE_DPAD_DOWN = 20,
+ AKEYCODE_DPAD_LEFT = 21,
+ AKEYCODE_DPAD_RIGHT = 22,
+ AKEYCODE_DPAD_CENTER = 23,
+ AKEYCODE_VOLUME_UP = 24,
+ AKEYCODE_VOLUME_DOWN = 25,
+ AKEYCODE_POWER = 26,
+ AKEYCODE_CAMERA = 27,
+ AKEYCODE_CLEAR = 28,
+ AKEYCODE_A = 29,
+ AKEYCODE_B = 30,
+ AKEYCODE_C = 31,
+ AKEYCODE_D = 32,
+ AKEYCODE_E = 33,
+ AKEYCODE_F = 34,
+ AKEYCODE_G = 35,
+ AKEYCODE_H = 36,
+ AKEYCODE_I = 37,
+ AKEYCODE_J = 38,
+ AKEYCODE_K = 39,
+ AKEYCODE_L = 40,
+ AKEYCODE_M = 41,
+ AKEYCODE_N = 42,
+ AKEYCODE_O = 43,
+ AKEYCODE_P = 44,
+ AKEYCODE_Q = 45,
+ AKEYCODE_R = 46,
+ AKEYCODE_S = 47,
+ AKEYCODE_T = 48,
+ AKEYCODE_U = 49,
+ AKEYCODE_V = 50,
+ AKEYCODE_W = 51,
+ AKEYCODE_X = 52,
+ AKEYCODE_Y = 53,
+ AKEYCODE_Z = 54,
+ AKEYCODE_COMMA = 55,
+ AKEYCODE_PERIOD = 56,
+ AKEYCODE_ALT_LEFT = 57,
+ AKEYCODE_ALT_RIGHT = 58,
+ AKEYCODE_SHIFT_LEFT = 59,
+ AKEYCODE_SHIFT_RIGHT = 60,
+ AKEYCODE_TAB = 61,
+ AKEYCODE_SPACE = 62,
+ AKEYCODE_SYM = 63,
+ AKEYCODE_EXPLORER = 64,
+ AKEYCODE_ENVELOPE = 65,
+ AKEYCODE_ENTER = 66,
+ AKEYCODE_DEL = 67,
+ AKEYCODE_GRAVE = 68,
+ AKEYCODE_MINUS = 69,
+ AKEYCODE_EQUALS = 70,
+ AKEYCODE_LEFT_BRACKET = 71,
+ AKEYCODE_RIGHT_BRACKET = 72,
+ AKEYCODE_BACKSLASH = 73,
+ AKEYCODE_SEMICOLON = 74,
+ AKEYCODE_APOSTROPHE = 75,
+ AKEYCODE_SLASH = 76,
+ AKEYCODE_AT = 77,
+ AKEYCODE_NUM = 78,
+ AKEYCODE_HEADSETHOOK = 79,
+ AKEYCODE_FOCUS = 80, // *Camera* focus
+ AKEYCODE_PLUS = 81,
+ AKEYCODE_MENU = 82,
+ AKEYCODE_NOTIFICATION = 83,
+ AKEYCODE_SEARCH = 84,
+ AKEYCODE_MEDIA_PLAY_PAUSE = 85,
+ AKEYCODE_MEDIA_STOP = 86,
+ AKEYCODE_MEDIA_NEXT = 87,
+ AKEYCODE_MEDIA_PREVIOUS = 88,
+ AKEYCODE_MEDIA_REWIND = 89,
+ AKEYCODE_MEDIA_FAST_FORWARD = 90,
+ AKEYCODE_MUTE = 91,
+ AKEYCODE_PAGE_UP = 92,
+ AKEYCODE_PAGE_DOWN = 93,
+ AKEYCODE_PICTSYMBOLS = 94,
+ AKEYCODE_SWITCH_CHARSET = 95,
+ AKEYCODE_BUTTON_A = 96,
+ AKEYCODE_BUTTON_B = 97,
+ AKEYCODE_BUTTON_C = 98,
+ AKEYCODE_BUTTON_X = 99,
+ AKEYCODE_BUTTON_Y = 100,
+ AKEYCODE_BUTTON_Z = 101,
+ AKEYCODE_BUTTON_L1 = 102,
+ AKEYCODE_BUTTON_R1 = 103,
+ AKEYCODE_BUTTON_L2 = 104,
+ AKEYCODE_BUTTON_R2 = 105,
+ AKEYCODE_BUTTON_THUMBL = 106,
+ AKEYCODE_BUTTON_THUMBR = 107,
+ AKEYCODE_BUTTON_START = 108,
+ AKEYCODE_BUTTON_SELECT = 109,
+ AKEYCODE_BUTTON_MODE = 110,
+
+ // NOTE: If you add a new keycode here you must also add it to several other files.
+ // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
+};
+
+struct _WinTranslatePair {
+
+ unsigned int keysym;
+ unsigned int keycode;
+};
+
+static _WinTranslatePair _ak_to_keycode[] = {
+ { KEY_TAB, AKEYCODE_TAB },
+ { KEY_ENTER, AKEYCODE_ENTER },
+ { KEY_SHIFT, AKEYCODE_SHIFT_LEFT },
+ { KEY_SHIFT, AKEYCODE_SHIFT_RIGHT },
+ { KEY_ALT, AKEYCODE_ALT_LEFT },
+ { KEY_ALT, AKEYCODE_ALT_RIGHT },
+ { KEY_MENU, AKEYCODE_MENU },
+ { KEY_PAUSE, AKEYCODE_MEDIA_PLAY_PAUSE },
+ { KEY_ESCAPE, AKEYCODE_BACK },
+ { KEY_SPACE, AKEYCODE_SPACE },
+ { KEY_PAGEUP, AKEYCODE_PAGE_UP },
+ { KEY_PAGEDOWN, AKEYCODE_PAGE_DOWN },
+ { KEY_HOME, AKEYCODE_HOME }, //(0x24)
+ { KEY_LEFT, AKEYCODE_DPAD_LEFT },
+ { KEY_UP, AKEYCODE_DPAD_UP },
+ { KEY_RIGHT, AKEYCODE_DPAD_RIGHT },
+ { KEY_DOWN, AKEYCODE_DPAD_DOWN },
+ { KEY_PERIODCENTERED, AKEYCODE_DPAD_CENTER },
+ { KEY_BACKSPACE, AKEYCODE_DEL },
+ { KEY_0, AKEYCODE_0 }, ////0 key
+ { KEY_1, AKEYCODE_1 }, ////1 key
+ { KEY_2, AKEYCODE_2 }, ////2 key
+ { KEY_3, AKEYCODE_3 }, ////3 key
+ { KEY_4, AKEYCODE_4 }, ////4 key
+ { KEY_5, AKEYCODE_5 }, ////5 key
+ { KEY_6, AKEYCODE_6 }, ////6 key
+ { KEY_7, AKEYCODE_7 }, ////7 key
+ { KEY_8, AKEYCODE_8 }, ////8 key
+ { KEY_9, AKEYCODE_9 }, ////9 key
+ { KEY_A, AKEYCODE_A }, ////A key
+ { KEY_B, AKEYCODE_B }, ////B key
+ { KEY_C, AKEYCODE_C }, ////C key
+ { KEY_D, AKEYCODE_D }, ////D key
+ { KEY_E, AKEYCODE_E }, ////E key
+ { KEY_F, AKEYCODE_F }, ////F key
+ { KEY_G, AKEYCODE_G }, ////G key
+ { KEY_H, AKEYCODE_H }, ////H key
+ { KEY_I, AKEYCODE_I }, ////I key
+ { KEY_J, AKEYCODE_J }, ////J key
+ { KEY_K, AKEYCODE_K }, ////K key
+ { KEY_L, AKEYCODE_L }, ////L key
+ { KEY_M, AKEYCODE_M }, ////M key
+ { KEY_N, AKEYCODE_N }, ////N key
+ { KEY_O, AKEYCODE_O }, ////O key
+ { KEY_P, AKEYCODE_P }, ////P key
+ { KEY_Q, AKEYCODE_Q }, ////Q key
+ { KEY_R, AKEYCODE_R }, ////R key
+ { KEY_S, AKEYCODE_S }, ////S key
+ { KEY_T, AKEYCODE_T }, ////T key
+ { KEY_U, AKEYCODE_U }, ////U key
+ { KEY_V, AKEYCODE_V }, ////V key
+ { KEY_W, AKEYCODE_W }, ////W key
+ { KEY_X, AKEYCODE_X }, ////X key
+ { KEY_Y, AKEYCODE_Y }, ////Y key
+ { KEY_Z, AKEYCODE_Z }, ////Z key
+ { KEY_HOMEPAGE, AKEYCODE_EXPLORER },
+ { KEY_LAUNCH0, AKEYCODE_BUTTON_A },
+ { KEY_LAUNCH1, AKEYCODE_BUTTON_B },
+ { KEY_LAUNCH2, AKEYCODE_BUTTON_C },
+ { KEY_LAUNCH3, AKEYCODE_BUTTON_X },
+ { KEY_LAUNCH4, AKEYCODE_BUTTON_Y },
+ { KEY_LAUNCH5, AKEYCODE_BUTTON_Z },
+ { KEY_LAUNCH6, AKEYCODE_BUTTON_L1 },
+ { KEY_LAUNCH7, AKEYCODE_BUTTON_R1 },
+ { KEY_LAUNCH8, AKEYCODE_BUTTON_L2 },
+ { KEY_LAUNCH9, AKEYCODE_BUTTON_R2 },
+ { KEY_LAUNCHA, AKEYCODE_BUTTON_THUMBL },
+ { KEY_LAUNCHB, AKEYCODE_BUTTON_THUMBR },
+ { KEY_LAUNCHC, AKEYCODE_BUTTON_START },
+ { KEY_LAUNCHD, AKEYCODE_BUTTON_SELECT },
+ { KEY_LAUNCHE, AKEYCODE_BUTTON_MODE },
+ { KEY_VOLUMEMUTE, AKEYCODE_MUTE },
+ { KEY_VOLUMEDOWN, AKEYCODE_VOLUME_DOWN },
+ { KEY_VOLUMEUP, AKEYCODE_VOLUME_UP },
+ { KEY_BACK, AKEYCODE_MEDIA_REWIND },
+ { KEY_FORWARD, AKEYCODE_MEDIA_FAST_FORWARD },
+ { KEY_MEDIANEXT, AKEYCODE_MEDIA_NEXT },
+ { KEY_MEDIAPREVIOUS, AKEYCODE_MEDIA_PREVIOUS },
+ { KEY_MEDIASTOP, AKEYCODE_MEDIA_STOP },
+ { KEY_PLUS, AKEYCODE_PLUS },
+ { KEY_EQUAL, AKEYCODE_EQUALS }, // the '+' key
+ { KEY_COMMA, AKEYCODE_COMMA }, // the ',' key
+ { KEY_MINUS, AKEYCODE_MINUS }, // the '-' key
+ { KEY_SLASH, AKEYCODE_SLASH }, // the '/?' key
+ { KEY_BACKSLASH, AKEYCODE_BACKSLASH },
+ { KEY_BRACKETLEFT, AKEYCODE_LEFT_BRACKET },
+ { KEY_BRACKETRIGHT, AKEYCODE_RIGHT_BRACKET },
+ { KEY_UNKNOWN, 0 }
+};
+/*
+TODO: map these android key:
+ AKEYCODE_SOFT_LEFT = 1,
+ AKEYCODE_SOFT_RIGHT = 2,
+ AKEYCODE_CALL = 5,
+ AKEYCODE_ENDCALL = 6,
+ AKEYCODE_STAR = 17,
+ AKEYCODE_POUND = 18,
+ AKEYCODE_POWER = 26,
+ AKEYCODE_CAMERA = 27,
+ AKEYCODE_CLEAR = 28,
+ AKEYCODE_SYM = 63,
+ AKEYCODE_ENVELOPE = 65,
+ AKEYCODE_GRAVE = 68,
+ AKEYCODE_SEMICOLON = 74,
+ AKEYCODE_APOSTROPHE = 75,
+ AKEYCODE_AT = 77,
+ AKEYCODE_NUM = 78,
+ AKEYCODE_HEADSETHOOK = 79,
+ AKEYCODE_FOCUS = 80, // *Camera* focus
+ AKEYCODE_NOTIFICATION = 83,
+ AKEYCODE_SEARCH = 84,
+ AKEYCODE_PICTSYMBOLS = 94,
+ AKEYCODE_SWITCH_CHARSET = 95,
+*/
+
+unsigned int android_get_keysym(unsigned int p_code);
+
+#endif // ANDROID_KEYS_UTILS_H
diff --git a/platform/android/api/api.cpp b/platform/android/api/api.cpp
index 2146c5409b..7efb545524 100644
--- a/platform/android/api/api.cpp
+++ b/platform/android/api/api.cpp
@@ -62,14 +62,14 @@ void JavaClassWrapper::_bind_methods() {
#if !defined(ANDROID_ENABLED)
-Variant JavaClass::call(const StringName &, const Variant **, int, Variant::CallError &) {
+Variant JavaClass::call(const StringName &, const Variant **, int, Callable::CallError &) {
return Variant();
}
JavaClass::JavaClass() {
}
-Variant JavaObject::call(const StringName &, const Variant **, int, Variant::CallError &) {
+Variant JavaObject::call(const StringName &, const Variant **, int, Callable::CallError &) {
return Variant();
}
diff --git a/platform/android/api/java_class_wrapper.h b/platform/android/api/java_class_wrapper.h
index 6c06d57ac1..d7322deb81 100644
--- a/platform/android/api/java_class_wrapper.h
+++ b/platform/android/api/java_class_wrapper.h
@@ -113,12 +113,12 @@ class JavaClass : public Reference {
break;
case ARG_TYPE_FLOAT | ARG_NUMBER_CLASS_BIT:
case ARG_TYPE_FLOAT:
- r_type = Variant::REAL;
+ r_type = Variant::FLOAT;
likelihood = 1.0;
break;
case ARG_TYPE_DOUBLE | ARG_NUMBER_CLASS_BIT:
case ARG_TYPE_DOUBLE:
- r_type = Variant::REAL;
+ r_type = Variant::FLOAT;
likelihood = 0.5;
break;
case ARG_TYPE_STRING: r_type = Variant::STRING; break;
@@ -126,49 +126,49 @@ class JavaClass : public Reference {
case ARG_ARRAY_BIT | ARG_TYPE_VOID: r_type = Variant::NIL; break;
case ARG_ARRAY_BIT | ARG_TYPE_BOOLEAN: r_type = Variant::ARRAY; break;
case ARG_ARRAY_BIT | ARG_TYPE_BYTE:
- r_type = Variant::POOL_BYTE_ARRAY;
+ r_type = Variant::PACKED_BYTE_ARRAY;
likelihood = 1.0;
break;
case ARG_ARRAY_BIT | ARG_TYPE_CHAR:
- r_type = Variant::POOL_BYTE_ARRAY;
+ r_type = Variant::PACKED_BYTE_ARRAY;
likelihood = 0.5;
break;
case ARG_ARRAY_BIT | ARG_TYPE_SHORT:
- r_type = Variant::POOL_INT_ARRAY;
+ r_type = Variant::PACKED_INT32_ARRAY;
likelihood = 0.3;
break;
case ARG_ARRAY_BIT | ARG_TYPE_INT:
- r_type = Variant::POOL_INT_ARRAY;
+ r_type = Variant::PACKED_INT32_ARRAY;
likelihood = 1.0;
break;
case ARG_ARRAY_BIT | ARG_TYPE_LONG:
- r_type = Variant::POOL_INT_ARRAY;
+ r_type = Variant::PACKED_INT32_ARRAY;
likelihood = 0.5;
break;
case ARG_ARRAY_BIT | ARG_TYPE_FLOAT:
- r_type = Variant::POOL_REAL_ARRAY;
+ r_type = Variant::PACKED_FLOAT32_ARRAY;
likelihood = 1.0;
break;
case ARG_ARRAY_BIT | ARG_TYPE_DOUBLE:
- r_type = Variant::POOL_REAL_ARRAY;
+ r_type = Variant::PACKED_FLOAT32_ARRAY;
likelihood = 0.5;
break;
- case ARG_ARRAY_BIT | ARG_TYPE_STRING: r_type = Variant::POOL_STRING_ARRAY; break;
+ case ARG_ARRAY_BIT | ARG_TYPE_STRING: r_type = Variant::PACKED_STRING_ARRAY; break;
case ARG_ARRAY_BIT | ARG_TYPE_CLASS: r_type = Variant::ARRAY; break;
}
}
_FORCE_INLINE_ static bool _convert_object_to_variant(JNIEnv *env, jobject obj, Variant &var, uint32_t p_sig);
- bool _call_method(JavaObject *p_instance, const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error, Variant &ret);
+ bool _call_method(JavaObject *p_instance, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error, Variant &ret);
friend class JavaClassWrapper;
- Map<StringName, List<MethodInfo> > methods;
+ Map<StringName, List<MethodInfo>> methods;
jclass _class;
#endif
public:
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
+ virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
JavaClass();
};
@@ -185,7 +185,7 @@ class JavaObject : public Reference {
#endif
public:
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
+ virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
#ifdef ANDROID_ENABLED
JavaObject(const Ref<JavaClass> &p_base, jobject *p_instance);
@@ -198,7 +198,7 @@ class JavaClassWrapper : public Object {
GDCLASS(JavaClassWrapper, Object);
#ifdef ANDROID_ENABLED
- Map<String, Ref<JavaClass> > class_cache;
+ Map<String, Ref<JavaClass>> class_cache;
friend class JavaClass;
jclass activityClass;
jmethodID findClass;
diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp
index 5a8e3b94da..e94dad9ac6 100644
--- a/platform/android/audio_driver_jandroid.cpp
+++ b/platform/android/audio_driver_jandroid.cpp
@@ -48,7 +48,7 @@ int AudioDriverAndroid::mix_rate = 44100;
bool AudioDriverAndroid::quit = false;
jobject AudioDriverAndroid::audioBuffer = NULL;
void *AudioDriverAndroid::audioBufferPinned = NULL;
-Mutex *AudioDriverAndroid::mutex = NULL;
+Mutex AudioDriverAndroid::mutex;
int32_t *AudioDriverAndroid::audioBuffer32 = NULL;
const char *AudioDriverAndroid::get_name() const {
@@ -58,7 +58,6 @@ const char *AudioDriverAndroid::get_name() const {
Error AudioDriverAndroid::init() {
- mutex = Mutex::create();
/*
// TODO: pass in/return a (Java) device ID, also whether we're opening for input or output
this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
@@ -133,7 +132,7 @@ void AudioDriverAndroid::thread_func(JNIEnv *env) {
int16_t *ptr = (int16_t *)audioBufferPinned;
int fc = audioBufferFrames;
- if (!s_ad->active || mutex->try_lock() != OK) {
+ if (!s_ad->active || mutex.try_lock() != OK) {
for (int i = 0; i < fc; i++) {
ptr[i] = 0;
@@ -143,7 +142,7 @@ void AudioDriverAndroid::thread_func(JNIEnv *env) {
s_ad->audio_server_process(fc / 2, audioBuffer32);
- mutex->unlock();
+ mutex.unlock();
for (int i = 0; i < fc; i++) {
@@ -167,14 +166,12 @@ AudioDriver::SpeakerMode AudioDriverAndroid::get_speaker_mode() const {
void AudioDriverAndroid::lock() {
- if (mutex)
- mutex->lock();
+ mutex.lock();
}
void AudioDriverAndroid::unlock() {
- if (mutex)
- mutex->unlock();
+ mutex.unlock();
}
void AudioDriverAndroid::finish() {
diff --git a/platform/android/audio_driver_jandroid.h b/platform/android/audio_driver_jandroid.h
index d3d1641c20..b1cc3f9aa0 100644
--- a/platform/android/audio_driver_jandroid.h
+++ b/platform/android/audio_driver_jandroid.h
@@ -37,7 +37,7 @@
class AudioDriverAndroid : public AudioDriver {
- static Mutex *mutex;
+ static Mutex mutex;
static AudioDriverAndroid *s_ad;
static jobject io;
static jmethodID _init_audio;
diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp
index 6e9864c803..222120f81f 100644
--- a/platform/android/audio_driver_opensl.cpp
+++ b/platform/android/audio_driver_opensl.cpp
@@ -44,8 +44,8 @@ void AudioDriverOpenSL::_buffer_callback(
if (pause) {
mix = false;
- } else if (mutex) {
- mix = mutex->try_lock() == OK;
+ } else {
+ mix = mutex.try_lock() == OK;
}
if (mix) {
@@ -58,8 +58,8 @@ void AudioDriverOpenSL::_buffer_callback(
}
}
- if (mutex && mix)
- mutex->unlock();
+ if (mix)
+ mutex.unlock();
const int32_t *src_buff = mixdown_buffer;
@@ -107,7 +107,6 @@ Error AudioDriverOpenSL::init() {
void AudioDriverOpenSL::start() {
- mutex = Mutex::create();
active = false;
SLresult res;
@@ -329,14 +328,14 @@ AudioDriver::SpeakerMode AudioDriverOpenSL::get_speaker_mode() const {
void AudioDriverOpenSL::lock() {
- if (active && mutex)
- mutex->lock();
+ if (active)
+ mutex.lock();
}
void AudioDriverOpenSL::unlock() {
- if (active && mutex)
- mutex->unlock();
+ if (active)
+ mutex.unlock();
}
void AudioDriverOpenSL::finish() {
@@ -359,7 +358,6 @@ void AudioDriverOpenSL::set_pause(bool p_pause) {
AudioDriverOpenSL::AudioDriverOpenSL() {
s_ad = this;
- mutex = Mutex::create(); //NULL;
pause = false;
active = false;
}
diff --git a/platform/android/audio_driver_opensl.h b/platform/android/audio_driver_opensl.h
index 57d9b30af6..569e2aa54b 100644
--- a/platform/android/audio_driver_opensl.h
+++ b/platform/android/audio_driver_opensl.h
@@ -40,7 +40,7 @@
class AudioDriverOpenSL : public AudioDriver {
bool active;
- Mutex *mutex;
+ Mutex mutex;
enum {
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 8b62360888..ff3ca0706c 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -164,7 +164,6 @@ def configure(env):
env.Tool('gcc')
env.use_windows_spawn_fix()
- mt_link = True
if (sys.platform.startswith("linux")):
host_subpath = "linux-x86_64"
elif (sys.platform.startswith("darwin")):
@@ -173,12 +172,8 @@ def configure(env):
if (platform.machine().endswith('64')):
host_subpath = "windows-x86_64"
else:
- mt_link = False
host_subpath = "windows"
- if env["android_arch"] == "arm64v8":
- mt_link = False
-
compiler_path = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/" + host_subpath + "/bin"
gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath
tools_path = gcc_toolchain_path + "/" + abi_subpath + "/bin"
@@ -205,7 +200,6 @@ def configure(env):
env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/include"])
env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++abi/include"])
- env.Append(CXXFLAGS=["-std=gnu++14"])
# Disable exceptions and rtti on non-tools (template) builds
if env['tools']:
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index f52b511522..ebcac884db 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -144,7 +144,7 @@ Error DirAccessJAndroid::change_dir(String p_dir) {
return OK;
}
-String DirAccessJAndroid::get_current_dir() {
+String DirAccessJAndroid::get_current_dir(bool p_include_drive) {
return "res://" + current_dir;
}
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
index caeb4b58b9..8dab3e50ce 100644
--- a/platform/android/dir_access_jandroid.h
+++ b/platform/android/dir_access_jandroid.h
@@ -65,7 +65,7 @@ public:
virtual String get_drive(int p_drive);
virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
- virtual String get_current_dir(); ///< return current dir location
+ virtual String get_current_dir(bool p_include_drive = true); ///< return current dir location
virtual bool file_exists(String p_file);
virtual bool dir_exists(String p_dir);
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index b9968c08aa..e7d4bc6c51 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -257,7 +257,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
Vector<Device> devices;
volatile bool devices_changed;
- Mutex *device_lock;
+ Mutex device_lock;
Thread *device_thread;
volatile bool quit_request;
@@ -288,7 +288,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
ldevices.push_back(d);
}
- ea->device_lock->lock();
+ MutexLock lock(ea->device_lock);
bool different = false;
@@ -337,7 +337,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
Vector<String> props = dp.split("\n");
String vendor;
String device;
- d.description + "Device ID: " + d.id + "\n";
+ d.description = "Device ID: " + d.id + "\n";
d.api_level = 0;
for (int j = 0; j < props.size(); j++) {
@@ -381,11 +381,9 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
ea->devices = ndevices;
ea->devices_changed = true;
}
-
- ea->device_lock->unlock();
}
- uint64_t sleep = OS::get_singleton()->get_power_state() == OS::POWERSTATE_ON_BATTERY ? 1000 : 100;
+ uint64_t sleep = 200;
uint64_t wait = 3000000;
uint64_t time = OS::get_singleton()->get_ticks_usec();
while (OS::get_singleton()->get_ticks_usec() - time < wait) {
@@ -610,7 +608,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
static Error save_apk_so(void *p_userdata, const SharedObject &p_so) {
if (!p_so.path.get_file().begins_with("lib")) {
String err = "Android .so file names must start with \"lib\", but got: " + p_so.path;
- ERR_PRINTS(err);
+ ERR_PRINT(err);
return FAILED;
}
APKExportData *ed = (APKExportData *)p_userdata;
@@ -631,7 +629,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
if (!exported) {
String abis_string = String(" ").join(abis);
String err = "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + abis_string;
- ERR_PRINTS(err);
+ ERR_PRINT(err);
return FAILED;
}
return OK;
@@ -642,9 +640,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
String dst_path = p_path.replace_first("res://", "assets/");
store_in_apk(ed, dst_path, p_data, _should_compress_asset(p_path, p_data) ? Z_DEFLATED : 0);
- if (ed->ep->step("File: " + p_path, 3 + p_file * 100 / p_total)) {
- return ERR_SKIP;
- }
return OK;
}
@@ -686,8 +681,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
int orientation = p_preset->get("screen/orientation");
- bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name") == "GLES3" &&
- !ProjectSettings::get_singleton()->get("rendering/quality/driver/fallback_to_gles2");
bool screen_support_small = p_preset->get("screen/support_small");
bool screen_support_normal = p_preset->get("screen/support_normal");
bool screen_support_large = p_preset->get("screen/support_large");
@@ -695,6 +688,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
int xr_mode_index = p_preset->get("xr_features/xr_mode");
+ String plugins = p_preset->get("custom_template/plugins");
+
Vector<String> perms;
const char **aperms = android_perms;
@@ -706,7 +701,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
aperms++;
}
- PoolStringArray user_perms = p_preset->get("permissions/custom_permissions");
+ PackedStringArray user_perms = p_preset->get("permissions/custom_permissions");
for (int i = 0; i < user_perms.size(); i++) {
String user_perm = user_perms[i].strip_edges();
@@ -842,11 +837,6 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
}
- if (tname == "uses-feature" && attrname == "glEsVersion") {
-
- encode_uint32(min_gles3 ? 0x00030000 : 0x00020000, &p_manifest.write[iofs + 16]);
- }
-
// FIXME: `attr_value != 0xFFFFFFFF` below added as a stopgap measure for GH-32553,
// but the issue should be debugged further and properly addressed.
if (tname == "meta-data" && attrname == "name" && value == "xr_mode_metadata_name") {
@@ -863,6 +853,11 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
}
}
+ if (tname == "meta-data" && attrname == "value" && value == "custom_template_plugins_value") {
+ // Update the meta-data 'android:value' attribute with the list of enabled plugins.
+ string_table.write[attr_value] = plugins;
+ }
+
iofs += 20;
}
@@ -1320,11 +1315,11 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
working_image->resize(p_icon.dimensions, p_icon.dimensions, Image::Interpolation::INTERPOLATE_LANCZOS);
}
- PoolVector<uint8_t> png_buffer;
+ Vector<uint8_t> png_buffer;
Error err = PNGDriverCommon::image_to_png(working_image, png_buffer);
if (err == OK) {
p_data.resize(png_buffer.size());
- memcpy(p_data.ptrw(), png_buffer.read().ptr(), p_data.size());
+ memcpy(p_data.ptrw(), png_buffer.ptr(), p_data.size());
} else {
String err_str = String("Failed to convert resized icon (") + p_processing_file_name + ") to png.";
WARN_PRINT(err_str.utf8().get_data());
@@ -1353,11 +1348,10 @@ public:
String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
if (driver == "GLES2") {
r_features->push_back("etc");
- } else if (driver == "GLES3") {
+ }
+ // FIXME: Review what texture formats are used for Vulkan.
+ if (driver == "Vulkan") {
r_features->push_back("etc2");
- if (ProjectSettings::get_singleton()->get("rendering/quality/driver/fallback_to_gles2")) {
- r_features->push_back("etc");
- }
}
Vector<String> abis = get_enabled_abis(p_preset);
@@ -1376,6 +1370,7 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_template/use_custom_build"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/plugins", PROPERTY_HINT_PLACEHOLDER_TEXT, "Plugin1,Plugin2,..."), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
@@ -1409,7 +1404,7 @@ public:
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + abi), is_default));
}
- r_options->push_back(ExportOption(PropertyInfo(Variant::POOL_STRING_ARRAY, "permissions/custom_permissions"), PoolStringArray()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "permissions/custom_permissions"), PackedStringArray()));
const char **perms = android_perms;
while (*perms) {
@@ -1427,7 +1422,7 @@ public:
return "Android";
}
- virtual Ref<Texture> get_logo() const {
+ virtual Ref<Texture2D> get_logo() const {
return logo;
}
@@ -1443,11 +1438,8 @@ public:
virtual int get_options_count() const {
- device_lock->lock();
- int dc = devices.size();
- device_lock->unlock();
-
- return dc;
+ MutexLock lock(device_lock);
+ return devices.size();
}
virtual String get_options_tooltip() const {
@@ -1458,16 +1450,14 @@ public:
virtual String get_option_label(int p_index) const {
ERR_FAIL_INDEX_V(p_index, devices.size(), "");
- device_lock->lock();
- String s = devices[p_index].name;
- device_lock->unlock();
- return s;
+ MutexLock lock(device_lock);
+ return devices[p_index].name;
}
virtual String get_option_tooltip(int p_index) const {
ERR_FAIL_INDEX_V(p_index, devices.size(), "");
- device_lock->lock();
+ MutexLock lock(device_lock);
String s = devices[p_index].description;
if (devices.size() == 1) {
// Tooltip will be:
@@ -1475,7 +1465,6 @@ public:
// Description
s = devices[p_index].name + "\n\n" + s;
}
- device_lock->unlock();
return s;
}
@@ -1490,15 +1479,14 @@ public:
return ERR_UNCONFIGURED;
}
- device_lock->lock();
+ MutexLock lock(device_lock);
EditorProgress ep("run", "Running on " + devices[p_device].name, 3);
String adb = EditorSettings::get_singleton()->get("export/android/adb");
// Export_temp APK.
- if (ep.step("Exporting APK", 0)) {
- device_lock->unlock();
+ if (ep.step("Exporting APK...", 0)) {
return ERR_SKIP;
}
@@ -1513,7 +1501,6 @@ public:
#define CLEANUP_AND_RETURN(m_err) \
{ \
DirAccess::remove_file_or_error(tmp_export_path); \
- device_lock->unlock(); \
return m_err; \
}
@@ -1547,7 +1534,7 @@ public:
}
print_line("Installing to device (please wait...): " + devices[p_device].name);
- if (ep.step("Installing to device (please wait...)", 2)) {
+ if (ep.step("Installing to device, please wait...", 2)) {
CLEANUP_AND_RETURN(ERR_SKIP);
}
@@ -1614,7 +1601,7 @@ public:
}
}
- if (ep.step("Running on Device...", 3)) {
+ if (ep.step("Running on device...", 3)) {
CLEANUP_AND_RETURN(ERR_SKIP);
}
args.clear();
@@ -1642,7 +1629,7 @@ public:
#undef CLEANUP_AND_RETURN
}
- virtual Ref<Texture> get_run_icon() const {
+ virtual Ref<Texture2D> get_run_icon() const {
return run_icon;
}
@@ -1764,260 +1751,6 @@ public:
return list;
}
- void _update_custom_build_project() {
-
- DirAccessRef da = DirAccess::open("res://android");
-
- ERR_FAIL_COND_MSG(!da, "Cannot open directory 'res://android'.");
- Map<String, List<String> > directory_paths;
- Map<String, List<String> > manifest_sections;
- Map<String, List<String> > gradle_sections;
- da->list_dir_begin();
- String d = da->get_next();
- while (d != String()) {
-
- if (!d.begins_with(".") && d != "build" && da->current_is_dir()) { //a dir and not the build dir
- //add directories found
- DirAccessRef ds = DirAccess::open(String("res://android").plus_file(d));
- if (ds) {
- ds->list_dir_begin();
- String sd = ds->get_next();
- while (sd != String()) {
-
- if (!sd.begins_with(".") && ds->current_is_dir()) {
- String key = sd.to_upper();
- if (!directory_paths.has(key)) {
- directory_paths[key] = List<String>();
- }
- String path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android").plus_file(d).plus_file(sd);
- directory_paths[key].push_back(path);
- print_line("Add: " + sd + ":" + path);
- }
-
- sd = ds->get_next();
- }
- ds->list_dir_end();
- }
- //parse manifest
- {
- FileAccessRef f = FileAccess::open(String("res://android").plus_file(d).plus_file("AndroidManifest.conf"), FileAccess::READ);
- if (f) {
-
- String section;
- while (!f->eof_reached()) {
- String l = f->get_line();
- String k = l.strip_edges();
- if (k.begins_with("[")) {
- section = k.substr(1, k.length() - 2).strip_edges().to_upper();
- print_line("Section: " + section);
- } else if (k != String()) {
- if (!manifest_sections.has(section)) {
- manifest_sections[section] = List<String>();
- }
- manifest_sections[section].push_back(l);
- }
- }
-
- f->close();
- }
- }
- //parse gradle
- {
- FileAccessRef f = FileAccess::open(String("res://android").plus_file(d).plus_file("gradle.conf"), FileAccess::READ);
- if (f) {
-
- String section;
- while (!f->eof_reached()) {
- String l = f->get_line().strip_edges();
- String k = l.strip_edges();
- if (k.begins_with("[")) {
- section = k.substr(1, k.length() - 2).strip_edges().to_upper();
- print_line("Section: " + section);
- } else if (k != String()) {
- if (!gradle_sections.has(section)) {
- gradle_sections[section] = List<String>();
- }
- gradle_sections[section].push_back(l);
- }
- }
- }
- }
- }
- d = da->get_next();
- }
- da->list_dir_end();
-
- { //fix gradle build
-
- String new_file;
- {
- FileAccessRef f = FileAccess::open("res://android/build/build.gradle", FileAccess::READ);
- if (f) {
-
- while (!f->eof_reached()) {
- String l = f->get_line();
-
- if (l.begins_with("//CHUNK_")) {
- String text = l.replace_first("//CHUNK_", "");
- int begin_pos = text.find("_BEGIN");
- if (begin_pos != -1) {
- text = text.substr(0, begin_pos);
- text = text.to_upper(); //just in case
-
- String end_marker = "//CHUNK_" + text + "_END";
- size_t pos = f->get_position();
- bool found = false;
- while (!f->eof_reached()) {
- l = f->get_line();
- if (l.begins_with(end_marker)) {
- found = true;
- break;
- }
- }
-
- new_file += "//CHUNK_" + text + "_BEGIN\n";
-
- if (!found) {
- ERR_PRINTS("No end marker found in build.gradle for chunk: " + text);
- f->seek(pos);
- } else {
-
- //add chunk lines
- if (gradle_sections.has(text)) {
- for (List<String>::Element *E = gradle_sections[text].front(); E; E = E->next()) {
- new_file += E->get() + "\n";
- }
- }
- new_file += end_marker + "\n";
- }
- } else {
- new_file += l + "\n"; //pass line by
- }
- } else if (l.begins_with("//DIR_")) {
- String text = l.replace_first("//DIR_", "");
- int begin_pos = text.find("_BEGIN");
- if (begin_pos != -1) {
- text = text.substr(0, begin_pos);
- text = text.to_upper(); //just in case
-
- String end_marker = "//DIR_" + text + "_END";
- size_t pos = f->get_position();
- bool found = false;
- while (!f->eof_reached()) {
- l = f->get_line();
- if (l.begins_with(end_marker)) {
- found = true;
- break;
- }
- }
-
- new_file += "//DIR_" + text + "_BEGIN\n";
-
- if (!found) {
- ERR_PRINTS("No end marker found in build.gradle for dir: " + text);
- f->seek(pos);
- } else {
- //add chunk lines
- if (directory_paths.has(text)) {
- for (List<String>::Element *E = directory_paths[text].front(); E; E = E->next()) {
- new_file += ",'" + E->get().replace("'", "\'") + "'";
- new_file += "\n";
- }
- }
- new_file += end_marker + "\n";
- }
- } else {
- new_file += l + "\n"; //pass line by
- }
-
- } else {
- new_file += l + "\n";
- }
- }
- }
- }
-
- FileAccessRef f = FileAccess::open("res://android/build/build.gradle", FileAccess::WRITE);
- f->store_string(new_file);
- f->close();
- }
-
- { //fix manifest
-
- String new_file;
- {
- FileAccessRef f = FileAccess::open("res://android/build/AndroidManifest.xml", FileAccess::READ);
- if (f) {
-
- while (!f->eof_reached()) {
- String l = f->get_line();
-
- if (l.begins_with("<!--CHUNK_")) {
- String text = l.replace_first("<!--CHUNK_", "");
- int begin_pos = text.find("_BEGIN-->");
- if (begin_pos != -1) {
- text = text.substr(0, begin_pos);
- text = text.to_upper(); //just in case
-
- String end_marker = "<!--CHUNK_" + text + "_END-->";
- size_t pos = f->get_position();
- bool found = false;
- while (!f->eof_reached()) {
- l = f->get_line();
- if (l.begins_with(end_marker)) {
- found = true;
- break;
- }
- }
-
- new_file += "<!--CHUNK_" + text + "_BEGIN-->\n";
-
- if (!found) {
- ERR_PRINTS("No end marker found in AndroidManifest.xml for chunk: " + text);
- f->seek(pos);
- } else {
- //add chunk lines
- if (manifest_sections.has(text)) {
- for (List<String>::Element *E = manifest_sections[text].front(); E; E = E->next()) {
- new_file += E->get() + "\n";
- }
- }
- new_file += end_marker + "\n";
- }
- } else {
- new_file += l + "\n"; //pass line by
- }
-
- } else if (l.strip_edges().begins_with("<application")) {
- String last_tag = "android:icon=\"@mipmap/icon\"";
- int last_tag_pos = l.find(last_tag);
- if (last_tag_pos == -1) {
- ERR_PRINTS("Not adding application attributes as the expected tag was not found in '<application': " + last_tag);
- new_file += l + "\n";
- } else {
- String base = l.substr(0, last_tag_pos + last_tag.length());
- if (manifest_sections.has("application_attribs")) {
- for (List<String>::Element *E = manifest_sections["application_attribs"].front(); E; E = E->next()) {
- String to_add = E->get().strip_edges();
- base += " " + to_add + " ";
- }
- }
- base += ">\n";
- new_file += base;
- }
- } else {
- new_file += l + "\n";
- }
- }
- }
- }
-
- FileAccessRef f = FileAccess::open("res://android/build/AndroidManifest.xml", FileAccess::WRITE);
- f->store_string(new_file);
- f->close();
- }
- }
-
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
@@ -2046,8 +1779,6 @@ public:
ERR_FAIL_COND_V_MSG(sdk_path == "", ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/custom_build_sdk_path'.");
- _update_custom_build_project();
-
OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required
String build_command;
@@ -2058,14 +1789,18 @@ public:
#endif
String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build");
+ String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/plugins");
build_command = build_path.plus_file(build_command);
String package_name = get_package_name(p_preset->get("package/unique_name"));
+ String plugins = p_preset->get("custom_template/plugins");
List<String> cmdline;
cmdline.push_back("build");
cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name.
+ cmdline.push_back("-Pcustom_template_plugins_dir=" + plugins_dir); // argument to specify the plugins directory.
+ cmdline.push_back("-Pcustom_template_plugins=" + plugins); // argument to specify the list of plugins to enable.
cmdline.push_back("-p"); // argument to specify the start directory.
cmdline.push_back(build_path); // start directory.
/*{ used for debug
@@ -2119,7 +1854,7 @@ public:
FileAccess *src_f = NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
- if (ep.step("Creating APK", 0)) {
+ if (ep.step("Creating APK...", 0)) {
return ERR_SKIP;
}
@@ -2281,7 +2016,7 @@ public:
ret = unzGoToNextFile(pkg);
}
- if (ep.step("Adding Files...", 1)) {
+ if (ep.step("Adding files...", 1)) {
CLEANUP_AND_RETURN(ERR_SKIP);
}
Error err = OK;
@@ -2581,7 +2316,6 @@ public:
run_icon.instance();
run_icon->create_from_image(img);
- device_lock = Mutex::create();
devices_changed = true;
quit_request = false;
device_thread = Thread::create(_device_poll_thread, this);
@@ -2590,7 +2324,6 @@ public:
~EditorExportPlatformAndroid() {
quit_request = true;
Thread::wait_to_finish(device_thread);
- memdelete(device_lock);
memdelete(device_thread);
}
};
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index 7e9ce70d80..cc480d1c84 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -6,28 +6,21 @@
android:versionName="1.0"
android:installLocation="auto" >
- <!-- Adding custom text to the manifest is fine, but do it outside the custom USER and APPLICATION BEGIN/END comments, -->
- <!-- as that gets rewritten. -->
-
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:xlargeScreens="true" />
- <!-- glEsVersion is modified by the exporter, changing this value here has no effect. -->
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
-<!-- Custom user permissions XML added by add-ons. It's recommended to add them from the export preset, though. -->
-<!--CHUNK_USER_PERMISSIONS_BEGIN-->
-<!--CHUNK_USER_PERMISSIONS_END-->
-
- <!-- Any tag in this line after android:icon will be erased when doing custom builds. -->
- <!-- If you want to add tags manually, do before it. -->
- <!-- WARNING: This should stay on a single line until the parsing code is improved. See GH-32414. -->
- <application android:label="@string/godot_project_name_string" android:allowBackup="false" tools:ignore="GoogleAppIndexingWarning" android:icon="@mipmap/icon" >
+ <application
+ android:label="@string/godot_project_name_string"
+ android:allowBackup="false"
+ tools:ignore="GoogleAppIndexingWarning"
+ android:icon="@mipmap/icon" >
<!-- The following metadata values are replaced when Godot exports, modifying them here has no effect. -->
<!-- Do these changes in the export preset. Adding new ones is fine. -->
@@ -37,6 +30,11 @@
android:name="xr_mode_metadata_name"
android:value="xr_mode_metadata_value" />
+ <!-- Metadata populated at export time and used by Godot to figure out which plugins must be enabled. -->
+ <meta-data
+ android:name="custom_template_plugins"
+ android:value="custom_template_plugins_value"/>
+
<activity
android:name=".GodotApp"
android:label="@string/godot_project_name_string"
@@ -53,10 +51,6 @@
</intent-filter>
</activity>
-<!-- Custom application XML added by add-ons. -->
-<!--CHUNK_APPLICATION_BEGIN-->
-<!--CHUNK_APPLICATION_END-->
-
</application>
</manifest>
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index 2e4f2ffab0..1a3bb77670 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -1,7 +1,4 @@
// Gradle build config for Godot Engine's Android port.
-//
-// Do not remove/modify comments ending with BEGIN/END, they are used to inject
-// addon-specific configuration.
apply from: 'config.gradle'
buildscript {
@@ -10,13 +7,10 @@ buildscript {
repositories {
google()
jcenter()
-//CHUNK_BUILDSCRIPT_REPOSITORIES_BEGIN
-//CHUNK_BUILDSCRIPT_REPOSITORIES_END
}
dependencies {
classpath libraries.androidGradlePlugin
-//CHUNK_BUILDSCRIPT_DEPENDENCIES_BEGIN
-//CHUNK_BUILDSCRIPT_DEPENDENCIES_END
+ classpath libraries.kotlinGradlePlugin
}
}
@@ -27,24 +21,35 @@ allprojects {
mavenCentral()
google()
jcenter()
-//CHUNK_ALLPROJECTS_REPOSITORIES_BEGIN
-//CHUNK_ALLPROJECTS_REPOSITORIES_END
}
}
dependencies {
implementation libraries.supportCoreUtils
+ implementation libraries.kotlinStdLib
+ implementation libraries.v4Support
if (rootProject.findProject(":lib")) {
implementation project(":lib")
+ } else if (rootProject.findProject(":godot:lib")) {
+ implementation project(":godot:lib")
} else {
// Custom build mode. In this scenario this project is the only one around and the Godot
// library is available through the pre-generated godot-lib.*.aar android archive files.
debugImplementation fileTree(dir: 'libs/debug', include: ['*.jar', '*.aar'])
releaseImplementation fileTree(dir: 'libs/release', include: ['*.jar', '*.aar'])
}
-//CHUNK_DEPENDENCIES_BEGIN
-//CHUNK_DEPENDENCIES_END
+
+ // Godot prebuilt plugins
+ implementation fileTree(dir: 'libs/plugins', include: ["GodotPayment*.aar"])
+
+ // Godot user plugins dependencies
+ String pluginsDir = getGodotPluginsDirectory()
+ String[] pluginsBinaries = getGodotPluginsBinaries()
+ if (pluginsDir != null && !pluginsDir.isEmpty() &&
+ pluginsBinaries != null && pluginsBinaries.size() > 0) {
+ implementation fileTree(dir: pluginsDir, include: pluginsBinaries)
+ }
}
android {
@@ -56,8 +61,6 @@ android {
applicationId getExportPackageName()
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
-//CHUNK_ANDROID_DEFAULTCONFIG_BEGIN
-//CHUNK_ANDROID_DEFAULTCONFIG_END
}
lintOptions {
@@ -68,6 +71,7 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
+ doNotStrip '**/*.so'
}
// Both signing and zip-aligning will be done at export time
@@ -79,37 +83,13 @@ android {
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
- java.srcDirs = [
- 'src'
-//DIR_SRC_BEGIN
-//DIR_SRC_END
- ]
- res.srcDirs = [
- 'res'
-//DIR_RES_BEGIN
-//DIR_RES_END
- ]
- aidl.srcDirs = [
- 'aidl'
-//DIR_AIDL_BEGIN
-//DIR_AIDL_END
- ]
- assets.srcDirs = [
- 'assets'
-//DIR_ASSETS_BEGIN
-//DIR_ASSETS_END
- ]
+ java.srcDirs = ['src']
+ res.srcDirs = ['res']
+ aidl.srcDirs = ['aidl']
+ assets.srcDirs = ['assets']
}
- debug.jniLibs.srcDirs = [
- 'libs/debug'
-//DIR_JNI_DEBUG_BEGIN
-//DIR_JNI_DEBUG_END
- ]
- release.jniLibs.srcDirs = [
- 'libs/release'
-//DIR_JNI_RELEASE_BEGIN
-//DIR_JNI_RELEASE_END
- ]
+ debug.jniLibs.srcDirs = ['libs/debug']
+ release.jniLibs.srcDirs = ['libs/release']
}
applicationVariants.all { variant ->
@@ -118,6 +98,3 @@ android {
}
}
}
-
-//CHUNK_GLOBAL_BEGIN
-//CHUNK_GLOBAL_END
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index 5550d3099d..eaaefcbccb 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -1,24 +1,66 @@
ext.versions = [
- androidGradlePlugin : '3.4.2',
- compileSdk : 28,
- minSdk : 18,
- targetSdk : 28,
- buildTools : '28.0.3',
- supportCoreUtils : '28.0.0'
+ androidGradlePlugin: '3.6.0',
+ compileSdk : 29,
+ minSdk : 18,
+ targetSdk : 29,
+ buildTools : '29.0.1',
+ supportCoreUtils : '28.0.0',
+ kotlinVersion : '1.3.61',
+ v4Support : '28.0.0'
]
ext.libraries = [
- androidGradlePlugin : "com.android.tools.build:gradle:$versions.androidGradlePlugin",
- supportCoreUtils : "com.android.support:support-core-utils:$versions.supportCoreUtils"
+ androidGradlePlugin: "com.android.tools.build:gradle:$versions.androidGradlePlugin",
+ supportCoreUtils : "com.android.support:support-core-utils:$versions.supportCoreUtils",
+ kotlinGradlePlugin : "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlinVersion",
+ kotlinStdLib : "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlinVersion",
+ v4Support : "com.android.support:support-v4:$versions.v4Support"
]
ext.getExportPackageName = { ->
- // Retrieve the app id from the project property set by the Godot build command.
- String appId = project.hasProperty("export_package_name") ? project.property("export_package_name") : ""
- // Check if the app id is valid, otherwise use the default.
- if (appId == null || appId.isEmpty()) {
- appId = "com.godot.game"
- }
- return appId
+ // Retrieve the app id from the project property set by the Godot build command.
+ String appId = project.hasProperty("export_package_name") ? project.property("export_package_name") : ""
+ // Check if the app id is valid, otherwise use the default.
+ if (appId == null || appId.isEmpty()) {
+ appId = "com.godot.game"
+ }
+ return appId
+}
+
+/**
+ * Parse the project properties for the 'custom_template_plugins' property and return
+ * their binaries for inclusion in the build dependencies.
+ *
+ * The listed plugins must have their binaries in the project plugins directory.
+ */
+ext.getGodotPluginsBinaries = { ->
+ String[] binDeps = []
+
+ // Retrieve the list of enabled plugins.
+ if (project.hasProperty("custom_template_plugins")) {
+ String pluginsList = project.property("custom_template_plugins")
+ if (pluginsList != null && !pluginsList.trim().isEmpty()) {
+ for (String plugin : pluginsList.split(",")) {
+ binDeps += plugin.trim() + "*.aar"
+ }
+ }
+ }
+
+ return binDeps
+}
+
+/**
+ * Parse the project properties for the 'custom_template_plugins_dir' property and return
+ * its value.
+ *
+ * The returned value is the directory containing user plugins.
+ */
+ext.getGodotPluginsDirectory = { ->
+ // The plugins directory is provided by the 'custom_template_plugins_dir' property.
+ String pluginsDir = project.hasProperty("custom_template_plugins_dir")
+ ? project.property("custom_template_plugins_dir")
+ : ""
+
+ return pluginsDir
}
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index 2052017888..865b61956c 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -9,6 +9,7 @@ buildscript {
}
dependencies {
classpath libraries.androidGradlePlugin
+ classpath libraries.kotlinGradlePlugin
}
}
@@ -24,7 +25,7 @@ ext {
sconsExt = org.gradle.internal.os.OperatingSystem.current().isWindows() ? ".bat" : ""
supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"]
- supportedTargets = ['release':"release", 'debug':"release_debug"]
+ supportedTargets = ["release", "debug"]
// Used by gradle to specify which architecture to build for by default when running `./gradlew build`.
// This command is usually used by Android Studio.
@@ -64,10 +65,10 @@ task copyReleaseBinaryToBin(type: Copy) {
}
/**
- * Copy the Godot android library archive debug file into the app debug libs directory.
+ * Copy the Godot android library archive debug file into the app module debug libs directory.
* Depends on the library build task to ensure the AAR file is generated prior to copying.
*/
-task copyDebugAAR(type: Copy) {
+task copyDebugAARToAppModule(type: Copy) {
dependsOn ':lib:assembleDebug'
from('lib/build/outputs/aar')
into('app/libs/debug')
@@ -75,16 +76,45 @@ task copyDebugAAR(type: Copy) {
}
/**
- * Copy the Godot android library archive release file into the app release libs directory.
+ * Copy the Godot android library archive debug file into the root bin directory.
* Depends on the library build task to ensure the AAR file is generated prior to copying.
*/
-task copyReleaseAAR(type: Copy) {
+task copyDebugAARToBin(type: Copy) {
+ dependsOn ':lib:assembleDebug'
+ from('lib/build/outputs/aar')
+ into(binDir)
+ include('godot-lib.debug.aar')
+}
+
+/**
+ * Copy the Godot android library archive release file into the app module release libs directory.
+ * Depends on the library build task to ensure the AAR file is generated prior to copying.
+ */
+task copyReleaseAARToAppModule(type: Copy) {
dependsOn ':lib:assembleRelease'
from('lib/build/outputs/aar')
into('app/libs/release')
include('godot-lib.release.aar')
}
+task copyGodotPaymentPluginToAppModule(type: Copy) {
+ dependsOn ':plugins:godotpayment:assembleRelease'
+ from('plugins/godotpayment/build/outputs/aar')
+ into('app/libs/plugins')
+ include('GodotPayment.release.aar')
+}
+
+/**
+ * Copy the Godot android library archive release file into the root bin directory.
+ * Depends on the library build task to ensure the AAR file is generated prior to copying.
+ */
+task copyReleaseAARToBin(type: Copy) {
+ dependsOn ':lib:assembleRelease'
+ from('lib/build/outputs/aar')
+ into(binDir)
+ include('godot-lib.release.aar')
+}
+
/**
* Generate Godot custom build template by zipping the source files from the app directory, as well
* as the AAR files generated by 'copyDebugAAR' and 'copyReleaseAAR'.
@@ -95,7 +125,7 @@ task zipCustomBuild(type: Zip) {
doFirst {
logger.lifecycle("Generating Godot custom build template")
}
- from(fileTree(dir: 'app', excludes: ['**/build/**', '**/.gradle/**', '**/*.iml']), fileTree(dir: '.', includes: ['gradle.properties','gradlew', 'gradlew.bat', 'gradle/**']))
+ from(fileTree(dir: 'app', excludes: ['**/build/**', '**/.gradle/**', '**/*.iml']), fileTree(dir: '.', includes: ['gradle.properties', 'gradlew', 'gradlew.bat', 'gradle/**']))
include '**/*'
archiveName 'android_source.zip'
destinationDir(file(binDir))
@@ -106,23 +136,28 @@ task zipCustomBuild(type: Zip) {
*/
task generateGodotTemplates(type: GradleBuild) {
// We exclude these gradle tasks so we can run the scons command manually.
- for (String buildType : supportedTargets.keySet()) {
+ for (String buildType : supportedTargets) {
startParameter.excludedTaskNames += ":lib:" + getSconsTaskName(buildType)
}
- tasks = []
+ tasks = ["copyGodotPaymentPluginToAppModule"]
// Only build the apks and aar files for which we have native shared libraries.
- for (String target : supportedTargets.keySet()) {
+ for (String target : supportedTargets) {
File targetLibs = new File("lib/libs/" + target)
- if (targetLibs != null && targetLibs.isDirectory()) {
- File[] targetLibsContents = targetLibs.listFiles()
- if (targetLibsContents != null && targetLibsContents.length > 0) {
- // Copy the generated aar library files to the custom build directory.
- tasks += "copy" + target.capitalize() + "AAR"
- // Copy the prebuilt binary templates to the bin directory.
- tasks += "copy" + target.capitalize() + "BinaryToBin"
- }
+ if (targetLibs != null
+ && targetLibs.isDirectory()
+ && targetLibs.listFiles() != null
+ && targetLibs.listFiles().length > 0) {
+ String capitalizedTarget = target.capitalize()
+ // Copy the generated aar library files to the custom build directory.
+ tasks += "copy" + capitalizedTarget + "AARToAppModule"
+ // Copy the generated aar library files to the bin directory.
+ tasks += "copy" + capitalizedTarget + "AARToBin"
+ // Copy the prebuilt binary templates to the bin directory.
+ tasks += "copy" + capitalizedTarget + "BinaryToBin"
+ } else {
+ logger.lifecycle("No native shared libs for target $target. Skipping build.")
}
}
@@ -133,20 +168,28 @@ task generateGodotTemplates(type: GradleBuild) {
* Clean the generated artifacts.
*/
task cleanGodotTemplates(type: Delete) {
- // Delete the generated native libs
- delete("lib/libs")
+ // Delete the generated native libs
+ delete("lib/libs")
+
+ // Delete the library generated AAR files
+ delete("lib/build/outputs/aar")
+
+ // Delete the godotpayment libs directory contents
+ delete("plugins/godotpayment/libs")
- // Delete the library generated AAR files
- delete("lib/build/outputs/aar")
+ // Delete the generated godotpayment aar
+ delete("plugins/godotpayment/build/outputs/aar")
- // Delete the app libs directory contents
- delete("app/libs")
+ // Delete the app libs directory contents
+ delete("app/libs")
- // Delete the generated binary apks
- delete("app/build/outputs/apk")
+ // Delete the generated binary apks
+ delete("app/build/outputs/apk")
- // Delete the Godot templates in the Godot bin directory
- delete("$binDir/android_debug.apk")
- delete("$binDir/android_release.apk")
- delete("$binDir/android_source.zip")
+ // Delete the Godot templates in the Godot bin directory
+ delete("$binDir/android_debug.apk")
+ delete("$binDir/android_release.apk")
+ delete("$binDir/android_source.zip")
+ delete("$binDir/godot-lib.debug.aar")
+ delete("$binDir/godot-lib.release.aar")
}
diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.properties b/platform/android/java/gradle/wrapper/gradle-wrapper.properties
index bf50265715..f56b0f6a5e 100644
--- a/platform/android/java/gradle/wrapper/gradle-wrapper.properties
+++ b/platform/android/java/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index eb97484b9c..062f91e08e 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -2,6 +2,8 @@ apply plugin: 'com.android.library'
dependencies {
implementation libraries.supportCoreUtils
+ implementation libraries.kotlinStdLib
+ implementation libraries.v4Support
}
def pathToRootDir = "../../../../"
@@ -24,6 +26,7 @@ android {
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/NOTICE'
+ doNotStrip '**/*.so'
}
sourceSets {
@@ -54,7 +57,7 @@ android {
// files is only setup for editing support.
gradle.startParameter.excludedTaskNames += taskPrefix + "externalNativeBuild" + buildType
- def releaseTarget = supportedTargets[buildType.toLowerCase()]
+ def releaseTarget = buildType.toLowerCase()
if (releaseTarget == null || releaseTarget == "") {
throw new GradleException("Invalid build type: " + buildType)
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 2f6a93fbb1..4e605f9950 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -61,8 +61,11 @@ import android.os.Messenger;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings.Secure;
+import android.support.annotation.CallSuper;
import android.support.annotation.Keep;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.v4.app.FragmentActivity;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -87,22 +90,19 @@ import com.google.android.vending.expansion.downloader.IStub;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
-import java.lang.reflect.Method;
import java.security.MessageDigest;
-import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
-import javax.microedition.khronos.opengles.GL10;
import org.godotengine.godot.input.GodotEditText;
-import org.godotengine.godot.payments.PaymentsManager;
+import org.godotengine.godot.plugin.GodotPlugin;
+import org.godotengine.godot.plugin.GodotPluginRegistry;
import org.godotengine.godot.utils.GodotNetUtils;
import org.godotengine.godot.utils.PermissionsUtil;
import org.godotengine.godot.xr.XRMode;
-public abstract class Godot extends Activity implements SensorEventListener, IDownloaderClient {
+public abstract class Godot extends FragmentActivity implements SensorEventListener, IDownloaderClient {
- static final int MAX_SINGLETONS = 64;
private IStub mDownloaderClientStub;
private TextView mStatusText;
private TextView mProgressFraction;
@@ -126,8 +126,7 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
private boolean activityResumed;
private int mState;
- // Used to dispatch events to the main thread.
- private final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
+ private GodotPluginRegistry pluginRegistry;
static private Intent mCurrentIntent;
@@ -154,83 +153,6 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
mPauseButton.setText(stringResourceID);
}
- static public class SingletonBase {
-
- protected void registerClass(String p_name, String[] p_methods) {
-
- GodotLib.singleton(p_name, this);
-
- Class clazz = getClass();
- Method[] methods = clazz.getDeclaredMethods();
- for (Method method : methods) {
- boolean found = false;
-
- for (String s : p_methods) {
- if (s.equals(method.getName())) {
- found = true;
- break;
- }
- }
- if (!found)
- continue;
-
- List<String> ptr = new ArrayList<String>();
-
- Class[] paramTypes = method.getParameterTypes();
- for (Class c : paramTypes) {
- ptr.add(c.getName());
- }
-
- String[] pt = new String[ptr.size()];
- ptr.toArray(pt);
-
- GodotLib.method(p_name, method.getName(), method.getReturnType().getName(), pt);
- }
-
- Godot.singletons[Godot.singleton_count++] = this;
- }
-
- /**
- * Invoked once during the Godot Android initialization process after creation of the
- * {@link GodotView} view.
- * <p>
- * This method should be overridden by descendants of this class that would like to add
- * their view/layout to the Godot view hierarchy.
- *
- * @return the view to be included; null if no views should be included.
- */
- @Nullable
- protected View onMainCreateView(Activity activity) {
- return null;
- }
-
- protected void onMainActivityResult(int requestCode, int resultCode, Intent data) {
- }
-
- protected void onMainRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
- }
-
- protected void onMainPause() {}
- protected void onMainResume() {}
- protected void onMainDestroy() {}
- protected boolean onMainBackPressed() { return false; }
-
- protected void onGLDrawFrame(GL10 gl) {}
- protected void onGLSurfaceChanged(GL10 gl, int width, int height) {} // singletons will always miss first onGLSurfaceChanged call
- //protected void onGLSurfaceCreated(GL10 gl, EGLConfig config) {} // singletons won't be ready until first GodotLib.step()
-
- public void registerMethods() {}
- }
-
- /*
- protected List<SingletonBase> singletons = new ArrayList<SingletonBase>();
- protected void instanceSingleton(SingletonBase s) {
-
- s.registerMethods();
- singletons.add(s);
- }
- */
-
private String[] command_line;
private boolean use_apk_expansion;
@@ -246,35 +168,27 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
public static GodotIO io;
public static GodotNetUtils netUtils;
- static SingletonBase[] singletons = new SingletonBase[MAX_SINGLETONS];
- static int singleton_count = 0;
-
public interface ResultCallback {
public void callback(int requestCode, int resultCode, Intent data);
}
public ResultCallback result_callback;
- private PaymentsManager mPaymentsManager = null;
-
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == PaymentsManager.REQUEST_CODE_FOR_PURCHASE) {
- mPaymentsManager.processPurchaseResponse(resultCode, data);
- } else if (result_callback != null) {
+ if (result_callback != null) {
result_callback.callback(requestCode, resultCode, data);
result_callback = null;
- };
-
- for (int i = 0; i < singleton_count; i++) {
+ }
- singletons[i].onMainActivityResult(requestCode, resultCode, data);
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onMainActivityResult(requestCode, resultCode, data);
}
- };
+ }
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
- for (int i = 0; i < singleton_count; i++) {
- singletons[i].onMainRequestPermissionsResult(requestCode, permissions, grantResults);
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onMainRequestPermissionsResult(requestCode, permissions, grantResults);
}
for (int i = 0; i < permissions.length; i++) {
@@ -283,12 +197,20 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
};
/**
+ * Invoked on the GL thread when the Godot main loop has started.
+ */
+ @CallSuper
+ protected void onGLGodotMainLoopStarted() {
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onGLGodotMainLoopStarted();
+ }
+ }
+
+ /**
* Used by the native code (java_godot_lib_jni.cpp) to complete initialization of the GLSurfaceView view and renderer.
*/
@Keep
private void onVideoInit() {
- boolean use_gl3 = getGLESVersionCode() >= 0x00030000;
-
final FrameLayout layout = new FrameLayout(this);
layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
setContentView(layout);
@@ -299,19 +221,18 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
// ...add to FrameLayout
layout.addView(edittext);
- mView = new GodotView(this, xrMode, use_gl3, use_32_bits, use_debug_opengl);
+ mView = new GodotView(this, xrMode, use_32_bits, use_debug_opengl);
layout.addView(mView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
edittext.setView(mView);
io.setEdit(edittext);
- final Godot godot = this;
mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Point fullSize = new Point();
- godot.getWindowManager().getDefaultDisplay().getSize(fullSize);
+ getWindowManager().getDefaultDisplay().getSize(fullSize);
Rect gameSize = new Rect();
- godot.mView.getWindowVisibleDisplayFrame(gameSize);
+ mView.getWindowVisibleDisplayFrame(gameSize);
final int keyboardHeight = fullSize.y - gameSize.bottom;
GodotLib.setVirtualKeyboardHeight(keyboardHeight);
@@ -323,23 +244,23 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
@Override
public void run() {
GodotLib.setup(current_command_line);
- setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on")));
- // The Godot Android plugins are setup on completion of GodotLib.setup
- mainThreadHandler.post(new Runnable() {
- @Override
- public void run() {
- // Include the non-null views returned in the Godot view hierarchy.
- for (int i = 0; i < singleton_count; i++) {
- View view = singletons[i].onMainCreateView(Godot.this);
- if (view != null) {
- layout.addView(view);
- }
- }
- }
- });
+ // Must occur after GodotLib.setup has completed.
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onGLRegisterPluginWithGodotNative();
+ }
+
+ setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on")));
}
});
+
+ // Include the returned non-null views in the Godot view hierarchy.
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ View pluginView = plugin.onMainCreateView(this);
+ if (pluginView != null) {
+ layout.addView(pluginView);
+ }
+ }
}
public void setKeepScreenOn(final boolean p_enabled) {
@@ -519,8 +440,6 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
result_callback = null;
- mPaymentsManager = PaymentsManager.createManager(this).initService();
-
godot_initialized = true;
}
@@ -537,6 +456,7 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
mClipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
+ pluginRegistry = GodotPluginRegistry.initializePluginRegistry(this);
//check for apk expansion API
if (true) {
@@ -676,9 +596,8 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
@Override
protected void onDestroy() {
- if (mPaymentsManager != null) mPaymentsManager.destroy();
- for (int i = 0; i < singleton_count; i++) {
- singletons[i].onMainDestroy();
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onMainDestroy();
}
GodotLib.ondestroy(this);
@@ -705,8 +624,8 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
mSensorManager.unregisterListener(this);
- for (int i = 0; i < singleton_count; i++) {
- singletons[i].onMainPause();
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onMainPause();
}
}
@@ -757,9 +676,8 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
- for (int i = 0; i < singleton_count; i++) {
-
- singletons[i].onMainResume();
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onMainResume();
}
}
@@ -852,8 +770,8 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
public void onBackPressed() {
boolean shouldQuit = true;
- for (int i = 0; i < singleton_count; i++) {
- if (singletons[i].onMainBackPressed()) {
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ if (plugin.onMainBackPressed()) {
shouldQuit = false;
}
}
@@ -868,6 +786,17 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
}
}
+ /**
+ * Queue a runnable to be run on the GL thread.
+ * <p>
+ * This must be called after the GL thread has started.
+ */
+ public final void runOnGLThread(@NonNull Runnable action) {
+ if (mView != null) {
+ mView.queueEvent(action);
+ }
+ }
+
private void forceQuit() {
System.exit(0);
}
@@ -992,8 +921,8 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
int keyCode;
if ((keyCode = cc[i]) != 0) {
// Simulate key down and up...
- GodotLib.key(0, keyCode, true);
- GodotLib.key(0, keyCode, false);
+ GodotLib.key(0, 0, keyCode, true);
+ GodotLib.key(0, 0, keyCode, false);
}
}
}
@@ -1001,10 +930,6 @@ public abstract class Godot extends Activity implements SensorEventListener, IDo
return true;
}
- public PaymentsManager getPaymentsManager() {
- return mPaymentsManager;
- }
-
public boolean requestPermission(String p_name) {
return PermissionsUtil.requestPermission(p_name, this);
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index e0b46673ba..89a65aea24 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -136,7 +136,7 @@ public class GodotLib {
/**
* Forward regular key events from the main thread to the GL thread.
*/
- public static native void key(int p_scancode, int p_unicode_char, boolean p_pressed);
+ public static native void key(int p_keycode, int p_scancode, int p_unicode_char, boolean p_pressed);
/**
* Forward game device's key events from the main thread to the GL thread.
@@ -176,22 +176,6 @@ public class GodotLib {
public static native void audio();
/**
- * Used to setup a {@link org.godotengine.godot.Godot.SingletonBase} instance.
- * @param p_name Name of the instance.
- * @param p_object Reference to the singleton instance.
- */
- public static native void singleton(String p_name, Object p_object);
-
- /**
- * Used to complete registration of the {@link org.godotengine.godot.Godot.SingletonBase} instance's methods.
- * @param p_sname Name of the instance
- * @param p_name Name of the method to register
- * @param p_ret Return type of the registered method
- * @param p_params Method parameters types
- */
- public static native void method(String p_sname, String p_name, String p_ret, String[] p_params);
-
- /**
* Used to access Godot global properties.
* @param p_key Property key
* @return String value of the property
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
index 26fa033f12..ee9a2aee4f 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java
@@ -30,9 +30,12 @@
package org.godotengine.godot;
+import android.content.Context;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
+import org.godotengine.godot.plugin.GodotPlugin;
+import org.godotengine.godot.plugin.GodotPluginRegistry;
import org.godotengine.godot.utils.GLUtils;
/**
@@ -40,8 +43,13 @@ import org.godotengine.godot.utils.GLUtils;
*/
class GodotRenderer implements GLSurfaceView.Renderer {
+ private final GodotPluginRegistry pluginRegistry;
private boolean activityJustResumed = false;
+ GodotRenderer() {
+ this.pluginRegistry = GodotPluginRegistry.getPluginRegistry();
+ }
+
public void onDrawFrame(GL10 gl) {
if (activityJustResumed) {
GodotLib.onRendererResumed();
@@ -49,21 +57,23 @@ class GodotRenderer implements GLSurfaceView.Renderer {
}
GodotLib.step();
- for (int i = 0; i < Godot.singleton_count; i++) {
- Godot.singletons[i].onGLDrawFrame(gl);
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onGLDrawFrame(gl);
}
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
-
GodotLib.resize(width, height);
- for (int i = 0; i < Godot.singleton_count; i++) {
- Godot.singletons[i].onGLSurfaceChanged(gl, width, height);
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onGLSurfaceChanged(gl, width, height);
}
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GodotLib.newcontext(GLUtils.use_32);
+ for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
+ plugin.onGLSurfaceCreated(gl, config);
+ }
}
void onActivityResumed() {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotView.java
index f938583082..8d3c2ae319 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotView.java
@@ -73,9 +73,8 @@ public class GodotView extends GLSurfaceView {
private final GestureDetector detector;
private final GodotRenderer godotRenderer;
- public GodotView(Godot activity, XRMode xrMode, boolean p_use_gl3, boolean p_use_32_bits, boolean p_use_debug_opengl) {
+ public GodotView(Godot activity, XRMode xrMode, boolean p_use_32_bits, boolean p_use_debug_opengl) {
super(activity);
- GLUtils.use_gl3 = p_use_gl3;
GLUtils.use_32 = p_use_32_bits;
GLUtils.use_debug_opengl = p_use_debug_opengl;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
index 44998aa6c0..e901b4b36d 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
@@ -123,7 +123,7 @@ public class GodotEditText extends EditText {
}
private void setMaxInputLength(EditText p_edit_text, int p_max_input_length) {
- if (p_max_input_length >= 0) {
+ if (p_max_input_length > 0) {
InputFilter[] filters = new InputFilter[1];
filters[0] = new InputFilter.LengthFilter(p_max_input_length);
p_edit_text.setFilters(filters);
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index b2b88088e8..e00ca86c41 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -98,11 +98,12 @@ public class GodotInputHandler implements InputDeviceListener {
});
}
} else {
+ final int scanCode = event.getScanCode();
final int chr = event.getUnicodeChar(0);
queueEvent(new Runnable() {
@Override
public void run() {
- GodotLib.key(keyCode, chr, false);
+ GodotLib.key(keyCode, scanCode, chr, false);
}
});
};
@@ -143,11 +144,12 @@ public class GodotInputHandler implements InputDeviceListener {
});
}
} else {
+ final int scanCode = event.getScanCode();
final int chr = event.getUnicodeChar(0);
queueEvent(new Runnable() {
@Override
public void run() {
- GodotLib.key(keyCode, chr, true);
+ GodotLib.key(keyCode, scanCode, chr, true);
}
});
};
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
index 3a154f1bf3..18f2d57661 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
@@ -91,8 +91,8 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
@Override
public void run() {
for (int i = 0; i < count; ++i) {
- GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
- GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
+ GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, true);
+ GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, false);
}
}
});
@@ -110,8 +110,13 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
@Override
public void run() {
for (int i = 0; i < count; ++i) {
- GodotLib.key(0, newChars[i], true);
- GodotLib.key(0, newChars[i], false);
+ int key = newChars[i];
+ if (key == '\n') {
+ // Return keys are handled through action events
+ continue;
+ }
+ GodotLib.key(0, 0, key, true);
+ GodotLib.key(0, 0, key, false);
}
}
});
@@ -127,15 +132,20 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
public void run() {
for (int i = 0; i < characters.length(); i++) {
final int ch = characters.codePointAt(i);
- GodotLib.key(0, ch, true);
- GodotLib.key(0, ch, false);
+ GodotLib.key(0, 0, ch, true);
+ GodotLib.key(0, 0, ch, false);
}
}
});
}
- if (pActionID == EditorInfo.IME_ACTION_DONE) {
+ if (pActionID == EditorInfo.IME_NULL) {
+ // Enter key has been pressed
+ GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, true);
+ GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, false);
+
this.mView.requestFocus();
+ return true;
}
return false;
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
new file mode 100644
index 0000000000..d5bf4fc70e
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
@@ -0,0 +1,256 @@
+/*************************************************************************/
+/* GodotPlugin.java */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+
+package org.godotengine.godot.plugin;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.view.View;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+import org.godotengine.godot.Godot;
+
+/**
+ * Base class for the Godot Android plugins.
+ * <p>
+ * A Godot Android plugin is a regular Android library packaged as an aar archive file with the following caveats:
+ * <p>
+ * - The library must have a dependency on the Godot Android library (godot-lib.aar).
+ * A stable version is available for each release.
+ * <p>
+ * - The library must include a <meta-data> tag in its manifest file setup as follow:
+ * <meta-data android:name="org.godotengine.plugin.v1.[PluginName]" android:value="[plugin.init.ClassFullName]" />
+ * Where:
+ * - 'PluginName' is the name of the plugin.
+ * - 'plugin.init.ClassFullName' is the full name (package + class name) of the plugin class
+ * extending {@link GodotPlugin}.
+ *
+ * A plugin can also define and provide c/c++ gdnative libraries and nativescripts for the target
+ * app/game to leverage.
+ * The shared library for the gdnative library will be automatically bundled by the aar build
+ * system.
+ * Godot '*.gdnlib' and '*.gdns' resource files must however be manually defined in the project
+ * 'assets' directory. The recommended path for these resources in the 'assets' directory should be:
+ * 'godot/plugin/v1/[PluginName]/'
+ */
+public abstract class GodotPlugin {
+
+ private final Godot godot;
+
+ public GodotPlugin(Godot godot) {
+ this.godot = godot;
+ }
+
+ /**
+ * Provides access to the Godot engine.
+ */
+ protected Godot getGodot() {
+ return godot;
+ }
+
+ /**
+ * Register the plugin with Godot native code.
+ */
+ public final void onGLRegisterPluginWithGodotNative() {
+ nativeRegisterSingleton(getPluginName());
+
+ Class clazz = getClass();
+ Method[] methods = clazz.getDeclaredMethods();
+ for (Method method : methods) {
+ boolean found = false;
+
+ for (String s : getPluginMethods()) {
+ if (s.equals(method.getName())) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ continue;
+
+ List<String> ptr = new ArrayList<String>();
+
+ Class[] paramTypes = method.getParameterTypes();
+ for (Class c : paramTypes) {
+ ptr.add(c.getName());
+ }
+
+ String[] pt = new String[ptr.size()];
+ ptr.toArray(pt);
+
+ nativeRegisterMethod(getPluginName(), method.getName(), method.getReturnType().getName(), pt);
+ }
+
+ // Get the list of gdnative libraries to register.
+ Set<String> gdnativeLibrariesPaths = getPluginGDNativeLibrariesPaths();
+ if (!gdnativeLibrariesPaths.isEmpty()) {
+ nativeRegisterGDNativeLibraries(gdnativeLibrariesPaths.toArray(new String[0]));
+ }
+ }
+
+ /**
+ * Invoked once during the Godot Android initialization process after creation of the
+ * {@link org.godotengine.godot.GodotView} view.
+ * <p>
+ * This method should be overridden by descendants of this class that would like to add
+ * their view/layout to the Godot view hierarchy.
+ *
+ * @return the view to be included; null if no views should be included.
+ */
+ @Nullable
+ public View onMainCreateView(Activity activity) {
+ return null;
+ }
+
+ /**
+ * @see Activity#onActivityResult(int, int, Intent)
+ */
+ public void onMainActivityResult(int requestCode, int resultCode, Intent data) {
+ }
+
+ /**
+ * @see Activity#onRequestPermissionsResult(int, String[], int[])
+ */
+ public void onMainRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+ }
+
+ /**
+ * @see Activity#onPause()
+ */
+ public void onMainPause() {}
+
+ /**
+ * @see Activity#onResume()
+ */
+ public void onMainResume() {}
+
+ /**
+ * @see Activity#onDestroy()
+ */
+ public void onMainDestroy() {}
+
+ /**
+ * @see Activity#onBackPressed()
+ */
+ public boolean onMainBackPressed() { return false; }
+
+ /**
+ * Invoked on the GL thread when the Godot main loop has started.
+ */
+ public void onGLGodotMainLoopStarted() {}
+
+ /**
+ * Invoked once per frame on the GL thread after the frame is drawn.
+ */
+ public void onGLDrawFrame(GL10 gl) {}
+
+ /**
+ * Called on the GL thread after the surface is created and whenever the OpenGL ES surface size
+ * changes.
+ */
+ public void onGLSurfaceChanged(GL10 gl, int width, int height) {}
+
+ /**
+ * Called on the GL thread when the surface is created or recreated.
+ */
+ public void onGLSurfaceCreated(GL10 gl, EGLConfig config) {}
+
+ /**
+ * Returns the name of the plugin.
+ * <p>
+ * This value must match the one listed in the plugin '<meta-data>' manifest entry.
+ */
+ @NonNull
+ public abstract String getPluginName();
+
+ /**
+ * Returns the list of methods to be exposed to Godot.
+ */
+ @NonNull
+ public abstract List<String> getPluginMethods();
+
+ /**
+ * Returns the paths for the plugin's gdnative libraries.
+ *
+ * The paths must be relative to the 'assets' directory and point to a '*.gdnlib' file.
+ */
+ @NonNull
+ protected Set<String> getPluginGDNativeLibrariesPaths() {
+ return Collections.emptySet();
+ }
+
+ /**
+ * Runs the specified action on the UI thread. If the current thread is the UI
+ * thread, then the action is executed immediately. If the current thread is
+ * not the UI thread, the action is posted to the event queue of the UI thread.
+ *
+ * @param action the action to run on the UI thread
+ */
+ protected void runOnUiThread(Runnable action) {
+ godot.runOnUiThread(action);
+ }
+
+ /**
+ * Queue the specified action to be run on the GL thread.
+ *
+ * @param action the action to run on the GL thread
+ */
+ protected void runOnGLThread(Runnable action) {
+ godot.runOnGLThread(action);
+ }
+
+ /**
+ * Used to setup a {@link GodotPlugin} instance.
+ * @param p_name Name of the instance.
+ */
+ private native void nativeRegisterSingleton(String p_name);
+
+ /**
+ * Used to complete registration of the {@link GodotPlugin} instance's methods.
+ * @param p_sname Name of the instance
+ * @param p_name Name of the method to register
+ * @param p_ret Return type of the registered method
+ * @param p_params Method parameters types
+ */
+ private native void nativeRegisterMethod(String p_sname, String p_name, String p_ret, String[] p_params);
+
+ /**
+ * Used to register gdnative libraries bundled by the plugin.
+ * @param gdnlibPaths Paths to the libraries relative to the 'assets' directory.
+ */
+ private native void nativeRegisterGDNativeLibraries(String[] gdnlibPaths);
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java
new file mode 100644
index 0000000000..b6d949b7bf
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java
@@ -0,0 +1,199 @@
+/*************************************************************************/
+/* GodotPluginRegistry.java */
+/*************************************************************************/
+/* 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. */
+/*************************************************************************/
+
+package org.godotengine.godot.plugin;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import org.godotengine.godot.Godot;
+
+/**
+ * Registry used to load and access the registered Godot Android plugins.
+ */
+public final class GodotPluginRegistry {
+
+ private static final String TAG = GodotPluginRegistry.class.getSimpleName();
+
+ private static final String GODOT_PLUGIN_V1_NAME_PREFIX = "org.godotengine.plugin.v1.";
+
+ /**
+ * Name for the metadata containing the list of Godot plugins to enable.
+ */
+ private static final String GODOT_ENABLED_PLUGINS_LABEL = "custom_template_plugins";
+
+ private static GodotPluginRegistry instance;
+ private final ConcurrentHashMap<String, GodotPlugin> registry;
+
+ private GodotPluginRegistry(Godot godot) {
+ registry = new ConcurrentHashMap<>();
+ loadPlugins(godot);
+ }
+
+ /**
+ * Retrieve the plugin tied to the given plugin name.
+ * @param pluginName Name of the plugin
+ * @return {@link GodotPlugin} handle if it exists, null otherwise.
+ */
+ @Nullable
+ public GodotPlugin getPlugin(String pluginName) {
+ return registry.get(pluginName);
+ }
+
+ /**
+ * Retrieve the full set of loaded plugins.
+ */
+ public Collection<GodotPlugin> getAllPlugins() {
+ return registry.values();
+ }
+
+ /**
+ * Parse the manifest file and load all included Godot Android plugins.
+ * <p>
+ * A plugin manifest entry is a '<meta-data>' tag setup as described in the {@link GodotPlugin}
+ * documentation.
+ *
+ * @param godot Godot instance
+ * @return A singleton instance of {@link GodotPluginRegistry}. This ensures that only one instance
+ * of each Godot Android plugins is available at runtime.
+ */
+ public static GodotPluginRegistry initializePluginRegistry(Godot godot) {
+ if (instance == null) {
+ instance = new GodotPluginRegistry(godot);
+ }
+
+ return instance;
+ }
+
+ /**
+ * Return the plugin registry if it's initialized.
+ * Throws a {@link IllegalStateException} exception if not.
+ *
+ * @throws IllegalStateException if {@link GodotPluginRegistry#initializePluginRegistry(Godot)} has not been called prior to calling this method.
+ */
+ public static GodotPluginRegistry getPluginRegistry() throws IllegalStateException {
+ if (instance == null) {
+ throw new IllegalStateException("Plugin registry hasn't been initialized.");
+ }
+
+ return instance;
+ }
+
+ private void loadPlugins(Godot godot) {
+ try {
+ ApplicationInfo appInfo = godot
+ .getPackageManager()
+ .getApplicationInfo(godot.getPackageName(), PackageManager.GET_META_DATA);
+ Bundle metaData = appInfo.metaData;
+ if (metaData == null || metaData.isEmpty()) {
+ return;
+ }
+
+ // When using the Godot editor for building and exporting the apk, this is used to check
+ // which plugins to enable since the custom build template may contain prebuilt plugins.
+ // When using a custom process to generate the apk, the metadata is not needed since
+ // it's assumed that the developer is aware of the dependencies included in the apk.
+ final Set<String> enabledPluginsSet;
+ if (metaData.containsKey(GODOT_ENABLED_PLUGINS_LABEL)) {
+ String enabledPlugins = metaData.getString(GODOT_ENABLED_PLUGINS_LABEL, "");
+ String[] enabledPluginsList = enabledPlugins.split(",");
+ if (enabledPluginsList.length == 0) {
+ // No plugins to enable. Aborting early.
+ return;
+ }
+
+ enabledPluginsSet = new HashSet<>();
+ for (String enabledPlugin : enabledPluginsList) {
+ enabledPluginsSet.add(enabledPlugin.trim());
+ }
+ } else {
+ enabledPluginsSet = null;
+ }
+
+ int godotPluginV1NamePrefixLength = GODOT_PLUGIN_V1_NAME_PREFIX.length();
+ for (String metaDataName : metaData.keySet()) {
+ // Parse the meta-data looking for entry with the Godot plugin name prefix.
+ if (metaDataName.startsWith(GODOT_PLUGIN_V1_NAME_PREFIX)) {
+ String pluginName = metaDataName.substring(godotPluginV1NamePrefixLength).trim();
+ if (enabledPluginsSet != null && !enabledPluginsSet.contains(pluginName)) {
+ Log.w(TAG, "Plugin " + pluginName + " is listed in the dependencies but is not enabled.");
+ continue;
+ }
+
+ // Retrieve the plugin class full name.
+ String pluginHandleClassFullName = metaData.getString(metaDataName);
+ if (!TextUtils.isEmpty(pluginHandleClassFullName)) {
+ try {
+ // Attempt to create the plugin init class via reflection.
+ @SuppressWarnings("unchecked")
+ Class<GodotPlugin> pluginClass = (Class<GodotPlugin>)Class
+ .forName(pluginHandleClassFullName);
+ Constructor<GodotPlugin> pluginConstructor = pluginClass
+ .getConstructor(Godot.class);
+ GodotPlugin pluginHandle = pluginConstructor.newInstance(godot);
+
+ // Load the plugin initializer into the registry using the plugin name
+ // as key.
+ if (!pluginName.equals(pluginHandle.getPluginName())) {
+ Log.w(TAG,
+ "Meta-data plugin name does not match the value returned by the plugin handle: " + pluginName + " =/= " + pluginHandle.getPluginName());
+ }
+ registry.put(pluginName, pluginHandle);
+ } catch (ClassNotFoundException e) {
+ Log.w(TAG, "Unable to load Godot plugin " + pluginName, e);
+ } catch (IllegalAccessException e) {
+ Log.w(TAG, "Unable to load Godot plugin " + pluginName, e);
+ } catch (InstantiationException e) {
+ Log.w(TAG, "Unable to load Godot plugin " + pluginName, e);
+ } catch (NoSuchMethodException e) {
+ Log.w(TAG, "Unable to load Godot plugin " + pluginName, e);
+ } catch (InvocationTargetException e) {
+ Log.w(TAG, "Unable to load Godot plugin " + pluginName, e);
+ }
+ } else {
+ Log.w(TAG, "Invalid plugin loader class for " + pluginName);
+ }
+ }
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Unable load Godot Android plugins from the manifest file.", e);
+ }
+ }
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java b/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java
index bbf876ea1f..9d29551f89 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java
@@ -44,7 +44,6 @@ public class GLUtils {
public static final boolean DEBUG = false;
- public static boolean use_gl3 = false;
public static boolean use_32 = false;
public static boolean use_debug_opengl = false;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt
new file mode 100644
index 0000000000..67faad8ddd
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt
@@ -0,0 +1,99 @@
+/*************************************************************************/
+/* VkRenderer.kt */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+@file:JvmName("VkRenderer")
+package org.godotengine.godot.vulkan
+
+import android.view.Surface
+
+/**
+ * Responsible to setting up and driving the Vulkan rendering logic.
+ *
+ * <h3>Threading</h3>
+ * The renderer will be called on a separate thread, so that rendering
+ * performance is decoupled from the UI thread. Clients typically need to
+ * communicate with the renderer from the UI thread, because that's where
+ * input events are received. Clients can communicate using any of the
+ * standard Java techniques for cross-thread communication, or they can
+ * use the [VkSurfaceView.queueOnVkThread] convenience method.
+ *
+ * @see [VkSurfaceView.startRenderer]
+ */
+internal class VkRenderer {
+
+ /**
+ * Called when the surface is created and signals the beginning of rendering.
+ */
+ fun onVkSurfaceCreated(surface: Surface) {
+ nativeOnVkSurfaceCreated(surface)
+ }
+
+ /**
+ * Called after the surface is created and whenever its size changes.
+ */
+ fun onVkSurfaceChanged(surface: Surface, width: Int, height: Int) {
+ nativeOnVkSurfaceChanged(surface, width, height)
+ }
+
+ /**
+ * Called to draw the current frame.
+ */
+ fun onVkDrawFrame() {
+ nativeOnVkDrawFrame()
+ }
+
+ /**
+ * Called when the rendering thread is resumed.
+ */
+ fun onVkResume() {
+ nativeOnVkResume()
+ }
+
+ /**
+ * Called when the rendering thread is paused.
+ */
+ fun onVkPause() {
+ nativeOnVkPause()
+ }
+
+ /**
+ * Called when the rendering thread is destroyed and used as signal to tear down the Vulkan logic.
+ */
+ fun onVkDestroy() {
+ nativeOnVkDestroy()
+ }
+
+ private external fun nativeOnVkSurfaceCreated(surface: Surface)
+ private external fun nativeOnVkSurfaceChanged(surface: Surface, width: Int, height: Int)
+ private external fun nativeOnVkResume()
+ private external fun nativeOnVkDrawFrame()
+ private external fun nativeOnVkPause()
+ private external fun nativeOnVkDestroy()
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt
new file mode 100644
index 0000000000..1c594f3201
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt
@@ -0,0 +1,136 @@
+/*************************************************************************/
+/* VkSurfaceView.kt */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+@file:JvmName("VkSurfaceView")
+package org.godotengine.godot.vulkan
+
+import android.content.Context
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+
+/**
+ * An implementation of SurfaceView that uses the dedicated surface for
+ * displaying Vulkan rendering.
+ * <p>
+ * A [VkSurfaceView] provides the following features:
+ * <p>
+ * <ul>
+ * <li>Manages a surface, which is a special piece of memory that can be
+ * composited into the Android view system.
+ * <li>Accepts a user-provided [VkRenderer] object that does the actual rendering.
+ * <li>Renders on a dedicated [VkThread] thread to decouple rendering performance from the
+ * UI thread.
+ * </ul>
+ */
+internal class VkSurfaceView(context: Context) : SurfaceView(context), SurfaceHolder.Callback {
+
+ companion object {
+ fun checkState(expression: Boolean, errorMessage: Any) {
+ check(expression) { errorMessage.toString() }
+ }
+ }
+
+ /**
+ * Thread used to drive the vulkan logic.
+ */
+ private val vkThread: VkThread by lazy {
+ VkThread(this, renderer)
+ }
+
+ /**
+ * Performs the actual rendering.
+ */
+ private lateinit var renderer: VkRenderer
+
+ init {
+ isClickable = true
+ holder.addCallback(this)
+ }
+
+ /**
+ * Set the [VkRenderer] associated with the view, and starts the thread that will drive the vulkan
+ * rendering.
+ *
+ * This method should be called once and only once in the life-cycle of [VkSurfaceView].
+ */
+ fun startRenderer(renderer: VkRenderer) {
+ checkState(!this::renderer.isInitialized, "startRenderer must only be invoked once")
+ this.renderer = renderer
+ vkThread.start()
+ }
+
+ /**
+ * Queues a runnable to be run on the Vulkan rendering thread.
+ *
+ * Must not be called before a [VkRenderer] has been set.
+ */
+ fun queueOnVkThread(runnable: Runnable) {
+ vkThread.queueEvent(runnable)
+ }
+
+ /**
+ * Resumes the rendering thread.
+ *
+ * Must not be called before a [VkRenderer] has been set.
+ */
+ fun onResume() {
+ vkThread.onResume()
+ }
+
+ /**
+ * Pauses the rendering thread.
+ *
+ * Must not be called before a [VkRenderer] has been set.
+ */
+ fun onPause() {
+ vkThread.onPause()
+ }
+
+ /**
+ * Tear down the rendering thread.
+ *
+ * Must not be called before a [VkRenderer] has been set.
+ */
+ fun onDestroy() {
+ vkThread.blockingExit()
+ }
+
+ override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
+ vkThread.onSurfaceChanged(width, height)
+ }
+
+ override fun surfaceDestroyed(holder: SurfaceHolder) {
+ vkThread.onSurfaceDestroyed()
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ vkThread.onSurfaceCreated()
+ }
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt
new file mode 100644
index 0000000000..2e332840bf
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt
@@ -0,0 +1,230 @@
+/*************************************************************************/
+/* VkThread.kt */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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. */
+/*************************************************************************/
+
+@file:JvmName("VkThread")
+package org.godotengine.godot.vulkan
+
+import android.util.Log
+import java.util.concurrent.locks.ReentrantLock
+import kotlin.concurrent.withLock
+
+/**
+ * Thread implementation for the [VkSurfaceView] onto which the vulkan logic is ran.
+ *
+ * The implementation is modeled after [android.opengl.GLSurfaceView]'s GLThread.
+ */
+internal class VkThread(private val vkSurfaceView: VkSurfaceView, private val vkRenderer: VkRenderer) : Thread(TAG) {
+
+ companion object {
+ private val TAG = VkThread::class.java.simpleName
+ }
+
+ /**
+ * Used to run events scheduled on the thread.
+ */
+ private val eventQueue = ArrayList<Runnable>()
+
+ /**
+ * Used to synchronize interaction with other threads (e.g: main thread).
+ */
+ private val lock = ReentrantLock()
+ private val lockCondition = lock.newCondition()
+
+ private var shouldExit = false
+ private var exited = false
+ private var rendererInitialized = false
+ private var rendererResumed = false
+ private var resumed = false
+ private var hasSurface = false
+ private var width = 0
+ private var height = 0
+
+ /**
+ * Determine when drawing can occur on the thread. This usually occurs after the
+ * [android.view.Surface] is available, the app is in a resumed state.
+ */
+ private val readyToDraw
+ get() = hasSurface && resumed
+
+ private fun threadExiting() {
+ lock.withLock {
+ exited = true
+ lockCondition.signalAll()
+ }
+ }
+
+ /**
+ * Queue an event on the [VkThread].
+ */
+ fun queueEvent(event: Runnable) {
+ lock.withLock {
+ eventQueue.add(event)
+ lockCondition.signalAll()
+ }
+ }
+
+ /**
+ * Request the thread to exit and block until it's done.
+ */
+ fun blockingExit() {
+ lock.withLock {
+ shouldExit = true
+ lockCondition.signalAll()
+ while (!exited) {
+ try {
+ Log.i(TAG, "Waiting on exit for $name")
+ lockCondition.await()
+ } catch (ex: InterruptedException) {
+ currentThread().interrupt()
+ }
+ }
+ }
+ }
+
+ /**
+ * Invoked when the app resumes.
+ */
+ fun onResume() {
+ lock.withLock {
+ resumed = true
+ lockCondition.signalAll()
+ }
+ }
+
+ /**
+ * Invoked when the app pauses.
+ */
+ fun onPause() {
+ lock.withLock {
+ resumed = false
+ lockCondition.signalAll()
+ }
+ }
+
+ /**
+ * Invoked when the [android.view.Surface] has been created.
+ */
+ fun onSurfaceCreated() {
+ // This is a no op because surface creation will always be followed by surfaceChanged()
+ // which provide all the needed information.
+ }
+
+ /**
+ * Invoked following structural updates to [android.view.Surface].
+ */
+ fun onSurfaceChanged(width: Int, height: Int) {
+ lock.withLock {
+ hasSurface = true
+ this.width = width
+ this.height = height
+ lockCondition.signalAll()
+ }
+ }
+
+ /**
+ * Invoked when the [android.view.Surface] is no longer available.
+ */
+ fun onSurfaceDestroyed() {
+ lock.withLock {
+ hasSurface = false
+ lockCondition.signalAll()
+ }
+ }
+
+ /**
+ * Thread loop modeled after [android.opengl.GLSurfaceView]'s GLThread.
+ */
+ override fun run() {
+ try {
+ while (true) {
+ var event: Runnable? = null
+ lock.withLock {
+ while (true) {
+ // Code path for exiting the thread loop.
+ if (shouldExit) {
+ vkRenderer.onVkDestroy()
+ return
+ }
+
+ // Check for events and execute them outside of the loop if found to avoid
+ // blocking the thread lifecycle by holding onto the lock.
+ if (eventQueue.isNotEmpty()) {
+ event = eventQueue.removeAt(0)
+ break;
+ }
+
+ if (readyToDraw) {
+ if (!rendererResumed) {
+ rendererResumed = true
+ vkRenderer.onVkResume()
+
+ if (!rendererInitialized) {
+ rendererInitialized = true
+ vkRenderer.onVkSurfaceCreated(vkSurfaceView.holder.surface)
+ }
+
+ vkRenderer.onVkSurfaceChanged(vkSurfaceView.holder.surface, width, height)
+ }
+
+ // Break out of the loop so drawing can occur without holding onto the lock.
+ break;
+ } else if (rendererResumed) {
+ // If we aren't ready to draw but are resumed, that means we either lost a surface
+ // or the app was paused.
+ rendererResumed = false
+ vkRenderer.onVkPause()
+ }
+ // We only reach this state if we are not ready to draw and have no queued events, so
+ // we wait.
+ // On state change, the thread will be awoken using the [lock] and [lockCondition], and
+ // we will resume execution.
+ lockCondition.await()
+ }
+ }
+
+ // Run queued event.
+ if (event != null) {
+ event?.run()
+ continue
+ }
+
+ // Draw only when there no more queued events.
+ vkRenderer.onVkDrawFrame()
+ }
+ } catch (ex: InterruptedException) {
+ Log.i(TAG, ex.message)
+ } catch (ex: IllegalStateException) {
+ Log.i(TAG, ex.message)
+ } finally {
+ threadExiting()
+ }
+ }
+
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java
index ce4defd7a7..8409e37f8f 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java
@@ -45,6 +45,8 @@ public class RegularConfigChooser implements GLSurfaceView.EGLConfigChooser {
private int[] mValue = new int[1];
+ // FIXME: Add support for Vulkan.
+
/* This EGL config specification is used to specify 2.0 rendering.
* We use a minimum size of 4 bits for red/green/blue, but will
* perform actual matching in chooseConfig() below.
@@ -59,15 +61,6 @@ public class RegularConfigChooser implements GLSurfaceView.EGLConfigChooser {
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL10.EGL_NONE
};
- private static int[] s_configAttribs3 = {
- EGL10.EGL_RED_SIZE, 4,
- EGL10.EGL_GREEN_SIZE, 4,
- EGL10.EGL_BLUE_SIZE, 4,
- // EGL10.EGL_DEPTH_SIZE, 16,
- // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE,
- EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, //apparently there is no EGL_OPENGL_ES3_BIT
- EGL10.EGL_NONE
- };
public RegularConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
mRedSize = r;
@@ -83,7 +76,7 @@ public class RegularConfigChooser implements GLSurfaceView.EGLConfigChooser {
/* Get the number of minimally matching EGL configurations
*/
int[] num_config = new int[1];
- egl.eglChooseConfig(display, GLUtils.use_gl3 ? s_configAttribs3 : s_configAttribs2, null, 0, num_config);
+ egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config);
int numConfigs = num_config[0];
@@ -94,7 +87,7 @@ public class RegularConfigChooser implements GLSurfaceView.EGLConfigChooser {
/* Allocate then read the array of minimally matching EGL configs
*/
EGLConfig[] configs = new EGLConfig[numConfigs];
- egl.eglChooseConfig(display, GLUtils.use_gl3 ? s_configAttribs3 : s_configAttribs2, configs, numConfigs, num_config);
+ egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);
if (GLUtils.DEBUG) {
GLUtils.printConfigs(egl, display, configs);
diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java
index 22bd4ced87..f2b4c95a2c 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java
@@ -52,24 +52,17 @@ public class RegularContextFactory implements GLSurfaceView.EGLContextFactory {
public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
String driver_name = GodotLib.getGlobal("rendering/quality/driver/driver_name");
- if (GLUtils.use_gl3 && !driver_name.equals("GLES3")) {
- GLUtils.use_gl3 = false;
- }
- if (GLUtils.use_gl3)
- Log.w(TAG, "creating OpenGL ES 3.0 context :");
- else
- Log.w(TAG, "creating OpenGL ES 2.0 context :");
+ // FIXME: Add support for Vulkan.
+ Log.w(TAG, "creating OpenGL ES 2.0 context :");
GLUtils.checkEglError(TAG, "Before eglCreateContext", egl);
EGLContext context;
if (GLUtils.use_debug_opengl) {
int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE };
- int[] attrib_list3 = { EGL_CONTEXT_CLIENT_VERSION, 3, _EGL_CONTEXT_FLAGS_KHR, _EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, EGL10.EGL_NONE };
- context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, GLUtils.use_gl3 ? attrib_list3 : attrib_list2);
+ context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list2);
} else {
int[] attrib_list2 = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
- int[] attrib_list3 = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL10.EGL_NONE };
- context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, GLUtils.use_gl3 ? attrib_list3 : attrib_list2);
+ context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list2);
}
GLUtils.checkEglError(TAG, "After eglCreateContext", egl);
return context;
diff --git a/platform/android/java/plugins/godotpayment/build.gradle b/platform/android/java/plugins/godotpayment/build.gradle
new file mode 100644
index 0000000000..4f376c4587
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/build.gradle
@@ -0,0 +1,31 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion versions.compileSdk
+ buildToolsVersion versions.buildTools
+
+ defaultConfig {
+ minSdkVersion versions.minSdk
+ targetSdkVersion versions.targetSdk
+ }
+
+ libraryVariants.all { variant ->
+ variant.outputs.all { output ->
+ output.outputFileName = "GodotPayment.${variant.name}.aar"
+ }
+ }
+
+}
+
+dependencies {
+ implementation libraries.supportCoreUtils
+ implementation libraries.v4Support
+
+ if (rootProject.findProject(":lib")) {
+ compileOnly project(":lib")
+ } else if (rootProject.findProject(":godot:lib")) {
+ compileOnly project(":godot:lib")
+ } else {
+ compileOnly fileTree(dir: 'libs', include: ['godot-lib*.aar'])
+ }
+}
diff --git a/platform/android/java/plugins/godotpayment/src/main/AndroidManifest.xml b/platform/android/java/plugins/godotpayment/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..61afa03799
--- /dev/null
+++ b/platform/android/java/plugins/godotpayment/src/main/AndroidManifest.xml
@@ -0,0 +1,11 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.godotengine.godot.plugin.payment">
+
+ <application>
+
+ <meta-data
+ android:name="org.godotengine.plugin.v1.GodotPayment"
+ android:value="org.godotengine.godot.plugin.payment.GodotPayment" />
+
+ </application>
+</manifest>
diff --git a/platform/android/java/lib/aidl/com/android/vending/billing/IInAppBillingService.aidl b/platform/android/java/plugins/godotpayment/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl
index 0f2bcae338..0f2bcae338 100644
--- a/platform/android/java/lib/aidl/com/android/vending/billing/IInAppBillingService.aidl
+++ b/platform/android/java/plugins/godotpayment/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/ConsumeTask.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ConsumeTask.java
index 95cc48f536..c15bc232ce 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/ConsumeTask.java
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ConsumeTask.java
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-package org.godotengine.godot.payments;
+package org.godotengine.godot.plugin.payment;
import android.content.Context;
import android.os.AsyncTask;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotPaymentV3.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java
index 93265d509f..c7d0a5de65 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotPaymentV3.java
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* GodotPaymentV3.java */
+/* GodotPayment.java */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,29 +28,53 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-package org.godotengine.godot;
+package org.godotengine.godot.plugin.payment;
-import android.app.Activity;
+import android.content.Intent;
+import android.support.annotation.NonNull;
import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import org.godotengine.godot.payments.PaymentsManager;
+import org.godotengine.godot.Dictionary;
+import org.godotengine.godot.Godot;
+import org.godotengine.godot.GodotLib;
+import org.godotengine.godot.plugin.GodotPlugin;
import org.json.JSONException;
import org.json.JSONObject;
-public class GodotPaymentV3 extends Godot.SingletonBase {
+public class GodotPayment extends GodotPlugin {
- private Godot activity;
private Integer purchaseCallbackId = 0;
private String accessToken;
private String purchaseValidationUrlPrefix;
private String transactionId;
- private PaymentsManager mPaymentManager;
- private Dictionary mSkuDetails = new Dictionary();
+ private final PaymentsManager mPaymentManager;
+ private final Dictionary mSkuDetails = new Dictionary();
+
+ public GodotPayment(Godot godot) {
+ super(godot);
+ mPaymentManager = new PaymentsManager(godot, this);
+ mPaymentManager.initService();
+ }
+
+ @Override
+ public void onMainActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == PaymentsManager.REQUEST_CODE_FOR_PURCHASE) {
+ mPaymentManager.processPurchaseResponse(resultCode, data);
+ }
+ }
+
+ @Override
+ public void onMainDestroy() {
+ super.onMainDestroy();
+ if (mPaymentManager != null) {
+ mPaymentManager.destroy();
+ }
+ }
public void purchase(final String sku, final String transactionId) {
- activity.runOnUiThread(new Runnable() {
+ runOnUiThread(new Runnable() {
@Override
public void run() {
mPaymentManager.requestPurchase(sku, transactionId);
@@ -58,21 +82,8 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
});
}
- static public Godot.SingletonBase initialize(Activity p_activity) {
-
- return new GodotPaymentV3(p_activity);
- }
-
- public GodotPaymentV3(Activity p_activity) {
-
- registerClass("GodotPayments", new String[] { "purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume", "querySkuDetails", "isConnected" });
- activity = (Godot)p_activity;
- mPaymentManager = activity.getPaymentsManager();
- mPaymentManager.setBaseSingleton(this);
- }
-
public void consumeUnconsumedPurchases() {
- activity.runOnUiThread(new Runnable() {
+ runOnUiThread(new Runnable() {
@Override
public void run() {
mPaymentManager.consumeUnconsumedPurchases();
@@ -149,7 +160,7 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
// request purchased items are not consumed
public void requestPurchased() {
- activity.runOnUiThread(new Runnable() {
+ runOnUiThread(new Runnable() {
@Override
public void run() {
mPaymentManager.requestPurchased();
@@ -227,4 +238,18 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
public void errorSkuDetail(String errorMessage) {
GodotLib.calldeferred(purchaseCallbackId, "sku_details_error", new Object[] { errorMessage });
}
+
+ @NonNull
+ @Override
+ public String getPluginName() {
+ return "GodotPayment";
+ }
+
+ @NonNull
+ @Override
+ public List<String> getPluginMethods() {
+ return Arrays.asList("purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix",
+ "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased",
+ "setAutoConsume", "consume", "querySkuDetails", "isConnected");
+ }
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/HandlePurchaseTask.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/HandlePurchaseTask.java
index 23d693cc8c..fe5685288b 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/HandlePurchaseTask.java
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/HandlePurchaseTask.java
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-package org.godotengine.godot.payments;
+package org.godotengine.godot.plugin.payment;
import android.app.Activity;
import android.content.Intent;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsCache.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsCache.java
index 84a7eda6e0..d5919e3d9d 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsCache.java
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsCache.java
@@ -28,11 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-package org.godotengine.godot.payments;
+package org.godotengine.godot.plugin.payment;
import android.content.Context;
import android.content.SharedPreferences;
-import android.util.Log;
public class PaymentsCache {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsManager.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsManager.java
index 90b958266b..bded1f452f 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsManager.java
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PaymentsManager.java
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-package org.godotengine.godot.payments;
+package org.godotengine.godot.plugin.payment;
import android.app.Activity;
import android.content.ComponentName;
@@ -43,7 +43,6 @@ import android.util.Log;
import com.android.vending.billing.IInAppBillingService;
import java.util.ArrayList;
import java.util.Arrays;
-import org.godotengine.godot.GodotPaymentV3;
import org.json.JSONException;
import org.json.JSONObject;
@@ -53,20 +52,13 @@ public class PaymentsManager {
public static final int REQUEST_CODE_FOR_PURCHASE = 0x1001;
private static boolean auto_consume = true;
- private Activity activity;
+ private final Activity activity;
+ private final GodotPayment godotPayment;
IInAppBillingService mService;
- public void setActivity(Activity activity) {
- this.activity = activity;
- }
-
- public static PaymentsManager createManager(Activity activity) {
- PaymentsManager manager = new PaymentsManager(activity);
- return manager;
- }
-
- private PaymentsManager(Activity activity) {
+ PaymentsManager(Activity activity, GodotPayment godotPayment) {
this.activity = activity;
+ this.godotPayment = godotPayment;
}
public PaymentsManager initService() {
@@ -90,9 +82,9 @@ public class PaymentsManager {
public void onServiceDisconnected(ComponentName name) {
mService = null;
- // At this stage, godotPaymentV3 might not have been initialized yet.
- if (godotPaymentV3 != null) {
- godotPaymentV3.callbackDisconnected();
+ // At this stage, godotPayment might not have been initialized yet.
+ if (godotPayment != null) {
+ godotPayment.callbackDisconnected();
}
}
@@ -100,9 +92,9 @@ public class PaymentsManager {
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IInAppBillingService.Stub.asInterface(service);
- // At this stage, godotPaymentV3 might not have been initialized yet.
- if (godotPaymentV3 != null) {
- godotPaymentV3.callbackConnected();
+ // At this stage, godotPayment might not have been initialized yet.
+ if (godotPayment != null) {
+ godotPayment.callbackConnected();
}
}
};
@@ -111,17 +103,17 @@ public class PaymentsManager {
new PurchaseTask(mService, activity) {
@Override
protected void error(String message) {
- godotPaymentV3.callbackFail(message);
+ godotPayment.callbackFail(message);
}
@Override
protected void canceled() {
- godotPaymentV3.callbackCancel();
+ godotPayment.callbackCancel();
}
@Override
protected void alreadyOwned() {
- godotPaymentV3.callbackAlreadyOwned(sku);
+ godotPayment.callbackAlreadyOwned(sku);
}
}
.purchase(sku, transactionId);
@@ -135,19 +127,19 @@ public class PaymentsManager {
new ReleaseAllConsumablesTask(mService, activity) {
@Override
protected void success(String sku, String receipt, String signature, String token) {
- godotPaymentV3.callbackSuccessProductMassConsumed(receipt, signature, sku);
+ godotPayment.callbackSuccessProductMassConsumed(receipt, signature, sku);
}
@Override
protected void error(String message) {
Log.d("godot", "consumeUnconsumedPurchases :" + message);
- godotPaymentV3.callbackFailConsume(message);
+ godotPayment.callbackFailConsume(message);
}
@Override
protected void notRequired() {
Log.d("godot", "callbackSuccessNoUnconsumedPurchases :");
- godotPaymentV3.callbackSuccessNoUnconsumedPurchases();
+ godotPayment.callbackSuccessNoUnconsumedPurchases();
}
}
.consumeItAll();
@@ -168,7 +160,7 @@ public class PaymentsManager {
final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
if (myPurchases == null || myPurchases.size() == 0) {
- godotPaymentV3.callbackPurchased("", "", "");
+ godotPayment.callbackPurchased("", "", "");
return;
}
@@ -186,7 +178,7 @@ public class PaymentsManager {
pc.setConsumableFlag("block", sku, true);
pc.setConsumableValue("token", sku, token);
- godotPaymentV3.callbackPurchased(receipt, signature, sku);
+ godotPayment.callbackPurchased(receipt, signature, sku);
} catch (JSONException e) {
}
}
@@ -203,7 +195,7 @@ public class PaymentsManager {
new HandlePurchaseTask(activity) {
@Override
protected void success(final String sku, final String signature, final String ticket) {
- godotPaymentV3.callbackSuccess(ticket, signature, sku);
+ godotPayment.callbackSuccess(ticket, signature, sku);
if (auto_consume) {
new ConsumeTask(mService, activity) {
@@ -213,7 +205,7 @@ public class PaymentsManager {
@Override
protected void error(String message) {
- godotPaymentV3.callbackFail(message);
+ godotPayment.callbackFail(message);
}
}
.consume(sku);
@@ -222,12 +214,12 @@ public class PaymentsManager {
@Override
protected void error(String message) {
- godotPaymentV3.callbackFail(message);
+ godotPayment.callbackFail(message);
}
@Override
protected void canceled() {
- godotPaymentV3.callbackCancel();
+ godotPayment.callbackCancel();
}
}
.handlePurchaseRequest(resultCode, data);
@@ -235,19 +227,19 @@ public class PaymentsManager {
public void validatePurchase(String purchaseToken, final String sku) {
- new ValidateTask(activity, godotPaymentV3) {
+ new ValidateTask(activity, godotPayment) {
@Override
protected void success() {
new ConsumeTask(mService, activity) {
@Override
protected void success(String ticket) {
- godotPaymentV3.callbackSuccess(ticket, null, sku);
+ godotPayment.callbackSuccess(ticket, null, sku);
}
@Override
protected void error(String message) {
- godotPaymentV3.callbackFail(message);
+ godotPayment.callbackFail(message);
}
}
.consume(sku);
@@ -255,12 +247,12 @@ public class PaymentsManager {
@Override
protected void error(String message) {
- godotPaymentV3.callbackFail(message);
+ godotPayment.callbackFail(message);
}
@Override
protected void canceled() {
- godotPaymentV3.callbackCancel();
+ godotPayment.callbackCancel();
}
}
.validatePurchase(sku);
@@ -274,12 +266,12 @@ public class PaymentsManager {
new ConsumeTask(mService, activity) {
@Override
protected void success(String ticket) {
- godotPaymentV3.callbackSuccessProductMassConsumed(ticket, "", sku);
+ godotPayment.callbackSuccessProductMassConsumed(ticket, "", sku);
}
@Override
protected void error(String message) {
- godotPaymentV3.callbackFailConsume(message);
+ godotPayment.callbackFailConsume(message);
}
}
.consume(sku);
@@ -387,9 +379,9 @@ public class PaymentsManager {
if (!skuDetails.containsKey("DETAILS_LIST")) {
int response = getResponseCodeFromBundle(skuDetails);
if (response != BILLING_RESPONSE_RESULT_OK) {
- godotPaymentV3.errorSkuDetail(getResponseDesc(response));
+ godotPayment.errorSkuDetail(getResponseDesc(response));
} else {
- godotPaymentV3.errorSkuDetail("No error but no detail list.");
+ godotPayment.errorSkuDetail("No error but no detail list.");
}
return;
}
@@ -398,22 +390,16 @@ public class PaymentsManager {
for (String thisResponse : responseList) {
Log.d("godot", "response = " + thisResponse);
- godotPaymentV3.addSkuDetail(thisResponse);
+ godotPayment.addSkuDetail(thisResponse);
}
} catch (RemoteException e) {
e.printStackTrace();
- godotPaymentV3.errorSkuDetail("RemoteException error!");
+ godotPayment.errorSkuDetail("RemoteException error!");
}
}
- godotPaymentV3.completeSkuDetail();
+ godotPayment.completeSkuDetail();
}
}))
.start();
}
-
- private GodotPaymentV3 godotPaymentV3;
-
- public void setBaseSingleton(GodotPaymentV3 godotPaymentV3) {
- this.godotPaymentV3 = godotPaymentV3;
- }
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/PurchaseTask.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PurchaseTask.java
index 09c9349124..eecd1d2151 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/PurchaseTask.java
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/PurchaseTask.java
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-package org.godotengine.godot.payments;
+package org.godotengine.godot.plugin.payment;
import android.app.Activity;
import android.app.PendingIntent;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ReleaseAllConsumablesTask.java
index a101780511..b7bd638feb 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ReleaseAllConsumablesTask.java
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-package org.godotengine.godot.payments;
+package org.godotengine.godot.plugin.payment;
import android.content.Context;
import android.os.AsyncTask;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/ValidateTask.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ValidateTask.java
index dbb6b8a783..179cc08ed1 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/payments/ValidateTask.java
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/ValidateTask.java
@@ -28,13 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-package org.godotengine.godot.payments;
+package org.godotengine.godot.plugin.payment;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import java.lang.ref.WeakReference;
-import org.godotengine.godot.GodotPaymentV3;
import org.godotengine.godot.utils.HttpRequester;
import org.godotengine.godot.utils.RequestParams;
import org.json.JSONException;
@@ -43,7 +42,7 @@ import org.json.JSONObject;
abstract public class ValidateTask {
private Activity context;
- private GodotPaymentV3 godotPaymentsV3;
+ private GodotPayment godotPayments;
private ProgressDialog dialog;
private String mSku;
@@ -80,9 +79,9 @@ abstract public class ValidateTask {
}
}
- public ValidateTask(Activity context, GodotPaymentV3 godotPaymentsV3) {
+ public ValidateTask(Activity context, GodotPayment godotPayments) {
this.context = context;
- this.godotPaymentsV3 = godotPaymentsV3;
+ this.godotPayments = godotPayments;
}
public void validatePurchase(final String sku) {
@@ -96,7 +95,7 @@ abstract public class ValidateTask {
private String doInBackground(String... params) {
PaymentsCache pc = new PaymentsCache(context);
- String url = godotPaymentsV3.getPurchaseValidationUrlPrefix();
+ String url = godotPayments.getPurchaseValidationUrlPrefix();
RequestParams param = new RequestParams();
param.setUrl(url);
param.put("ticket", pc.getConsumableValue("ticket", mSku));
diff --git a/platform/android/java/settings.gradle b/platform/android/java/settings.gradle
index f6921c70aa..9536d3de6d 100644
--- a/platform/android/java/settings.gradle
+++ b/platform/android/java/settings.gradle
@@ -3,3 +3,4 @@ rootProject.name = "Godot"
include ':app'
include ':lib'
+include ':plugins:godotpayment'
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index fe2fd89710..13550c4b11 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -32,9 +32,9 @@
#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) {
+bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error, Variant &ret) {
- Map<StringName, List<MethodInfo> >::Element *M = methods.find(p_method);
+ Map<StringName, List<MethodInfo>>::Element *M = methods.find(p_method);
if (!M)
return false;
@@ -44,20 +44,20 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
for (List<MethodInfo>::Element *E = M->get().front(); E; E = E->next()) {
if (!p_instance && !E->get()._static) {
- r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
continue;
}
int pc = E->get().param_types.size();
if (pc > p_argcount) {
- r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = pc;
continue;
}
if (pc < p_argcount) {
- r_error.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
r_error.argument = pc;
continue;
}
@@ -97,7 +97,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
case ARG_TYPE_DOUBLE: {
if (!p_args[i]->is_num())
- arg_expected = Variant::REAL;
+ arg_expected = Variant::FLOAT;
} break;
case ARG_TYPE_STRING: {
@@ -141,7 +141,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
}
if (arg_expected != Variant::NIL) {
- r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = i;
r_error.expected = arg_expected;
valid = false;
@@ -158,7 +158,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
if (!method)
return true; //no version convinces
- r_error.error = Variant::CallError::CALL_OK;
+ r_error.error = Callable::CallError::CALL_OK;
jvalue *argv = NULL;
@@ -405,7 +405,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
}
}
- r_error.error = Variant::CallError::CALL_OK;
+ r_error.error = Callable::CallError::CALL_OK;
bool success = true;
switch (method->return_type) {
@@ -501,7 +501,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
if (!_convert_object_to_variant(env, obj, ret, method->return_type)) {
ret = Variant();
- r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
success = false;
}
env->DeleteLocalRef(obj);
@@ -517,7 +517,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
return success;
}
-Variant JavaClass::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+Variant JavaClass::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
Variant ret;
bool found = _call_method(NULL, p_method, p_args, p_argcount, r_error, ret);
@@ -533,7 +533,7 @@ JavaClass::JavaClass() {
/////////////////////
-Variant JavaObject::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
+Variant JavaObject::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
return Variant();
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index dedb2ee114..0b1d070441 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -33,14 +33,15 @@
#include "java_godot_wrapper.h"
#include "android/asset_manager_jni.h"
+#include "android_keys_utils.h"
#include "api/java_class_wrapper.h"
#include "audio_driver_jandroid.h"
#include "core/engine.h"
-#include "core/os/keyboard.h"
#include "core/project_settings.h"
#include "dir_access_jandroid.h"
#include "file_access_android.h"
#include "file_access_jandroid.h"
+#include "jni_utils.h"
#include "main/input_default.h"
#include "main/main.h"
#include "net_socket_android.h"
@@ -54,544 +55,6 @@ static OS_Android *os_android = NULL;
static GodotJavaWrapper *godot_java = NULL;
static GodotIOJavaWrapper *godot_io_java = NULL;
-struct jvalret {
-
- jobject obj;
- jvalue val;
- jvalret() { obj = NULL; }
-};
-
-jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_arg, bool force_jobject = false) {
-
- jvalret v;
-
- switch (p_type) {
-
- case Variant::BOOL: {
-
- if (force_jobject) {
- jclass bclass = env->FindClass("java/lang/Boolean");
- jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V");
- jvalue val;
- val.z = (bool)(*p_arg);
- jobject obj = env->NewObjectA(bclass, ctor, &val);
- v.val.l = obj;
- v.obj = obj;
- env->DeleteLocalRef(bclass);
- } else {
- v.val.z = *p_arg;
- };
- } break;
- case Variant::INT: {
-
- if (force_jobject) {
-
- jclass bclass = env->FindClass("java/lang/Integer");
- jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V");
- jvalue val;
- val.i = (int)(*p_arg);
- jobject obj = env->NewObjectA(bclass, ctor, &val);
- v.val.l = obj;
- v.obj = obj;
- env->DeleteLocalRef(bclass);
-
- } else {
- v.val.i = *p_arg;
- };
- } break;
- case Variant::REAL: {
-
- if (force_jobject) {
-
- jclass bclass = env->FindClass("java/lang/Double");
- jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V");
- jvalue val;
- val.d = (double)(*p_arg);
- jobject obj = env->NewObjectA(bclass, ctor, &val);
- v.val.l = obj;
- v.obj = obj;
- env->DeleteLocalRef(bclass);
-
- } else {
- v.val.f = *p_arg;
- };
- } break;
- case Variant::STRING: {
-
- String s = *p_arg;
- jstring jStr = env->NewStringUTF(s.utf8().get_data());
- v.val.l = jStr;
- v.obj = jStr;
- } break;
- case Variant::POOL_STRING_ARRAY: {
-
- PoolVector<String> sarray = *p_arg;
- jobjectArray arr = env->NewObjectArray(sarray.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
-
- for (int j = 0; j < sarray.size(); j++) {
-
- jstring str = env->NewStringUTF(sarray[j].utf8().get_data());
- env->SetObjectArrayElement(arr, j, str);
- env->DeleteLocalRef(str);
- }
- v.val.l = arr;
- v.obj = arr;
-
- } break;
-
- case Variant::DICTIONARY: {
-
- Dictionary dict = *p_arg;
- jclass dclass = env->FindClass("org/godotengine/godot/Dictionary");
- jmethodID ctor = env->GetMethodID(dclass, "<init>", "()V");
- jobject jdict = env->NewObject(dclass, ctor);
-
- Array keys = dict.keys();
-
- jobjectArray jkeys = env->NewObjectArray(keys.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
- for (int j = 0; j < keys.size(); j++) {
- jstring str = env->NewStringUTF(String(keys[j]).utf8().get_data());
- env->SetObjectArrayElement(jkeys, j, str);
- env->DeleteLocalRef(str);
- };
-
- jmethodID set_keys = env->GetMethodID(dclass, "set_keys", "([Ljava/lang/String;)V");
- jvalue val;
- val.l = jkeys;
- env->CallVoidMethodA(jdict, set_keys, &val);
- env->DeleteLocalRef(jkeys);
-
- jobjectArray jvalues = env->NewObjectArray(keys.size(), env->FindClass("java/lang/Object"), NULL);
-
- for (int j = 0; j < keys.size(); j++) {
- Variant var = dict[keys[j]];
- jvalret v = _variant_to_jvalue(env, var.get_type(), &var, true);
- env->SetObjectArrayElement(jvalues, j, v.val.l);
- if (v.obj) {
- env->DeleteLocalRef(v.obj);
- }
- };
-
- jmethodID set_values = env->GetMethodID(dclass, "set_values", "([Ljava/lang/Object;)V");
- val.l = jvalues;
- env->CallVoidMethodA(jdict, set_values, &val);
- env->DeleteLocalRef(jvalues);
- env->DeleteLocalRef(dclass);
-
- v.val.l = jdict;
- v.obj = jdict;
- } break;
-
- case Variant::POOL_INT_ARRAY: {
-
- PoolVector<int> array = *p_arg;
- jintArray arr = env->NewIntArray(array.size());
- PoolVector<int>::Read r = array.read();
- env->SetIntArrayRegion(arr, 0, array.size(), r.ptr());
- v.val.l = arr;
- v.obj = arr;
-
- } break;
- case Variant::POOL_BYTE_ARRAY: {
- PoolVector<uint8_t> array = *p_arg;
- jbyteArray arr = env->NewByteArray(array.size());
- PoolVector<uint8_t>::Read r = array.read();
- env->SetByteArrayRegion(arr, 0, array.size(), reinterpret_cast<const signed char *>(r.ptr()));
- v.val.l = arr;
- v.obj = arr;
-
- } break;
- case Variant::POOL_REAL_ARRAY: {
-
- PoolVector<float> array = *p_arg;
- jfloatArray arr = env->NewFloatArray(array.size());
- PoolVector<float>::Read r = array.read();
- env->SetFloatArrayRegion(arr, 0, array.size(), r.ptr());
- v.val.l = arr;
- v.obj = arr;
-
- } break;
- default: {
-
- v.val.i = 0;
- } break;
- }
- return v;
-}
-
-String _get_class_name(JNIEnv *env, jclass cls, bool *array) {
-
- jclass cclass = env->FindClass("java/lang/Class");
- jmethodID getName = env->GetMethodID(cclass, "getName", "()Ljava/lang/String;");
- jstring clsName = (jstring)env->CallObjectMethod(cls, getName);
-
- if (array) {
- jmethodID isArray = env->GetMethodID(cclass, "isArray", "()Z");
- jboolean isarr = env->CallBooleanMethod(cls, isArray);
- (*array) = isarr ? true : false;
- }
- String name = jstring_to_string(clsName, env);
- env->DeleteLocalRef(clsName);
-
- return name;
-}
-
-Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
-
- if (obj == NULL) {
- return Variant();
- }
-
- jclass c = env->GetObjectClass(obj);
- bool array;
- String name = _get_class_name(env, c, &array);
-
- if (name == "java.lang.String") {
-
- return jstring_to_string((jstring)obj, env);
- };
-
- if (name == "[Ljava.lang.String;") {
-
- jobjectArray arr = (jobjectArray)obj;
- int stringCount = env->GetArrayLength(arr);
- PoolVector<String> sarr;
-
- for (int i = 0; i < stringCount; i++) {
- jstring string = (jstring)env->GetObjectArrayElement(arr, i);
- sarr.push_back(jstring_to_string(string, env));
- env->DeleteLocalRef(string);
- }
-
- return sarr;
- };
-
- if (name == "java.lang.Boolean") {
-
- jmethodID boolValue = env->GetMethodID(c, "booleanValue", "()Z");
- bool ret = env->CallBooleanMethod(obj, boolValue);
- return ret;
- };
-
- if (name == "java.lang.Integer" || name == "java.lang.Long") {
-
- jclass nclass = env->FindClass("java/lang/Number");
- jmethodID longValue = env->GetMethodID(nclass, "longValue", "()J");
- jlong ret = env->CallLongMethod(obj, longValue);
- return ret;
- };
-
- if (name == "[I") {
-
- jintArray arr = (jintArray)obj;
- int fCount = env->GetArrayLength(arr);
- PoolVector<int> sarr;
- sarr.resize(fCount);
-
- PoolVector<int>::Write w = sarr.write();
- env->GetIntArrayRegion(arr, 0, fCount, w.ptr());
- w.release();
- return sarr;
- };
-
- if (name == "[B") {
-
- jbyteArray arr = (jbyteArray)obj;
- int fCount = env->GetArrayLength(arr);
- PoolVector<uint8_t> sarr;
- sarr.resize(fCount);
-
- PoolVector<uint8_t>::Write w = sarr.write();
- env->GetByteArrayRegion(arr, 0, fCount, reinterpret_cast<signed char *>(w.ptr()));
- w.release();
- return sarr;
- };
-
- if (name == "java.lang.Float" || name == "java.lang.Double") {
-
- jclass nclass = env->FindClass("java/lang/Number");
- jmethodID doubleValue = env->GetMethodID(nclass, "doubleValue", "()D");
- double ret = env->CallDoubleMethod(obj, doubleValue);
- return ret;
- };
-
- if (name == "[D") {
-
- jdoubleArray arr = (jdoubleArray)obj;
- int fCount = env->GetArrayLength(arr);
- PoolRealArray sarr;
- sarr.resize(fCount);
-
- PoolRealArray::Write w = sarr.write();
-
- for (int i = 0; i < fCount; i++) {
-
- double n;
- env->GetDoubleArrayRegion(arr, i, 1, &n);
- w.ptr()[i] = n;
- };
- return sarr;
- };
-
- if (name == "[F") {
-
- jfloatArray arr = (jfloatArray)obj;
- int fCount = env->GetArrayLength(arr);
- PoolRealArray sarr;
- sarr.resize(fCount);
-
- PoolRealArray::Write w = sarr.write();
-
- for (int i = 0; i < fCount; i++) {
-
- float n;
- env->GetFloatArrayRegion(arr, i, 1, &n);
- w.ptr()[i] = n;
- };
- return sarr;
- };
-
- if (name == "[Ljava.lang.Object;") {
-
- jobjectArray arr = (jobjectArray)obj;
- int objCount = env->GetArrayLength(arr);
- Array varr;
-
- for (int i = 0; i < objCount; i++) {
- jobject jobj = env->GetObjectArrayElement(arr, i);
- Variant v = _jobject_to_variant(env, jobj);
- varr.push_back(v);
- env->DeleteLocalRef(jobj);
- }
-
- return varr;
- };
-
- if (name == "java.util.HashMap" || name == "org.godotengine.godot.Dictionary") {
-
- Dictionary ret;
- jclass oclass = c;
- jmethodID get_keys = env->GetMethodID(oclass, "get_keys", "()[Ljava/lang/String;");
- jobjectArray arr = (jobjectArray)env->CallObjectMethod(obj, get_keys);
-
- PoolStringArray keys = _jobject_to_variant(env, arr);
- env->DeleteLocalRef(arr);
-
- jmethodID get_values = env->GetMethodID(oclass, "get_values", "()[Ljava/lang/Object;");
- arr = (jobjectArray)env->CallObjectMethod(obj, get_values);
-
- Array vals = _jobject_to_variant(env, arr);
- env->DeleteLocalRef(arr);
-
- for (int i = 0; i < keys.size(); i++) {
-
- ret[keys[i]] = vals[i];
- };
-
- return ret;
- };
-
- env->DeleteLocalRef(c);
-
- return Variant();
-}
-
-class JNISingleton : public Object {
-
- GDCLASS(JNISingleton, Object);
-
- struct MethodData {
-
- jmethodID method;
- Variant::Type ret_type;
- Vector<Variant::Type> argtypes;
- };
-
- jobject instance;
- Map<StringName, MethodData> method_map;
-
-public:
- virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
-
- ERR_FAIL_COND_V(!instance, Variant());
-
- r_error.error = Variant::CallError::CALL_OK;
-
- Map<StringName, MethodData>::Element *E = method_map.find(p_method);
- if (!E) {
-
- r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
-
- int ac = E->get().argtypes.size();
- if (ac < p_argcount) {
-
- r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = ac;
- return Variant();
- }
-
- if (ac > p_argcount) {
-
- r_error.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = ac;
- return Variant();
- }
-
- for (int i = 0; i < p_argcount; i++) {
-
- if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
-
- r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = i;
- r_error.expected = E->get().argtypes[i];
- }
- }
-
- jvalue *v = NULL;
-
- if (p_argcount) {
-
- v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
- }
-
- JNIEnv *env = ThreadAndroid::get_env();
-
- int res = env->PushLocalFrame(16);
-
- ERR_FAIL_COND_V(res != 0, Variant());
-
- List<jobject> to_erase;
- for (int i = 0; i < p_argcount; i++) {
-
- jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
- v[i] = vr.val;
- if (vr.obj)
- to_erase.push_back(vr.obj);
- }
-
- Variant ret;
-
- switch (E->get().ret_type) {
-
- case Variant::NIL: {
-
- env->CallVoidMethodA(instance, E->get().method, v);
- } break;
- case Variant::BOOL: {
-
- ret = env->CallBooleanMethodA(instance, E->get().method, v) == JNI_TRUE;
- } break;
- case Variant::INT: {
-
- ret = env->CallIntMethodA(instance, E->get().method, v);
- } break;
- case Variant::REAL: {
-
- ret = env->CallFloatMethodA(instance, E->get().method, v);
- } break;
- case Variant::STRING: {
-
- jobject o = env->CallObjectMethodA(instance, E->get().method, v);
- ret = jstring_to_string((jstring)o, env);
- env->DeleteLocalRef(o);
- } break;
- case Variant::POOL_STRING_ARRAY: {
-
- jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- ret = _jobject_to_variant(env, arr);
-
- env->DeleteLocalRef(arr);
- } break;
- case Variant::POOL_INT_ARRAY: {
-
- jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- PoolVector<int> sarr;
- sarr.resize(fCount);
-
- PoolVector<int>::Write w = sarr.write();
- env->GetIntArrayRegion(arr, 0, fCount, w.ptr());
- w.release();
- ret = sarr;
- env->DeleteLocalRef(arr);
- } break;
- case Variant::POOL_REAL_ARRAY: {
-
- jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
-
- int fCount = env->GetArrayLength(arr);
- PoolVector<float> sarr;
- sarr.resize(fCount);
-
- PoolVector<float>::Write w = sarr.write();
- env->GetFloatArrayRegion(arr, 0, fCount, w.ptr());
- w.release();
- ret = sarr;
- env->DeleteLocalRef(arr);
- } break;
-
- case Variant::DICTIONARY: {
-
- jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
- ret = _jobject_to_variant(env, obj);
- env->DeleteLocalRef(obj);
-
- } break;
- default: {
-
- env->PopLocalFrame(NULL);
- ERR_FAIL_V(Variant());
- } break;
- }
-
- while (to_erase.size()) {
- env->DeleteLocalRef(to_erase.front()->get());
- to_erase.pop_front();
- }
-
- env->PopLocalFrame(NULL);
-
- return ret;
- }
-
- jobject get_instance() const {
-
- return instance;
- }
- void set_instance(jobject p_instance) {
-
- instance = p_instance;
- }
-
- void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
-
- MethodData md;
- md.method = p_method;
- md.argtypes = p_args;
- md.ret_type = p_ret_type;
- method_map[p_name] = md;
- }
-
- JNISingleton() {
- instance = NULL;
- }
-};
-
-struct TST {
-
- int a;
- TST() {
-
- a = 5;
- }
-};
-
-TST tst;
-
static bool initialized = false;
static int step = 0;
@@ -600,20 +63,16 @@ static Vector3 accelerometer;
static Vector3 gravity;
static Vector3 magnetometer;
static Vector3 gyroscope;
-static HashMap<String, JNISingleton *> jni_singletons;
-// virtual Error native_video_play(String p_path);
-// virtual bool native_video_is_playing();
-// virtual void native_video_pause();
-// virtual void native_video_stop();
+extern "C" {
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jclass clazz, jint 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) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject activity, jobject p_asset_manager, jboolean p_use_apk_expansion) {
initialized = true;
@@ -646,7 +105,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
godot_java->on_video_init(env);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jobject obj, jobject activity) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz, jobject activity) {
// lets cleanup
if (godot_io_java) {
delete godot_io_java;
@@ -659,47 +118,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env
}
}
-static void _initialize_java_modules() {
-
- if (!ProjectSettings::get_singleton()->has_setting("android/modules")) {
- return;
- }
-
- String modules = ProjectSettings::get_singleton()->get("android/modules");
- modules = modules.strip_edges();
- if (modules == String()) {
- return;
- }
- Vector<String> mods = modules.split(",", false);
-
- if (mods.size()) {
- jobject cls = godot_java->get_class_loader();
-
- // 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++) {
-
- String m = mods[i];
-
- print_line("Loading Android module: " + m);
- jstring strClassName = env->NewStringUTF(m.utf8().get_data());
- jclass singletonClass = (jclass)env->CallObjectMethod(cls, findClass, strClassName);
- ERR_CONTINUE_MSG(!singletonClass, "Couldn't find singleton for class: " + m + ".");
-
- jmethodID initialize = env->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lorg/godotengine/godot/Godot$SingletonBase;");
- ERR_CONTINUE_MSG(!initialize, "Couldn't find proper initialize function 'public static Godot.SingletonBase Class::initialize(Activity p_activity)' initializer for singleton class: " + m + ".");
-
- jobject obj = env->CallStaticObjectMethod(singletonClass, initialize, godot_java->get_activity());
- env->NewGlobalRef(obj);
- }
- }
-}
-
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jobject obj, jobjectArray p_cmdline) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline) {
ThreadAndroid::setup_thread();
const char **cmdline = NULL;
@@ -739,16 +158,15 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
}
java_class_wrapper = memnew(JavaClassWrapper(godot_java->get_activity()));
- _initialize_java_modules();
}
-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_resize(JNIEnv *env, jclass clazz, jint width, jint height) {
if (os_android)
os_android->set_display_size(Size2(width, height));
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jobject obj, bool p_32_bits) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jboolean p_32_bits) {
if (os_android) {
if (step == 0) {
@@ -763,14 +181,14 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en
}
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz) {
if (step == 0)
return;
os_android->main_loop_request_go_back();
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz) {
if (step == -1)
return;
@@ -789,6 +207,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job
}
os_android->main_loop_begin();
+ godot_java->on_gl_godot_main_loop_started(env);
++step;
}
@@ -803,7 +222,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job
}
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jobject obj, jint ev, jint pointer, jint count, jintArray positions) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint count, jintArray positions) {
if (step == 0)
return;
@@ -827,282 +246,28 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jo
*/
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jobject obj, jint p_type, jint p_x, jint p_y) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jint p_x, jint p_y) {
if (step == 0)
return;
os_android->process_hover(p_type, Point2(p_x, p_y));
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubletap(JNIEnv *env, jobject obj, jint p_x, jint p_y) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubletap(JNIEnv *env, jclass clazz, jint p_x, jint p_y) {
if (step == 0)
return;
os_android->process_double_tap(Point2(p_x, p_y));
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jobject obj, jint p_x, jint p_y) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y) {
if (step == 0)
return;
os_android->process_scroll(Point2(p_x, p_y));
}
-/*
- * Android Key codes.
- */
-enum {
- AKEYCODE_UNKNOWN = 0,
- AKEYCODE_SOFT_LEFT = 1,
- AKEYCODE_SOFT_RIGHT = 2,
- AKEYCODE_HOME = 3,
- AKEYCODE_BACK = 4,
- AKEYCODE_CALL = 5,
- AKEYCODE_ENDCALL = 6,
- AKEYCODE_0 = 7,
- AKEYCODE_1 = 8,
- AKEYCODE_2 = 9,
- AKEYCODE_3 = 10,
- AKEYCODE_4 = 11,
- AKEYCODE_5 = 12,
- AKEYCODE_6 = 13,
- AKEYCODE_7 = 14,
- AKEYCODE_8 = 15,
- AKEYCODE_9 = 16,
- AKEYCODE_STAR = 17,
- AKEYCODE_POUND = 18,
- AKEYCODE_DPAD_UP = 19,
- AKEYCODE_DPAD_DOWN = 20,
- AKEYCODE_DPAD_LEFT = 21,
- AKEYCODE_DPAD_RIGHT = 22,
- AKEYCODE_DPAD_CENTER = 23,
- AKEYCODE_VOLUME_UP = 24,
- AKEYCODE_VOLUME_DOWN = 25,
- AKEYCODE_POWER = 26,
- AKEYCODE_CAMERA = 27,
- AKEYCODE_CLEAR = 28,
- AKEYCODE_A = 29,
- AKEYCODE_B = 30,
- AKEYCODE_C = 31,
- AKEYCODE_D = 32,
- AKEYCODE_E = 33,
- AKEYCODE_F = 34,
- AKEYCODE_G = 35,
- AKEYCODE_H = 36,
- AKEYCODE_I = 37,
- AKEYCODE_J = 38,
- AKEYCODE_K = 39,
- AKEYCODE_L = 40,
- AKEYCODE_M = 41,
- AKEYCODE_N = 42,
- AKEYCODE_O = 43,
- AKEYCODE_P = 44,
- AKEYCODE_Q = 45,
- AKEYCODE_R = 46,
- AKEYCODE_S = 47,
- AKEYCODE_T = 48,
- AKEYCODE_U = 49,
- AKEYCODE_V = 50,
- AKEYCODE_W = 51,
- AKEYCODE_X = 52,
- AKEYCODE_Y = 53,
- AKEYCODE_Z = 54,
- AKEYCODE_COMMA = 55,
- AKEYCODE_PERIOD = 56,
- AKEYCODE_ALT_LEFT = 57,
- AKEYCODE_ALT_RIGHT = 58,
- AKEYCODE_SHIFT_LEFT = 59,
- AKEYCODE_SHIFT_RIGHT = 60,
- AKEYCODE_TAB = 61,
- AKEYCODE_SPACE = 62,
- AKEYCODE_SYM = 63,
- AKEYCODE_EXPLORER = 64,
- AKEYCODE_ENVELOPE = 65,
- AKEYCODE_ENTER = 66,
- AKEYCODE_DEL = 67,
- AKEYCODE_GRAVE = 68,
- AKEYCODE_MINUS = 69,
- AKEYCODE_EQUALS = 70,
- AKEYCODE_LEFT_BRACKET = 71,
- AKEYCODE_RIGHT_BRACKET = 72,
- AKEYCODE_BACKSLASH = 73,
- AKEYCODE_SEMICOLON = 74,
- AKEYCODE_APOSTROPHE = 75,
- AKEYCODE_SLASH = 76,
- AKEYCODE_AT = 77,
- AKEYCODE_NUM = 78,
- AKEYCODE_HEADSETHOOK = 79,
- AKEYCODE_FOCUS = 80, // *Camera* focus
- AKEYCODE_PLUS = 81,
- AKEYCODE_MENU = 82,
- AKEYCODE_NOTIFICATION = 83,
- AKEYCODE_SEARCH = 84,
- AKEYCODE_MEDIA_PLAY_PAUSE = 85,
- AKEYCODE_MEDIA_STOP = 86,
- AKEYCODE_MEDIA_NEXT = 87,
- AKEYCODE_MEDIA_PREVIOUS = 88,
- AKEYCODE_MEDIA_REWIND = 89,
- AKEYCODE_MEDIA_FAST_FORWARD = 90,
- AKEYCODE_MUTE = 91,
- AKEYCODE_PAGE_UP = 92,
- AKEYCODE_PAGE_DOWN = 93,
- AKEYCODE_PICTSYMBOLS = 94,
- AKEYCODE_SWITCH_CHARSET = 95,
- AKEYCODE_BUTTON_A = 96,
- AKEYCODE_BUTTON_B = 97,
- AKEYCODE_BUTTON_C = 98,
- AKEYCODE_BUTTON_X = 99,
- AKEYCODE_BUTTON_Y = 100,
- AKEYCODE_BUTTON_Z = 101,
- AKEYCODE_BUTTON_L1 = 102,
- AKEYCODE_BUTTON_R1 = 103,
- AKEYCODE_BUTTON_L2 = 104,
- AKEYCODE_BUTTON_R2 = 105,
- AKEYCODE_BUTTON_THUMBL = 106,
- AKEYCODE_BUTTON_THUMBR = 107,
- AKEYCODE_BUTTON_START = 108,
- AKEYCODE_BUTTON_SELECT = 109,
- AKEYCODE_BUTTON_MODE = 110,
-
- // NOTE: If you add a new keycode here you must also add it to several other files.
- // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
-};
-
-struct _WinTranslatePair {
-
- unsigned int keysym;
- unsigned int keycode;
-};
-
-static _WinTranslatePair _ak_to_keycode[] = {
- { KEY_TAB, AKEYCODE_TAB },
- { KEY_ENTER, AKEYCODE_ENTER },
- { KEY_SHIFT, AKEYCODE_SHIFT_LEFT },
- { KEY_SHIFT, AKEYCODE_SHIFT_RIGHT },
- { KEY_ALT, AKEYCODE_ALT_LEFT },
- { KEY_ALT, AKEYCODE_ALT_RIGHT },
- { KEY_MENU, AKEYCODE_MENU },
- { KEY_PAUSE, AKEYCODE_MEDIA_PLAY_PAUSE },
- { KEY_ESCAPE, AKEYCODE_BACK },
- { KEY_SPACE, AKEYCODE_SPACE },
- { KEY_PAGEUP, AKEYCODE_PAGE_UP },
- { KEY_PAGEDOWN, AKEYCODE_PAGE_DOWN },
- { KEY_HOME, AKEYCODE_HOME }, //(0x24)
- { KEY_LEFT, AKEYCODE_DPAD_LEFT },
- { KEY_UP, AKEYCODE_DPAD_UP },
- { KEY_RIGHT, AKEYCODE_DPAD_RIGHT },
- { KEY_DOWN, AKEYCODE_DPAD_DOWN },
- { KEY_PERIODCENTERED, AKEYCODE_DPAD_CENTER },
- { KEY_BACKSPACE, AKEYCODE_DEL },
- { KEY_0, AKEYCODE_0 }, ////0 key
- { KEY_1, AKEYCODE_1 }, ////1 key
- { KEY_2, AKEYCODE_2 }, ////2 key
- { KEY_3, AKEYCODE_3 }, ////3 key
- { KEY_4, AKEYCODE_4 }, ////4 key
- { KEY_5, AKEYCODE_5 }, ////5 key
- { KEY_6, AKEYCODE_6 }, ////6 key
- { KEY_7, AKEYCODE_7 }, ////7 key
- { KEY_8, AKEYCODE_8 }, ////8 key
- { KEY_9, AKEYCODE_9 }, ////9 key
- { KEY_A, AKEYCODE_A }, ////A key
- { KEY_B, AKEYCODE_B }, ////B key
- { KEY_C, AKEYCODE_C }, ////C key
- { KEY_D, AKEYCODE_D }, ////D key
- { KEY_E, AKEYCODE_E }, ////E key
- { KEY_F, AKEYCODE_F }, ////F key
- { KEY_G, AKEYCODE_G }, ////G key
- { KEY_H, AKEYCODE_H }, ////H key
- { KEY_I, AKEYCODE_I }, ////I key
- { KEY_J, AKEYCODE_J }, ////J key
- { KEY_K, AKEYCODE_K }, ////K key
- { KEY_L, AKEYCODE_L }, ////L key
- { KEY_M, AKEYCODE_M }, ////M key
- { KEY_N, AKEYCODE_N }, ////N key
- { KEY_O, AKEYCODE_O }, ////O key
- { KEY_P, AKEYCODE_P }, ////P key
- { KEY_Q, AKEYCODE_Q }, ////Q key
- { KEY_R, AKEYCODE_R }, ////R key
- { KEY_S, AKEYCODE_S }, ////S key
- { KEY_T, AKEYCODE_T }, ////T key
- { KEY_U, AKEYCODE_U }, ////U key
- { KEY_V, AKEYCODE_V }, ////V key
- { KEY_W, AKEYCODE_W }, ////W key
- { KEY_X, AKEYCODE_X }, ////X key
- { KEY_Y, AKEYCODE_Y }, ////Y key
- { KEY_Z, AKEYCODE_Z }, ////Z key
- { KEY_HOMEPAGE, AKEYCODE_EXPLORER },
- { KEY_LAUNCH0, AKEYCODE_BUTTON_A },
- { KEY_LAUNCH1, AKEYCODE_BUTTON_B },
- { KEY_LAUNCH2, AKEYCODE_BUTTON_C },
- { KEY_LAUNCH3, AKEYCODE_BUTTON_X },
- { KEY_LAUNCH4, AKEYCODE_BUTTON_Y },
- { KEY_LAUNCH5, AKEYCODE_BUTTON_Z },
- { KEY_LAUNCH6, AKEYCODE_BUTTON_L1 },
- { KEY_LAUNCH7, AKEYCODE_BUTTON_R1 },
- { KEY_LAUNCH8, AKEYCODE_BUTTON_L2 },
- { KEY_LAUNCH9, AKEYCODE_BUTTON_R2 },
- { KEY_LAUNCHA, AKEYCODE_BUTTON_THUMBL },
- { KEY_LAUNCHB, AKEYCODE_BUTTON_THUMBR },
- { KEY_LAUNCHC, AKEYCODE_BUTTON_START },
- { KEY_LAUNCHD, AKEYCODE_BUTTON_SELECT },
- { KEY_LAUNCHE, AKEYCODE_BUTTON_MODE },
- { KEY_VOLUMEMUTE, AKEYCODE_MUTE },
- { KEY_VOLUMEDOWN, AKEYCODE_VOLUME_DOWN },
- { KEY_VOLUMEUP, AKEYCODE_VOLUME_UP },
- { KEY_BACK, AKEYCODE_MEDIA_REWIND },
- { KEY_FORWARD, AKEYCODE_MEDIA_FAST_FORWARD },
- { KEY_MEDIANEXT, AKEYCODE_MEDIA_NEXT },
- { KEY_MEDIAPREVIOUS, AKEYCODE_MEDIA_PREVIOUS },
- { KEY_MEDIASTOP, AKEYCODE_MEDIA_STOP },
- { KEY_PLUS, AKEYCODE_PLUS },
- { KEY_EQUAL, AKEYCODE_EQUALS }, // the '+' key
- { KEY_COMMA, AKEYCODE_COMMA }, // the ',' key
- { KEY_MINUS, AKEYCODE_MINUS }, // the '-' key
- { KEY_SLASH, AKEYCODE_SLASH }, // the '/?' key
- { KEY_BACKSLASH, AKEYCODE_BACKSLASH },
- { KEY_BRACKETLEFT, AKEYCODE_LEFT_BRACKET },
- { KEY_BRACKETRIGHT, AKEYCODE_RIGHT_BRACKET },
- { KEY_UNKNOWN, 0 }
-};
-/*
-TODO: map these android key:
- AKEYCODE_SOFT_LEFT = 1,
- AKEYCODE_SOFT_RIGHT = 2,
- AKEYCODE_CALL = 5,
- AKEYCODE_ENDCALL = 6,
- AKEYCODE_STAR = 17,
- AKEYCODE_POUND = 18,
- AKEYCODE_POWER = 26,
- AKEYCODE_CAMERA = 27,
- AKEYCODE_CLEAR = 28,
- AKEYCODE_SYM = 63,
- AKEYCODE_ENVELOPE = 65,
- AKEYCODE_GRAVE = 68,
- AKEYCODE_SEMICOLON = 74,
- AKEYCODE_APOSTROPHE = 75,
- AKEYCODE_AT = 77,
- AKEYCODE_NUM = 78,
- AKEYCODE_HEADSETHOOK = 79,
- AKEYCODE_FOCUS = 80, // *Camera* focus
- AKEYCODE_NOTIFICATION = 83,
- AKEYCODE_SEARCH = 84,
- AKEYCODE_PICTSYMBOLS = 94,
- AKEYCODE_SWITCH_CHARSET = 95,
-*/
-
-static unsigned int android_get_keysym(unsigned int p_code) {
- for (int i = 0; _ak_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
-
- if (_ak_to_keycode[i].keycode == p_code) {
-
- return _ak_to_keycode[i].keysym;
- }
- }
-
- return KEY_UNKNOWN;
-}
-
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jobject obj, jint p_device, jint p_button, jboolean p_pressed) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed) {
if (step == 0)
return;
@@ -1115,7 +280,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env
os_android->process_joy_event(jevent);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jobject obj, jint p_device, jint p_axis, jfloat p_value) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value) {
if (step == 0)
return;
@@ -1128,7 +293,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env,
os_android->process_joy_event(jevent);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jobject obj, jint p_device, jint p_hat_x, jint p_hat_y) {
+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 == 0)
return;
@@ -1153,58 +318,59 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j
os_android->process_joy_event(jevent);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jobject obj, jint p_device, jboolean p_connected, jstring p_name) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jclass clazz, jint p_device, jboolean p_connected, jstring p_name) {
if (os_android) {
String name = jstring_to_string(p_name, env);
os_android->joy_connection_changed(p_device, p_connected, name);
}
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed) {
+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 == 0)
return;
Ref<InputEventKey> ievent;
ievent.instance();
int val = p_unicode_char;
- int scancode = android_get_keysym(p_scancode);
- ievent->set_scancode(scancode);
+ int keycode = android_get_keysym(p_keycode);
+ int phy_keycode = android_get_keysym(p_scancode);
+ ievent->set_keycode(keycode);
+ ievent->set_physical_keycode(phy_keycode);
ievent->set_unicode(val);
ievent->set_pressed(p_pressed);
if (val == '\n') {
- ievent->set_scancode(KEY_ENTER);
+ ievent->set_keycode(KEY_ENTER);
} else if (val == 61448) {
- ievent->set_scancode(KEY_BACKSPACE);
+ ievent->set_keycode(KEY_BACKSPACE);
ievent->set_unicode(KEY_BACKSPACE);
} else if (val == 61453) {
- ievent->set_scancode(KEY_ENTER);
+ ievent->set_keycode(KEY_ENTER);
ievent->set_unicode(KEY_ENTER);
- } else if (p_scancode == 4) {
-
+ } else if (p_keycode == 4) {
os_android->main_loop_request_go_back();
}
os_android->process_event(ievent);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) {
accelerometer = Vector3(x, y, z);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) {
gravity = Vector3(x, y, z);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) {
magnetometer = Vector3(x, y, z);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) {
gyroscope = Vector3(x, y, z);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jobject obj) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jclass clazz) {
if (step == 0)
return;
@@ -1212,7 +378,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env,
os_android->main_loop_focusin();
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, jobject obj) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, jclass clazz) {
if (step == 0)
return;
@@ -1220,134 +386,22 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env,
os_android->main_loop_focusout();
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jobject obj) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jclass clazz) {
ThreadAndroid::setup_thread();
AudioDriverAndroid::thread_func(env);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv *env, jobject obj, jstring name, jobject p_object) {
-
- String singname = jstring_to_string(name, env);
- JNISingleton *s = memnew(JNISingleton);
- s->set_instance(env->NewGlobalRef(p_object));
- jni_singletons[singname] = s;
-
- Engine::get_singleton()->add_singleton(Engine::Singleton(singname, s));
- ProjectSettings::get_singleton()->set(singname, s);
-}
-
-static Variant::Type get_jni_type(const String &p_type) {
-
- static struct {
- const char *name;
- Variant::Type type;
- } _type_to_vtype[] = {
- { "void", Variant::NIL },
- { "boolean", Variant::BOOL },
- { "int", Variant::INT },
- { "float", Variant::REAL },
- { "double", Variant::REAL },
- { "java.lang.String", Variant::STRING },
- { "[I", Variant::POOL_INT_ARRAY },
- { "[B", Variant::POOL_BYTE_ARRAY },
- { "[F", Variant::POOL_REAL_ARRAY },
- { "[Ljava.lang.String;", Variant::POOL_STRING_ARRAY },
- { "org.godotengine.godot.Dictionary", Variant::DICTIONARY },
- { NULL, Variant::NIL }
- };
-
- int idx = 0;
-
- while (_type_to_vtype[idx].name) {
-
- if (p_type == _type_to_vtype[idx].name)
- return _type_to_vtype[idx].type;
-
- idx++;
- }
-
- return Variant::NIL;
-}
-
-static const char *get_jni_sig(const String &p_type) {
-
- static struct {
- const char *name;
- const char *sig;
- } _type_to_vtype[] = {
- { "void", "V" },
- { "boolean", "Z" },
- { "int", "I" },
- { "float", "F" },
- { "double", "D" },
- { "java.lang.String", "Ljava/lang/String;" },
- { "org.godotengine.godot.Dictionary", "Lorg/godotengine/godot/Dictionary;" },
- { "[I", "[I" },
- { "[B", "[B" },
- { "[F", "[F" },
- { "[Ljava.lang.String;", "[Ljava/lang/String;" },
- { NULL, "V" }
- };
-
- int idx = 0;
-
- while (_type_to_vtype[idx].name) {
-
- if (p_type == _type_to_vtype[idx].name)
- return _type_to_vtype[idx].sig;
-
- idx++;
- }
-
- return "Ljava/lang/Object;";
-}
-
-JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jobject obj, jstring path) {
+JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jclass clazz, jstring path) {
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 = jstring_to_string(sname, env);
-
- ERR_FAIL_COND(!jni_singletons.has(singname));
-
- JNISingleton *s = jni_singletons.get(singname);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jint ID, jstring method, jobjectArray params) {
- String mname = jstring_to_string(name, env);
- String retval = jstring_to_string(ret, env);
- Vector<Variant::Type> types;
- String cs = "(";
-
- int stringCount = env->GetArrayLength(args);
-
- for (int i = 0; i < stringCount; i++) {
-
- jstring string = (jstring)env->GetObjectArrayElement(args, i);
- const String rawString = jstring_to_string(string, env);
- types.push_back(get_jni_type(rawString));
- cs += get_jni_sig(rawString);
- }
-
- cs += ")";
- cs += get_jni_sig(retval);
- jclass cls = env->GetObjectClass(s->get_instance());
- jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
- if (!mid) {
-
- print_line("Failed getting method ID " + mname);
- }
-
- s->add_method(mname, mid, types, get_jni_type(retval));
-}
-
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params) {
-
- Object *obj = ObjectDB::get_instance(ID);
+ Object *obj = ObjectDB::get_instance(ObjectID((uint64_t)ID));
ERR_FAIL_COND(!obj);
int res = env->PushLocalFrame(16);
@@ -1370,16 +424,16 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *en
env->DeleteLocalRef(obj);
};
- Variant::CallError err;
+ Callable::CallError err;
obj->call(str_method, (const Variant **)vptr, count, err);
// something
env->PopLocalFrame(NULL);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jint ID, jstring method, jobjectArray params) {
- Object *obj = ObjectDB::get_instance(ID);
+ Object *obj = ObjectDB::get_instance(ObjectID((uint64_t)ID));
ERR_FAIL_COND(!obj);
int res = env->PushLocalFrame(16);
@@ -1403,7 +457,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *
env->PopLocalFrame(NULL);
}
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jobject p_obj, jstring p_permission, jboolean p_result) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jclass clazz, jstring p_permission, jboolean p_result) {
String permission = jstring_to_string(p_permission, env);
if (permission == "android.permission.RECORD_AUDIO" && p_result) {
AudioDriver::get_singleton()->capture_start();
@@ -1431,3 +485,4 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIE
os_android->get_main_loop()->notification(MainLoop::NOTIFICATION_APP_PAUSED);
}
}
+}
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 71d4547f65..a7a5970440 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -37,36 +37,34 @@
// 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 that's 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, jobject obj, jobject activity);
-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);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jobject obj);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jobject obj);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jobject obj, jint ev, jint pointer, jint count, jintArray positions);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jobject obj, jint p_type, jint p_x, jint p_y);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubletap(JNIEnv *env, jobject obj, jint p_x, jint p_y);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jobject obj, jint p_x, jint p_y);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jobject obj, jint p_device, jint p_button, jboolean p_pressed);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jobject obj, jint p_device, jint p_axis, jfloat p_value);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jobject obj, jint p_device, jint p_hat_x, jint p_hat_y);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jobject obj, jint p_device, jboolean p_connected, jstring p_name);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jobject obj);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jobject obj);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, jobject obj);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv *env, jobject obj, jstring name, jobject p_object);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
-JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jobject obj, jstring path);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jobject p_obj, jstring p_permission, jboolean p_result);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jclass clazz, jobject activity, jobject p_asset_manager, jboolean p_use_apk_expansion);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ondestroy(JNIEnv *env, jclass clazz, jobject activity);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jclass clazz, jobjectArray p_cmdline);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv *env, jclass clazz, jint width, jint height);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *env, jclass clazz, jboolean p_32_bits);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint count, jintArray positions);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jint p_x, jint p_y);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubletap(JNIEnv *env, jclass clazz, jint p_x, jint p_y);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y);
+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);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jclass clazz, jint p_device, jboolean p_connected, jstring p_name);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jclass clazz);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jclass clazz);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, jclass clazz);
+JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jclass clazz, jstring path);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jint ID, jstring method, jobjectArray params);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jint ID, jstring method, jobjectArray params);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jclass clazz, jint p_height);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jclass clazz, jstring p_permission, jboolean p_result);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIEnv *env, jclass clazz);
}
diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp
index 893b786c0b..7b677c186e 100644
--- a/platform/android/java_godot_wrapper.cpp
+++ b/platform/android/java_godot_wrapper.cpp
@@ -66,6 +66,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) {
_is_activity_resumed = p_env->GetMethodID(cls, "isActivityResumed", "()Z");
_vibrate = p_env->GetMethodID(cls, "vibrate", "(I)V");
_get_input_fallback_mapping = p_env->GetMethodID(cls, "getInputFallbackMapping", "()Ljava/lang/String;");
+ _on_gl_godot_main_loop_started = p_env->GetMethodID(cls, "onGLGodotMainLoopStarted", "()V");
}
GodotJavaWrapper::~GodotJavaWrapper() {
@@ -99,13 +100,6 @@ jobject GodotJavaWrapper::get_class_loader() {
}
}
-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)
@@ -114,6 +108,15 @@ void GodotJavaWrapper::on_video_init(JNIEnv *p_env) {
p_env->CallVoidMethod(godot_instance, _on_video_init);
}
+void GodotJavaWrapper::on_gl_godot_main_loop_started(JNIEnv *p_env) {
+ if (_on_gl_godot_main_loop_started) {
+ if (p_env == NULL) {
+ p_env = ThreadAndroid::get_env();
+ }
+ }
+ p_env->CallVoidMethod(godot_instance, _on_gl_godot_main_loop_started);
+}
+
void GodotJavaWrapper::restart(JNIEnv *p_env) {
if (_restart)
if (p_env == NULL)
diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h
index 655f5170bf..cdab2ecc9c 100644
--- a/platform/android/java_godot_wrapper.h
+++ b/platform/android/java_godot_wrapper.h
@@ -61,6 +61,7 @@ private:
jmethodID _is_activity_resumed = 0;
jmethodID _vibrate = 0;
jmethodID _get_input_fallback_mapping = 0;
+ jmethodID _on_gl_godot_main_loop_started = 0;
public:
GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance);
@@ -71,8 +72,8 @@ public:
jobject get_class_loader();
- void gfx_init(bool gl2);
void on_video_init(JNIEnv *p_env = NULL);
+ void on_gl_godot_main_loop_started(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);
diff --git a/platform/android/jni_utils.cpp b/platform/android/jni_utils.cpp
new file mode 100644
index 0000000000..3fa4e80884
--- /dev/null
+++ b/platform/android/jni_utils.cpp
@@ -0,0 +1,434 @@
+/*************************************************************************/
+/* jni_utils.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "jni_utils.h"
+
+jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_arg, bool force_jobject) {
+
+ jvalret v;
+
+ switch (p_type) {
+
+ case Variant::BOOL: {
+
+ if (force_jobject) {
+ jclass bclass = env->FindClass("java/lang/Boolean");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(Z)V");
+ jvalue val;
+ val.z = (bool)(*p_arg);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ v.val.l = obj;
+ v.obj = obj;
+ env->DeleteLocalRef(bclass);
+ } else {
+ v.val.z = *p_arg;
+ };
+ } break;
+ case Variant::INT: {
+
+ if (force_jobject) {
+
+ jclass bclass = env->FindClass("java/lang/Integer");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(I)V");
+ jvalue val;
+ val.i = (int)(*p_arg);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ v.val.l = obj;
+ v.obj = obj;
+ env->DeleteLocalRef(bclass);
+
+ } else {
+ v.val.i = *p_arg;
+ };
+ } break;
+ case Variant::FLOAT: {
+
+ if (force_jobject) {
+
+ jclass bclass = env->FindClass("java/lang/Double");
+ jmethodID ctor = env->GetMethodID(bclass, "<init>", "(D)V");
+ jvalue val;
+ val.d = (double)(*p_arg);
+ jobject obj = env->NewObjectA(bclass, ctor, &val);
+ v.val.l = obj;
+ v.obj = obj;
+ env->DeleteLocalRef(bclass);
+
+ } else {
+ v.val.f = *p_arg;
+ };
+ } break;
+ case Variant::STRING: {
+
+ String s = *p_arg;
+ jstring jStr = env->NewStringUTF(s.utf8().get_data());
+ v.val.l = jStr;
+ v.obj = jStr;
+ } break;
+ case Variant::PACKED_STRING_ARRAY: {
+
+ Vector<String> sarray = *p_arg;
+ jobjectArray arr = env->NewObjectArray(sarray.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
+
+ for (int j = 0; j < sarray.size(); j++) {
+
+ jstring str = env->NewStringUTF(sarray[j].utf8().get_data());
+ env->SetObjectArrayElement(arr, j, str);
+ env->DeleteLocalRef(str);
+ }
+ v.val.l = arr;
+ v.obj = arr;
+
+ } break;
+
+ case Variant::DICTIONARY: {
+
+ Dictionary dict = *p_arg;
+ jclass dclass = env->FindClass("org/godotengine/godot/Dictionary");
+ jmethodID ctor = env->GetMethodID(dclass, "<init>", "()V");
+ jobject jdict = env->NewObject(dclass, ctor);
+
+ Array keys = dict.keys();
+
+ jobjectArray jkeys = env->NewObjectArray(keys.size(), env->FindClass("java/lang/String"), env->NewStringUTF(""));
+ for (int j = 0; j < keys.size(); j++) {
+ jstring str = env->NewStringUTF(String(keys[j]).utf8().get_data());
+ env->SetObjectArrayElement(jkeys, j, str);
+ env->DeleteLocalRef(str);
+ };
+
+ jmethodID set_keys = env->GetMethodID(dclass, "set_keys", "([Ljava/lang/String;)V");
+ jvalue val;
+ val.l = jkeys;
+ env->CallVoidMethodA(jdict, set_keys, &val);
+ env->DeleteLocalRef(jkeys);
+
+ jobjectArray jvalues = env->NewObjectArray(keys.size(), env->FindClass("java/lang/Object"), NULL);
+
+ for (int j = 0; j < keys.size(); j++) {
+ Variant var = dict[keys[j]];
+ jvalret v = _variant_to_jvalue(env, var.get_type(), &var, true);
+ env->SetObjectArrayElement(jvalues, j, v.val.l);
+ if (v.obj) {
+ env->DeleteLocalRef(v.obj);
+ }
+ };
+
+ jmethodID set_values = env->GetMethodID(dclass, "set_values", "([Ljava/lang/Object;)V");
+ val.l = jvalues;
+ env->CallVoidMethodA(jdict, set_values, &val);
+ env->DeleteLocalRef(jvalues);
+ env->DeleteLocalRef(dclass);
+
+ v.val.l = jdict;
+ v.obj = jdict;
+ } break;
+
+ case Variant::PACKED_INT32_ARRAY: {
+
+ Vector<int> array = *p_arg;
+ jintArray arr = env->NewIntArray(array.size());
+ const int *r = array.ptr();
+ env->SetIntArrayRegion(arr, 0, array.size(), r);
+ v.val.l = arr;
+ v.obj = arr;
+
+ } break;
+ case Variant::PACKED_BYTE_ARRAY: {
+ Vector<uint8_t> array = *p_arg;
+ jbyteArray arr = env->NewByteArray(array.size());
+ const uint8_t *r = array.ptr();
+ env->SetByteArrayRegion(arr, 0, array.size(), reinterpret_cast<const signed char *>(r));
+ v.val.l = arr;
+ v.obj = arr;
+
+ } break;
+ case Variant::PACKED_FLOAT32_ARRAY: {
+
+ Vector<float> array = *p_arg;
+ jfloatArray arr = env->NewFloatArray(array.size());
+ const float *r = array.ptr();
+ env->SetFloatArrayRegion(arr, 0, array.size(), r);
+ v.val.l = arr;
+ v.obj = arr;
+
+ } break;
+#ifndef _MSC_VER
+#warning This is missing 64 bits arrays, I have no idea how to do it in JNI
+#endif
+
+ default: {
+
+ v.val.i = 0;
+ } break;
+ }
+ return v;
+}
+
+String _get_class_name(JNIEnv *env, jclass cls, bool *array) {
+
+ jclass cclass = env->FindClass("java/lang/Class");
+ jmethodID getName = env->GetMethodID(cclass, "getName", "()Ljava/lang/String;");
+ jstring clsName = (jstring)env->CallObjectMethod(cls, getName);
+
+ if (array) {
+ jmethodID isArray = env->GetMethodID(cclass, "isArray", "()Z");
+ jboolean isarr = env->CallBooleanMethod(cls, isArray);
+ (*array) = isarr ? true : false;
+ }
+ String name = jstring_to_string(clsName, env);
+ env->DeleteLocalRef(clsName);
+
+ return name;
+}
+
+Variant _jobject_to_variant(JNIEnv *env, jobject obj) {
+
+ if (obj == NULL) {
+ return Variant();
+ }
+
+ jclass c = env->GetObjectClass(obj);
+ bool array;
+ String name = _get_class_name(env, c, &array);
+
+ if (name == "java.lang.String") {
+
+ return jstring_to_string((jstring)obj, env);
+ };
+
+ if (name == "[Ljava.lang.String;") {
+
+ jobjectArray arr = (jobjectArray)obj;
+ int stringCount = env->GetArrayLength(arr);
+ Vector<String> sarr;
+
+ for (int i = 0; i < stringCount; i++) {
+ jstring string = (jstring)env->GetObjectArrayElement(arr, i);
+ sarr.push_back(jstring_to_string(string, env));
+ env->DeleteLocalRef(string);
+ }
+
+ return sarr;
+ };
+
+ if (name == "java.lang.Boolean") {
+
+ jmethodID boolValue = env->GetMethodID(c, "booleanValue", "()Z");
+ bool ret = env->CallBooleanMethod(obj, boolValue);
+ return ret;
+ };
+
+ if (name == "java.lang.Integer" || name == "java.lang.Long") {
+
+ jclass nclass = env->FindClass("java/lang/Number");
+ jmethodID longValue = env->GetMethodID(nclass, "longValue", "()J");
+ jlong ret = env->CallLongMethod(obj, longValue);
+ return ret;
+ };
+
+ if (name == "[I") {
+
+ jintArray arr = (jintArray)obj;
+ int fCount = env->GetArrayLength(arr);
+ Vector<int> sarr;
+ sarr.resize(fCount);
+
+ int *w = sarr.ptrw();
+ env->GetIntArrayRegion(arr, 0, fCount, w);
+ return sarr;
+ };
+
+ if (name == "[B") {
+
+ jbyteArray arr = (jbyteArray)obj;
+ int fCount = env->GetArrayLength(arr);
+ Vector<uint8_t> sarr;
+ sarr.resize(fCount);
+
+ uint8_t *w = sarr.ptrw();
+ env->GetByteArrayRegion(arr, 0, fCount, reinterpret_cast<signed char *>(w));
+ return sarr;
+ };
+
+ if (name == "java.lang.Float" || name == "java.lang.Double") {
+
+ jclass nclass = env->FindClass("java/lang/Number");
+ jmethodID doubleValue = env->GetMethodID(nclass, "doubleValue", "()D");
+ double ret = env->CallDoubleMethod(obj, doubleValue);
+ return ret;
+ };
+
+ if (name == "[D") {
+
+ jdoubleArray arr = (jdoubleArray)obj;
+ int fCount = env->GetArrayLength(arr);
+ PackedFloat32Array sarr;
+ sarr.resize(fCount);
+
+ real_t *w = sarr.ptrw();
+
+ for (int i = 0; i < fCount; i++) {
+
+ double n;
+ env->GetDoubleArrayRegion(arr, i, 1, &n);
+ w[i] = n;
+ };
+ return sarr;
+ };
+
+ if (name == "[F") {
+
+ jfloatArray arr = (jfloatArray)obj;
+ int fCount = env->GetArrayLength(arr);
+ PackedFloat32Array sarr;
+ sarr.resize(fCount);
+
+ real_t *w = sarr.ptrw();
+
+ for (int i = 0; i < fCount; i++) {
+
+ float n;
+ env->GetFloatArrayRegion(arr, i, 1, &n);
+ w[i] = n;
+ };
+ return sarr;
+ };
+
+ if (name == "[Ljava.lang.Object;") {
+
+ jobjectArray arr = (jobjectArray)obj;
+ int objCount = env->GetArrayLength(arr);
+ Array varr;
+
+ for (int i = 0; i < objCount; i++) {
+ jobject jobj = env->GetObjectArrayElement(arr, i);
+ Variant v = _jobject_to_variant(env, jobj);
+ varr.push_back(v);
+ env->DeleteLocalRef(jobj);
+ }
+
+ return varr;
+ };
+
+ if (name == "java.util.HashMap" || name == "org.godotengine.godot.Dictionary") {
+
+ Dictionary ret;
+ jclass oclass = c;
+ jmethodID get_keys = env->GetMethodID(oclass, "get_keys", "()[Ljava/lang/String;");
+ jobjectArray arr = (jobjectArray)env->CallObjectMethod(obj, get_keys);
+
+ PackedStringArray keys = _jobject_to_variant(env, arr);
+ env->DeleteLocalRef(arr);
+
+ jmethodID get_values = env->GetMethodID(oclass, "get_values", "()[Ljava/lang/Object;");
+ arr = (jobjectArray)env->CallObjectMethod(obj, get_values);
+
+ Array vals = _jobject_to_variant(env, arr);
+ env->DeleteLocalRef(arr);
+
+ for (int i = 0; i < keys.size(); i++) {
+
+ ret[keys[i]] = vals[i];
+ };
+
+ return ret;
+ };
+
+ env->DeleteLocalRef(c);
+
+ return Variant();
+}
+
+Variant::Type get_jni_type(const String &p_type) {
+
+ static struct {
+ const char *name;
+ Variant::Type type;
+ } _type_to_vtype[] = {
+ { "void", Variant::NIL },
+ { "boolean", Variant::BOOL },
+ { "int", Variant::INT },
+ { "float", Variant::FLOAT },
+ { "double", Variant::FLOAT },
+ { "java.lang.String", Variant::STRING },
+ { "[I", Variant::PACKED_INT32_ARRAY },
+ { "[B", Variant::PACKED_BYTE_ARRAY },
+ { "[F", Variant::PACKED_FLOAT32_ARRAY },
+ { "[Ljava.lang.String;", Variant::PACKED_STRING_ARRAY },
+ { "org.godotengine.godot.Dictionary", Variant::DICTIONARY },
+ { NULL, Variant::NIL }
+ };
+
+ int idx = 0;
+
+ while (_type_to_vtype[idx].name) {
+
+ if (p_type == _type_to_vtype[idx].name)
+ return _type_to_vtype[idx].type;
+
+ idx++;
+ }
+
+ return Variant::NIL;
+}
+
+const char *get_jni_sig(const String &p_type) {
+
+ static struct {
+ const char *name;
+ const char *sig;
+ } _type_to_vtype[] = {
+ { "void", "V" },
+ { "boolean", "Z" },
+ { "int", "I" },
+ { "float", "F" },
+ { "double", "D" },
+ { "java.lang.String", "Ljava/lang/String;" },
+ { "org.godotengine.godot.Dictionary", "Lorg/godotengine/godot/Dictionary;" },
+ { "[I", "[I" },
+ { "[B", "[B" },
+ { "[F", "[F" },
+ { "[Ljava.lang.String;", "[Ljava/lang/String;" },
+ { NULL, "V" }
+ };
+
+ int idx = 0;
+
+ while (_type_to_vtype[idx].name) {
+
+ if (p_type == _type_to_vtype[idx].name)
+ return _type_to_vtype[idx].sig;
+
+ idx++;
+ }
+
+ return "Ljava/lang/Object;";
+}
diff --git a/platform/android/jni_utils.h b/platform/android/jni_utils.h
new file mode 100644
index 0000000000..925340a680
--- /dev/null
+++ b/platform/android/jni_utils.h
@@ -0,0 +1,242 @@
+/*************************************************************************/
+/* jni_utils.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 JNI_UTILS_H
+#define JNI_UTILS_H
+
+#include "string_android.h"
+#include <core/engine.h>
+#include <core/variant.h>
+#include <jni.h>
+
+struct jvalret {
+
+ jobject obj;
+ jvalue val;
+ jvalret() { obj = NULL; }
+};
+
+jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant *p_arg, bool force_jobject = false);
+
+String _get_class_name(JNIEnv *env, jclass cls, bool *array);
+
+Variant _jobject_to_variant(JNIEnv *env, jobject obj);
+
+Variant::Type get_jni_type(const String &p_type);
+
+const char *get_jni_sig(const String &p_type);
+
+class JNISingleton : public Object {
+
+ GDCLASS(JNISingleton, Object);
+
+ struct MethodData {
+
+ jmethodID method;
+ Variant::Type ret_type;
+ Vector<Variant::Type> argtypes;
+ };
+
+ jobject instance;
+ Map<StringName, MethodData> method_map;
+
+public:
+ virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+
+ ERR_FAIL_COND_V(!instance, Variant());
+
+ r_error.error = Callable::CallError::CALL_OK;
+
+ Map<StringName, MethodData>::Element *E = method_map.find(p_method);
+ if (!E) {
+
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+
+ int ac = E->get().argtypes.size();
+ if (ac < p_argcount) {
+
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = ac;
+ return Variant();
+ }
+
+ if (ac > p_argcount) {
+
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = ac;
+ return Variant();
+ }
+
+ for (int i = 0; i < p_argcount; i++) {
+
+ if (!Variant::can_convert(p_args[i]->get_type(), E->get().argtypes[i])) {
+
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = i;
+ r_error.expected = E->get().argtypes[i];
+ }
+ }
+
+ jvalue *v = NULL;
+
+ if (p_argcount) {
+
+ v = (jvalue *)alloca(sizeof(jvalue) * p_argcount);
+ }
+
+ JNIEnv *env = ThreadAndroid::get_env();
+
+ int res = env->PushLocalFrame(16);
+
+ ERR_FAIL_COND_V(res != 0, Variant());
+
+ List<jobject> to_erase;
+ for (int i = 0; i < p_argcount; i++) {
+
+ jvalret vr = _variant_to_jvalue(env, E->get().argtypes[i], p_args[i]);
+ v[i] = vr.val;
+ if (vr.obj)
+ to_erase.push_back(vr.obj);
+ }
+
+ Variant ret;
+
+ switch (E->get().ret_type) {
+
+ case Variant::NIL: {
+
+ env->CallVoidMethodA(instance, E->get().method, v);
+ } break;
+ case Variant::BOOL: {
+
+ ret = env->CallBooleanMethodA(instance, E->get().method, v) == JNI_TRUE;
+ } break;
+ case Variant::INT: {
+
+ ret = env->CallIntMethodA(instance, E->get().method, v);
+ } break;
+ case Variant::FLOAT: {
+
+ ret = env->CallFloatMethodA(instance, E->get().method, v);
+ } break;
+ case Variant::STRING: {
+
+ jobject o = env->CallObjectMethodA(instance, E->get().method, v);
+ ret = jstring_to_string((jstring)o, env);
+ env->DeleteLocalRef(o);
+ } break;
+ case Variant::PACKED_STRING_ARRAY: {
+
+ jobjectArray arr = (jobjectArray)env->CallObjectMethodA(instance, E->get().method, v);
+
+ ret = _jobject_to_variant(env, arr);
+
+ env->DeleteLocalRef(arr);
+ } break;
+ case Variant::PACKED_INT32_ARRAY: {
+
+ jintArray arr = (jintArray)env->CallObjectMethodA(instance, E->get().method, v);
+
+ int fCount = env->GetArrayLength(arr);
+ Vector<int> sarr;
+ sarr.resize(fCount);
+
+ int *w = sarr.ptrw();
+ env->GetIntArrayRegion(arr, 0, fCount, w);
+ ret = sarr;
+ env->DeleteLocalRef(arr);
+ } break;
+ case Variant::PACKED_FLOAT32_ARRAY: {
+
+ jfloatArray arr = (jfloatArray)env->CallObjectMethodA(instance, E->get().method, v);
+
+ int fCount = env->GetArrayLength(arr);
+ Vector<float> sarr;
+ sarr.resize(fCount);
+
+ float *w = sarr.ptrw();
+ env->GetFloatArrayRegion(arr, 0, fCount, w);
+ ret = sarr;
+ env->DeleteLocalRef(arr);
+ } break;
+
+#ifndef _MSC_VER
+#warning This is missing 64 bits arrays, I have no idea how to do it in JNI
+#endif
+ case Variant::DICTIONARY: {
+
+ jobject obj = env->CallObjectMethodA(instance, E->get().method, v);
+ ret = _jobject_to_variant(env, obj);
+ env->DeleteLocalRef(obj);
+
+ } break;
+ default: {
+
+ env->PopLocalFrame(NULL);
+ ERR_FAIL_V(Variant());
+ } break;
+ }
+
+ while (to_erase.size()) {
+ env->DeleteLocalRef(to_erase.front()->get());
+ to_erase.pop_front();
+ }
+
+ env->PopLocalFrame(NULL);
+
+ return ret;
+ }
+
+ jobject get_instance() const {
+
+ return instance;
+ }
+ void set_instance(jobject p_instance) {
+
+ instance = p_instance;
+ }
+
+ void add_method(const StringName &p_name, jmethodID p_method, const Vector<Variant::Type> &p_args, Variant::Type p_ret_type) {
+
+ MethodData md;
+ md.method = p_method;
+ md.argtypes = p_args;
+ md.ret_type = p_ret_type;
+ method_map[p_name] = md;
+ }
+
+ JNISingleton() {
+ instance = NULL;
+ }
+};
+
+#endif // JNI_UTILS_H
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 44c5b5d6b4..8021d6dd07 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -32,8 +32,9 @@
#include "core/io/file_access_buffered_fa.h"
#include "core/project_settings.h"
+#if defined(OPENGL_ENABLED)
#include "drivers/gles2/rasterizer_gles2.h"
-#include "drivers/gles3/rasterizer_gles3.h"
+#endif
#include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h"
#include "file_access_android.h"
@@ -67,8 +68,6 @@ int OS_Android::get_video_driver_count() const {
const char *OS_Android::get_video_driver_name(int p_driver) const {
switch (p_driver) {
- case VIDEO_DRIVER_GLES3:
- return "GLES3";
case VIDEO_DRIVER_GLES2:
return "GLES2";
}
@@ -92,7 +91,7 @@ void OS_Android::initialize_core() {
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
else {
#ifdef USE_JAVA_FILE_ACCESS
- FileAccess::make_default<FileAccessBufferedFA<FileAccessJAndroid> >(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessBufferedFA<FileAccessJAndroid>>(FileAccess::ACCESS_RESOURCES);
#else
//FileAccess::make_default<FileAccessBufferedFA<FileAccessAndroid> >(FileAccess::ACCESS_RESOURCES);
FileAccess::make_default<FileAccessAndroid>(FileAccess::ACCESS_RESOURCES);
@@ -123,46 +122,27 @@ 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 = 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) {
- godot_java->gfx_init(false);
- RasterizerGLES3::register_config();
- RasterizerGLES3::make_current();
- break;
- } else {
- if (GLOBAL_GET("rendering/quality/driver/fallback_to_gles2")) {
- p_video_driver = VIDEO_DRIVER_GLES2;
- use_gl3 = false;
- continue;
- } else {
- gl_initialization_error = true;
- break;
- }
- }
+ // FIXME: Add Vulkan support. Readd fallback code from Vulkan to GLES2?
+
+#if defined(OPENGL_ENABLED)
+ if (video_driver_index == VIDEO_DRIVER_GLES2) {
+ bool gl_initialization_error = false;
+
+ if (RasterizerGLES2::is_viable() == OK) {
+ RasterizerGLES2::register_config();
+ RasterizerGLES2::make_current();
} else {
- if (RasterizerGLES2::is_viable() == OK) {
- godot_java->gfx_init(true);
- RasterizerGLES2::register_config();
- RasterizerGLES2::make_current();
- break;
- } else {
- gl_initialization_error = true;
- break;
- }
+ gl_initialization_error = true;
}
- }
- if (gl_initialization_error) {
- OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.\n"
- "Please try updating your Android version.",
- "Unable to initialize Video driver");
- return ERR_UNAVAILABLE;
+ if (gl_initialization_error) {
+ OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.\n"
+ "Please try updating your Android version.",
+ "Unable to initialize video driver");
+ return ERR_UNAVAILABLE;
+ }
}
+#endif
video_driver_index = p_video_driver;
@@ -178,8 +158,6 @@ Error OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int
input = memnew(InputDefault);
input->set_fallback_mapping(godot_java->get_input_fallback_mapping());
- //power_manager = memnew(PowerAndroid);
-
return OK;
}
@@ -507,9 +485,8 @@ void OS_Android::process_double_tap(Point2 p_pos) {
ev.instance();
ev->set_position(p_pos);
ev->set_global_position(p_pos);
- ev->set_pressed(true);
+ ev->set_pressed(false);
ev->set_doubleclick(true);
- ev->set_button_index(1);
input->parse_input_event(ev);
}
@@ -751,7 +728,6 @@ void OS_Android::vibrate_handheld(int p_duration_ms) {
bool OS_Android::_check_internal_feature_support(const String &p_feature) {
if (p_feature == "mobile") {
- //TODO support etc2 only if GLES3 driver is selected
return true;
}
#if defined(__aarch64__)
@@ -783,6 +759,8 @@ OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_god
//rasterizer = NULL;
use_gl2 = false;
+ visual_server = NULL;
+
godot_java = p_godot_java;
godot_io_java = p_godot_io_java;
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index c2f9a0992f..ec6ffe5438 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -37,7 +37,6 @@
#include "core/os/main_loop.h"
#include "drivers/unix/os_unix.h"
#include "main/input_default.h"
-//#include "power_android.h"
#include "servers/audio_server.h"
#include "servers/visual/rasterizer.h"
@@ -93,8 +92,6 @@ private:
GodotJavaWrapper *godot_java;
GodotIOJavaWrapper *godot_io_java;
- //PowerAndroid *power_manager_func;
-
int video_driver_index;
public:
diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp
new file mode 100644
index 0000000000..7413236e5d
--- /dev/null
+++ b/platform/android/plugin/godot_plugin_jni.cpp
@@ -0,0 +1,115 @@
+/*************************************************************************/
+/* godot_plugin_jni.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 "godot_plugin_jni.h"
+
+#include <core/engine.h>
+#include <core/error_macros.h>
+#include <core/project_settings.h>
+#include <platform/android/jni_utils.h>
+#include <platform/android/string_android.h>
+
+static HashMap<String, JNISingleton *> jni_singletons;
+
+extern "C" {
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jobject obj, jstring name) {
+
+ String singname = jstring_to_string(name, env);
+ JNISingleton *s = memnew(JNISingleton);
+ s->set_instance(env->NewGlobalRef(obj));
+ jni_singletons[singname] = s;
+
+ Engine::get_singleton()->add_singleton(Engine::Singleton(singname, s));
+ ProjectSettings::get_singleton()->set(singname, s);
+}
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args) {
+
+ String singname = jstring_to_string(sname, env);
+
+ ERR_FAIL_COND(!jni_singletons.has(singname));
+
+ JNISingleton *s = jni_singletons.get(singname);
+
+ String mname = jstring_to_string(name, env);
+ String retval = jstring_to_string(ret, env);
+ Vector<Variant::Type> types;
+ String cs = "(";
+
+ int stringCount = env->GetArrayLength(args);
+
+ for (int i = 0; i < stringCount; i++) {
+
+ jstring string = (jstring)env->GetObjectArrayElement(args, i);
+ const String rawString = jstring_to_string(string, env);
+ types.push_back(get_jni_type(rawString));
+ cs += get_jni_sig(rawString);
+ }
+
+ cs += ")";
+ cs += get_jni_sig(retval);
+ jclass cls = env->GetObjectClass(s->get_instance());
+ jmethodID mid = env->GetMethodID(cls, mname.ascii().get_data(), cs.ascii().get_data());
+ if (!mid) {
+
+ print_line("Failed getting method ID " + mname);
+ }
+
+ s->add_method(mname, mid, types, get_jni_type(retval));
+}
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jobject obj, jobjectArray gdnlib_paths) {
+ int gdnlib_count = env->GetArrayLength(gdnlib_paths);
+ if (gdnlib_count == 0) {
+ return;
+ }
+
+ // Retrieve the current list of gdnative libraries.
+ Array singletons = Array();
+ if (ProjectSettings::get_singleton()->has_setting("gdnative/singletons")) {
+ singletons = ProjectSettings::get_singleton()->get("gdnative/singletons");
+ }
+
+ // Insert the libraries provided by the plugin
+ for (int i = 0; i < gdnlib_count; i++) {
+ jstring relative_path = (jstring)env->GetObjectArrayElement(gdnlib_paths, i);
+
+ String path = "res://" + jstring_to_string(relative_path, env);
+ if (!singletons.has(path)) {
+ singletons.push_back(path);
+ }
+ env->DeleteLocalRef(relative_path);
+ }
+
+ // Insert the updated list back into project settings.
+ ProjectSettings::get_singleton()->set("gdnative/singletons", singletons);
+}
+}
diff --git a/platform/android/plugin/godot_plugin_jni.h b/platform/android/plugin/godot_plugin_jni.h
new file mode 100644
index 0000000000..0d613d3bfe
--- /dev/null
+++ b/platform/android/plugin/godot_plugin_jni.h
@@ -0,0 +1,43 @@
+/*************************************************************************/
+/* godot_plugin_jni.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 GODOT_PLUGIN_JNI_H
+#define GODOT_PLUGIN_JNI_H
+
+#include <android/log.h>
+#include <jni.h>
+
+extern "C" {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jobject obj, jstring name);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterMethod(JNIEnv *env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterGDNativeLibraries(JNIEnv *env, jobject obj, jobjectArray gdnlib_paths);
+}
+
+#endif // GODOT_PLUGIN_JNI_H
diff --git a/platform/android/power_android.cpp b/platform/android/power_android.cpp
deleted file mode 100644
index b0a90312e5..0000000000
--- a/platform/android/power_android.cpp
+++ /dev/null
@@ -1,255 +0,0 @@
-/*************************************************************************/
-/* power_android.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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. */
-/*************************************************************************/
-
-/*
-Adapted from corresponding SDL 2.0 code.
-*/
-
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include "power_android.h"
-
-#include "core/error_macros.h"
-
-static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder) {
- if (refholder->m_env) {
- JNIEnv *env = refholder->m_env;
- (*env)->PopLocalFrame(env, NULL);
- --s_active;
- }
-}
-
-static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *func) {
- struct LocalReferenceHolder refholder;
- refholder.m_env = NULL;
- refholder.m_func = func;
- return refholder;
-}
-
-static bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JNIEnv *env) {
- const int capacity = 16;
- if ((*env)->PushLocalFrame(env, capacity) < 0) {
- return false;
- }
- ++s_active;
- refholder->m_env = env;
- return true;
-}
-
-static SDL_bool LocalReferenceHolder_IsActive(void) {
- return s_active > 0;
-}
-
-ANativeWindow *Android_JNI_GetNativeWindow(void) {
- ANativeWindow *anw;
- jobject s;
- JNIEnv *env = Android_JNI_GetEnv();
-
- s = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetNativeSurface);
- anw = ANativeWindow_fromSurface(env, s);
- (*env)->DeleteLocalRef(env, s);
-
- return anw;
-}
-
-/*
- * CODE CHUNK IMPORTED FROM SDL 2.0
- * returns 0 on success or -1 on error (others undefined then)
- * returns truthy or falsy value in plugged, charged and battery
- * returns the value in seconds and percent or -1 if not available
- */
-int Android_JNI_GetPowerInfo(int *plugged, int *charged, int *battery, int *seconds, int *percent) {
- env = Android_JNI_GetEnv();
- refs = LocalReferenceHolder_Setup(__FUNCTION__);
-
- if (!LocalReferenceHolder_Init(&refs, env)) {
- LocalReferenceHolder_Cleanup(&refs);
- return -1;
- }
- mid = (*env)->GetStaticMethodID(env, mActivityClass, "getContext", "()Landroid/content/Context;");
- context = (*env)->CallStaticObjectMethod(env, mActivityClass, mid);
- action = (*env)->NewStringUTF(env, "android.intent.action.BATTERY_CHANGED");
- cls = (*env)->FindClass(env, "android/content/IntentFilter");
- mid = (*env)->GetMethodID(env, cls, "<init>", "(Ljava/lang/String;)V");
- filter = (*env)->NewObject(env, cls, mid, action);
- (*env)->DeleteLocalRef(env, action);
- mid = (*env)->GetMethodID(env, mActivityClass, "registerReceiver", "(Landroid/content/BroadcastReceiver;Landroid/content/IntentFilter;)Landroid/content/Intent;");
- intent = (*env)->CallObjectMethod(env, context, mid, NULL, filter);
- (*env)->DeleteLocalRef(env, filter);
- cls = (*env)->GetObjectClass(env, intent);
- imid = (*env)->GetMethodID(env, cls, "getIntExtra", "(Ljava/lang/String;I)I");
-// Watch out for C89 scoping rules because of the macro
-#define GET_INT_EXTRA(var, key) \
- int var; \
- iname = (*env)->NewStringUTF(env, key); \
- var = (*env)->CallIntMethod(env, intent, imid, iname, -1); \
- (*env)->DeleteLocalRef(env, iname);
- bmid = (*env)->GetMethodID(env, cls, "getBooleanExtra", "(Ljava/lang/String;Z)Z");
-// Watch out for C89 scoping rules because of the macro
-#define GET_BOOL_EXTRA(var, key) \
- int var; \
- bname = (*env)->NewStringUTF(env, key); \
- var = (*env)->CallBooleanMethod(env, intent, bmid, bname, JNI_FALSE); \
- (*env)->DeleteLocalRef(env, bname);
- if (plugged) {
- // Watch out for C89 scoping rules because of the macro
- GET_INT_EXTRA(plug, "plugged") // == BatteryManager.EXTRA_PLUGGED (API 5)
- if (plug == -1) {
- LocalReferenceHolder_Cleanup(&refs);
- return -1;
- }
- // 1 == BatteryManager.BATTERY_PLUGGED_AC
- // 2 == BatteryManager.BATTERY_PLUGGED_USB
- *plugged = (0 < plug) ? 1 : 0;
- }
- if (charged) {
- // Watch out for C89 scoping rules because of the macro
- GET_INT_EXTRA(status, "status") // == BatteryManager.EXTRA_STATUS (API 5)
- if (status == -1) {
- LocalReferenceHolder_Cleanup(&refs);
- return -1;
- }
- // 5 == BatteryManager.BATTERY_STATUS_FULL
- *charged = (status == 5) ? 1 : 0;
- }
- if (battery) {
- GET_BOOL_EXTRA(present, "present") // == BatteryManager.EXTRA_PRESENT (API 5)
- *battery = present ? 1 : 0;
- }
- if (seconds) {
- *seconds = -1; // not possible
- }
- if (percent) {
- int level;
- int scale;
- // Watch out for C89 scoping rules because of the macro
- {
- GET_INT_EXTRA(level_temp, "level") // == BatteryManager.EXTRA_LEVEL (API 5)
- level = level_temp;
- }
- // Watch out for C89 scoping rules because of the macro
- {
- GET_INT_EXTRA(scale_temp, "scale") // == BatteryManager.EXTRA_SCALE (API 5)
- scale = scale_temp;
- }
- if ((level == -1) || (scale == -1)) {
- LocalReferenceHolder_Cleanup(&refs);
- return -1;
- }
- *percent = level * 100 / scale;
- }
- (*env)->DeleteLocalRef(env, intent);
- LocalReferenceHolder_Cleanup(&refs);
-
- return 0;
-}
-
-bool PowerAndroid::GetPowerInfo_Android() {
- int battery;
- int plugged;
- int charged;
-
- if (Android_JNI_GetPowerInfo(&plugged, &charged, &battery, &this->nsecs_left, &this->percent_left) != -1) {
- if (plugged) {
- if (charged) {
- this->power_state = OS::POWERSTATE_CHARGED;
- } else if (battery) {
- this->power_state = OS::POWERSTATE_CHARGING;
- } else {
- this->power_state = OS::POWERSTATE_NO_BATTERY;
- this->nsecs_left = -1;
- this->percent_left = -1;
- }
- } else {
- this->power_state = OS::POWERSTATE_ON_BATTERY;
- }
- } else {
- this->power_state = OS::POWERSTATE_UNKNOWN;
- this->nsecs_left = -1;
- this->percent_left = -1;
- }
-
- return true;
-}
-
-OS::PowerState PowerAndroid::get_power_state() {
- if (GetPowerInfo_Android()) {
- return power_state;
- } else {
- WARN_PRINT("Power management is not implemented on this platform, defaulting to POWERSTATE_UNKNOWN");
- return OS::POWERSTATE_UNKNOWN;
- }
-}
-
-int PowerAndroid::get_power_seconds_left() {
- if (GetPowerInfo_Android()) {
- return nsecs_left;
- } else {
- WARN_PRINT("Power management is not implemented on this platform, defaulting to -1");
- return -1;
- }
-}
-
-int PowerAndroid::get_power_percent_left() {
- if (GetPowerInfo_Android()) {
- return percent_left;
- } else {
- WARN_PRINT("Power management is not implemented on this platform, defaulting to -1");
- return -1;
- }
-}
-
-PowerAndroid::PowerAndroid() :
- nsecs_left(-1),
- percent_left(-1),
- power_state(OS::POWERSTATE_UNKNOWN) {
-}
-
-PowerAndroid::~PowerAndroid() {
-}
diff --git a/platform/android/power_android.h b/platform/android/vulkan/vk_renderer_jni.cpp
index 9f77f3fc6b..3026e7daad 100644
--- a/platform/android/power_android.h
+++ b/platform/android/vulkan/vk_renderer_jni.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* power_android.h */
+/* vk_renderer_jni.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,53 +28,31 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef POWER_ANDROID_H
-#define POWER_ANDROID_H
+#include "vk_renderer_jni.h"
-#include "core/os/os.h"
+extern "C" {
-#include <android/native_window_jni.h>
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkSurfaceCreated(JNIEnv *env, jobject obj, jobject j_surface) {
+ // TODO: complete
+}
-class PowerAndroid {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkSurfaceChanged(JNIEnv *env, jobject object, jobject j_surface, jint width, jint height) {
+ // TODO: complete
+}
- struct LocalReferenceHolder {
- JNIEnv *m_env;
- const char *m_func;
- };
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkResume(JNIEnv *env, jobject obj) {
+ // TODO: complete
+}
-private:
- static struct LocalReferenceHolder refs;
- static JNIEnv *env;
- static jmethodID mid;
- static jobject context;
- static jstring action;
- static jclass cls;
- static jobject filter;
- static jobject intent;
- static jstring iname;
- static jmethodID imid;
- static jstring bname;
- static jmethodID bmid;
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkDrawFrame(JNIEnv *env, jobject obj) {
+ // TODO: complete
+}
- int nsecs_left;
- int percent_left;
- OS::PowerState power_state;
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkPause(JNIEnv *env, jobject obj) {
+ // TODO: complete
+}
- bool GetPowerInfo_Android();
- bool UpdatePowerInfo();
-
-public:
- static int s_active;
-
- PowerAndroid();
- virtual ~PowerAndroid();
- static bool LocalReferenceHolder_Init(struct LocalReferenceHolder *refholder, JNIEnv *env);
- static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *func);
- static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder);
-
- OS::PowerState get_power_state();
- int get_power_seconds_left();
- int get_power_percent_left();
-};
-
-#endif // POWER_ANDROID_H
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkDestroy(JNIEnv *env, jobject obj) {
+ // TODO: complete
+}
+}
diff --git a/platform/android/vulkan/vk_renderer_jni.h b/platform/android/vulkan/vk_renderer_jni.h
new file mode 100644
index 0000000000..017766fea2
--- /dev/null
+++ b/platform/android/vulkan/vk_renderer_jni.h
@@ -0,0 +1,46 @@
+/*************************************************************************/
+/* vk_renderer_jni.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2020 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 VK_RENDERER_JNI_H
+#define VK_RENDERER_JNI_H
+
+#include <android/log.h>
+#include <jni.h>
+
+extern "C" {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkSurfaceCreated(JNIEnv *env, jobject obj, jobject j_surface);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkSurfaceChanged(JNIEnv *env, jobject object, jobject j_surface, jint width, jint height);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkResume(JNIEnv *env, jobject obj);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkDrawFrame(JNIEnv *env, jobject obj);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkPause(JNIEnv *env, jobject obj);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_vulkan_VkRenderer_nativeOnVkDestroy(JNIEnv *env, jobject obj);
+}
+
+#endif // VK_RENDERER_JNI_H