1/**************************************************************************/
2/* java_class_wrapper.h */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifndef JAVA_CLASS_WRAPPER_H
32#define JAVA_CLASS_WRAPPER_H
33
34#include "core/object/ref_counted.h"
35
36#ifdef ANDROID_ENABLED
37#include <android/log.h>
38#include <jni.h>
39#endif
40
41#ifdef ANDROID_ENABLED
42class JavaObject;
43#endif
44
45class JavaClass : public RefCounted {
46 GDCLASS(JavaClass, RefCounted);
47
48#ifdef ANDROID_ENABLED
49 enum ArgumentType{
50 ARG_TYPE_VOID,
51 ARG_TYPE_BOOLEAN,
52 ARG_TYPE_BYTE,
53 ARG_TYPE_CHAR,
54 ARG_TYPE_SHORT,
55 ARG_TYPE_INT,
56 ARG_TYPE_LONG,
57 ARG_TYPE_FLOAT,
58 ARG_TYPE_DOUBLE,
59 ARG_TYPE_STRING, //special case
60 ARG_TYPE_CLASS,
61 ARG_ARRAY_BIT = 1 << 16,
62 ARG_NUMBER_CLASS_BIT = 1 << 17,
63 ARG_TYPE_MASK = (1 << 16) - 1
64 };
65
66 RBMap<StringName, Variant> constant_map;
67
68 struct MethodInfo {
69 bool _static = false;
70 Vector<uint32_t> param_types;
71 Vector<StringName> param_sigs;
72 uint32_t return_type = 0;
73 jmethodID method;
74 };
75
76 _FORCE_INLINE_ static void _convert_to_variant_type(int p_sig, Variant::Type &r_type, float &likelihood) {
77 likelihood = 1.0;
78 r_type = Variant::NIL;
79
80 switch (p_sig) {
81 case ARG_TYPE_VOID:
82 r_type = Variant::NIL;
83 break;
84 case ARG_TYPE_BOOLEAN | ARG_NUMBER_CLASS_BIT:
85 case ARG_TYPE_BOOLEAN:
86 r_type = Variant::BOOL;
87 break;
88 case ARG_TYPE_BYTE | ARG_NUMBER_CLASS_BIT:
89 case ARG_TYPE_BYTE:
90 r_type = Variant::INT;
91 likelihood = 0.1;
92 break;
93 case ARG_TYPE_CHAR | ARG_NUMBER_CLASS_BIT:
94 case ARG_TYPE_CHAR:
95 r_type = Variant::INT;
96 likelihood = 0.2;
97 break;
98 case ARG_TYPE_SHORT | ARG_NUMBER_CLASS_BIT:
99 case ARG_TYPE_SHORT:
100 r_type = Variant::INT;
101 likelihood = 0.3;
102 break;
103 case ARG_TYPE_INT | ARG_NUMBER_CLASS_BIT:
104 case ARG_TYPE_INT:
105 r_type = Variant::INT;
106 likelihood = 1.0;
107 break;
108 case ARG_TYPE_LONG | ARG_NUMBER_CLASS_BIT:
109 case ARG_TYPE_LONG:
110 r_type = Variant::INT;
111 likelihood = 0.5;
112 break;
113 case ARG_TYPE_FLOAT | ARG_NUMBER_CLASS_BIT:
114 case ARG_TYPE_FLOAT:
115 r_type = Variant::FLOAT;
116 likelihood = 1.0;
117 break;
118 case ARG_TYPE_DOUBLE | ARG_NUMBER_CLASS_BIT:
119 case ARG_TYPE_DOUBLE:
120 r_type = Variant::FLOAT;
121 likelihood = 0.5;
122 break;
123 case ARG_TYPE_STRING:
124 r_type = Variant::STRING;
125 break;
126 case ARG_TYPE_CLASS:
127 r_type = Variant::OBJECT;
128 break;
129 case ARG_ARRAY_BIT | ARG_TYPE_VOID:
130 r_type = Variant::NIL;
131 break;
132 case ARG_ARRAY_BIT | ARG_TYPE_BOOLEAN:
133 r_type = Variant::ARRAY;
134 break;
135 case ARG_ARRAY_BIT | ARG_TYPE_BYTE:
136 r_type = Variant::PACKED_BYTE_ARRAY;
137 likelihood = 1.0;
138 break;
139 case ARG_ARRAY_BIT | ARG_TYPE_CHAR:
140 r_type = Variant::PACKED_BYTE_ARRAY;
141 likelihood = 0.5;
142 break;
143 case ARG_ARRAY_BIT | ARG_TYPE_SHORT:
144 r_type = Variant::PACKED_INT32_ARRAY;
145 likelihood = 0.3;
146 break;
147 case ARG_ARRAY_BIT | ARG_TYPE_INT:
148 r_type = Variant::PACKED_INT32_ARRAY;
149 likelihood = 1.0;
150 break;
151 case ARG_ARRAY_BIT | ARG_TYPE_LONG:
152 r_type = Variant::PACKED_INT32_ARRAY;
153 likelihood = 0.5;
154 break;
155 case ARG_ARRAY_BIT | ARG_TYPE_FLOAT:
156 r_type = Variant::PACKED_FLOAT32_ARRAY;
157 likelihood = 1.0;
158 break;
159 case ARG_ARRAY_BIT | ARG_TYPE_DOUBLE:
160 r_type = Variant::PACKED_FLOAT32_ARRAY;
161 likelihood = 0.5;
162 break;
163 case ARG_ARRAY_BIT | ARG_TYPE_STRING:
164 r_type = Variant::PACKED_STRING_ARRAY;
165 break;
166 case ARG_ARRAY_BIT | ARG_TYPE_CLASS:
167 r_type = Variant::ARRAY;
168 break;
169 }
170 }
171
172 _FORCE_INLINE_ static bool _convert_object_to_variant(JNIEnv *env, jobject obj, Variant &var, uint32_t p_sig);
173
174 bool _call_method(JavaObject *p_instance, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error, Variant &ret);
175
176 friend class JavaClassWrapper;
177 HashMap<StringName, List<MethodInfo>> methods;
178 jclass _class;
179#endif
180
181public:
182 virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
183
184 JavaClass();
185};
186
187class JavaObject : public RefCounted {
188 GDCLASS(JavaObject, RefCounted);
189
190#ifdef ANDROID_ENABLED
191 Ref<JavaClass> base_class;
192 friend class JavaClass;
193
194 jobject instance;
195#endif
196
197public:
198 virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
199
200#ifdef ANDROID_ENABLED
201 JavaObject(const Ref<JavaClass> &p_base, jobject *p_instance);
202 ~JavaObject();
203#endif
204};
205
206class JavaClassWrapper : public Object {
207 GDCLASS(JavaClassWrapper, Object);
208
209#ifdef ANDROID_ENABLED
210 RBMap<String, Ref<JavaClass>> class_cache;
211 friend class JavaClass;
212 jclass activityClass;
213 jmethodID findClass;
214 jmethodID getDeclaredMethods;
215 jmethodID getFields;
216 jmethodID getParameterTypes;
217 jmethodID getReturnType;
218 jmethodID getModifiers;
219 jmethodID getName;
220 jmethodID Class_getName;
221 jmethodID Field_getName;
222 jmethodID Field_getModifiers;
223 jmethodID Field_get;
224 jmethodID Boolean_booleanValue;
225 jmethodID Byte_byteValue;
226 jmethodID Character_characterValue;
227 jmethodID Short_shortValue;
228 jmethodID Integer_integerValue;
229 jmethodID Long_longValue;
230 jmethodID Float_floatValue;
231 jmethodID Double_doubleValue;
232 jobject classLoader;
233
234 bool _get_type_sig(JNIEnv *env, jobject obj, uint32_t &sig, String &strsig);
235#endif
236
237 static JavaClassWrapper *singleton;
238
239protected:
240 static void _bind_methods();
241
242public:
243 static JavaClassWrapper *get_singleton() { return singleton; }
244
245 Ref<JavaClass> wrap(const String &p_class);
246
247#ifdef ANDROID_ENABLED
248 JavaClassWrapper(jobject p_activity = nullptr);
249#else
250 JavaClassWrapper();
251#endif
252};
253
254#endif // JAVA_CLASS_WRAPPER_H
255